"Fossies" - the Fresh Open Source Software Archive

Member "coda-6.9.5/coda-src/venus/comm.cc" (1 Aug 2007, 30348 Bytes) of package /linux/misc/old/coda-6.9.5.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "comm.cc" see the Fossies "Dox" file reference documentation.

    1 /* BLURB gpl
    2 
    3                            Coda File System
    4                               Release 6
    5 
    6           Copyright (c) 1987-2003 Carnegie Mellon University
    7                   Additional copyrights listed below
    8 
    9 This  code  is  distributed "AS IS" without warranty of any kind under
   10 the terms of the GNU General Public Licence Version 2, as shown in the
   11 file  LICENSE.  The  technical and financial  contributors to Coda are
   12 listed in the file CREDITS.
   13 
   14                         Additional copyrights
   15                            none currently
   16 
   17 #*/
   18 
   19 /*
   20  *
   21  * Implementation of the Venus Communications subsystem.
   22  *
   23  *    This module should be split up into:
   24  *        1. A subsystem independent module, libcomm.a, containing base classes srvent and connent.
   25  *        2. A subsystem dependent module containing derived classes v_srvent and v_connent.
   26  *
   27  */
   28 
   29 #ifdef __cplusplus
   30 extern "C" {
   31 #endif
   32 
   33 #ifdef HAVE_CONFIG_H
   34 #include <config.h>
   35 #endif
   36 
   37 #include <sys/param.h>
   38 #include <sys/types.h>
   39 #include <sys/socket.h>
   40 #include <netinet/in.h>
   41 #ifdef HAVE_ARPA_INET_H
   42 #include <arpa/inet.h>
   43 #endif
   44 #include <sys/time.h>
   45 #include <errno.h>
   46 #ifdef HAVE_NETDB_H
   47 #include <netdb.h>
   48 #endif
   49 #include <stdio.h>
   50 #include "coda_string.h"
   51 #include <struct.h>
   52 #include <unistd.h>
   53 #include <stdlib.h>
   54 
   55 #include <rpc2/rpc2.h>
   56 #include <rpc2/se.h>
   57 #include <rpc2/errors.h>
   58 
   59 extern int Fcon_Init(); 
   60 extern void SFTP_SetDefaults (SFTP_Initializer *initPtr);
   61 extern void SFTP_Activate (SFTP_Initializer *initPtr);
   62 
   63 /* interfaces */
   64 #include <vice.h>
   65 
   66 #ifdef __cplusplus
   67 }
   68 #endif
   69 
   70 /* from vv */
   71 #include <inconsist.h>
   72 
   73 /* from venus */
   74 #include "comm.h"
   75 #include "fso.h"
   76 #include "mariner.h"
   77 #include "user.h"
   78 #include "venus.private.h"
   79 #include "venusrecov.h"
   80 #include "venusvol.h"
   81 #include "vproc.h"
   82 
   83 int COPModes = 6;   /* ASYNCCOP2 | PIGGYCOP2 */
   84 char myHostName[MAXHOSTNAMELEN];
   85 int rpc2_retries = UNSET_RT;
   86 int rpc2_timeout = UNSET_TO;
   87 int sftp_windowsize = UNSET_WS;
   88 int sftp_sendahead = UNSET_SA;
   89 int sftp_ackpoint = UNSET_AP;
   90 int sftp_packetsize = UNSET_PS;
   91 int rpc2_timeflag = UNSET_ST;
   92 int mrpc2_timeflag = UNSET_MT;
   93 
   94 extern long RPC2_Perror;
   95 struct CommQueueStruct CommQueue;
   96 
   97 olist *srvent::srvtab;
   98 char srvent::srvtab_sync;
   99 olist *connent::conntab;
  100 char connent::conntab_sync;
  101 
  102 #ifdef  VENUSDEBUG
  103 int connent::allocs = 0;
  104 int connent::deallocs = 0;
  105 int srvent::allocs = 0;
  106 int srvent::deallocs = 0;
  107 #endif /* VENUSDEBUG */
  108 
  109 
  110 void CommInit() {
  111     /* Initialize unset command-line parameters. */
  112     if (sftp_windowsize == UNSET_WS) sftp_windowsize = DFLT_WS;
  113     if (sftp_sendahead == UNSET_SA) sftp_sendahead = DFLT_SA;
  114     if (sftp_ackpoint == UNSET_AP) sftp_ackpoint = DFLT_AP;
  115     if (sftp_packetsize == UNSET_PS) sftp_packetsize = DFLT_PS;
  116     if (rpc2_timeflag == UNSET_ST)
  117     srv_ElapseSwitch = DFLT_ST;
  118     else
  119     srv_ElapseSwitch = rpc2_timeflag;
  120     if (mrpc2_timeflag == UNSET_MT)
  121     srv_MultiStubWork[0].opengate = DFLT_MT;
  122     else
  123     srv_MultiStubWork[0].opengate = mrpc2_timeflag;
  124 
  125     /* Sanity check COPModes. */
  126     if ( (ASYNCCOP1 && !ASYNCCOP2) ||
  127      (PIGGYCOP2 && !ASYNCCOP2) )
  128     CHOKE("CommInit: bogus COPModes (%x)", COPModes);
  129 
  130     /* Initialize comm queue */
  131     memset((void *)&CommQueue, 0, sizeof(CommQueueStruct));
  132 
  133     /* Hostname is needed for file server connections. */
  134     if (gethostname(myHostName, MAXHOSTNAMELEN) < 0)
  135     CHOKE("CommInit: gethostname failed");
  136 
  137     /* Initialize Connections. */
  138     connent::conntab = new olist;
  139 
  140     /* Initialize Servers. */
  141     srvent::srvtab = new olist;
  142 
  143     RPC2_Perror = 0;
  144 
  145     /* Port initialization. */
  146     RPC2_PortIdent port1;
  147     port1.Tag = RPC2_PORTBYINETNUMBER;
  148     port1.Value.InetPortNumber = htons(masquerade_port);
  149 
  150     /* SFTP initialization. */
  151     SFTP_Initializer sei;
  152     SFTP_SetDefaults(&sei);
  153     sei.WindowSize = sftp_windowsize;
  154     sei.SendAhead = sftp_sendahead;
  155     sei.AckPoint = sftp_ackpoint;
  156     sei.PacketSize = sftp_packetsize;
  157     sei.EnforceQuota = 1;
  158     sei.Port.Tag = (PortTag)0;
  159     SFTP_Activate(&sei);
  160 
  161     /* RPC2 initialization. */
  162     struct timeval tv;
  163     tv.tv_sec = rpc2_timeout;
  164     tv.tv_usec = 0;
  165     if (RPC2_Init(RPC2_VERSION, 0, &port1, rpc2_retries, &tv) != RPC2_SUCCESS)
  166     CHOKE("CommInit: RPC2_Init failed");
  167 
  168     /* Fire up the probe daemon. */
  169     PROD_Init();
  170 }
  171 
  172 
  173 /* *****  Connection  ***** */
  174 
  175 int srvent::GetConn(connent **cpp, uid_t uid, int Force)
  176 {
  177     LOG(100, ("srvent::GetConn: host = %s, uid = %d, force = %d\n",
  178               name, uid, Force));
  179 
  180     *cpp = 0;
  181     int code = 0;
  182     connent *c = 0;
  183 
  184     /* Grab an existing connection if one is free. */
  185     {
  186     /* Check whether there is already a free connection. */
  187     struct ConnKey Key; Key.host = host; Key.uid = uid;
  188     conn_iterator next(&Key);
  189     while ((c = next())) {
  190         /* the iterator grabs a reference, so in-use connections
  191          * will have a refcount of 2 */
  192         if (c->RefCount() <= 1 && !c->dying) {
  193         c->GetRef();
  194                 *cpp = c;
  195                 return 0;
  196         }
  197     }
  198     }
  199 
  200     /* Try to connect to the server on behalf of the user. */
  201     RPC2_Handle ConnHandle = 0;
  202     int auth = 1;
  203     code = Connect(&ConnHandle, &auth, uid, Force);
  204 
  205     switch(code) {
  206     case 0:      break;
  207     case EINTR:  return(EINTR);
  208     case EPERM:
  209     case ERETRY: return(ERETRY);
  210     default:     return(ETIMEDOUT);
  211     }
  212 
  213     /* Create and install the new connent. */
  214     c = new connent(this, uid, ConnHandle, auth);
  215     if (!c) return(ENOMEM);
  216 
  217     c->GetRef();
  218     connent::conntab->insert(&c->tblhandle);
  219     *cpp = c;
  220     return(0);
  221 }
  222 
  223 
  224 void PutConn(connent **cpp)
  225 {
  226     connent *c = *cpp;
  227     *cpp = 0;
  228     if (!c) {
  229     LOG(100, ("PutConn: null conn\n"));
  230     return;
  231     }
  232 
  233     LOG(100, ("PutConn: host = %s, uid = %d, cid = %d, auth = %d\n",
  234           c->srv->Name(), c->uid, c->connid, c->authenticated));
  235 
  236     c->PutRef();
  237 
  238     if (c->RefCount() || !c->dying)
  239     return;
  240 
  241     connent::conntab->remove(&c->tblhandle);
  242     delete c;
  243 }
  244 
  245 
  246 void ConnPrint() {
  247     ConnPrint(stdout);
  248 }
  249 
  250 
  251 void ConnPrint(FILE *fp) {
  252     fflush(fp);
  253     ConnPrint(fileno(fp));
  254 }
  255 
  256 
  257 void ConnPrint(int fd) {
  258     if (connent::conntab == 0) return;
  259 
  260     fdprint(fd, "Connections: count = %d\n", connent::conntab->count());
  261 
  262     /* Iterate through the individual entries. */
  263     conn_iterator next;
  264     connent *c;
  265     while ((c = next()))
  266     c->print(fd);
  267 
  268     fdprint(fd, "\n");
  269 }
  270 
  271 
  272 connent::connent(srvent *server, uid_t Uid, RPC2_Handle cid, int authflag)
  273 {
  274     LOG(1, ("connent::connent: host = %s, uid = %d, cid = %d, auth = %d\n",
  275          server->Name(), uid, cid, authflag));
  276 
  277     /* These members are immutable. */
  278     server->GetRef();
  279     srv = server;
  280     uid = Uid;
  281     connid = cid;
  282     authenticated = authflag;
  283 
  284     /* These members are mutable. */
  285     inuse = 0;
  286     dying = 0;
  287 
  288 #ifdef  VENUSDEBUG
  289     allocs++;
  290 #endif
  291 }
  292 
  293 
  294 connent::~connent() {
  295     int code;
  296 #ifdef  VENUSDEBUG
  297     deallocs++;
  298 #endif
  299 
  300     LOG(1, ("connent::~connent: host = %s, uid = %d, cid = %d, auth = %d\n",
  301         srv->Name(), uid, connid, authenticated));
  302 
  303     CODA_ASSERT(!RefCount());
  304 
  305     /* Be nice and disconnect if the server is available. */
  306     if (srv->ServerIsUp()) {
  307     /* Make the RPC call. */
  308     MarinerLog("fetch::DisconnectFS %s\n", srv->Name());
  309     UNI_START_MESSAGE(ViceDisconnectFS_OP);
  310     code = (int) ViceDisconnectFS(connid);
  311     UNI_END_MESSAGE(ViceDisconnectFS_OP);
  312     MarinerLog("fetch::disconnectfs done\n");
  313     code = CheckResult(code, 0);
  314     UNI_RECORD_STATS(ViceDisconnectFS_OP);
  315     }
  316 
  317     code = (int) RPC2_Unbind(connid);
  318     connid = 0;
  319     PutServer(&srv);
  320     LOG(1, ("connent::~connent: RPC2_Unbind -> %s\n", RPC2_ErrorMsg(code)));
  321 }
  322 
  323 
  324 /* Mark this conn as dying. */
  325 void connent::Suicide(void)
  326 {
  327     LOG(1, ("connent::Suicide\n"));
  328     dying = 1;
  329 }
  330 
  331 /* Maps return codes from Vice:
  332     0       Success,
  333     EINTR       Call was interrupted,
  334     ETIMEDOUT   Host did not respond,
  335     ERETRY      Retryable error,
  336     Other (> 0) Non-retryable error (valid kernel return code).
  337 */
  338 int connent::CheckResult(int code, VolumeId vid, int TranslateEINCOMP) {
  339     LOG(100, ("connent::CheckResult: code = %d, vid = %x\n",
  340          code, vid));
  341 
  342     /* ViceOp succeeded. */
  343     if (code == 0) return(0);
  344 
  345     /* Translate RPC and Volume errors, and update server state. */
  346     switch(code) {
  347     default:
  348         if (code < 0)
  349         srv->ServerError(&code);
  350 
  351         if (code == ETIMEDOUT || code == ERETRY)
  352         dying = 1;
  353         break;
  354 
  355     case VBUSY:
  356         code = EWOULDBLOCK;
  357         break;
  358 
  359     case VNOVOL:
  360         code = ENXIO;
  361         break;
  362 
  363     case VNOVNODE:
  364         code = ENOENT;
  365         break;
  366 
  367     case VLOGSTALE:
  368         code = EALREADY;
  369         break;
  370 
  371     case VSALVAGE:
  372     case VVOLEXISTS:
  373     case VNOSERVICE:
  374     case VOFFLINE:
  375     case VONLINE:
  376     case VNOSERVER:
  377     case VMOVED:
  378     case VFAIL:
  379         eprint("connent::CheckResult: illegal code (%d)", code);
  380         code = EINVAL;
  381         break;
  382     }
  383 
  384     /* Coerce EINCOMPATIBLE to ERETRY. */
  385     if (TranslateEINCOMP && code == EINCOMPATIBLE)
  386         code = ERETRY;
  387 
  388     if (code == ETIMEDOUT && VprocInterrupted()) return(EINTR);
  389     return(code);
  390 }
  391 
  392 
  393 void connent::print(int fd) {
  394     fdprint(fd, "%#08x : host = %s, uid = %d, cid = %d, auth = %d, inuse = %u, dying = %d\n",
  395          (long)this, srv->Name(), uid, connid, authenticated, inuse, dying);
  396 }
  397 
  398 
  399 conn_iterator::conn_iterator(struct ConnKey *Key) : olist_iterator((olist&)*connent::conntab) {
  400     key = Key;
  401 }
  402 
  403 
  404 conn_iterator::~conn_iterator()
  405 {
  406     if (clink && clink != (void *)-1) {
  407     connent *c = strbase(connent, clink, tblhandle);
  408     PutConn(&c);
  409     }
  410 }
  411 
  412 connent *conn_iterator::operator()()
  413 {
  414     olink *o, *prev = clink;
  415     connent *next = NULL;
  416 
  417     while ((o = olist_iterator::operator()())) {
  418     next = strbase(connent, o, tblhandle);
  419     if (next->dying) continue;
  420     if (!key || ((key->host.s_addr == next->srv->host.s_addr ||
  421               key->host.s_addr == INADDR_ANY) &&
  422              (key->uid == next->uid || key->uid == ANYUSER_UID)))
  423     {
  424         next->GetRef();
  425         break;
  426     }
  427     }
  428     if (prev && prev != (void *)-1) {
  429     connent *c = strbase(connent, prev, tblhandle);
  430     PutConn(&c);
  431     }
  432     return o ? next : NULL;
  433 }
  434 
  435 
  436 /* ***** Server  ***** */
  437 
  438 /*
  439  *    Notes on the srvent::connid field:
  440  *
  441  *    The server's connid is the "local handle" of the current callback connection.
  442  *
  443  *    A srvent::connid value of 0 serves as a flag that the server is incommunicado
  444  *    (i.,e., "down" from the point of view of this Venus).  Two other values are distinguished
  445  *    and mean that the server is "quasi-up": -1 indicates that the server has never been
  446  *    contacted (i.e., at initialization), -2 indicates that the server has just NAK'ed an RPC.
  447  */
  448 
  449 void Srvr_Wait() {
  450     LOG(0, ("WAITING(SRVRQ):\n"));
  451     START_TIMING();
  452     VprocWait((char *)&srvent::srvtab_sync);
  453     END_TIMING();
  454     LOG(0, ("WAIT OVER, elapsed = %3.1f\n", elapsed));
  455 }
  456 
  457 
  458 void Srvr_Signal() {
  459     LOG(10, ("SIGNALLING(SRVRQ):\n"));
  460     VprocSignal((char *)&srvent::srvtab_sync);
  461 }
  462 
  463 
  464 srvent *FindServer(struct in_addr *host)
  465 {
  466     srv_iterator next;
  467     srvent *s;
  468 
  469     while ((s = next()))
  470     if (s->host.s_addr == host->s_addr)
  471             return(s);
  472 
  473     return(0);
  474 }
  475 
  476 
  477 srvent *FindServerByCBCid(RPC2_Handle connid)
  478 {
  479     if (connid == 0) return(0);
  480 
  481     srv_iterator next;
  482     srvent *s;
  483 
  484     while ((s = next()))
  485     if (s->connid == connid) return(s);
  486 
  487     return(0);
  488 }
  489 
  490 
  491 srvent *GetServer(struct in_addr *host, RealmId realmid)
  492 {
  493     CODA_ASSERT(host && host->s_addr);
  494     LOG(100, ("GetServer: host = %s\n", inet_ntoa(*host)));
  495 
  496     srvent *s = FindServer(host);
  497     if (s) {
  498     s->GetRef();
  499     if (s->realmid == realmid)
  500         return s;
  501 
  502     s->Reset();
  503     PutServer(&s);
  504     }
  505 
  506     s = new srvent(host, realmid);
  507 
  508     srvent::srvtab->insert(&s->tblhandle);
  509 
  510     return s;
  511 }
  512 
  513 
  514 void PutServer(srvent **spp)
  515 {
  516     if (*spp) {
  517     LOG(100, ("PutServer: %s\n", (*spp)->name));
  518         (*spp)->PutRef();
  519     }
  520     *spp = NULL;
  521 }
  522 
  523 
  524 /*
  525  *    The probe routines exploit parallelism in three ways:
  526  *       1. MultiRPC is used to perform the Probe RPC (actually, a ViceGetTime)
  527  *       2. Slave vprocs are used to overlap the probing of "up" servers and 
  528  *      the binding/probing of "down" servers.  Otherwise probing of "up"
  529  *      servers may be delayed for the binding to "down" servers.
  530  *       3. (Additional) slave vprocs are used to overlap the binding of 
  531  *          "down" servers
  532  *
  533  *    Note that item 3 is only needed because MultiBind functionality is not 
  534  *    yet a part of MultiRPC.
  535  */
  536 
  537 probeslave::probeslave(ProbeSlaveTask Task, void *Arg, void *Result, char *Sync) : vproc("ProbeSlave", NULL, VPT_ProbeDaemon, 32768) {
  538     LOG(100, ("probeslave::probeslave(%#x): %-16s : lwpid = %d\n", this, name, lwpid));
  539 
  540     task = Task;
  541     arg = Arg;
  542     result = Result;
  543     sync = Sync;
  544 
  545     /* Poke main procedure. */
  546     start_thread();
  547 }
  548 
  549 void probeslave::main(void)
  550 {
  551     switch(task) {
  552     case ProbeUpServers:
  553         ProbeServers(1);
  554         break;
  555 
  556     case ProbeDownServers:
  557         ProbeServers(0);
  558         break;
  559 
  560     case BindToServer:
  561         {
  562         /* *result gets pointer to connent on success, 0 on failure. */
  563         struct in_addr *Host = (struct in_addr *)arg;
  564             srvent *s = FindServer(Host);
  565         if (s) {
  566         s->GetRef();
  567         s->GetConn((connent **)result, ANYUSER_UID, 1);
  568         PutServer(&s);
  569         }
  570         }
  571         break;
  572 
  573     default:
  574         CHOKE("probeslave::main: bogus task (%d)", task);
  575     }
  576 
  577     /* Signal reaper, then commit suicide. */
  578     (*sync)++;
  579     VprocSignal(sync);
  580     idle = 1;
  581     delete VprocSelf();
  582 }
  583 
  584 void ProbeServers(int Up)
  585 {
  586     LOG(1, ("ProbeServers: %s\n", Up ? "Up" : "Down"));
  587 
  588     /* Hosts and Connections are arrays of addresses and connents respectively
  589      * representing the servers to be probed.  HowMany is the current size of
  590      * these arrays, and ix is the number of entries actually used. */
  591     const int GrowSize = 32;
  592     int HowMany = GrowSize;
  593     struct in_addr *Hosts;
  594     int ix = 0;
  595 
  596     Hosts = (struct in_addr *)malloc(HowMany * sizeof(struct in_addr));
  597     /* Fill in the Hosts array for each server that is to be probed. */
  598     {
  599     srv_iterator next;
  600     srvent *s;
  601     while ((s = next())) {
  602         if (!s->probeme)
  603         continue;
  604 
  605         if ((Up && s->ServerIsDown()) || (!Up && !s->ServerIsDown()))
  606         continue;
  607 
  608         /* Grow the Hosts array if necessary. */
  609         if (ix == HowMany) {
  610         HowMany += GrowSize;
  611         Hosts = (struct in_addr *)
  612             realloc(Hosts, HowMany * sizeof(struct in_addr));
  613         memset(&Hosts[ix], 0, GrowSize * sizeof(struct in_addr));
  614         }
  615 
  616         /* Stuff the address in the Hosts array. */
  617         memcpy(&Hosts[ix], &s->host, sizeof(struct in_addr));
  618         ix++;
  619     }
  620     }
  621 
  622     if (ix)
  623     DoProbes(ix, Hosts);
  624 
  625     /* the incorrect "free" in DoProbes() is moved here */
  626     free(Hosts);
  627 }
  628 
  629 
  630 void DoProbes(int HowMany, struct in_addr *Hosts)
  631 {
  632     connent **Connections = 0;
  633     int i;
  634 
  635     CODA_ASSERT(HowMany > 0);
  636 
  637     Connections = (connent **)malloc(HowMany * sizeof(connent *));
  638     memset(Connections, 0, HowMany * sizeof(connent *));
  639 
  640     /* Bind to the servers. */
  641     MultiBind(HowMany, Hosts, Connections);
  642 
  643     /* Probe them. */
  644     int AnyHandlesValid = 0;
  645     RPC2_Handle *Handles = (RPC2_Handle *)malloc(HowMany * sizeof(RPC2_Handle));
  646     for (i = 0; i < HowMany; i++) {
  647     if (Connections[i] == 0) { Handles[i] = 0; continue; }
  648 
  649     AnyHandlesValid = 1;
  650     Handles[i] = Connections[i]->connid;
  651     }
  652 
  653     if (AnyHandlesValid)
  654     MultiProbe(HowMany, Handles);
  655 
  656     free(Handles);
  657 
  658     for (i = 0; i < HowMany; i++)
  659     PutConn(&Connections[i]);
  660     free(Connections);
  661 }
  662 
  663 
  664 void MultiBind(int HowMany, struct in_addr *Hosts, connent **Connections)
  665 {
  666     if (LogLevel >= 1) {
  667     dprint("MultiBind: HowMany = %d\n\tHosts = [ ", HowMany);
  668     for (int i = 0; i < HowMany; i++)
  669         fprintf(logFile, "%s ", inet_ntoa(Hosts[i]));
  670     fprintf(logFile, "]\n");
  671     }
  672 
  673     int ix, slaves = 0;
  674     char slave_sync = 0;
  675     for (ix = 0; ix < HowMany; ix++) {
  676     /* Try to get a connection without forcing a bind. */
  677     connent *c = 0;
  678     int code;
  679     srvent *s = FindServer(&Hosts[ix]);
  680 
  681     if (!s) continue;
  682 
  683     s->GetRef();
  684     code = s->GetConn(&c, ANYUSER_UID);
  685     PutServer(&s);
  686 
  687     if (code == 0) {
  688         /* Stuff the connection in the array. */
  689         Connections[ix] = c;
  690         continue;
  691     }
  692 
  693     /* Force a bind, but have a slave do it so we can bind in parallel. */
  694     {
  695         slaves++;
  696         (void)new probeslave(BindToServer, (void *)(&Hosts[ix]),
  697                  (void *)(&Connections[ix]), &slave_sync);
  698     }
  699     }
  700 
  701     /* Reap any slaves we created. */
  702     while (slave_sync != slaves) {
  703     LOG(1, ("MultiBind: waiting (%d, %d)\n", slave_sync, slaves));
  704     VprocWait(&slave_sync);
  705     }
  706 }
  707 
  708 
  709 void MultiProbe(int HowMany, RPC2_Handle *Handles)
  710 {
  711     if (LogLevel >= 1) {
  712     dprint("MultiProbe: HowMany = %d\n\tHandles = [ ", HowMany);
  713     for (int i = 0; i < HowMany; i++)
  714         fprintf(logFile, "%x ", Handles[i]);
  715     fprintf(logFile, "]\n");
  716     }
  717 
  718     /* Make multiple copies of the IN/OUT and OUT parameters. */
  719     RPC2_Unsigned  **secs_ptrs =
  720     (RPC2_Unsigned **)malloc(HowMany * sizeof(RPC2_Unsigned *));
  721     CODA_ASSERT(secs_ptrs);
  722     RPC2_Unsigned   *secs_bufs =
  723     (RPC2_Unsigned *)malloc(HowMany * sizeof(RPC2_Unsigned));
  724     CODA_ASSERT(secs_bufs);
  725     for (int i = 0; i < HowMany; i++)
  726     secs_ptrs[i] = &secs_bufs[i]; 
  727     RPC2_Integer  **usecs_ptrs =
  728     (RPC2_Integer **)malloc(HowMany * sizeof(RPC2_Integer *));
  729     CODA_ASSERT(usecs_ptrs);
  730     RPC2_Integer   *usecs_bufs =
  731     (RPC2_Integer *)malloc(HowMany * sizeof(RPC2_Integer));
  732     CODA_ASSERT(usecs_bufs);
  733     for (int ii = 0; ii < HowMany; ii++)
  734     usecs_ptrs[ii] = &usecs_bufs[ii]; 
  735 
  736     /* Make the RPC call. */
  737     MarinerLog("fetch::Probe\n");
  738     MULTI_START_MESSAGE(ViceGetTime_OP);
  739     int code = (int) MRPC_MakeMulti(ViceGetTime_OP, ViceGetTime_PTR,
  740                    HowMany, Handles, 0, 0, HandleProbe, 0,
  741                    secs_ptrs, usecs_ptrs);
  742     MULTI_END_MESSAGE(ViceGetTime_OP);
  743     MarinerLog("fetch::probe done\n");
  744 
  745     /* CheckResult is done dynamically by HandleProbe(). */
  746     MULTI_RECORD_STATS(ViceGetTime_OP);
  747 
  748     /* Discard dynamic data structures. */
  749     free(secs_ptrs);
  750     free(secs_bufs);
  751     free(usecs_ptrs);
  752     free(usecs_bufs);
  753 }
  754 
  755 
  756 long HandleProbe(int HowMany, RPC2_Handle Handles[], long offset, long rpcval, ...)
  757 {
  758     RPC2_Handle RPCid = Handles[offset];
  759 
  760     if (RPCid != 0) {
  761     /* Get the {host,port} pair for this call. */
  762     RPC2_PeerInfo thePeer;
  763     int rc = RPC2_GetPeerInfo(RPCid, &thePeer);
  764     if (thePeer.RemoteHost.Tag != RPC2_HOSTBYINETADDR ||
  765         thePeer.RemotePort.Tag != RPC2_PORTBYINETNUMBER) {
  766         LOG(0, ("HandleProbe: RPC2_GetPeerInfo return code = %d\n", rc));
  767         LOG(0, ("HandleProbe: thePeer.RemoteHost.Tag = %d\n", thePeer.RemoteHost.Tag));
  768         LOG(0, ("HandleProbe: thePeer.RemotePort.Tag = %d\n", thePeer.RemotePort.Tag));
  769         return 0;
  770         /* CHOKE("HandleProbe: getpeerinfo returned bogus type!"); */
  771     }
  772 
  773     /* Locate the server and update its status. */
  774     srvent *s = FindServer(&thePeer.RemoteHost.Value.InetAddress);
  775     if (!s)
  776         CHOKE("HandleProbe: no srvent (RPCid = %d, PeerHost = %s)",
  777                   RPCid, inet_ntoa(thePeer.RemoteHost.Value.InetAddress));
  778     LOG(1, ("HandleProbe: (%s, %d)\n", s->name, rpcval));
  779     if (rpcval < 0) {
  780         int rc = rpcval;
  781         s->ServerError(&rc);
  782     }
  783     }
  784 
  785     return(0);
  786 }
  787 
  788 
  789 /* Report which servers are down. */
  790 void DownServers(char *buf, unsigned int *bufsize)
  791 {
  792     char *cp = buf;
  793     unsigned int maxsize = *bufsize;
  794     *bufsize = 0;
  795 
  796     /* Copy each down server's address into the buffer. */
  797     srv_iterator next;
  798     srvent *s;
  799     while ((s = next()))
  800     if (s->ServerIsDown()) {
  801         /* Make sure there is room in the buffer for this entry. */
  802         if ((cp - buf) + sizeof(struct in_addr) > maxsize) return;
  803 
  804         memcpy(cp, &s->host, sizeof(struct in_addr));
  805         cp += sizeof(struct in_addr);
  806     }
  807 
  808     /* Null terminate the list.  Make sure there is room in the buffer for the
  809      * terminator. */
  810     if ((cp - buf) + sizeof(struct in_addr) > maxsize) return;
  811     memset(cp, 0, sizeof(struct in_addr));
  812     cp += sizeof(struct in_addr);
  813 
  814     *bufsize = (cp - buf);
  815 }
  816 
  817 
  818 /* Report which of a given set of servers is down. */
  819 void DownServers(int nservers, struct in_addr *hostids,
  820                  char *buf, unsigned int *bufsize)
  821 {
  822     char *cp = buf;
  823     unsigned int maxsize = *bufsize;
  824     *bufsize = 0;
  825 
  826     /* Copy each down server's address into the buffer. */
  827     for (int i = 0; i < nservers; i++) {
  828     srvent *s = FindServer(&hostids[i]);
  829     if (s && s->ServerIsDown()) {
  830         /* Make sure there is room in the buffer for this entry. */
  831         if ((cp - buf) + sizeof(struct in_addr) > maxsize) return;
  832 
  833         memcpy(cp, &s->host, sizeof(struct in_addr));
  834         cp += sizeof(struct in_addr);
  835     }
  836     }
  837 
  838     /* Null terminate the list.  Make sure there is room in the buffer for the
  839      * terminator. */
  840     if ((cp - buf) + sizeof(struct in_addr) > maxsize) return;
  841     memset(cp, 0, sizeof(struct in_addr));
  842     cp += sizeof(struct in_addr);
  843 
  844     *bufsize = (cp - buf);
  845 }
  846 
  847 
  848 /* 
  849  * Update bandwidth estimates for all up servers.
  850  * Reset estimates and declare connectivity strong if there are
  851  * no recent observations.  Called by the probe daemon.
  852  */
  853 void CheckServerBW(long curr_time)
  854 {
  855     srv_iterator next;
  856     srvent *s;
  857     unsigned long bw = INIT_BW;
  858 
  859     while ((s = next())) {
  860     if (s->ServerIsUp()) 
  861         (void) s->GetBandwidth(&bw);
  862     }
  863 }
  864 
  865 
  866 void ServerPrint() {
  867     ServerPrint(stdout);
  868 }
  869 
  870 void ServerPrint(FILE *f)
  871 {
  872     if (srvent::srvtab == 0) return;
  873 
  874     fprintf(f, "Servers: count = %d\n", srvent::srvtab->count());
  875 
  876     srv_iterator next;
  877     srvent *s;
  878     while ((s = next())) s->print(f);
  879 
  880     fprintf(f, "\n");
  881 }
  882 
  883 
  884 srvent::srvent(struct in_addr *Host, RealmId realm)
  885 {
  886     LOG(1, ("srvent::srvent: host = %s\n", inet_ntoa(*Host)));
  887 
  888     struct hostent *h = gethostbyaddr((char *)Host, sizeof(struct in_addr), AF_INET);
  889     if (h) {
  890     name = new char[strlen(h->h_name) + 1];
  891     strcpy(name, h->h_name);
  892     TRANSLATE_TO_LOWER(name);
  893     }
  894     else {
  895     name = new char[16];
  896     sprintf(name, "%s", inet_ntoa(*Host));
  897     }
  898 
  899     host = *Host;
  900     realmid = realm;
  901     connid = -1;
  902     Xbinding = 0;
  903     probeme = 0;
  904     bw = INIT_BW;
  905     lastobs.tv_sec = lastobs.tv_usec = 0;
  906     VGAPlusSHA_Supported = 0;  /* default is old-style server */
  907     refcount = 1;
  908 
  909 #ifdef  VENUSDEBUG
  910     allocs++;
  911 #endif
  912 }
  913 
  914 srvent::~srvent()
  915 {
  916 #ifdef  VENUSDEBUG
  917     deallocs++;
  918 #endif
  919 
  920     LOG(1, ("srvent::~srvent: host = %s, conn = %d\n", name, connid));
  921 
  922     srvent::srvtab->remove(&tblhandle);
  923 
  924     Reset();
  925 
  926     delete [] name;
  927 }
  928 
  929 
  930 int srvent::Connect(RPC2_Handle *cidp, int *authp, uid_t uid, int Force)
  931 {
  932     LOG(100, ("srvent::Connect: host = %s, uid = %d, force = %d\n",
  933          name, uid, Force));
  934 
  935     int code = 0;
  936 
  937     /* See whether this server is down or already binding. */
  938     for (;;) {
  939     if (ServerIsDown() && !Force) {
  940         LOG(100, ("srvent::Connect: server (%s) is down\n", name));
  941         return(ETIMEDOUT);
  942     }
  943 
  944     if (!Xbinding) break;
  945     if (VprocInterrupted()) return(EINTR);
  946     Srvr_Wait();
  947     if (VprocInterrupted()) return(EINTR);
  948     }
  949 
  950     /* Get the user entry and attempt to connect to it. */
  951     Xbinding = 1;
  952     {
  953     Realm *realm = REALMDB->GetRealm(realmid);
  954     userent *u = realm->GetUser(uid);
  955     code = u->Connect(cidp, authp, &host);
  956     PutUser(&u);
  957     realm->PutRef();
  958     }
  959     Xbinding = 0;
  960     Srvr_Signal();
  961 
  962     /* Interpret result. */
  963     if (code < 0)
  964     switch (code) {
  965         case RPC2_NOTAUTHENTICATED:
  966         code = EPERM; break;
  967 
  968         case RPC2_NOBINDING:
  969         case RPC2_SEFAIL2:
  970         case RPC2_FAIL:
  971         code = ETIMEDOUT; break;
  972 
  973         default:
  974 /*
  975         CHOKE("srvent::Connect: illegal RPC code (%s)", RPC2_ErrorMsg(code));
  976 */
  977         code = ETIMEDOUT; break;
  978     }
  979     if (!ServerIsDown() && code == ETIMEDOUT) {
  980     /* Not already considered down. */
  981     MarinerLog("connection::unreachable %s\n", name);
  982     Reset();
  983     }
  984 
  985     if (code == ETIMEDOUT && VprocInterrupted()) return(EINTR);
  986     return(code);
  987 }
  988 
  989 int srvent::GetStatistics(ViceStatistics *Stats)
  990 {
  991     LOG(100, ("srvent::GetStatistics: host = %s\n", name));
  992 
  993     int code = 0;
  994     connent *c = 0;
  995 
  996     memset(Stats, 0, sizeof(ViceStatistics));
  997     
  998     code = GetConn(&c, ANYUSER_UID);
  999     if (code != 0) goto Exit;
 1000 
 1001     /* Make the RPC call. */
 1002     MarinerLog("fetch::GetStatistics %s\n", name);
 1003     UNI_START_MESSAGE(ViceGetStatistics_OP);
 1004     code = (int) ViceGetStatistics(c->connid, Stats);
 1005     UNI_END_MESSAGE(ViceGetStatistics_OP);
 1006     MarinerLog("fetch::getstatistics done\n");
 1007     code = c->CheckResult(code, 0);
 1008     UNI_RECORD_STATS(ViceGetStatistics_OP);
 1009 
 1010 Exit:
 1011     PutConn(&c);
 1012     return(code);
 1013 }
 1014 
 1015 
 1016 void srvent::Reset()
 1017 {
 1018     LOG(1, ("srvent::Reset: host = %s\n", name));
 1019 
 1020     /* Unbind callback connection for this server. */
 1021     if (connid) {
 1022     int code = (int) RPC2_Unbind(connid);
 1023     LOG(1, ("srvent::Reset: RPC2_Unbind -> %s\n", RPC2_ErrorMsg(code)));
 1024     connid = 0;
 1025     }
 1026 
 1027     /* Kill all direct connections to this server. */
 1028     {
 1029     struct ConnKey Key; Key.host = host; Key.uid = ANYUSER_UID;
 1030     conn_iterator conn_next(&Key);
 1031     connent *c = 0;
 1032     while ((c = conn_next()))
 1033         c->Suicide();
 1034     }
 1035 
 1036     /* Send a downevent to volumes associated with this server */
 1037     /* Also kills all indirect connections to the server. */
 1038     VDB->DownEvent(&host);
 1039 }
 1040 
 1041 
 1042 void srvent::ServerError(int *codep)
 1043 {
 1044     LOG(1, ("srvent::ServerError: %s error (%s)\n",
 1045         name, RPC2_ErrorMsg(*codep)));
 1046 
 1047     /* Translate the return code. */
 1048     switch (*codep) {
 1049     case RPC2_FAIL:
 1050     case RPC2_NOCONNECTION:
 1051     case RPC2_TIMEOUT:
 1052     case RPC2_DEAD:
 1053     case RPC2_SEFAIL2:
 1054         *codep = ETIMEDOUT; break;
 1055 
 1056     case RPC2_SEFAIL1:
 1057     case RPC2_SEFAIL3:
 1058     case RPC2_SEFAIL4:
 1059         *codep = EIO; break;
 1060 
 1061     case RPC2_NAKED:
 1062     case RPC2_NOTCLIENT:
 1063         *codep = ERETRY; break;
 1064 
 1065         case RPC2_INVALIDOPCODE:
 1066         *codep = EOPNOTSUPP; break;
 1067 
 1068     default:
 1069         /* Map RPC2 warnings into EINVAL. */
 1070         if (*codep > RPC2_ELIMIT) { *codep = EINVAL; break; }
 1071         CHOKE("srvent::ServerError: illegal RPC code (%d)", *codep);
 1072     }
 1073 
 1074     if (!ServerIsDown()) {
 1075     /* Reset if TIMED'out or NAK'ed. */
 1076     switch (*codep) {
 1077         case ETIMEDOUT:
 1078         MarinerLog("connection::unreachable %s\n", name);
 1079         Reset();
 1080         break;
 1081 
 1082         case ERETRY:
 1083         /* Must have missed a down event! */
 1084         eprint("%s nak'ed", name);
 1085         Reset();
 1086         connid = -2;
 1087         VDB->UpEvent(&host);
 1088         break;
 1089 
 1090         default:
 1091         break;
 1092     }
 1093     }
 1094 }
 1095 
 1096 
 1097 void srvent::ServerUp(RPC2_Handle newconnid)
 1098 {
 1099     LOG(1, ("srvent::ServerUp: %s, connid = %d, newconnid = %d\n",
 1100          name, connid, newconnid));
 1101 
 1102     switch(connid) {
 1103     case 0:
 1104     MarinerLog("connection::up %s\n", name);
 1105     connid = newconnid;
 1106     VDB->UpEvent(&host);
 1107     break;
 1108 
 1109     case -1:
 1110     /* Initial case.  */
 1111     connid = newconnid;
 1112     VDB->UpEvent(&host);
 1113         break;
 1114 
 1115     case -2:
 1116     /* Following NAK.  Don't signal another UpEvent! */
 1117     connid = newconnid;
 1118         break;
 1119 
 1120     default:
 1121     /* Already considered up.  Must have missed a down event! */
 1122     Reset();
 1123     connid = newconnid;
 1124     VDB->UpEvent(&host);
 1125     }
 1126 
 1127     /* Poke any threads waiting for a change in communication state. */
 1128     Rtry_Signal();
 1129 }
 1130 
 1131 
 1132 long srvent::GetLiveness(struct timeval *tp)
 1133 {
 1134     long rc = 0;
 1135     struct timeval t;
 1136 
 1137     LOG(100, ("srvent::GetLiveness (%s)\n", name));
 1138 
 1139     tp->tv_sec = tp->tv_usec = 0;
 1140     t.tv_sec = t.tv_usec = 0;
 1141 
 1142     /* we don't have a real connid if the server is down or "quasi-up" */
 1143     if (connid <= 0) 
 1144     return(ETIMEDOUT);
 1145 
 1146     /* Our peer is at the other end of the callback connection */
 1147     if ((rc = RPC2_GetPeerLiveness(connid, tp, &t)) != RPC2_SUCCESS)
 1148     return(rc);
 1149 
 1150     LOG(100, ("srvent::GetLiveness: (%s), RPC %ld.%0ld, SE %ld.%0ld\n",
 1151           name, tp->tv_sec, tp->tv_usec, t.tv_sec, t.tv_usec));
 1152 
 1153     if (tp->tv_sec < t.tv_sec ||
 1154     (tp->tv_sec == t.tv_sec && tp->tv_usec < t.tv_usec))
 1155     *tp = t;    /* structure assignment */
 1156 
 1157     return(0);
 1158 }
 1159 
 1160 
 1161 /* 
 1162  * calculates current bandwidth to server, taking the current estimates from
 1163  * RPC2/SFTP.
 1164  *
 1165  * Triggers weakly/strongly connected transitions if appropriate.
 1166  */
 1167 
 1168 /* returns bandwidth in Bytes/sec, or INIT_BW if it couldn't be obtained */
 1169 long srvent::GetBandwidth(unsigned long *Bandwidth)
 1170 {
 1171     long rc = 0;
 1172     unsigned long oldbw = bw;
 1173     unsigned long bwmin, bwmax;
 1174 
 1175     LOG(1, ("srvent::GetBandwidth (%s) lastobs %ld.%06ld\n",
 1176           name, lastobs.tv_sec, lastobs.tv_usec));
 1177 
 1178     /* we don't have a real connid if the server is down or "quasi-up" */
 1179     if (connid <= 0)
 1180     return(ETIMEDOUT);
 1181 
 1182     /* retrieve the bandwidth information from RPC2 */
 1183     if ((rc = RPC2_GetBandwidth(connid, &bwmin, &bw, &bwmax)) != RPC2_SUCCESS)
 1184     return(rc);
 1185 
 1186     LOG(1, ("srvent:GetBandWidth: --> new BW %d bytes/sec\n", bw));
 1187 
 1188     /* update last observation time */
 1189     RPC2_GetLastObs(connid, &lastobs);
 1190 
 1191     *Bandwidth = bw;
 1192     /* only report new bandwidth estimate if it has changed by more than ~10% */
 1193     if ((bw > (oldbw + oldbw / 8)) || (bw < (oldbw - oldbw / 8)))
 1194     {
 1195     MarinerLog("connection::bandwidth %s %d %d %d\n", name, bwmin,bw,bwmax);
 1196     }
 1197     LOG(1, ("srvent::GetBandwidth (%s) returns %d bytes/sec\n",
 1198           name, *Bandwidth));
 1199     return(0);
 1200 }
 1201 
 1202 
 1203 void srvent::print(FILE *f)
 1204 {
 1205     fprintf(f, "%p : %-16s : cid = %d, host = %s, binding = %d, bw = %ld\n",
 1206             this, name, (int)connid, inet_ntoa(host), Xbinding, bw);
 1207     PrintRef(f);
 1208 }
 1209 
 1210 
 1211 srv_iterator::srv_iterator() : olist_iterator((olist&)*srvent::srvtab) {
 1212 }
 1213 
 1214 
 1215 srvent *srv_iterator::operator()() {
 1216     olink *o = olist_iterator::operator()();
 1217     if (!o) return(0);
 1218 
 1219     srvent *s = strbase(srvent, o, tblhandle);
 1220     return(s);
 1221 }
 1222 
 1223 
 1224 /* hooks in librpc2 that existed for the old libfail functionality. We use
 1225  * these leftover hooks to implement cfs disconnect and cfs reconnect */
 1226 extern int (*Fail_SendPredicate)(unsigned char ip1, unsigned char ip2,
 1227                  unsigned char ip3, unsigned char ip4,
 1228                  unsigned char color, RPC2_PacketBuffer *pb,
 1229                  struct sockaddr_in *sin, int fd);
 1230 extern int (*Fail_RecvPredicate)(unsigned char ip1, unsigned char ip2,
 1231                  unsigned char ip3, unsigned char ip4,
 1232                  unsigned char color, RPC2_PacketBuffer *pb,
 1233                  struct sockaddr_in *sin, int fd);
 1234 
 1235 static int DropPacket(unsigned char ip1, unsigned char ip2,
 1236               unsigned char ip3, unsigned char ip4,
 1237               unsigned char color, RPC2_PacketBuffer *pb,
 1238               struct sockaddr_in *sin, int fd)
 1239 {
 1240     /* Tell rpc2 to drop the packet */
 1241     return 0;
 1242 }
 1243 
 1244 int FailDisconnect(int nservers, struct in_addr *hostids)
 1245 {
 1246     Fail_SendPredicate = Fail_RecvPredicate = &DropPacket;
 1247     return 0;
 1248 }
 1249 
 1250 int FailReconnect(int nservers, struct in_addr *hostids)
 1251 {
 1252     Fail_SendPredicate = Fail_RecvPredicate = NULL;
 1253     return 0;
 1254 }
 1255