Contents of /trunk/mkinitrd-magellan/klibc/usr/kinit/nfsmount/sunrpc.c
Parent Directory | 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)
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 | } |