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