Magellan Linux

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

Parent Directory Parent Directory | Revision Log Revision Log


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