]>
Commit | Line | Data |
---|---|---|
e3a22658 | 1 | diff -Nur autofs-4.1.3.orig/lib/rpc_subs.c autofs-4.1.3/lib/rpc_subs.c |
2 | --- autofs-4.1.3.orig/lib/rpc_subs.c 2004-06-14 21:55:29.000000000 +0800 | |
3 | +++ autofs-4.1.3/lib/rpc_subs.c 2004-06-14 21:54:35.000000000 +0800 | |
4 | @@ -1,38 +1,284 @@ | |
5 | +/* ----------------------------------------------------------------------- * | |
6 | + * | |
7 | + * rpc_subs.c - routines for rpc discovery | |
8 | + * | |
9 | + * Copyright 2004 Ian Kent <raven@themaw.net> - All Rights Reserved | |
10 | + * Copyright 2004 Jeff Moyer <jmoyer@redaht.com> - All Rights Reserved | |
11 | + * | |
12 | + * This program is free software; you can redistribute it and/or modify | |
13 | + * it under the terms of the GNU General Public License as published by | |
14 | + * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139, | |
15 | + * USA; either version 2 of the License, or (at your option) any later | |
16 | + * version; incorporated herein by reference. | |
17 | + * | |
18 | + * ----------------------------------------------------------------------- */ | |
19 | + | |
20 | #include <rpc/rpc.h> | |
21 | +#include <rpc/pmap_prot.h> | |
22 | #include <nfs/nfs.h> | |
23 | #include <linux/nfs2.h> | |
24 | #include <linux/nfs3.h> | |
25 | #include <rpc/xdr.h> | |
26 | - | |
27 | + | |
28 | +#include <unistd.h> | |
29 | +#include <sys/socket.h> | |
30 | +#include <netdb.h> | |
31 | +#include <netinet/in.h> | |
32 | +#include <sys/fcntl.h> | |
33 | +#include <errno.h> | |
34 | + | |
35 | #include "automount.h" | |
36 | ||
37 | +#define PMAP_TOUT_UDP 2 | |
38 | +#define PMAP_TOUT_TCP 3 | |
39 | + | |
40 | +struct conn_info { | |
41 | + const char *host; | |
42 | + unsigned short port; | |
43 | + unsigned long program; | |
44 | + unsigned long version; | |
45 | + struct protoent *proto; | |
46 | + unsigned int send_sz; | |
47 | + unsigned int recv_sz; | |
48 | + struct timeval timeout; | |
49 | +}; | |
50 | + | |
51 | +/* | |
52 | + * Create a UDP RPC client | |
53 | + */ | |
54 | +static CLIENT* create_udp_client(struct conn_info *info) | |
55 | +{ | |
56 | + int fd = -1; | |
57 | + CLIENT *client; | |
58 | + struct sockaddr_in addr; | |
59 | + struct hostent *hp; | |
60 | + | |
61 | + if (info->proto->p_proto != IPPROTO_UDP) | |
62 | + return NULL; | |
63 | + | |
64 | + memset(&addr, 0, sizeof(addr)); | |
65 | + | |
66 | + hp = gethostbyname(info->host); | |
67 | + if (!hp) | |
68 | + return NULL; | |
69 | + | |
70 | + addr.sin_family = AF_INET; | |
71 | + addr.sin_port = htons(info->port); | |
72 | + memcpy(&addr.sin_addr.s_addr, hp->h_addr, hp->h_length); | |
73 | + | |
74 | + client = clntudp_bufcreate(&addr, | |
75 | + info->program, info->version, | |
76 | + info->timeout, &fd, | |
77 | + info->send_sz, info->recv_sz); | |
78 | + | |
79 | + return client; | |
80 | +} | |
81 | + | |
82 | +/* | |
83 | + * Perform a non-blocking connect on the socket fd. | |
84 | + * | |
85 | + * tout contains the timeout. It will be modified to contain the time | |
86 | + * remaining (i.e. time provided - time elasped). | |
87 | + */ | |
88 | +static int connect_nb(int fd, struct sockaddr_in *addr, struct timeval *tout) | |
89 | +{ | |
90 | + int flags, ret, len; | |
91 | + fd_set wset, rset; | |
92 | + | |
93 | + flags = fcntl(fd, F_GETFL, 0); | |
94 | + if (flags < 0) | |
95 | + return -1; | |
96 | + | |
97 | + ret = fcntl(fd, F_SETFL, flags | O_NONBLOCK); | |
98 | + if (ret < 0) | |
99 | + return -1; | |
100 | + | |
101 | + /* | |
102 | + * From here on subsequent sys calls could change errno so | |
103 | + * we set ret = -errno to capture it in case we decide to | |
104 | + * use it later. | |
105 | + */ | |
106 | + ret = connect(fd, (struct sockaddr *)addr, sizeof(struct sockaddr)); | |
107 | + if (ret < 0 && errno != EINPROGRESS) { | |
108 | + ret = -errno; | |
109 | + goto done; | |
110 | + } | |
111 | + | |
112 | + if (ret == 0) | |
113 | + goto done; | |
114 | + | |
115 | + /* now wait */ | |
116 | + FD_ZERO(&rset); | |
117 | + FD_SET(fd, &rset); | |
118 | + wset = rset; | |
119 | + | |
120 | + ret = select(fd + 1, &rset, &wset, NULL, tout); | |
121 | + if (ret <= 0) { | |
122 | + if (ret == 0) | |
123 | + ret = -ETIMEDOUT; | |
124 | + else | |
125 | + ret = -errno; | |
126 | + goto done; | |
127 | + } | |
128 | + | |
129 | + if (FD_ISSET(fd, &rset) || FD_ISSET(fd, &wset)) { | |
130 | + int stat; | |
131 | + | |
132 | + len = sizeof(ret); | |
133 | + stat = getsockopt(fd, SOL_SOCKET, SO_ERROR, &ret, &len); | |
134 | + if (stat < 0) { | |
135 | + ret = -errno; | |
136 | + goto done; | |
137 | + } | |
138 | + | |
139 | + /* Oops - something wrong with connect */ | |
140 | + if (ret) | |
141 | + ret = -ret; | |
142 | + } | |
143 | + | |
144 | +done: | |
145 | + fcntl(fd, F_SETFL, flags); | |
146 | + return ret; | |
147 | +} | |
148 | + | |
149 | +/* | |
150 | + * Create a TCP RPC client using non-blocking connect | |
151 | + */ | |
152 | +static CLIENT* create_tcp_client(struct conn_info *info) | |
153 | +{ | |
154 | + int fd; | |
155 | + CLIENT *client; | |
156 | + struct sockaddr_in addr; | |
157 | + struct hostent *hp; | |
158 | + int ret; | |
159 | + | |
160 | + if (info->proto->p_proto != IPPROTO_TCP) | |
161 | + return NULL; | |
162 | + | |
163 | + memset(&addr, 0, sizeof(addr)); | |
164 | + | |
165 | + hp = gethostbyname(info->host); | |
166 | + if (!hp) | |
167 | + return NULL; | |
168 | + | |
169 | + addr.sin_family = AF_INET; | |
170 | + addr.sin_port = htons(info->port); | |
171 | + memcpy(&addr.sin_addr.s_addr, hp->h_addr, hp->h_length); | |
172 | + | |
173 | + fd = socket(PF_INET, SOCK_STREAM, info->proto->p_proto); | |
174 | + if (fd < 0) | |
175 | + return NULL; | |
176 | + | |
177 | + ret = connect_nb(fd, &addr, &info->timeout); | |
178 | + if (ret < 0) | |
179 | + goto out_close; | |
180 | + | |
181 | + client = clnttcp_create(&addr, | |
182 | + info->program, info->version, &fd, | |
183 | + info->send_sz, info->recv_sz); | |
184 | + if (!client) | |
185 | + goto out_close; | |
186 | + | |
187 | + return client; | |
188 | + | |
189 | +out_close: | |
190 | + close(fd); | |
191 | + return NULL; | |
192 | +} | |
193 | + | |
194 | +static unsigned short portmap_getport(struct conn_info *info) | |
195 | +{ | |
196 | + struct conn_info pmap_info; | |
197 | + unsigned short port = 0; | |
198 | + CLIENT *client; | |
199 | + enum clnt_stat stat; | |
200 | + struct pmap parms; | |
201 | + | |
202 | + pmap_info.host = info->host; | |
203 | + pmap_info.port = PMAPPORT; | |
204 | + pmap_info.program = PMAPPROG; | |
205 | + pmap_info.version = PMAPVERS; | |
206 | + pmap_info.proto = info->proto; | |
207 | + pmap_info.send_sz = RPCSMALLMSGSIZE; | |
208 | + pmap_info.recv_sz = RPCSMALLMSGSIZE; | |
209 | + pmap_info.timeout.tv_sec = PMAP_TOUT_UDP; | |
210 | + pmap_info.timeout.tv_usec = 0; | |
211 | + | |
212 | + if (info->proto->p_proto == IPPROTO_TCP) { | |
213 | + pmap_info.timeout.tv_sec = PMAP_TOUT_TCP; | |
214 | + client = create_tcp_client(&pmap_info); | |
215 | + } else | |
216 | + client = create_udp_client(&pmap_info); | |
217 | + | |
218 | + if (!client) | |
219 | + return 0; | |
220 | + | |
221 | + parms.pm_prog = info->program; | |
222 | + parms.pm_vers = info->version; | |
223 | + parms.pm_prot = info->proto->p_proto; | |
224 | + parms.pm_port = 0; | |
225 | + | |
226 | + stat = clnt_call(client, PMAPPROC_GETPORT, | |
227 | + (xdrproc_t) xdr_pmap, (caddr_t) &parms, | |
228 | + (xdrproc_t) xdr_u_short, (caddr_t) &port, | |
229 | + pmap_info.timeout); | |
230 | + | |
231 | + clnt_destroy(client); | |
232 | + | |
233 | + if (stat != RPC_SUCCESS) | |
234 | + return 0; | |
235 | + | |
236 | + return port; | |
237 | +} | |
238 | + | |
239 | static int rpc_ping_proto(const char *host, | |
240 | - unsigned long nfs_version, const char *proto, | |
241 | + unsigned long nfs_version, | |
242 | + const char *proto, | |
243 | long seconds, long micros) | |
244 | { | |
245 | + struct conn_info info; | |
246 | CLIENT *client; | |
247 | - struct timeval tout; | |
248 | enum clnt_stat stat; | |
249 | + struct protoent *prot; | |
250 | + | |
251 | + prot = getprotobyname(proto); | |
252 | + if (!prot) | |
253 | + return 1; | |
254 | + | |
255 | + info.host = host; | |
256 | + info.program = NFS_PROGRAM; | |
257 | + info.version = nfs_version; | |
258 | + info.proto = prot; | |
259 | + info.send_sz = 0; | |
260 | + info.recv_sz = 0; | |
261 | + info.timeout.tv_sec = seconds; | |
262 | + info.timeout.tv_usec = micros; | |
263 | ||
264 | - client = clnt_create(host, NFS_PROGRAM, nfs_version, proto); | |
265 | - if (client == NULL) { | |
266 | + info.port = portmap_getport(&info); | |
267 | + if (!info.port) | |
268 | return 0; | |
269 | - } | |
270 | ||
271 | - tout.tv_sec = seconds; | |
272 | - tout.tv_usec = micros; | |
273 | + if (prot->p_proto == IPPROTO_UDP) { | |
274 | + info.send_sz = UDPMSGSIZE; | |
275 | + info.recv_sz = UDPMSGSIZE; | |
276 | + client = create_udp_client(&info); | |
277 | + } else | |
278 | + client = create_tcp_client(&info); | |
279 | + | |
280 | + if (!client) | |
281 | + return 0; | |
282 | ||
283 | - clnt_control(client, CLSET_TIMEOUT, (char *)&tout); | |
284 | - clnt_control(client, CLSET_RETRY_TIMEOUT, (char *)&tout); | |
285 | + clnt_control(client, CLSET_TIMEOUT, (char *) &info.timeout); | |
286 | + clnt_control(client, CLSET_RETRY_TIMEOUT, (char *) &info.timeout); | |
287 | ||
288 | stat = clnt_call(client, NFSPROC_NULL, | |
289 | - (xdrproc_t)xdr_void, 0, (xdrproc_t)xdr_void, 0, tout); | |
290 | + (xdrproc_t) xdr_void, 0, (xdrproc_t) xdr_void, 0, | |
291 | + info.timeout); | |
292 | ||
293 | clnt_destroy(client); | |
294 | ||
295 | - if (stat != RPC_SUCCESS) { | |
296 | + if (stat != RPC_SUCCESS) | |
297 | return 0; | |
298 | - } | |
299 | ||
300 | return 1; | |
301 | } | |
302 | @@ -108,10 +354,39 @@ | |
303 | ||
304 | taken = elapsed(start, end); | |
305 | ||
306 | - if (result != NULL) { | |
307 | + if (result != NULL) | |
308 | *result = taken; | |
309 | - } | |
310 | ||
311 | return status; | |
312 | } | |
313 | ||
314 | +#if 0 | |
315 | +#include <stdio.h> | |
316 | + | |
317 | +int main(int argc, char **argv) | |
318 | +{ | |
319 | + int ret; | |
320 | + double res = 0.0; | |
321 | + | |
322 | + ret = rpc_ping("budgie", 10, 0); | |
323 | + printf("ret = %d\n", ret); | |
324 | + | |
325 | + res = 0.0; | |
326 | + ret = rpc_time("raven", NFS2_VERSION, RPC_PING_TCP, 10, 0, &res); | |
327 | + printf("v2 tcp ret = %d, res = %f\n", ret, res); | |
328 | + | |
329 | + res = 0.0; | |
330 | + ret = rpc_time("raven", NFS3_VERSION, RPC_PING_TCP, 10, 0, &res); | |
331 | + printf("v3 tcp ret = %d, res = %f\n", ret, res); | |
332 | + | |
333 | + res = 0.0; | |
334 | + ret = rpc_time("raven", NFS2_VERSION, RPC_PING_UDP, 10, 0, &res); | |
335 | + printf("v2 udp ret = %d, res = %f\n", ret, res); | |
336 | + | |
337 | + res = 0.0; | |
338 | + ret = rpc_time("raven", NFS3_VERSION, RPC_PING_UDP, 10, 0, &res); | |
339 | + printf("v3 udp ret = %d, res = %f\n", ret, res); | |
340 | + | |
341 | + exit(0); | |
342 | +} | |
343 | +#endif |