]> git.decadent.org.uk Git - nfs-utils.git/blob - utils/mount/network.c
mount.nfs: Shorter timeout for TCP connects
[nfs-utils.git] / utils / mount / network.c
1 /*
2  * network.c -- Provide common network functions for NFS mount/umount
3  *
4  * Copyright (C) 2007 Oracle.  All rights reserved.
5  * Copyright (C) 2007 Chuck Lever <chuck.lever@oracle.com>
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public
18  * License along with this program; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 021110-1307, USA.
21  *
22  */
23
24 #include <ctype.h>
25 #include <unistd.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <stdlib.h>
29 #include <errno.h>
30 #include <netdb.h>
31 #include <time.h>
32 #include <rpc/rpc.h>
33 #include <rpc/pmap_prot.h>
34 #include <rpc/pmap_clnt.h>
35 #include <sys/socket.h>
36
37 #include "xcommon.h"
38 #include "mount.h"
39 #include "nls.h"
40 #include "nfs_mount.h"
41 #include "mount_constants.h"
42 #include "network.h"
43
44 #ifdef HAVE_RPCSVC_NFS_PROT_H
45 #include <rpcsvc/nfs_prot.h>
46 #else
47 #include <linux/nfs.h>
48 #define nfsstat nfs_stat
49 #endif
50
51 #ifndef NFS_PORT
52 #define NFS_PORT 2049
53 #endif
54
55 #define PMAP_TIMEOUT    (10)
56 #define CONNECT_TIMEOUT (20)
57 #define MOUNT_TIMEOUT   (30)
58
59 #if SIZEOF_SOCKLEN_T - 0 == 0
60 #define socklen_t unsigned int
61 #endif
62
63 extern int nfs_mount_data_version;
64 extern char *progname;
65 extern int verbose;
66
67 static const unsigned long nfs_to_mnt[] = {
68         0,
69         0,
70         1,
71         3,
72 };
73
74 static const unsigned long mnt_to_nfs[] = {
75         0,
76         2,
77         2,
78         3,
79 };
80
81 /*
82  * Map an NFS version into the corresponding Mountd version
83  */
84 unsigned long nfsvers_to_mnt(const unsigned long vers)
85 {
86         if (vers <= 3)
87                 return nfs_to_mnt[vers];
88         return 0;
89 }
90
91 /*
92  * Map a Mountd version into the corresponding NFS version
93  */
94 static unsigned long mntvers_to_nfs(const unsigned long vers)
95 {
96         if (vers <= 3)
97                 return mnt_to_nfs[vers];
98         return 0;
99 }
100
101 static const unsigned int probe_udp_only[] = {
102         IPPROTO_UDP,
103         0,
104 };
105
106 static const unsigned int probe_udp_first[] = {
107         IPPROTO_UDP,
108         IPPROTO_TCP,
109         0,
110 };
111
112 static const unsigned int probe_tcp_first[] = {
113         IPPROTO_TCP,
114         IPPROTO_UDP,
115         0,
116 };
117
118 static const unsigned long probe_nfs2_only[] = {
119         2,
120         0,
121 };
122
123 static const unsigned long probe_nfs3_first[] = {
124         3,
125         2,
126         0,
127 };
128
129 static const unsigned long probe_mnt1_first[] = {
130         1,
131         2,
132         0,
133 };
134
135 static const unsigned long probe_mnt3_first[] = {
136         3,
137         1,
138         2,
139         0,
140 };
141
142 int nfs_gethostbyname(const char *hostname, struct sockaddr_in *saddr)
143 {
144         struct hostent *hp;
145
146         saddr->sin_family = AF_INET;
147         if (!inet_aton(hostname, &saddr->sin_addr)) {
148                 if ((hp = gethostbyname(hostname)) == NULL) {
149                         nfs_error(_("%s: can't get address for %s\n"),
150                                         progname, hostname);
151                         return 0;
152                 } else {
153                         if (hp->h_length > sizeof(*saddr)) {
154                                 nfs_error(_("%s: got bad hp->h_length\n"),
155                                                 progname);
156                                 hp->h_length = sizeof(*saddr);
157                         }
158                         memcpy(&saddr->sin_addr, hp->h_addr, hp->h_length);
159                 }
160         }
161         return 1;
162 }
163
164 /*
165  * Attempt to connect a socket, but time out after "timeout" seconds.
166  *
167  * On error return, caller closes the socket.
168  */
169 static int connect_to(int fd, struct sockaddr *addr,
170                         socklen_t addrlen, int timeout)
171 {
172         int ret, saved;
173         fd_set rset, wset;
174         struct timeval tv = {
175                 .tv_sec = timeout,
176         };
177
178         saved = fcntl(fd, F_GETFL, 0);
179         fcntl(fd, F_SETFL, saved | O_NONBLOCK);
180
181         ret = connect(fd, addr, addrlen);
182         if (ret < 0 && errno != EINPROGRESS)
183                 return -1;
184         if (ret == 0)
185                 goto out;
186
187         FD_ZERO(&rset);
188         FD_SET(fd, &rset);
189         wset = rset;
190         ret = select(fd + 1, &rset, &wset, NULL, &tv);
191         if (ret == 0) {
192                 errno = ETIMEDOUT;
193                 return -1;
194         }
195         if (FD_ISSET(fd, &rset) || FD_ISSET(fd, &wset)) {
196                 int error;
197                 socklen_t len = sizeof(error);
198                 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0)
199                         return -1;
200                 if (error) {
201                         errno = error;
202                         return -1;
203                 }
204         } else
205                 return -1;
206
207 out:
208         fcntl(fd, F_SETFL, saved);
209         return 0;
210 }
211
212 /*
213  * Create a socket that is locally bound to a reserved or non-reserved
214  * port. For any failures, RPC_ANYSOCK is returned which will cause 
215  * the RPC code to create the socket instead. 
216  */
217 static int get_socket(struct sockaddr_in *saddr, unsigned int p_prot,
218                         unsigned int timeout, int resvp, int conn)
219 {
220         int so, cc, type;
221         struct sockaddr_in laddr;
222         socklen_t namelen = sizeof(laddr);
223
224         type = (p_prot == IPPROTO_UDP ? SOCK_DGRAM : SOCK_STREAM);
225         if ((so = socket (AF_INET, type, p_prot)) < 0)
226                 goto err_socket;
227
228         laddr.sin_family = AF_INET;
229         laddr.sin_port = 0;
230         laddr.sin_addr.s_addr = htonl(INADDR_ANY);
231         if (resvp) {
232                 if (bindresvport(so, &laddr) < 0)
233                         goto err_bindresvport;
234         } else {
235                 cc = bind(so, (struct sockaddr *)&laddr, namelen);
236                 if (cc < 0)
237                         goto err_bind;
238         }
239         if (type == SOCK_STREAM || (conn && type == SOCK_DGRAM)) {
240                 cc = connect_to(so, (struct sockaddr *)saddr, namelen,
241                                 timeout);
242                 if (cc < 0)
243                         goto err_connect;
244         }
245         return so;
246
247 err_socket:
248         rpc_createerr.cf_stat = RPC_SYSTEMERROR;
249         rpc_createerr.cf_error.re_errno = errno;
250         if (verbose) {
251                 nfs_error(_("%s: Unable to create %s socket: errno %d (%s)\n"),
252                         progname, p_prot == IPPROTO_UDP ? _("UDP") : _("TCP"),
253                         errno, strerror(errno));
254         }
255         return RPC_ANYSOCK;
256
257 err_bindresvport:
258         rpc_createerr.cf_stat = RPC_SYSTEMERROR;
259         rpc_createerr.cf_error.re_errno = errno;
260         if (verbose) {
261                 nfs_error(_("%s: Unable to bindresvport %s socket: errno %d"
262                                 " (%s)\n"),
263                         progname, p_prot == IPPROTO_UDP ? _("UDP") : _("TCP"),
264                         errno, strerror(errno));
265         }
266         close(so);
267         return RPC_ANYSOCK;
268
269 err_bind:
270         rpc_createerr.cf_stat = RPC_SYSTEMERROR;
271         rpc_createerr.cf_error.re_errno = errno;
272         if (verbose) {
273                 nfs_error(_("%s: Unable to bind to %s socket: errno %d (%s)\n"),
274                         progname, p_prot == IPPROTO_UDP ? _("UDP") : _("TCP"),
275                         errno, strerror(errno));
276         }
277         close(so);
278         return RPC_ANYSOCK;
279
280 err_connect:
281         rpc_createerr.cf_stat = RPC_SYSTEMERROR;
282         rpc_createerr.cf_error.re_errno = errno;
283         if (verbose) {
284                 nfs_error(_("%s: Unable to connect to %s:%d, errno %d (%s)\n"),
285                         progname, inet_ntoa(saddr->sin_addr),
286                         ntohs(saddr->sin_port), errno, strerror(errno));
287         }
288         close(so);
289         return RPC_ANYSOCK;
290 }
291
292 /*
293  * getport() is very similar to pmap_getport() with the exception that
294  * this version tries to use an ephemeral port, since reserved ports are
295  * not needed for GETPORT queries.  This conserves the very limited
296  * reserved port space, which helps reduce failed socket binds
297  * during mount storms.
298  *
299  * A side effect of calling this function is that rpccreateerr is set.
300  */
301 static unsigned short getport(struct sockaddr_in *saddr,
302                                 unsigned long program,
303                                 unsigned long version,
304                                 unsigned int proto)
305 {
306         unsigned short port = 0;
307         int socket;
308         CLIENT *clnt = NULL;
309         enum clnt_stat stat;
310
311         saddr->sin_port = htons(PMAPPORT);
312
313         /*
314          * Try to get a socket with a non-privileged port.
315          * clnt*create() will create one anyway if this
316          * fails.
317          */
318         socket = get_socket(saddr, proto, PMAP_TIMEOUT, FALSE, FALSE);
319         if (socket == RPC_ANYSOCK) {
320                 if (proto == IPPROTO_TCP && errno == ETIMEDOUT) {
321                         /*
322                          * TCP SYN timed out, so exit now.
323                          */
324                         rpc_createerr.cf_stat = RPC_TIMEDOUT;
325                 }
326                 return 0;
327         }
328
329         switch (proto) {
330         case IPPROTO_UDP:
331                 clnt = clntudp_bufcreate(saddr,
332                                          PMAPPROG, PMAPVERS,
333                                          RETRY_TIMEOUT, &socket,
334                                          RPCSMALLMSGSIZE,
335                                          RPCSMALLMSGSIZE);
336                 break;
337         case IPPROTO_TCP:
338                 clnt = clnttcp_create(saddr, PMAPPROG, PMAPVERS, &socket,
339                                       RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
340                 break;
341         }
342         if (clnt != NULL) {
343                 struct pmap parms = {
344                         .pm_prog        = program,
345                         .pm_vers        = version,
346                         .pm_prot        = proto,
347                 };
348
349                 stat = clnt_call(clnt, PMAPPROC_GETPORT,
350                                  (xdrproc_t)xdr_pmap, (caddr_t)&parms,
351                                  (xdrproc_t)xdr_u_short, (caddr_t)&port,
352                                  TIMEOUT);
353                 if (stat) {
354                         clnt_geterr(clnt, &rpc_createerr.cf_error);
355                         rpc_createerr.cf_stat = stat;
356                 }
357                 clnt_destroy(clnt);
358                 if (stat != RPC_SUCCESS)
359                         port = 0;
360                 else if (port == 0)
361                         rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
362         }
363         if (socket != 1)
364                 close(socket);
365
366         return port;
367 }
368
369 /*
370  * Use the portmapper to discover whether or not the service we want is
371  * available. The lists 'versions' and 'protos' define ordered sequences
372  * of service versions and udp/tcp protocols to probe for.
373  */
374 static int probe_port(clnt_addr_t *server, const unsigned long *versions,
375                         const unsigned int *protos)
376 {
377         struct sockaddr_in *saddr = &server->saddr;
378         struct pmap *pmap = &server->pmap;
379         const unsigned long prog = pmap->pm_prog, *p_vers;
380         const unsigned int prot = (u_int)pmap->pm_prot, *p_prot;
381         const u_short port = (u_short) pmap->pm_port;
382         unsigned long vers = pmap->pm_vers;
383         unsigned short p_port;
384
385         p_prot = prot ? &prot : protos;
386         p_vers = vers ? &vers : versions;
387         rpc_createerr.cf_stat = 0;
388         for (;;) {
389                 p_port = getport(saddr, prog, *p_vers, *p_prot);
390                 if (p_port) {
391                         if (!port || port == p_port) {
392                                 saddr->sin_port = htons(p_port);
393                                 if (verbose) {
394                                         printf(_("%s: trying %s prog %ld vers "
395                                                 "%ld prot %s port %d\n"),
396                                                 progname,
397                                                 inet_ntoa(saddr->sin_addr),
398                                                 prog, *p_vers,
399                                                 *p_prot == IPPROTO_UDP ?
400                                                         "udp" : "tcp",
401                                                 p_port);
402                                 }
403                                 if (clnt_ping(saddr, prog, *p_vers, *p_prot, NULL))
404                                         goto out_ok;
405                                 if (rpc_createerr.cf_stat == RPC_TIMEDOUT)
406                                         goto out_bad;
407                         }
408                 }
409                 if (rpc_createerr.cf_stat != RPC_PROGNOTREGISTERED)
410                         goto out_bad;
411
412                 if (!prot) {
413                         if (*++p_prot)
414                                 continue;
415                         p_prot = protos;
416                 }
417                 if (vers == pmap->pm_vers) {
418                         p_vers = versions;
419                         vers = 0;
420                 }
421                 if (vers || !*++p_vers)
422                         break;
423         }
424
425 out_bad:
426         return 0;
427
428 out_ok:
429         if (!vers)
430                 pmap->pm_vers = *p_vers;
431         if (!prot)
432                 pmap->pm_prot = *p_prot;
433         if (!port)
434                 pmap->pm_port = p_port;
435         rpc_createerr.cf_stat = 0;
436         return 1;
437 }
438
439 static int probe_nfsport(clnt_addr_t *nfs_server)
440 {
441         struct pmap *pmap = &nfs_server->pmap;
442
443         if (pmap->pm_vers && pmap->pm_prot && pmap->pm_port)
444                 return 1;
445
446         if (nfs_mount_data_version >= 4)
447                 return probe_port(nfs_server, probe_nfs3_first, probe_tcp_first);
448         else
449                 return probe_port(nfs_server, probe_nfs2_only, probe_udp_only);
450 }
451
452 static int probe_mntport(clnt_addr_t *mnt_server)
453 {
454         struct pmap *pmap = &mnt_server->pmap;
455
456         if (pmap->pm_vers && pmap->pm_prot && pmap->pm_port)
457                 return 1;
458
459         if (nfs_mount_data_version >= 4)
460                 return probe_port(mnt_server, probe_mnt3_first, probe_udp_first);
461         else
462                 return probe_port(mnt_server, probe_mnt1_first, probe_udp_only);
463 }
464
465 int probe_bothports(clnt_addr_t *mnt_server, clnt_addr_t *nfs_server)
466 {
467         struct pmap *nfs_pmap = &nfs_server->pmap;
468         struct pmap *mnt_pmap = &mnt_server->pmap;
469         struct pmap save_nfs, save_mnt;
470         int res;
471         const unsigned long *probe_vers;
472
473         if (mnt_pmap->pm_vers && !nfs_pmap->pm_vers)
474                 nfs_pmap->pm_vers = mntvers_to_nfs(mnt_pmap->pm_vers);
475         else if (nfs_pmap->pm_vers && !mnt_pmap->pm_vers)
476                 mnt_pmap->pm_vers = nfsvers_to_mnt(nfs_pmap->pm_vers);
477         if (nfs_pmap->pm_vers)
478                 goto version_fixed;
479
480         memcpy(&save_nfs, nfs_pmap, sizeof(save_nfs));
481         memcpy(&save_mnt, mnt_pmap, sizeof(save_mnt));
482         probe_vers = (nfs_mount_data_version >= 4) ?
483                         probe_mnt3_first : probe_mnt1_first;
484
485         for (; *probe_vers; probe_vers++) {
486                 nfs_pmap->pm_vers = mntvers_to_nfs(*probe_vers);
487                 if ((res = probe_nfsport(nfs_server) != 0)) {
488                         mnt_pmap->pm_vers = nfsvers_to_mnt(nfs_pmap->pm_vers);
489                         if ((res = probe_mntport(mnt_server)) != 0)
490                                 return 1;
491                         memcpy(mnt_pmap, &save_mnt, sizeof(*mnt_pmap));
492                 }
493                 switch (rpc_createerr.cf_stat) {
494                 case RPC_PROGVERSMISMATCH:
495                 case RPC_PROGNOTREGISTERED:
496                         break;
497                 default:
498                         goto out_bad;
499                 }
500                 memcpy(nfs_pmap, &save_nfs, sizeof(*nfs_pmap));
501         }
502
503 out_bad:
504         return 0;
505
506 version_fixed:
507         if (!probe_nfsport(nfs_server))
508                 goto out_bad;
509         return probe_mntport(mnt_server);
510 }
511
512 static int probe_statd(void)
513 {
514         struct sockaddr_in addr;
515         unsigned short port;
516
517         memset(&addr, 0, sizeof(addr));
518         addr.sin_family = AF_INET;
519         addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
520         port = getport(&addr, 100024, 1, IPPROTO_UDP);
521
522         if (port == 0)
523                 return 0;
524         addr.sin_port = htons(port);
525
526         if (clnt_ping(&addr, 100024, 1, IPPROTO_UDP, NULL) <= 0)
527                 return 0;
528
529         return 1;
530 }
531
532 /*
533  * Attempt to start rpc.statd
534  */
535 int start_statd(void)
536 {
537 #ifdef START_STATD
538         struct stat stb;
539 #endif
540
541         if (probe_statd())
542                 return 1;
543
544 #ifdef START_STATD
545         if (stat(START_STATD, &stb) == 0) {
546                 if (S_ISREG(stb.st_mode) && (stb.st_mode & S_IXUSR)) {
547                         system(START_STATD);
548                         if (probe_statd())
549                                 return 1;
550                 }
551         }
552 #endif
553
554         return 0;
555 }
556
557 /*
558  * nfs_call_umount - ask the server to remove a share from it's rmtab
559  * @mnt_server: address of RPC MNT program server
560  * @argp: directory path of share to "unmount"
561  *
562  * Returns one if the unmount call succeeded; zero if the unmount
563  * failed for any reason.
564  *
565  * Note that a side effect of calling this function is that rpccreateerr
566  * is set.
567  */
568 int nfs_call_umount(clnt_addr_t *mnt_server, dirpath *argp)
569 {
570         CLIENT *clnt;
571         enum clnt_stat res = 0;
572         int msock;
573
574         switch (mnt_server->pmap.pm_vers) {
575         case 3:
576         case 2:
577         case 1:
578                 if (!probe_mntport(mnt_server))
579                         return 0;
580                 clnt = mnt_openclnt(mnt_server, &msock);
581                 if (!clnt)
582                         return 0;
583                 res = clnt_call(clnt, MOUNTPROC_UMNT,
584                                 (xdrproc_t)xdr_dirpath, (caddr_t)argp,
585                                 (xdrproc_t)xdr_void, NULL,
586                                 TIMEOUT);
587                 mnt_closeclnt(clnt, msock);
588                 if (res == RPC_SUCCESS)
589                         return 1;
590                 break;
591         default:
592                 res = RPC_SUCCESS;
593                 break;
594         }
595
596         if (res == RPC_SUCCESS)
597                 return 1;
598         return 0;
599 }
600
601 CLIENT *mnt_openclnt(clnt_addr_t *mnt_server, int *msock)
602 {
603         struct sockaddr_in *mnt_saddr = &mnt_server->saddr;
604         struct pmap *mnt_pmap = &mnt_server->pmap;
605         CLIENT *clnt = NULL;
606
607         mnt_saddr->sin_port = htons((u_short)mnt_pmap->pm_port);
608         *msock = get_socket(mnt_saddr, mnt_pmap->pm_prot, MOUNT_TIMEOUT,
609                                 TRUE, FALSE);
610         if (*msock == RPC_ANYSOCK) {
611                 if (rpc_createerr.cf_error.re_errno == EADDRINUSE)
612                         /*
613                          * Probably in-use by a TIME_WAIT connection,
614                          * It is worth waiting a while and trying again.
615                          */
616                         rpc_createerr.cf_stat = RPC_TIMEDOUT;
617                 return NULL;
618         }
619
620         switch (mnt_pmap->pm_prot) {
621         case IPPROTO_UDP:
622                 clnt = clntudp_bufcreate(mnt_saddr,
623                                          mnt_pmap->pm_prog, mnt_pmap->pm_vers,
624                                          RETRY_TIMEOUT, msock,
625                                          MNT_SENDBUFSIZE, MNT_RECVBUFSIZE);
626                 break;
627         case IPPROTO_TCP:
628                 clnt = clnttcp_create(mnt_saddr,
629                                       mnt_pmap->pm_prog, mnt_pmap->pm_vers,
630                                       msock,
631                                       MNT_SENDBUFSIZE, MNT_RECVBUFSIZE);
632                 break;
633         }
634         if (clnt) {
635                 /* try to mount hostname:dirname */
636                 clnt->cl_auth = authunix_create_default();
637                 return clnt;
638         }
639         return NULL;
640 }
641
642 void mnt_closeclnt(CLIENT *clnt, int msock)
643 {
644         auth_destroy(clnt->cl_auth);
645         clnt_destroy(clnt);
646         close(msock);
647 }
648
649 /*
650  * Sigh... getport() doesn't actually check the version number.
651  * In order to make sure that the server actually supports the service
652  * we're requesting, we open and RPC client, and fire off a NULL
653  * RPC call.
654  */
655 int clnt_ping(struct sockaddr_in *saddr, const unsigned long prog,
656                 const unsigned long vers, const unsigned int prot,
657                 struct sockaddr_in *caddr)
658 {
659         CLIENT *clnt = NULL;
660         int sock, stat;
661         static char clnt_res;
662         struct sockaddr dissolve;
663
664         rpc_createerr.cf_stat = stat = errno = 0;
665         sock = get_socket(saddr, prot, CONNECT_TIMEOUT, FALSE, TRUE);
666         if (sock == RPC_ANYSOCK) {
667                 if (errno == ETIMEDOUT) {
668                         /*
669                          * TCP timeout. Bubble up the error to see 
670                          * how it should be handled.
671                          */
672                         rpc_createerr.cf_stat = RPC_TIMEDOUT;
673                 }
674                 return 0;
675         }
676
677         if (caddr) {
678                 /* Get the address of our end of this connection */
679                 socklen_t len = sizeof(*caddr);
680                 if (getsockname(sock, caddr, &len) != 0)
681                         caddr->sin_family = 0;
682         }
683
684         switch(prot) {
685         case IPPROTO_UDP:
686                 /* The socket is connected (so we could getsockname successfully),
687                  * but some servers on multi-homed hosts reply from
688                  * the wrong address, so if we stay connected, we lose the reply.
689                  */
690                 dissolve.sa_family = AF_UNSPEC;
691                 connect(sock, &dissolve, sizeof(dissolve));
692
693                 clnt = clntudp_bufcreate(saddr, prog, vers,
694                                          RETRY_TIMEOUT, &sock,
695                                          RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
696                 break;
697         case IPPROTO_TCP:
698                 clnt = clnttcp_create(saddr, prog, vers, &sock,
699                                       RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
700                 break;
701         }
702         if (!clnt) {
703                 close(sock);
704                 return 0;
705         }
706         memset(&clnt_res, 0, sizeof(clnt_res));
707         stat = clnt_call(clnt, NULLPROC,
708                          (xdrproc_t)xdr_void, (caddr_t)NULL,
709                          (xdrproc_t)xdr_void, (caddr_t)&clnt_res,
710                          TIMEOUT);
711         if (stat) {
712                 clnt_geterr(clnt, &rpc_createerr.cf_error);
713                 rpc_createerr.cf_stat = stat;
714         }
715         clnt_destroy(clnt);
716         close(sock);
717
718         if (stat == RPC_SUCCESS)
719                 return 1;
720         else
721                 return 0;
722 }