Annotation of /trunk/mkinitrd-magellan/klibc/usr/kinit/nfsmount/sunrpc.c
Parent Directory | Revision Log
Revision 815 -
(hide 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)
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 | niro | 532 | #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 | niro | 815 | rpc->call->hdr.frag_hdr = htonl(LAST_FRAG | (rpc->call_len - 4)); |
59 | niro | 532 | 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 | } |