libafs: Put back GetCapabilities user reference
[openafs.git] / src / afs / afs_server.c
index c00dd21..e177358 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Copyright 2000, International Business Machines Corporation and others.
  * All Rights Reserved.
- * 
+ *
  * This software has been released under the terms of the IBM Public
  * License.  For details, see the LICENSE file in the top-level source
  * directory or online at http://www.openafs.org/dl/license10.html
  * afsi_SetServerIPRank
  * afs_GetServer
  * afs_ActivateServer
- * 
+ *
  *
  * Local:
  * HaveCallBacksFrom
  * CheckVLServer
  * afs_SortOneServer
  * afs_SetServerPrefs
- * 
+ *
  */
 #include <afsconfig.h>
 #include "afs/param.h"
@@ -130,8 +130,8 @@ GetUpDownStats(struct server *srv)
 void
 afs_MarkServerUpOrDown(struct srvAddr *sa, int a_isDown)
 {
-    register struct server *a_serverP = sa->server;
-    register struct srvAddr *sap;
+    struct server *a_serverP = sa->server;
+    struct srvAddr *sap;
     osi_timeval_t currTime, *currTimeP;        /*Current time */
     afs_int32 downTime;                /*Computed downtime, in seconds */
     struct afs_stats_SrvUpDownInfo *upDownP;   /*Ptr to up/down info record */
@@ -153,7 +153,7 @@ afs_MarkServerUpOrDown(struct srvAddr *sa, int a_isDown)
                return;
            }
        }
-       /* 
+       /*
         * All ips are down we treat the whole server down
         */
        a_serverP->flags |= SRVR_ISDOWN;
