(linenum→info "unix/slp.c:2238")

glibc/2.7/nis/nis_findserv.c

    1: /* Copyright (C) 1997, 1998, 2000, 2001 Free Software Foundation, Inc.
    2:    This file is part of the GNU C Library.
    3:    Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997.
    4: 
    5:    The GNU C Library is free software; you can redistribute it and/or
    6:    modify it under the terms of the GNU Lesser General Public
    7:    License as published by the Free Software Foundation; either
    8:    version 2.1 of the License, or (at your option) any later version.
    9: 
   10:    The GNU C Library is distributed in the hope that it will be useful,
   11:    but WITHOUT ANY WARRANTY; without even the implied warranty of
   12:    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   13:    Lesser General Public License for more details.
   14: 
   15:    You should have received a copy of the GNU Lesser General Public
   16:    License along with the GNU C Library; if not, write to the Free
   17:    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   18:    02111-1307 USA.  */
   19: 
   20: #include <string.h>
   21: #include <time.h>
   22: #include <unistd.h>
   23: #include <sys/ioctl.h>
   24: #include <sys/socket.h>
   25: #include <rpc/pmap_prot.h>
   26: #include <rpc/pmap_clnt.h>
   27: #include <rpcsvc/nis.h>
   28: 
   29: #include "nis_intern.h"
   30: 
   31: /* Private data kept per client handle, from sunrpc/clnt_udp.c */
   32: struct cu_data
   33:   {
   34:     int cu_sock;
   35:     bool_t cu_closeit;
   36:     struct sockaddr_in cu_raddr;
   37:     int cu_rlen;
   38:     struct timeval cu_wait;
   39:     struct timeval cu_total;
   40:     struct rpc_err cu_error;
   41:     XDR cu_outxdrs;
   42:     u_int cu_xdrpos;
   43:     u_int cu_sendsz;
   44:     char *cu_outbuf;
   45:     u_int cu_recvsz;
   46:     char cu_inbuf[1];
   47:   };
   48: 
   49: 
   50: /* The following is the original routine from sunrpc/pm_getport.c.
   51:    The only change is the much shorter timeout. */
   52: /*
   53:  * pmap_getport.c
   54:  * Client interface to pmap rpc service.
   55:  *
   56:  * Copyright (C) 1984, Sun Microsystems, Inc.
   57:  */
   58: 
   59: /*
   60:  * Find the mapped port for program,version.
   61:  * Calls the pmap service remotely to do the lookup.
   62:  * Returns 0 if no map exists.
   63:  */
   64: u_short
   65: __pmap_getnisport (struct sockaddr_in *address, u_long program,
   66:                    u_long version, u_int protocol)
   67: {
   68:   const struct timeval timeout = {1, 0};
   69:   const struct timeval tottimeout = {1, 0};
   70:   u_short port = 0;
   71:   int socket = -1;
   72:   CLIENT *client;
   73:   struct pmap parms;
   74: 
   75:   address->sin_port = htons (PMAPPORT);
   76:   client = clntudp_bufcreate (address, PMAPPROG, PMAPVERS, timeout, &socket,
   77:                               RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
   78:   if (client != (CLIENT *) NULL)
   79:     {
   80:       parms.pm_prog = program;
   81:       parms.pm_vers = version;
   82:       parms.pm_prot = protocol;
   83:       parms.pm_port = 0;        /* not needed or used */
   84:       if (CLNT_CALL (client, PMAPPROC_GETPORT, (xdrproc_t) xdr_pmap,
   85:                      (caddr_t) & parms, (xdrproc_t) xdr_u_short,
   86:                      (caddr_t) & port, tottimeout) != RPC_SUCCESS)
   87:         {
   88:           rpc_createerr.cf_stat = RPC_PMAPFAILURE;
   89:           clnt_geterr (client, &rpc_createerr.cf_error);
   90:         }
   91:       else
   92:         {
   93:           if (port == 0)
   94:             rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
   95:         }
   96:       CLNT_DESTROY (client);
   97:     }
   98:   /* (void)close(socket); CLNT_DESTROY already closed it */
   99:   address->sin_port = 0;
  100:   return port;
  101: }
  102: 
  103: /* This is now the public function, which should find the fastest server */
  104: 
  105: struct findserv_req
  106: {
  107:   struct sockaddr_in sin;
  108:   u_int32_t xid;
  109:   u_int server_nr;
  110:   u_int server_ep;
  111: };
  112: 
  113: 
  114: static long int
  115: __nis_findfastest_with_timeout (dir_binding *bind,
  116:                                 const struct timeval *timeout)
  117: {
  118:   static const struct timeval TIMEOUT00 = { 0, 0 };
  119:   struct findserv_req *pings;
  120:   struct sockaddr_in sin, saved_sin;
  121:   int found = -1;
  122:   u_int32_t xid_seed;
  123:   int sock, dontblock = 1;
  124:   CLIENT *clnt;
  125:   u_long i, j, pings_count, pings_max, fastest = -1;
  126:   struct cu_data *cu;
  127: 
  128:   pings_max = bind->server_len * 2;     /* Reserve a little bit more memory
  129:                                            for multihomed hosts */
  130:   pings_count = 0;
  131:   pings = malloc (sizeof (struct findserv_req) * pings_max);
  132:   xid_seed = (u_int32_t) (time (NULL) ^ getpid ());
  133: 
  134:   if (__builtin_expect (pings == NULL, 0))
  135:     return -1;
  136: 
  137:   memset (&sin, '\0', sizeof (sin));
  138:   sin.sin_family = AF_INET;
  139:   for (i = 0; i < bind->server_len; i++)
  140:     for (j = 0; j < bind->server_val[i].ep.ep_len; ++j)
  141:       if (strcmp (bind->server_val[i].ep.ep_val[j].family, "inet") == 0)
  142:         if ((bind->server_val[i].ep.ep_val[j].proto == NULL) ||
  143:             (bind->server_val[i].ep.ep_val[j].proto[0] == '-') ||
  144:             (bind->server_val[i].ep.ep_val[j].proto[0] == '\0'))
  145:           {
  146:             sin.sin_addr.s_addr =
  147:               inetstr2int (bind->server_val[i].ep.ep_val[j].uaddr);
  148:             if (sin.sin_addr.s_addr == 0)
  149:               continue;
  150:             sin.sin_port = htons (__pmap_getnisport (&sin, NIS_PROG,
  151:                                                      NIS_VERSION,
  152:                                                      IPPROTO_UDP));
  153:             if (sin.sin_port == 0)
  154:               continue;
  155: 
  156:             if (pings_count >= pings_max)
  157:               {
  158:                 struct findserv_req *new_pings;
  159: 
  160:                 pings_max += 10;
  161:                 new_pings = realloc (pings, sizeof (struct findserv_req) *
  162:                                      pings_max);
  163:                 if (__builtin_expect (new_pings == NULL, 0))
  164:                   {
  165:                     free (pings);
  166:                     return -1;
  167:                   }
  168:                 pings = new_pings;
  169:               }
  170:             memcpy ((char *) &pings[pings_count].sin, (char *) &sin,
  171:                     sizeof (sin));
  172:             memcpy ((char *)&saved_sin, (char *)&sin, sizeof(sin));
  173:             pings[pings_count].xid = xid_seed + pings_count;
  174:             pings[pings_count].server_nr = i;
  175:             pings[pings_count].server_ep = j;
  176:             ++pings_count;
  177:           }
  178: 
  179:   /* Make sure at least one server was assigned */
  180:   if (pings_count == 0)
  181:     {
  182:       free (pings);
  183:       return -1;
  184:     }
  185: 
  186:   /* Create RPC handle */
  187:   sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  188:   clnt = clntudp_create (&saved_sin, NIS_PROG, NIS_VERSION, *timeout, &sock);
  189:   if (clnt == NULL)
  190:     {
  191:       close (sock);
  192:       free (pings);
  193:       return -1;
  194:     }
  195:   auth_destroy (clnt->cl_auth);
  196:   clnt->cl_auth = authunix_create_default ();
  197:   cu = (struct cu_data *) clnt->cl_private;
  198:   ioctl (sock, FIONBIO, &dontblock);
  199:   /* Send to all servers the NULLPROC */
  200:   for (i = 0; i < pings_count; ++i)
  201:     {
  202:       /* clntudp_call() will increment, subtract one */
  203:       *((u_int32_t *) (cu->cu_outbuf)) = pings[i].xid - 1;
  204:       memcpy ((char *) &cu->cu_raddr, (char *) &pings[i].sin,
  205:               sizeof (struct sockaddr_in));
  206:       /* Transmit to NULLPROC, return immediately. */
  207:       clnt_call (clnt, NULLPROC,
  208:                  (xdrproc_t) xdr_void, (caddr_t) 0,
  209:                  (xdrproc_t) xdr_void, (caddr_t) 0, TIMEOUT00);
  210:     }
  211: 
  212:   while (found == -1) {
  213:     /* Receive reply from NULLPROC asynchronously. Note null inproc. */
  214:     int rc = clnt_call (clnt, NULLPROC,
  215:                         (xdrproc_t) NULL, (caddr_t) 0,
  216:                         (xdrproc_t) xdr_void, (caddr_t) 0,
  217:                         *timeout);
  218:     if (RPC_SUCCESS == rc) {
  219:       fastest = *((u_int32_t *) (cu->cu_inbuf)) - xid_seed;
  220:       if (fastest < pings_count) {
  221:         bind->server_used = pings[fastest].server_nr;
  222:         bind->current_ep = pings[fastest].server_ep;
  223:         found = 1;
  224:       }
  225:     } else {
  226:       /*      clnt_perror(clnt, "__nis_findfastest"); */
  227:       break;
  228:     }
  229:   }
  230: 
  231: 
  232:   auth_destroy (clnt->cl_auth);
  233:   clnt_destroy (clnt);
  234:   close (sock);
  235: 
  236:   free (pings);
  237: 
  238:   return found;
  239: }
  240: 
  241: 
  242: long int
  243: __nis_findfastest (dir_binding *bind)
  244: {
  245:   struct timeval timeout = { __NIS_PING_TIMEOUT_START, 0 };
  246:   long int found = -1;
  247:   long int retry = __NIS_PING_RETRY + 1;
  248: 
  249:   while (retry--)
  250:     {
  251:       found = __nis_findfastest_with_timeout (bind, &timeout);
  252:       if (found != -1)
  253:         break;
  254:       timeout.tv_sec += __NIS_PING_TIMEOUT_INCREMENT;
  255:     }
  256: 
  257:   return found;
  258: }
Syntax (Markdown)