blacklist-move-init-checks-back-into-req-code-20081020
[openafs.git] / src / afs / afs_conn.c
index dc1f3cd..252e72c 100644 (file)
 /*
  * Implements:
  */
-#include "../afs/param.h"      /* Should be always first */
 #include <afsconfig.h>
+#include "afs/param.h"
 
-RCSID("$Header$");
+RCSID
+    ("$Header$");
 
-#include "../afs/stds.h"
-#include "../afs/sysincludes.h"        /* Standard vendor system headers */
+#include "afs/stds.h"
+#include "afs/sysincludes.h"   /* Standard vendor system headers */
 
 #if !defined(UKERNEL)
+#if !defined(AFS_LINUX20_ENV)
 #include <net/if.h>
+#endif
 #include <netinet/in.h>
 
 #ifdef AFS_SGI62_ENV
-#include "../h/hashing.h"
+#include "h/hashing.h"
 #endif
-#if !defined(AFS_HPUX110_ENV) && !defined(AFS_LINUX20_ENV)
+#if !defined(AFS_HPUX110_ENV) && !defined(AFS_LINUX20_ENV) && !defined(AFS_DARWIN60_ENV)
 #include <netinet/in_var.h>
 #endif /* ! AFS_HPUX110_ENV */
 #endif /* !defined(UKERNEL) */
 
-#include "../afs/afsincludes.h"        /* Afs-based standard headers */
-#include "../afs/afs_stats.h"   /* afs statistics */
+#include "afsincludes.h"       /* Afs-based standard headers */
+#include "afs/afs_stats.h"     /* afs statistics */
 
 #if    defined(AFS_SUN56_ENV)
 #include <inet/led.h>
@@ -42,169 +45,195 @@ RCSID("$Header$");
 #include <inet/ip.h>
 #endif
 
-/* Imported variables */
-/* these are for storing alternate interface addresses - from afs_callback.c */
-extern struct interfaceAddr afs_cb_interface;
-
-
-/* Imported functions. */
-struct rx_securityClass *rxnull_NewClientSecurityObject();
-struct rx_securityClass *rxkad_NewClientSecurityObject();
-
 /* Exported variables */
-afs_rwlock_t afs_xconn;                        /* allocation lock for new things */
-afs_rwlock_t afs_xinterface;           /* for multiple client address */
-
-/* Local variables */
-afs_int32 cryptall = 0;
+afs_rwlock_t afs_xconn;                /* allocation lock for new things */
+afs_rwlock_t afs_xinterface;   /* for multiple client address */
+afs_int32 cryptall = 0;                /* encrypt all communications */
 
 
 unsigned int VNOSERVERS = 0;
