Magellan Linux

Contents of /trunk/mkinitrd-magellan/klibc/usr/kinit/nfsmount/sunrpc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 815 - (show annotations) (download)
Fri Apr 24 18:32:46 2009 UTC (15 years ago) by niro
File MIME type: text/plain
File size: 4993 byte(s)
-updated to klibc-1.5.15
1 #include <sys/types.h>
2 #include <sys/socket.h>
3 #include <netinet/in.h>
4 #include <errno.h>
5 #include <poll.h>
6 #include <stdio.h>
7 #include <string.h>
8 #include <stdlib.h>
9
10 #include "nfsmount.h"
11 #include "sunrpc.h"
12
13 /*
14 * The magic offset is needed here because RPC over TCP includes a
15 * field that RPC over UDP doesn't. Luvverly.
16 */
17 static int rpc_do_reply(struct client *clnt, struct rpc *rpc, size_t off)
18 {
19 int ret;
20
21 if ((ret = read(clnt->sock,
22 ((char *)rpc->reply) + off,
23 rpc->reply_len - off)) == -1) {
24 perror("read");
25 goto bail;
26 } else if (ret < sizeof(struct rpc_reply) - off) {
27 fprintf(stderr, "short read: %d < %zu\n", ret,
28 sizeof(struct rpc_reply) - off);
29 goto bail;
30 }
31 rpc->reply_len = ret + off;
32
33 if ((!off && !(ntohl(rpc->reply->hdr.frag_hdr) & LAST_FRAG)) ||
34 rpc->reply->hdr.udp.xid != rpc->call->hdr.udp.xid ||
35 rpc->reply->hdr.udp.msg_type != htonl(RPC_REPLY)) {
36 fprintf(stderr, "bad reply\n");
37 goto bail;
38 }
39
40 if (ntohl(rpc->reply->state) != REPLY_OK) {
41 fprintf(stderr, "rpc failed: %d\n", ntohl(rpc->reply->state));
42 goto bail;
43 }
44
45 ret = 0;
46 goto done;
47
48 bail:
49 ret = -1;
50 done:
51 return ret;
52 }
53
54 static void rpc_header(struct client *clnt, struct rpc *rpc)
55 {
56 (void)clnt;
57
58 rpc->call->hdr.frag_hdr = htonl(LAST_FRAG | (rpc->call_len - 4));
59 rpc->call->hdr.udp.xid = lrand48();
60 rpc->call->hdr.udp.msg_type = htonl(RPC_CALL);
61 rpc->call->rpc_vers = htonl(2);
62 }
63
64 static int rpc_call_tcp(struct client *clnt, struct rpc *rpc)
65 {
66 int ret;
67
68 rpc_header(clnt, rpc);
69
70 if ((ret = write(clnt->sock, rpc->call, rpc->call_len)) == -1) {
71 perror("write");
72 goto bail;
73 } else if (ret < rpc->call_len) {
74 fprintf(stderr, "short write: %d < %zu\n", ret, rpc->call_len);
75 goto bail;
76 }
77
78 ret = rpc_do_reply(clnt, rpc, 0);
79 goto done;
80
81 bail:
82 ret = -1;
83
84 done:
85 return ret;
86 }
87
88 static int rpc_call_udp(struct client *clnt, struct rpc *rpc)
89 {
90 #define NR_FDS 1
91 #define TIMEOUT_MS 3000
92 #define MAX_TRIES 100
93 #define UDP_HDR_OFF (sizeof(struct rpc_header) - sizeof(struct rpc_udp_header))
94 struct pollfd fds[NR_FDS];
95 int ret = -1;
96 int i;
97
98 rpc_header(clnt, rpc);
99
100 fds[0].fd = clnt->sock;
101 fds[0].events = POLLRDNORM;
102
103 rpc->call_len -= UDP_HDR_OFF;
104
105 for (i = 0; i < MAX_TRIES; i++) {
106 int timeout_ms = TIMEOUT_MS + (lrand48() % (TIMEOUT_MS / 2));
107 if ((ret = write(clnt->sock,
108 ((char *)rpc->call) + UDP_HDR_OFF,
109 rpc->call_len)) == -1) {
110 perror("write");
111 goto bail;
112 } else if (ret < rpc->call_len) {
113 fprintf(stderr, "short write: %d < %zu\n", ret,
114 rpc->call_len);
115 goto bail;
116 }
117 for (; i < MAX_TRIES; i++) {
118 if ((ret = poll(fds, NR_FDS, timeout_ms)) == -1) {
119 perror("poll");
120 goto bail;
121 }
122 if (ret == 0) {
123 DEBUG(("Timeout #%d\n", i + 1));
124 break;
125 }
126 if ((ret = rpc_do_reply(clnt, rpc, UDP_HDR_OFF)) == 0) {
127 goto done;
128 } else {
129 DEBUG(("Failed on try #%d - retrying\n",
130 i + 1));
131 }
132 }
133 }
134
135 bail:
136 ret = -1;
137
138 done:
139 return ret;
140 }
141
142 struct client *tcp_client(uint32_t server, uint16_t port, uint32_t flags)
143 {
144 struct client *clnt = malloc(sizeof(*clnt));
145 struct sockaddr_in addr;
146 int sock;
147
148 if (clnt == NULL) {
149 perror("malloc");
150 goto bail;
151 }
152
153 memset(clnt, 0, sizeof(clnt));
154
155 if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
156 perror("socket");
157 goto bail;
158 }
159
160 if ((flags & CLI_RESVPORT) && bindresvport(sock, 0) == -1) {
161 perror("bindresvport");
162 goto bail;
163 }
164
165 clnt->sock = sock;
166 clnt->call_stub = rpc_call_tcp;
167
168 addr.sin_family = AF_INET;
169 addr.sin_port = htons(port);
170 addr.sin_addr.s_addr = server;
171
172 if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
173 perror("connect");
174 goto bail;
175 }
176
177 goto done;
178 bail:
179 if (clnt) {
180 free(clnt);
181 clnt = NULL;
182 }
183 done:
184 return clnt;
185 }
186
187 struct client *udp_client(uint32_t server, uint16_t port, uint32_t flags)
188 {
189 struct client *clnt = malloc(sizeof(*clnt));
190 struct sockaddr_in addr;
191 int sock;
192
193 if (clnt == NULL) {
194 perror("malloc");
195 goto bail;
196 }
197
198 memset(clnt, 0, sizeof(clnt));
199
200 if ((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
201 perror("socket");
202 goto bail;
203 }
204
205 if ((flags & CLI_RESVPORT) && bindresvport(sock, 0) == -1) {
206 perror("bindresvport");
207 goto bail;
208 } else {
209 struct sockaddr_in me;
210
211 me.sin_family = AF_INET;
212 me.sin_port = 0;
213 me.sin_addr.s_addr = INADDR_ANY;
214
215 if (0 && bind(sock, (struct sockaddr *)&me, sizeof(me)) == -1) {
216 perror("bind");
217 goto bail;
218 }
219 }
220
221 clnt->sock = sock;
222 clnt->call_stub = rpc_call_udp;
223
224 addr.sin_family = AF_INET;
225 addr.sin_port = htons(port);
226 addr.sin_addr.s_addr = server;
227
228 if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
229 perror("connect");
230 goto bail;
231 }
232
233 goto done;
234 bail:
235 if (clnt) {
236 free(clnt);
237 clnt = NULL;
238 }
239 done:
240 return clnt;
241 }
242
243 void client_free(struct client *c)
244 {
245 if (c->sock != -1)
246 close(c->sock);
247 free(c);
248 }
249
250 int rpc_call(struct client *client, struct rpc *rpc)
251 {
252 return client->call_stub(client, rpc);
253 }