@@ -240,10 +240,10 @@ afs_MarkServerUpOrDown(struct srvAddr *sa, int a_isDown)
 afs_int32
 afs_ServerDown(struct srvAddr *sa)
 {
-    register struct server *aserver = sa->server;
+    struct server *aserver = sa->server;
 
     AFS_STATCNT(ServerDown);
-    if (aserver->flags & SRVR_ISDOWN || sa->sa_flags & SRVADDR_ISDOWN) 
+    if (aserver->flags & SRVR_ISDOWN || sa->sa_flags & SRVADDR_ISDOWN)
        return 0;
     afs_MarkServerUpOrDown(sa, SRVR_ISDOWN);
     if (sa->sa_portal == aserver->cell->vlport)
@@ -260,9 +260,9 @@ afs_ServerDown(struct srvAddr *sa)
 int
 afs_HaveCallBacksFrom(struct server *aserver)
 {
-    register afs_int32 now;
-    register int i;
-    register struct vcache *tvc;
+    afs_int32 now;
+    int i;
+    struct vcache *tvc;
 
     AFS_STATCNT(HaveCallBacksFrom);
     now = osi_Time();          /* for checking for expired callbacks */
@@ -283,11 +283,12 @@ afs_HaveCallBacksFrom(struct server *aserver)
 
 
 static void
-CheckVLServer(register struct srvAddr *sa, struct vrequest *areq)
+CheckVLServer(struct srvAddr *sa, struct vrequest *areq)
 {
-    register struct server *aserver = sa->server;
-    register struct afs_conn *tc;
-    register afs_int32 code;
+    struct server *aserver = sa->server;
+    struct afs_conn *tc;
+    afs_int32 code;
+    struct rx_connection *rxconn;
 
     AFS_STATCNT(CheckVLServer);
     /* Ping dead servers to see if they're back */
@@ -298,22 +299,22 @@ CheckVLServer(register struct srvAddr *sa, struct vrequest *areq)
        return;                 /* can't do much */
 
     tc = afs_ConnByHost(aserver, aserver->cell->vlport,
-                       aserver->cell->cellNum, areq, 1, SHARED_LOCK);
+                       aserver->cell->cellNum, areq, 1, SHARED_LOCK, &rxconn);
     if (!tc)
        return;
-    rx_SetConnDeadTime(tc->id, 3);
+    rx_SetConnDeadTime(rxconn, 3);
 
     RX_AFS_GUNLOCK();
-    code = VL_ProbeServer(tc->id);
+    code = VL_ProbeServer(rxconn);
     RX_AFS_GLOCK();
-    rx_SetConnDeadTime(tc->id, afs_rx_deadtime);
-    afs_PutConn(tc, SHARED_LOCK);
+    rx_SetConnDeadTime(rxconn, afs_rx_deadtime);
+    afs_PutConn(tc, rxconn, SHARED_LOCK);
     /*
      * If probe worked, or probe call not yet defined (for compatibility
      * with old vlsevers), then we treat this server as running again
      */
     if (code == 0 || (code <= -450 && code >= -470)) {
-       if (tc->srvr == sa) {
+       if (tc->parent->srvr == sa) {
            afs_MarkServerUpOrDown(sa, 0);
            print_internet_address("afs: volume location server ", sa,
                                   " is back up", 2);
@@ -422,7 +423,7 @@ afs_CountServers(void)
 
            /*
             * Any further tallying for this record will only be done if it has
-            * been activated. 
+            * been activated.
             */
            if ((currSrvP->flags & AFS_SERVER_FLAG_ACTIVATED)
                && currSrvP->addr && currSrvP->cell) {
@@ -505,6 +506,7 @@ ForceAllNewConnections(void)
     }
 
     addrs = afs_osi_Alloc(srvAddrCount * sizeof(*addrs));
+    osi_Assert(addrs != NULL);
     j = 0;
     for (i = 0; i < NSERVERS; i++) {
        for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
@@ -522,31 +524,260 @@ ForceAllNewConnections(void)
     }
 }
 
+static void
+CkSrv_MarkUpDown(struct afs_conn **conns, int nconns, afs_int32 *results)
+{
+    struct srvAddr *sa;
+    struct afs_conn *tc;
+    afs_int32 i;
+
+    for(i = 0; i < nconns; i++){
+       tc = conns[i];
+       sa = tc->parent->srvr;
+
+       if (( results[i] >= 0 ) && (sa->sa_flags & SRVADDR_ISDOWN) &&
+           (tc->parent->srvr == sa)) {
+           /* server back up */
+           print_internet_address("afs: file server ", sa, " is back up", 2);
+
+           ObtainWriteLock(&afs_xserver, 244);
+           ObtainWriteLock(&afs_xsrvAddr, 245);
+           afs_MarkServerUpOrDown(sa, 0);
+           ReleaseWriteLock(&afs_xsrvAddr);
+           ReleaseWriteLock(&afs_xserver);
+
+           if (afs_waitForeverCount) {
+               afs_osi_Wakeup(&afs_waitForever);
+           }
+       } else {
+           if (results[i] < 0) {
+               /* server crashed */
+               afs_ServerDown(sa);
+               ForceNewConnections(sa);  /* multi homed clients */
+           }
+       }
+    }
+}
+
+void
+CkSrv_SetTime(struct rx_connection **rxconns, int nconns, int nservers,
+             struct afs_conn **conns, struct srvAddr **addrs)
+{
+    struct afs_conn *tc;
+    afs_int32 start, end = 0, delta;
+    osi_timeval_t tv;
+    struct srvAddr *sa;
+    afs_int32 *conntimer, *results, *deltas;
+    afs_int32 i = 0;
+    char tbuffer[CVBS];
+
+    conntimer = afs_osi_Alloc(nservers * sizeof (afs_int32));
+    osi_Assert(conntimer != NULL);
+    results = afs_osi_Alloc(nservers * sizeof (afs_int32));
+    osi_Assert(results != NULL);
+    deltas = afs_osi_Alloc(nservers * sizeof (afs_int32));
+    osi_Assert(deltas != NULL);
+
+    /* make sure we're starting from zero */
+    memset(&deltas, 0, sizeof(deltas));
+
+    start = osi_Time();         /* time the gettimeofday call */
+    AFS_GUNLOCK();
+    if ( afs_setTimeHost == NULL ) {
+       multi_Rx(rxconns,nconns)
+       {
+           tv.tv_sec = tv.tv_usec = 0;
+           multi_RXAFS_GetTime(
+               (afs_uint32 *)&tv.tv_sec, (afs_uint32 *)&tv.tv_usec);
+           tc = conns[multi_i];
+           sa = tc->parent->srvr;
+           if (conntimer[multi_i] == 1)
+               rx_SetConnDeadTime(rxconns[multi_i], afs_rx_deadtime);
+           end = osi_Time();
+           results[multi_i]=multi_error;
+           if ((start == end) && !multi_error)
+               deltas[multi_i] = end - tv.tv_sec;
+       } multi_End;
+    } else {                   /* find and query setTimeHost only */
+       for ( i = 0 ; i < nservers ; i++ ) {
+           if ( conns[i] == NULL || conns[i]->parent->srvr == NULL )
+               continue;
+           if ( conns[i]->parent->srvr->server == afs_setTimeHost ) {
+               tv.tv_sec = tv.tv_usec = 0;
+               results[i] = RXAFS_GetTime(rxconns[i],
+                                          (afs_uint32 *)&tv.tv_sec,
+                                          (afs_uint32 *)&tv.tv_usec);
+               end = osi_Time();
+               if ((start == end) && !results[i])
+                   deltas[i] = end - tv.tv_sec;
+               break;
+           }
+       }
+    }
+    AFS_GLOCK();
+
+    if ( afs_setTimeHost == NULL )
+       CkSrv_MarkUpDown(conns, nconns, results);
+    else /* We lack info for other than this host */
+       CkSrv_MarkUpDown(&conns[i], 1, &results[i]);
+
+    /*
+     * If we're supposed to set the time, and the call worked
+     * quickly (same second response) and this is the host we
+     * use for the time and the time is really different, then
+     * really set the time
+     */
+    if (afs_setTime != 0) {
+       for (i=0; i<nconns; i++) {
+           delta = deltas[i];
+           tc = conns[i];
+           sa = tc->parent->srvr;
+
+           if ((tc->parent->srvr->server == afs_setTimeHost ||
+                /* Sync only to a server in the local cell */
+                (afs_setTimeHost == (struct server *)0 &&
+                 afs_IsPrimaryCell(sa->server->cell)))) {
+               /* set the time */
+               char msgbuf[90];  /* strlen("afs: setting clock...") + slop */
+               delta = end - tv.tv_sec;   /* how many secs fast we are */
+
+               afs_setTimeHost = tc->parent->srvr->server;
+               /* see if clock has changed enough to make it worthwhile */
+               if (delta >= AFS_MINCHANGE || delta <= -AFS_MINCHANGE) {
+                   end = osi_Time();
+                   if (delta > AFS_MAXCHANGEBACK) {
+                       /* setting clock too far back, just do it a little */
+                       tv.tv_sec = end - AFS_MAXCHANGEBACK;
+                   } else {
+                       tv.tv_sec = end - delta;
+                   }
+                   afs_osi_SetTime(&tv);
+                   if (delta > 0) {
+                       strcpy(msgbuf, "afs: setting clock back ");
+                       if (delta > AFS_MAXCHANGEBACK) {
+                           afs_strcat(msgbuf,
+                                      afs_cv2string(&tbuffer[CVBS],
+                                                    AFS_MAXCHANGEBACK));
+                           afs_strcat(msgbuf, " seconds (of ");
+                           afs_strcat(msgbuf,
+                                      afs_cv2string(&tbuffer[CVBS],
+                                                    delta -
+                                                    AFS_MAXCHANGEBACK));
+                           afs_strcat(msgbuf, ", via ");
+                           print_internet_address(msgbuf, sa,
+                                                  "); clock is still fast.",
+                                                  0);
+                       } else {
+                           afs_strcat(msgbuf,
+                                      afs_cv2string(&tbuffer[CVBS], delta));
+                           afs_strcat(msgbuf, " seconds (via ");
+                           print_internet_address(msgbuf, sa, ").", 0);
+                       }
+                   } else {
+                       strcpy(msgbuf, "afs: setting clock ahead ");
+                       afs_strcat(msgbuf,
+                                  afs_cv2string(&tbuffer[CVBS], -delta));
+                       afs_strcat(msgbuf, " seconds (via ");
+                       print_internet_address(msgbuf, sa, ").", 0);
+                   }
+                    /* We're only going to set it once; why bother looping? */
+                   break;
+               }
+           }
+       }
+    }
+    afs_osi_Free(conntimer, nservers * sizeof(afs_int32));
+    afs_osi_Free(deltas, nservers * sizeof(afs_int32));
+    afs_osi_Free(results, nservers * sizeof(afs_int32));
+}
+
+void
+CkSrv_GetCaps(struct rx_connection **rxconns, int nconns, int nservers,
+             struct afs_conn **conns, struct srvAddr **addrs)
+{
+    Capabilities *caps;
+    afs_int32 *results;
+    afs_int32 i;
+    struct server *ts;
+
+    caps = afs_osi_Alloc(nservers * sizeof (Capabilities));
+    osi_Assert(caps != NULL);
+    memset(caps, 0, nservers * sizeof(Capabilities));
+
+    results = afs_osi_Alloc(nservers * sizeof (afs_int32));
+    osi_Assert(results != NULL);
+
+    AFS_GUNLOCK();
+    multi_Rx(rxconns,nconns)
+      {
+       multi_RXAFS_GetCapabilities(&caps[multi_i]);
+       results[multi_i] = multi_error;
+      } multi_End;
+    AFS_GLOCK();
+
+    for ( i = 0 ; i < nconns ; i++ ) {
+       ts = addrs[i]->server;
+       if ( !ts )
+           continue;
+       ts->capabilities = 0;
+       ts->flags |= SCAPS_KNOWN;
+       if ( results[i] == RXGEN_OPCODE ) {
+           /* Mark server as up - it responded */
+           results[i] = 0;
+           continue;
+       }
+       if ( results[i] >= 0 )
+           /* we currently handle 32-bits of capabilities */
+           if (caps[i].Capabilities_len > 0) {
+               ts->capabilities = caps[i].Capabilities_val[0];
+               xdr_free((xdrproc_t)xdr_Capabilities, &caps[i]);
+               caps[i].Capabilities_val = NULL;
+               caps[i].Capabilities_len = 0;
+           }
+    }
+    CkSrv_MarkUpDown(conns, nconns, results);
+
+    afs_osi_Free(caps, nservers * sizeof(Capabilities));
+    afs_osi_Free(results, nservers * sizeof(afs_int32));
+}
+
 /* check down servers (if adown), or running servers (if !adown) */
 void
 afs_CheckServers(int adown, struct cell *acellp)
 {
+    afs_LoopServers(adown?AFS_LS_DOWN:AFS_LS_UP, acellp, 1, CkSrv_GetCaps,
+                   afs_setTime?CkSrv_SetTime:NULL);
+}
+
+/* adown: AFS_LS_UP   - check only up
+ *        AFS_LS_DOWN - check only down.
+ *        AFS_LS_ALL  - check all */
+void
+afs_LoopServers(int adown, struct cell *acellp, int vlalso,
+               void (*func1) (struct rx_connection **rxconns, int nconns,
+                              int nservers, struct afs_conn **conns,
+                              struct srvAddr **addrs),
+               void (*func2) (struct rx_connection **rxconns, int nconns,
+                              int nservers, struct afs_conn **conns,
+                              struct srvAddr **addrs))
+{
     struct vrequest treq;
     struct server *ts;
     struct srvAddr *sa;
-    struct afs_conn *tc;
+    struct afs_conn *tc = NULL;
     afs_int32 i, j;
     afs_int32 code;
-    afs_int32 start, end = 0, delta;
-    osi_timeval_t tv;
     struct unixuser *tu;
-    char tbuffer[CVBS];
     int srvAddrCount;
     struct srvAddr **addrs;
     struct afs_conn **conns;
     int nconns;
-    struct rx_connection **rxconns;      
-    afs_int32 *conntimer, *deltas, *results;
-    Capabilities *caps = NULL;
+    struct rx_connection **rxconns;
+    afs_int32 *conntimer, *results;
 
     AFS_STATCNT(afs_CheckServers);
 
-    /* 
+    /*
      * No sense in doing the server checks if we are running in disconnected
      * mode
      */
@@ -571,6 +802,7 @@ afs_CheckServers(int adown, struct cell *acellp)
     }
 
     addrs = afs_osi_Alloc(srvAddrCount * sizeof(*addrs));
+    osi_Assert(addrs != NULL);
     j = 0;
     for (i = 0; i < NSERVERS; i++) {
        for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
@@ -583,17 +815,17 @@ afs_CheckServers(int adown, struct cell *acellp)
     ReleaseReadLock(&afs_xsrvAddr);
     ReleaseReadLock(&afs_xserver);
 
-    conns = (struct afs_conn **)afs_osi_Alloc(j * sizeof(struct afs_conn *));
-    rxconns = (struct rx_connection **)afs_osi_Alloc(j * sizeof(struct rx_connection *));
-    conntimer = (afs_int32 *)afs_osi_Alloc(j * sizeof (afs_int32));
-    deltas = (afs_int32 *)afs_osi_Alloc(j * sizeof (afs_int32));
-    results = (afs_int32 *)afs_osi_Alloc(j * sizeof (afs_int32));
-
-    caps = (Capabilities *)afs_osi_Alloc(j * sizeof (Capabilities));
-    memset(caps, 0, j * sizeof(Capabilities));
+    conns = afs_osi_Alloc(j * sizeof(struct afs_conn *));
+    osi_Assert(conns != NULL);
+    rxconns = afs_osi_Alloc(j * sizeof(struct rx_connection *));
+    osi_Assert(rxconns != NULL);
+    conntimer = afs_osi_Alloc(j * sizeof (afs_int32));
+    osi_Assert(conntimer != NULL);
+    results = afs_osi_Alloc(j * sizeof (afs_int32));
+    osi_Assert(results != NULL);
 
     for (i = 0; i < j; i++) {
-       deltas[i] = 0;
+       struct rx_connection *rxconn;
        sa = addrs[i];
        ts = sa->server;
        if (!ts)
@@ -605,13 +837,14 @@ afs_CheckServers(int adown, struct cell *acellp)
        if (acellp && acellp != ts->cell)
            continue;
 
-       if ((!adown && (sa->sa_flags & SRVADDR_ISDOWN))
-           || (adown && !(sa->sa_flags & SRVADDR_ISDOWN)))
+       if (((adown==AFS_LS_DOWN) && !(sa->sa_flags & SRVADDR_ISDOWN))
+           || ((adown==AFS_LS_UP) && (sa->sa_flags & SRVADDR_ISDOWN)))
            continue;
 
        /* check vlserver with special code */
        if (sa->sa_portal == AFS_VLPORT) {
-           CheckVLServer(sa, &treq);
+           if (vlalso)
+               CheckVLServer(sa, &treq);
            continue;
        }
 
@@ -621,17 +854,17 @@ afs_CheckServers(int adown, struct cell *acellp)
        /* get a connection, even if host is down; bumps conn ref count */
        tu = afs_GetUser(treq.uid, ts->cell->cellNum, SHARED_LOCK);
        tc = afs_ConnBySA(sa, ts->cell->fsport, ts->cell->cellNum, tu,
-                         1 /*force */ , 1 /*create */ , SHARED_LOCK);
+                         1 /*force */ , 1 /*create */ , SHARED_LOCK, &rxconn);
        afs_PutUser(tu, SHARED_LOCK);
        if (!tc)
            continue;
 
        if ((sa->sa_flags & SRVADDR_ISDOWN) || afs_HaveCallBacksFrom(sa->server)
-           || (tc->srvr->server == afs_setTimeHost)) {
-           conns[nconns]=tc; 
-           rxconns[nconns]=tc->id;
+           || (tc->parent->srvr->server == afs_setTimeHost)) {
+           conns[nconns]=tc;
+           rxconns[nconns]=rxconn;
            if (sa->sa_flags & SRVADDR_ISDOWN) {
-               rx_SetConnDeadTime(tc->id, 3);
+               rx_SetConnDeadTime(rxconn, 3);
                conntimer[nconns]=1;
            } else {
                conntimer[nconns]=0;
@@ -640,176 +873,24 @@ afs_CheckServers(int adown, struct cell *acellp)
        }
     } /* Outer loop over addrs */
 
-    AFS_GUNLOCK();
-    multi_Rx(rxconns,nconns)
-      {
-       multi_RXAFS_GetCapabilities(&caps[multi_i]);
-       results[multi_i] = multi_error;
-      } multi_End;
-    AFS_GLOCK();
-
-    for ( i = 0 ; i < nconns ; i++ ) {
-       ts = addrs[i]->server;
-       if ( !ts )
-           continue;
-       ts->capabilities = 0;
-       ts->flags |= SCAPS_KNOWN;
-       if ( results[i] == RXGEN_OPCODE ) {
-           /* Mark server as up - it responded */
-           results[i] = 0;
-           continue;
-       }
-       if ( results[i] >= 0 )
-           /* we currently handle 32-bits of capabilities */
-           if (caps[i].Capabilities_len > 0) {
-               ts->capabilities = caps[i].Capabilities_val[0];
-               xdr_free((xdrproc_t)xdr_Capabilities, &caps[i]);
-               caps[i].Capabilities_val = NULL;
-               caps[i].Capabilities_len = 0;
-           }
-    }
+    (*func1)(rxconns, nconns, j, conns, addrs);
 
-    if ( afs_setTime != 0 ) {
-       start = osi_Time();         /* time the gettimeofday call */
-       AFS_GUNLOCK();
-       if ( afs_setTimeHost == NULL ) {
-           multi_Rx(rxconns,nconns)
-             {
-               tv.tv_sec = tv.tv_usec = 0;
-               multi_RXAFS_GetTime(
-                       (afs_uint32 *)&tv.tv_sec, (afs_uint32 *)&tv.tv_usec);
-               tc = conns[multi_i];
-               sa = tc->srvr;
-               if (conntimer[multi_i] == 1)
-                 rx_SetConnDeadTime(tc->id, afs_rx_deadtime);
-               end = osi_Time();
-               results[multi_i]=multi_error;
-               if ((start == end) && !multi_error)
-                 deltas[multi_i] = end - tv.tv_sec;
-
-             } multi_End;
-           }
-       else {                  /* find and query setTimeHost only */
-           for ( i = 0 ; i < j ; i++ ) {
-               if ( conns[i] == NULL || conns[i]->srvr == NULL )
-                   continue;
-               if ( conns[i]->srvr->server == afs_setTimeHost ) {
-                   tv.tv_sec = tv.tv_usec = 0;
-                   results[i] = RXAFS_GetTime(rxconns[i],
-                               (afs_uint32 *)&tv.tv_sec, (afs_uint32 *)&tv.tv_usec);
-                   end = osi_Time();
-                   if ((start == end) && !results[i])
-                       deltas[i] = end - tv.tv_sec;
-                   break;
-               }
-           }
-       }
-       AFS_GLOCK();
-    }
-    
-    for(i=0;i<nconns;i++){
-      tc = conns[i];
-      sa = tc->srvr;
-      
-      if (( results[i] >= 0 ) && (sa->sa_flags & SRVADDR_ISDOWN) && (tc->srvr == sa)) {
-       /* server back up */
-       print_internet_address("afs: file server ", sa, " is back up", 2);
-       
-       ObtainWriteLock(&afs_xserver, 244);
-       ObtainWriteLock(&afs_xsrvAddr, 245);        
-       afs_MarkServerUpOrDown(sa, 0);
-       ReleaseWriteLock(&afs_xsrvAddr);
-       ReleaseWriteLock(&afs_xserver);
-       
-       if (afs_waitForeverCount) {
-         afs_osi_Wakeup(&afs_waitForever);
-       }
-      } else {
-       if (results[i] < 0) {
-         /* server crashed */
-         afs_ServerDown(sa);
-         ForceNewConnections(sa);  /* multi homed clients */
-       }
-      }
+    if (func2) {
+       (*func2)(rxconns, nconns, j, conns, addrs);
     }
 
-    /*
-     * If we're supposed to set the time, and the call worked
-     * quickly (same second response) and this is the host we
-     * use for the time and the time is really different, then
-     * really set the time
-     */
-    if (afs_setTime != 0) {
-       for (i=0; i<nconns; i++) {
-           delta = deltas[i];
-           tc = conns[i];
-           sa = tc->srvr;
-           
-           if ((tc->srvr->server == afs_setTimeHost ||
-                /* Sync only to a server in the local cell */
-                (afs_setTimeHost == (struct server *)0 &&
-                 afs_IsPrimaryCell(sa->server->cell)))) {
-               /* set the time */
-               char msgbuf[90];  /* strlen("afs: setting clock...") + slop */
-               delta = end - tv.tv_sec;   /* how many secs fast we are */
-               
-               afs_setTimeHost = tc->srvr->server;
-               /* see if clock has changed enough to make it worthwhile */
-               if (delta >= AFS_MINCHANGE || delta <= -AFS_MINCHANGE) {
-                   end = osi_Time();
-                   if (delta > AFS_MAXCHANGEBACK) {
-                       /* setting clock too far back, just do it a little */
-                       tv.tv_sec = end - AFS_MAXCHANGEBACK;
-                   } else {
-                       tv.tv_sec = end - delta;
-                   }
-                   afs_osi_SetTime(&tv);
-                   if (delta > 0) {
-                       strcpy(msgbuf, "afs: setting clock back ");
-                       if (delta > AFS_MAXCHANGEBACK) {
-                           afs_strcat(msgbuf, 
-                                      afs_cv2string(&tbuffer[CVBS], 
-                                                    AFS_MAXCHANGEBACK));
-                           afs_strcat(msgbuf, " seconds (of ");
-                           afs_strcat(msgbuf, 
-                                      afs_cv2string(&tbuffer[CVBS], 
-                                                    delta - 
-                                                    AFS_MAXCHANGEBACK));
-                           afs_strcat(msgbuf, ", via ");
-                           print_internet_address(msgbuf, sa, 
-                                                  "); clock is still fast.",
-                                                  0);
-                       } else {
-                           afs_strcat(msgbuf, 
-                                      afs_cv2string(&tbuffer[CVBS], delta));
-                           afs_strcat(msgbuf, " seconds (via ");
-                           print_internet_address(msgbuf, sa, ").", 0);
-                       }
-                   } else {
-                       strcpy(msgbuf, "afs: setting clock ahead ");
-                       afs_strcat(msgbuf, 
-                                  afs_cv2string(&tbuffer[CVBS], -delta));
-                       afs_strcat(msgbuf, " seconds (via ");
-                       print_internet_address(msgbuf, sa, ").", 0);
-                   }
-                    /* We're only going to set it once; why bother looping? */
-                   break; 
-               }
-           }
-       }
-    }
     for (i = 0; i < nconns; i++) {
-       afs_PutConn(conns[i], SHARED_LOCK);     /* done with it now */
+       if (conntimer[i] == 1)
+           rx_SetConnDeadTime(rxconns[i], afs_rx_deadtime);
+       afs_PutConn(conns[i], rxconns[i], SHARED_LOCK);     /* done with it now */
     }
-    
+
     afs_osi_Free(addrs, srvAddrCount * sizeof(*addrs));
     afs_osi_Free(conns, j * sizeof(struct afs_conn *));
     afs_osi_Free(rxconns, j * sizeof(struct rx_connection *));
     afs_osi_Free(conntimer, j * sizeof(afs_int32));
-    afs_osi_Free(deltas, j * sizeof(afs_int32));
     afs_osi_Free(results, j * sizeof(afs_int32));
-    afs_osi_Free(caps, j * sizeof(Capabilities));
-    
+
 } /*afs_CheckServers*/
 
 
@@ -856,19 +937,19 @@ afs_FindServer(afs_int32 aserver, afs_uint16 aport, afsUUID * uuidp,
 
 /* Rules:
    X = (aX + c) % m
-   m is a power of two 
+   m is a power of two
    a % 8 is 5
    a is 0.73m  should be 0.01m .. 0.99m
    c is more or less immaterial.  1 or a is suggested.
-  
+
 NB:  LOW ORDER BITS are not very random.  To get small random numbers,
-     treat result as <1, with implied binary point, and multiply by 
+     treat result as <1, with implied binary point, and multiply by
      desired modulus.
 NB:  Has to be unsigned, since shifts on signed quantities may preserve
      the sign bit.
 */
-/* added rxi_getaddr() to try to get as much initial randomness as 
-   possible, since at least one customer reboots ALL their clients 
+/* added rxi_getaddr() to try to get as much initial randomness as
+   possible, since at least one customer reboots ALL their clients
    simultaneously -- so osi_Time is bound to be the same on some of the
    clients.  This is probably OK, but I don't want to see too much of it.
 */
@@ -879,7 +960,7 @@ unsigned int
 afs_random(void)
 {
     static afs_int32 state = 0;
-    register int i;
+    int i;
 
     AFS_STATCNT(afs_random);
     if (!state) {
@@ -904,7 +985,7 @@ afs_random(void)
 /* returns int 0..14 using the high bits of a pseudo-random number instead of
    the low bits, as the low bits are "less random" than the high ones...
    slight roundoff error exists, an excercise for the reader.
-   need to multiply by something with lots of ones in it, so multiply by 
+   need to multiply by something with lots of ones in it, so multiply by
    8 or 16 is right out.
  */
 int
@@ -993,7 +1074,7 @@ afs_SortServers(struct server *aservers[], int count)
 }                              /*afs_SortServers */
 
 /* afs_SetServerPrefs is rather system-dependent.  It pokes around in kernel
-   data structures to determine what the local IP addresses and subnet masks 
+   data structures to determine what the local IP addresses and subnet masks
    are in order to choose which server(s) are on the local subnet.
 
    As I see it, there are several cases:
@@ -1005,19 +1086,19 @@ afs_SortServers(struct server *aservers[], int count)
    4. The server is on a different logical subnet or net than this host, but
    this host is a 'metric 0 gateway' to it.  Ie, two address-spaces share
    one physical medium.
-   5. This host has a direct (point-to-point, ie, PPP or SLIP) link to the 
+   5. This host has a direct (point-to-point, ie, PPP or SLIP) link to the
    server.
    6. This host and the server are disjoint.
 
    That is a rough order of preference.  If a point-to-point link has a high
-   metric, I'm assuming that it is a very slow link, and putting it at the 
-   bottom of the list (at least until RX works better over slow links).  If 
-   its metric is 1, I'm assuming that it's relatively fast (T1) and putting 
+   metric, I'm assuming that it is a very slow link, and putting it at the
+   bottom of the list (at least until RX works better over slow links).  If
+   its metric is 1, I'm assuming that it's relatively fast (T1) and putting
    it ahead of #6.
    It's not easy to check for case #4, so I'm ignoring it for the time being.
 
    BSD "if" code keeps track of some rough network statistics (cf 'netstat -i')
-   That could be used to prefer certain servers fairly easily.  Maybe some 
+   That could be used to prefer certain servers fairly easily.  Maybe some
    other time...
 
    NOTE: this code is very system-dependent, and very dependent on the TCP/IP
@@ -1146,8 +1227,8 @@ typedef struct ill_s {
 /*
  * The IP addresses and ranks are determined by afsd (in user space) and
  * passed into the kernel at startup time through the AFSOP_ADVISEADDR
- * system call. These are stored in the data structure 
- * called 'afs_cb_interface'. 
+ * system call. These are stored in the data structure
+ * called 'afs_cb_interface'.
  *
  * struct srvAddr *sa;         remote server
  * afs_int32 addr;                one of my local addr in net order
@@ -1191,7 +1272,7 @@ afsi_SetServerIPRank(struct srvAddr *sa, afs_int32 addr,
     return;
 }
 #else /* AFS_USERSPACE_IP_ADDR */
-#if (! defined(AFS_SUN5_ENV)) && !defined(AFS_DARWIN_ENV) && defined(USEIFADDR)
+#if (! defined(AFS_SUN5_ENV)) && (! defined(AFS_DARWIN_ENV)) && (! defined(AFS_OBSD47_ENV)) && defined(USEIFADDR)
 void
 afsi_SetServerIPRank(struct srvAddr *sa, struct in_ifaddr *ifa)
 {
@@ -1228,7 +1309,7 @@ afsi_SetServerIPRank(struct srvAddr *sa, struct in_ifaddr *ifa)
 #endif /* IFF_POINTTOPOINT */
 }
 #endif /*(!defined(AFS_SUN5_ENV)) && defined(USEIFADDR) */
-#if defined(AFS_DARWIN_ENV) && defined(USEIFADDR)
+#if (defined(AFS_DARWIN_ENV) || defined(AFS_OBSD47_ENV)) && defined(USEIFADDR)
 #ifndef afs_min
 #define afs_min(A,B) ((A)<(B)) ? (A) : (B)
 #endif
@@ -1245,7 +1326,7 @@ afsi_SetServerIPRank(struct srvAddr *sa, rx_ifaddr_t ifa)
     if (rx_ifaddr_address_family(ifa) != AF_INET)
        return;
     t = rx_ifaddr_address(ifa, &sout, sizeof(sout));
-    if (t == 0) {
+    if (t != 0) {
        sin = (struct sockaddr_in *)&sout;
        myAddr = ntohl(sin->sin_addr.s_addr);   /* one of my IP addr in host order */
     } else {
@@ -1253,16 +1334,16 @@ afsi_SetServerIPRank(struct srvAddr *sa, rx_ifaddr_t ifa)
     }
     serverAddr = ntohl(sa->sa_ip);     /* server's IP addr in host order */
     t = rx_ifaddr_netmask(ifa, &sout, sizeof(sout));
-    if (t == 0) {
+    if (t != 0) {
        sin = (struct sockaddr_in *)&sout;
        subnetmask = ntohl(sin->sin_addr.s_addr);       /* subnet mask in host order */
     } else {
        subnetmask = 0;
     }
     t = rx_ifaddr_dstaddress(ifa, &sout, sizeof(sout));
-    if (t == 0) {
+    if (t != 0) {
        sin = (struct sockaddr_in *)&sout;
-       myDstaddr = sin->sin_addr.s_addr;
+       myDstaddr = ntohl(sin->sin_addr.s_addr);
     } else {
        myDstaddr = 0;
     }
@@ -1392,7 +1473,7 @@ afs_SetServerPrefs(struct srvAddr *sa)
             }
         }
     }
-    
+
     rw_exit(&afsifinfo_lock);
 #else
     for (ill = (struct ill_s *)*addr /*ill_g_headp */ ; ill;
@@ -1406,7 +1487,7 @@ afs_SetServerPrefs(struct srvAddr *sa)
            subnet = ipif->ipif_local_addr & ipif->ipif_net_mask;
            subnetmask = ipif->ipif_net_mask;
            /*
-            * Generate the local net using the local address and 
+            * Generate the local net using the local address and
             * whate we know about Class A, B and C networks.
             */
            if (IN_CLASSA(ipif->ipif_local_addr)) {
@@ -1694,6 +1775,7 @@ afs_GetCapabilities(struct server *ts)
     struct vrequest treq;
     struct afs_conn *tc;
     struct unixuser *tu;
+    struct rx_connection *rxconn;
     afs_int32 code;
 
     if ( !ts || !ts->cell )
@@ -1707,14 +1789,21 @@ afs_GetCapabilities(struct server *ts)
     if ( !tu )
        return;
     tc = afs_ConnBySA(ts->addr, ts->cell->fsport, ts->cell->cellNum, tu, 0, 1,
-                                                               SHARED_LOCK);
+                                                               SHARED_LOCK,
+                                                                &rxconn);
+    afs_PutUser(tu, SHARED_LOCK);
     if ( !tc )
        return;
     /* InitCallBackStateN, triggered by our RPC, may need this */
     ReleaseWriteLock(&afs_xserver);
-    code = RXAFS_GetCapabilities(tc->id, &caps);
+    code = RXAFS_GetCapabilities(rxconn, &caps);
     ObtainWriteLock(&afs_xserver, 723);
-    afs_PutConn(tc, SHARED_LOCK);
+    /* we forced a conn above; important we mark it down if needed */
+    if ((code < 0) && (code != RXGEN_OPCODE)) {
+       afs_ServerDown(tc->parent->srvr);
+       ForceNewConnections(tc->parent->srvr); /* multi homed clients */
+    }
+    afs_PutConn(tc, rxconn, SHARED_LOCK);
     if ( code && code != RXGEN_OPCODE ) {
        afs_warn("RXAFS_GetCapabilities failed with code %d\n", code);
        /* better not be anything to free. we failed! */
@@ -1745,7 +1834,6 @@ afs_GetServer(afs_uint32 * aserverp, afs_int32 nservers, afs_int32 acell,
 {
     struct server *oldts = 0, *ts, *newts, *orphts = 0;
     struct srvAddr *oldsa, *newsa, *nextsa, *orphsa;
-    u_short fsport;
     afs_int32 iphash, k, srvcount = 0;
     unsigned int srvhash;
 
@@ -1792,7 +1880,7 @@ afs_GetServer(afs_uint32 * aserverp, afs_int32 nservers, afs_int32 acell,
     if (oldts) {
        newts = oldts;
     } else {
-       newts = (struct server *)afs_osi_Alloc(sizeof(struct server));
+       newts = afs_osi_Alloc(sizeof(struct server));
        if (!newts)
            panic("malloc of server struct");
        afs_totalServers++;
@@ -1814,8 +1902,6 @@ afs_GetServer(afs_uint32 * aserverp, afs_int32 nservers, afs_int32 acell,
     if (acell)
        newts->cell = afs_GetCell(acell, 0);
 
-    fsport = (newts->cell ? newts->cell->fsport : AFS_FSPORT);
-
     /* For each IP address we are registering */
     for (k = 0; k < nservers; k++) {
        iphash = SHash(aserverp[k]);
@@ -1837,7 +1923,7 @@ afs_GetServer(afs_uint32 * aserverp, afs_int32 nservers, afs_int32 acell,
        if (oldsa) {
            newsa = oldsa;
        } else {
-           newsa = (struct srvAddr *)afs_osi_Alloc(sizeof(struct srvAddr));
+           newsa = afs_osi_Alloc(sizeof(struct srvAddr));
            if (!newsa)
                panic("malloc of srvAddr struct");
            afs_totalSrvAddrs++;
@@ -1887,8 +1973,7 @@ afs_GetServer(afs_uint32 * aserverp, afs_int32 nservers, afs_int32 acell,
 
            /* Have a srvAddr struct. Now get a server struct (if not already) */
            if (!orphts) {
-               orphts =
-                   (struct server *)afs_osi_Alloc(sizeof(struct server));
+               orphts = afs_osi_Alloc(sizeof(struct server));
                if (!orphts)
                    panic("malloc of lo server struct");
                memset(orphts, 0, sizeof(struct server));
@@ -1896,7 +1981,7 @@ afs_GetServer(afs_uint32 * aserverp, afs_int32 nservers, afs_int32 acell,
 
                /* Add the orphaned server to the afs_servers[] hash chain.
                 * Its iphash does not matter since we never look up the server
-                * in the afs_servers table by its ip address (only by uuid - 
+                * in the afs_servers table by its ip address (only by uuid -
                 * which this has none).
                 */
                iphash = SHash(aserverp[k]);
@@ -1974,26 +2059,17 @@ afs_RemoveAllConns(void)
     int i;
     struct server *ts, *nts;
     struct srvAddr *sa;
-    struct afs_conn *tc, *ntc;
 
     ObtainReadLock(&afs_xserver);
     ObtainWriteLock(&afs_xconn, 1001);
-    
+
     /*printf("Destroying connections ... ");*/
     for (i = 0; i < NSERVERS; i++) {
         for (ts = afs_servers[i]; ts; ts = nts) {
             nts = ts->next;
             for (sa = ts->addr; sa; sa = sa->next_sa) {
                 if (sa->conns) {
-                    tc = sa->conns;
-                    while (tc) {
-                        ntc = tc->next;
-                        AFS_GUNLOCK();
-                        rx_DestroyConnection(tc->id);
-                        AFS_GLOCK();
-                        afs_osi_Free(tc, sizeof(struct afs_conn));
-                        tc = ntc;
-                    }
+                    afs_ReleaseConns(sa->conns);
                     sa->conns = NULL;
                 }
             }
@@ -2003,7 +2079,7 @@ afs_RemoveAllConns(void)
 
     ReleaseWriteLock(&afs_xconn);
     ReleaseReadLock(&afs_xserver);
-    
+
 }
 
 void