-struct conn *afs_Conn(afid, areq, locktype)
-    register struct VenusFid *afid;
-    register struct vrequest *areq;
-    afs_int32 locktype;
+
+/**
+ * Try setting up a connection to the server containing the specified fid.
+ * Gets the volume, checks if it's up and does the connection by server address.
+ *
+ * @param afid 
+ * @param areq Request filled in by the caller.
+ * @param locktype Type of lock that will be used.
+ *
+ * @return The conn struct, or NULL.
+ */
+struct conn *
+afs_Conn(register struct VenusFid *afid, register struct vrequest *areq,
+        afs_int32 locktype)
 {
-   u_short fsport=AFS_FSPORT;
-   struct volume *tv;
-   struct conn *tconn = (struct conn *)0;
-   struct srvAddr *lowp= (struct srvAddr *)0;
-   struct unixuser *tu;
-   int notbusy;
-   int i;
-   struct srvAddr *sa1p;
-
-   AFS_STATCNT(afs_Conn);
-   tv = afs_GetVolume(afid, areq, READ_LOCK);
-   if (!tv) {
-      if (areq) {
-        afs_FinalizeReq(areq);
-        areq->volumeError = 1;
-      }
-      return (struct conn *) 0;
-   }
-
-   if (tv->serverHost[0] && tv->serverHost[0]->cell) {
-      fsport = tv->serverHost[0]->cell->fsport;
-   }    
-   else {
-      VNOSERVERS++;
-   }
-
-   /* First is always lowest rank, if it's up */
-   if ((tv->status[0] == not_busy) && tv->serverHost[0] && 
-       !(tv->serverHost[0]->addr->sa_flags & SRVR_ISDOWN))
-      lowp = tv->serverHost[0]->addr;
-
-   /* Otherwise we look at all of them. There are seven levels of
-    * not_busy. This means we will check a volume seven times before it
-    * is marked offline. Ideally, we only need two levels, but this
-    * serves a second purpose of waiting some number of seconds before
-    * the client decides the volume is offline (ie: a clone could finish
-    * in this time).
-    */
-   for (notbusy = not_busy; (!lowp && (notbusy <= end_not_busy)); notbusy++) {
-      for (i=0 ;i<MAXHOSTS && tv->serverHost[i];i++) {
-        if (tv->status[i] != notbusy) {
-           if (tv->status[i] == rd_busy || tv->status[i] == rdwr_busy) {
-              if (!areq->busyCount)
-                 areq->busyCount++;
-           } else if (tv->status[i] == offline) {
-              if (!areq->volumeError) 
-                 areq->volumeError = VOLMISSING;
+    u_short fsport = AFS_FSPORT;
+    struct volume *tv;
+    struct conn *tconn = NULL;
+    struct srvAddr *lowp = NULL;
+    struct unixuser *tu;
+    int notbusy;
+    int i;
+    struct srvAddr *sa1p;
+
+    AFS_STATCNT(afs_Conn);
+    /* Get fid's volume. */
+    tv = afs_GetVolume(afid, areq, READ_LOCK);
+    if (!tv) {
+       if (areq) {
+           afs_FinalizeReq(areq);
+           areq->volumeError = 1;
+       }
+       return NULL;
+    }
+
+    if (tv->serverHost[0] && tv->serverHost[0]->cell) {
+       fsport = tv->serverHost[0]->cell->fsport;
+    } else {
+       VNOSERVERS++;
+    }
+
+    /* First is always lowest rank, if it's up */
+    if ((tv->status[0] == not_busy) && tv->serverHost[0]
+       && !(tv->serverHost[0]->addr->sa_flags & SRVR_ISDOWN) &&
+       !(((areq->idleError > 0) || (areq->tokenError > 0))
+         && (areq->skipserver[0] == 1)))
+       lowp = tv->serverHost[0]->addr;
+
+    /* Otherwise we look at all of them. There are seven levels of
+     * not_busy. This means we will check a volume seven times before it
+     * is marked offline. Ideally, we only need two levels, but this
+     * serves a second purpose of waiting some number of seconds before
+     * the client decides the volume is offline (ie: a clone could finish
+     * in this time).
+     */
+    for (notbusy = not_busy; (!lowp && (notbusy <= end_not_busy)); notbusy++) {
+       for (i = 0; i < MAXHOSTS && tv->serverHost[i]; i++) {
+           if (((areq->tokenError > 0)||(areq->idleError > 0)) 
+               && (areq->skipserver[i] == 1))
+               continue;
+           if (tv->status[i] != notbusy) {
+               if (tv->status[i] == rd_busy || tv->status[i] == rdwr_busy) {
+                   if (!areq->busyCount)
+                       areq->busyCount++;
+               } else if (tv->status[i] == offline) {
+                   if (!areq->volumeError)
+                       areq->volumeError = VOLMISSING;
+               }
+               continue;
            }
-           continue;
-        }
-        for (sa1p = tv->serverHost[i]->addr; sa1p; sa1p = sa1p->next_sa) {
-           if (sa1p->sa_flags & SRVR_ISDOWN)
-              continue;
-           if (!lowp || (lowp->sa_iprank > sa1p->sa_iprank))
-              lowp = sa1p;
-        }
-      }
-   }
-   afs_PutVolume(tv, READ_LOCK);
-
-   if (lowp) {
-      tu = afs_GetUser(areq->uid, afid->Cell, SHARED_LOCK);
-      tconn = afs_ConnBySA(lowp, fsport, afid->Cell, tu,
-                          0/*!force*/, 1/*create*/, locktype);
-
-      afs_PutUser(tu, SHARED_LOCK);
-   }
-
-   return tconn;
-} /*afs_Conn*/
-
-
-struct conn *afs_ConnBySA(struct srvAddr *sap, unsigned short aport,
-                         afs_int32 acell, struct unixuser *tu,
-                         int force_if_down, afs_int32 create, afs_int32 locktype)
+           for (sa1p = tv->serverHost[i]->addr; sa1p; sa1p = sa1p->next_sa) {
+               if (sa1p->sa_flags & SRVR_ISDOWN)
+                   continue;
+               if (!lowp || (lowp->sa_iprank > sa1p->sa_iprank))
+                   lowp = sa1p;
+           }
+       }
+    }
+    afs_PutVolume(tv, READ_LOCK);
+
+    if (lowp) {
+       tu = afs_GetUser(areq->uid, afid->Cell, SHARED_LOCK);
+       tconn = afs_ConnBySA(lowp, fsport, afid->Cell, tu, 0 /*!force */ ,
+                            1 /*create */ , locktype);
+
+       afs_PutUser(tu, SHARED_LOCK);
+    }
+
+    return tconn;
+}                              /*afs_Conn */
+
+
+/**
+ * Connects to a server by it's server address.
+ *
+ * @param sap Server address.
+ * @param aport Server port.
+ * @param acell
+ * @param tu Connect as this user.
+ * @param force_if_down
+ * @param create
+ * @param locktype Specifies type of lock to be used for this function.
+ *
+ * @return The new connection.
+ */
+struct conn *
+afs_ConnBySA(struct srvAddr *sap, unsigned short aport, afs_int32 acell,
+            struct unixuser *tu, int force_if_down, afs_int32 create,
+            afs_int32 locktype)
 {
-    struct conn *tc=0;
-    struct rx_securityClass *csec;     /*Security class object*/
-    int isec;                          /*Security index*/
+    struct conn *tc = 0;
+    struct rx_securityClass *csec;     /*Security class object */
+    int isec;                  /*Security index */
     int service;
 
     if (!sap || ((sap->sa_flags & SRVR_ISDOWN) && !force_if_down)) {
        /* sa is known down, and we don't want to force it.  */
-       return (struct conn *)0;
+       return NULL;
     }
 
-    ObtainSharedLock(&afs_xconn,15);
-    for (tc = sap->conns; tc; tc=tc->next) {
-       if (tc->user == tu && tc->port == aport) {
-         break;
-       }
-    }          
+    ObtainSharedLock(&afs_xconn, 15);
+    /* Get conn by port and user. */
+    for (tc = sap->conns; tc; tc = tc->next) {
+       if (tc->user == tu && tc->port == aport) {
+           break;
+       }
+    }
 
     if (!tc && !create) {
-       ReleaseSharedLock(&afs_xconn);
-       return (struct conn *)0;
+       /* Not found and can't create a new one. */
+       ReleaseSharedLock(&afs_xconn);
+       return NULL;
+    }
+    
+    if (AFS_IS_DISCONNECTED && !AFS_IN_SYNC) {
+        afs_warnuser("afs_ConnBySA: disconnected\n");
+        ReleaseSharedLock(&afs_xconn);
+        return NULL;
     }
 
     if (!tc) {
-       /* No such connection structure exists.  Create one and splice it in.
-       * Make sure the server record has been marked as used (for the purposes
-       * of calculating up & down times, it's now considered to be an
-       * ``active'' server).  Also make sure the server's lastUpdateEvalTime
-       * gets set, marking the time of its ``birth''.
-       */
-       UpgradeSToWLock(&afs_xconn,37);
-       tc = (struct conn *) afs_osi_Alloc(sizeof(struct conn));
-       bzero((char *)tc, sizeof(struct conn));
+       /* No such connection structure exists.  Create one and splice it in.
+        * Make sure the server record has been marked as used (for the purposes
+        * of calculating up & down times, it's now considered to be an
+        * ``active'' server).  Also make sure the server's lastUpdateEvalTime
+        * gets set, marking the time of its ``birth''.
+        */
+       UpgradeSToWLock(&afs_xconn, 37);
+       tc = (struct conn *)afs_osi_Alloc(sizeof(struct conn));
+       memset((char *)tc, 0, sizeof(struct conn));
 
        tc->user = tu;
        tc->port = aport;
        tc->srvr = sap;
-       tc->refCount = 0;   /* bumped below */
+       tc->refCount = 0;       /* bumped below */
        tc->forceConnectFS = 1;
-       tc->id = (struct rx_connection *) 0;
+       tc->id = (struct rx_connection *)0;
        tc->next = sap->conns;
        sap->conns = tc;
-       afs_ActivateServer(sap); 
+       afs_ActivateServer(sap);
 
        ConvertWToSLock(&afs_xconn);
-    }
+    } /* end of if (!tc) */
     tc->refCount++;
 
     if (tu->states & UTokensBad) {
        /* we may still have an authenticated RPC connection here,
-         * we'll have to create a new, unauthenticated, connection.
-         * Perhaps a better way to do this would be to set
-         * conn->forceConnectFS on all conns when the token first goes
-         * bad, but that's somewhat trickier, due to locking
-         * constraints (though not impossible).
-         */
+        * we'll have to create a new, unauthenticated, connection.
+        * Perhaps a better way to do this would be to set
+        * conn->forceConnectFS on all conns when the token first goes
+        * bad, but that's somewhat trickier, due to locking
+        * constraints (though not impossible).
+        */
        if (tc->id && (rx_SecurityClassOf(tc->id) != 0)) {
-          tc->forceConnectFS = 1;      /* force recreation of connection */
+           tc->forceConnectFS = 1;     /* force recreation of connection */
        }
        tu->vid = UNDEFVID;     /* forcibly disconnect the authentication info */
     }
 
