Annotation of /trunk/mkinitrd-magellan/klibc/usr/kinit/nfsmount/sunrpc.c
Parent Directory | Revision Log
Revision 1297 -
(hide 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)
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 | niro | 532 | #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 | niro | 815 | rpc->call->hdr.frag_hdr = htonl(LAST_FRAG | (rpc->call_len - 4)); |
58 | niro | 532 | 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 | niro | 1122 | dprintf("Timeout #%d\n", i + 1); |
123 | niro | 532 | break; |
124 | } | ||
125 | if ((ret = rpc_do_reply(clnt, rpc, UDP_HDR_OFF)) == 0) { | ||
126 | goto done; | ||
127 | } else { | ||
128 | niro | 1122 | dprintf("Failed on try #%d - retrying\n", |
129 | i + 1); | ||
130 | niro | 532 | } |
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 | } |