-    if (tc->forceConnectFS) { 
-       UpgradeSToWLock(&afs_xconn,38);
-       csec = (struct rx_securityClass *) 0;
+    if (tc->forceConnectFS) {
+       UpgradeSToWLock(&afs_xconn, 38);
+       csec = (struct rx_securityClass *)0;
        if (tc->id) {
            AFS_GUNLOCK();
            rx_DestroyConnection(tc->id);
@@ -220,62 +249,72 @@ struct conn *afs_ConnBySA(struct srvAddr *sap, unsigned short aport,
            service = 1;
        isec = 0;
        if (tu->vid != UNDEFVID) {
-             int level;
-
-             if (cryptall) {
-               level=rxkad_crypt;
-             } else {
-               level=rxkad_clear;
-             }
-             isec=2;
-             /* kerberos tickets on channel 2 */
-             csec = rxkad_NewClientSecurityObject(level, tu->ct.HandShakeKey,
-                                                  /* kvno */ 
-                                                  tu->ct.AuthHandle, 
-                                                  tu->stLen, tu->stp);
+           int level;
+
+           if (cryptall) {
+               level = rxkad_crypt;
+           } else {
+               level = rxkad_clear;
+           }
+           isec = 2;
+           /* kerberos tickets on channel 2 */
+           csec = rxkad_NewClientSecurityObject(level,
+                                                 (struct ktc_encryptionKey *)tu->ct.HandShakeKey,
+                                                /* kvno */
+                                                tu->ct.AuthHandle, tu->stLen,
+                                                tu->stp);
        }
        if (isec == 0)
            csec = rxnull_NewClientSecurityObject();
        AFS_GUNLOCK();
        tc->id = rx_NewConnection(sap->sa_ip, aport, service, csec, isec);
        AFS_GLOCK();
-        if (service == 52) { 
-           rx_SetConnHardDeadTime(tc->id, AFS_HARDDEADTIME);
-       }
-
+       if (service == 52) {
+           rx_SetConnHardDeadTime(tc->id, afs_rx_harddead);
+       }
+       rx_SetConnIdleDeadTime(tc->id, afs_rx_idledead);
 
        tc->forceConnectFS = 0; /* apparently we're appropriately connected now */
        if (csec)
            rxs_Release(csec);
        ConvertWToSLock(&afs_xconn);
-    }
+    } /* end of if (tc->forceConnectFS)*/
 
     ReleaseSharedLock(&afs_xconn);
     return tc;
 }
-/*
- * afs_ConnByHost
- *
+
+/**
  * forceConnectFS is set whenever we must recompute the connection. UTokensBad
  * is true only if we know that the tokens are bad.  We thus clear this flag
  * when we get a new set of tokens..
  * Having force... true and UTokensBad true simultaneously means that the tokens
  * went bad and we're supposed to create a new, unauthenticated, connection.
+ *
+ * @param aserver Server to connect to.
+ * @param aport Connection port.
+ * @param acell The cell where all of this happens.
+ * @param areq The request.
+ * @param aforce Force connection?
+ * @param locktype Type of lock to be used.
+ *
+ * @return The established connection.
  */
-struct conn *afs_ConnByHost(aserver, aport, acell, areq, aforce, locktype)
-    struct server *aserver;
-    afs_int32 acell;
-    unsigned short aport;
-    struct vrequest *areq;
-    int aforce;
-    afs_int32 locktype;
-{ /*afs_ConnByHost*/
-
+struct conn *
+afs_ConnByHost(struct server *aserver, unsigned short aport, afs_int32 acell,
+              struct vrequest *areq, int aforce, afs_int32 locktype)
+{
     struct unixuser *tu;
-    struct conn *tc=0;
-    struct srvAddr *sa=0;
+    struct conn *tc = 0;
+    struct srvAddr *sa = 0;
 
     AFS_STATCNT(afs_ConnByHost);
+
+    if (AFS_IS_DISCONNECTED && !AFS_IN_SYNC) {
+        afs_warnuser("afs_ConnByHost: disconnected\n");
+        return NULL;
+    }
+
 /* 
   1.  look for an existing connection
   2.  create a connection at an address believed to be up
@@ -284,36 +323,46 @@ struct conn *afs_ConnByHost(aserver, aport, acell, areq, aforce, locktype)
 
     tu = afs_GetUser(areq->uid, acell, SHARED_LOCK);
 
-    for (sa = aserver->addr; sa; sa = sa->next_sa) {   
-       tc = afs_ConnBySA(sa, aport, acell, tu, aforce, 
-                        0/*don't create one*/,
-                        locktype);
-       if (tc) 
+    for (sa = aserver->addr; sa; sa = sa->next_sa) {
+       tc = afs_ConnBySA(sa, aport, acell, tu, aforce,
+                         0 /*don't create one */ ,
+                         locktype);
+       if (tc)
            break;
     }
 
     if (!tc) {
-       for (sa = aserver->addr; sa; sa = sa->next_sa) {        
-         tc = afs_ConnBySA(sa, aport, acell, tu, aforce, 
-                           1/*create one*/,
-                           locktype);
-         if (tc) 
-              break;
-       }
+       for (sa = aserver->addr; sa; sa = sa->next_sa) {
+           tc = afs_ConnBySA(sa, aport, acell, tu, aforce,
+                             1 /*create one */ ,
+                             locktype);
+           if (tc)
+               break;
+       }
     }
 
     afs_PutUser(tu, SHARED_LOCK);
     return tc;
 
-} /*afs_ConnByHost*/
+}                              /*afs_ConnByHost */
 
 
-struct conn *afs_ConnByMHosts(ahosts, aport, acell, areq, locktype)
-    struct server *ahosts[];
-    afs_int32 acell;
-    unsigned short aport;
-    register struct vrequest *areq;
-    afs_int32 locktype;
+/**
+ * Connect by multiple hosts.
+ * Try to connect to one of the hosts from the ahosts array.
+ *
+ * @param ahosts Multiple hosts to connect to.
+ * @param aport Connection port.
+ * @param acell The cell where all of this happens.
+ * @param areq The request.
+ * @param locktype Type of lock to be used.
+ *
+ * @return The established connection or NULL.
+ */
+struct conn *
+afs_ConnByMHosts(struct server *ahosts[], unsigned short aport,
+                afs_int32 acell, register struct vrequest *areq,
+                afs_int32 locktype)
 {
     register afs_int32 i;
     register struct conn *tconn;
@@ -321,50 +370,49 @@ struct conn *afs_ConnByMHosts(ahosts, aport, acell, areq, locktype)
 
     /* try to find any connection from the set */
     AFS_STATCNT(afs_ConnByMHosts);
-    for (i=0;i<MAXCELLHOSTS;i++) {
-       if ((ts = ahosts[i]) == (struct server *) 0) break;
-       tconn = afs_ConnByHost(ts, aport, acell, 
-                              areq, 0, locktype);
+    for (i = 0; i < MAXCELLHOSTS; i++) {
+       if ((ts = ahosts[i]) == NULL)
+           break;
+       tconn = afs_ConnByHost(ts, aport, acell, areq, 0, locktype);
        if (tconn) {
-          return tconn;
+           return tconn;
        }
     }
-    return (struct conn *) 0;
+    return NULL;
 
-} /*afs_ConnByMHosts*/
+}                              /*afs_ConnByMHosts */
 
 
-void afs_PutConn(ac, locktype)
-    register struct conn *ac;
-    afs_int32 locktype;
+/**
+ * Decrement reference count to this connection.
+ * @param ac
+ * @param locktype
+ */
+void
+afs_PutConn(register struct conn *ac, afs_int32 locktype)
 {
     AFS_STATCNT(afs_PutConn);
     ac->refCount--;
-} /*afs_PutConn*/
+}                              /*afs_PutConn */
 
 
-/* for multi homed clients, an RPC may timeout because of a
-client network interface going down. We need to reopen new 
-connections in this case
-*/
-ForceNewConnections(sap)
-struct srvAddr *sap;
+/** 
+ * For multi homed clients, a RPC may timeout because of a 
+ * client network interface going down. We need to reopen new 
+ * connections in this case.
+ *
+ * @param sap Server address.
+ */
+void
+ForceNewConnections(struct srvAddr *sap)
 {
-       struct conn *tc=0;
+    struct conn *tc = 0;
 
-       if ( !sap) return; /* defensive check */
+    if (!sap)
+       return;                 /* defensive check */
 
-       /* if client is not multihomed, do nothing */
-       ObtainReadLock(&afs_xinterface);
-       if ( afs_cb_interface.numberOfInterfaces <= 1 )
-       {
-               ReleaseReadLock(&afs_xinterface);
-               return;
-       }
-       ReleaseReadLock(&afs_xinterface);
-       
-       ObtainWriteLock(&afs_xconn,413);
-       for (tc = sap->conns; tc; tc=tc->next)
-               tc->forceConnectFS=1;
-       ReleaseWriteLock(&afs_xconn);
+    ObtainWriteLock(&afs_xconn, 413);
+    for (tc = sap->conns; tc; tc = tc->next)
+       tc->forceConnectFS = 1;
+    ReleaseWriteLock(&afs_xconn);
 }