rx-protect-servers-from-half-reachable-clients-20020119
[openafs.git] / src / rx / rx.c
index 4509653..0e5df40 100644 (file)
@@ -9,9 +9,16 @@
 
 /* RX:  Extended Remote Procedure Call */
 
+#include <afsconfig.h>
 #ifdef KERNEL
 #include "../afs/param.h"
-#include <afsconfig.h>
+#else
+#include <afs/param.h>
+#endif
+
+RCSID("$Header$");
+
+#ifdef KERNEL
 #include "../afs/sysincludes.h"
 #include "../afs/afsincludes.h"
 #ifndef UKERNEL
@@ -67,8 +74,6 @@ extern afs_int32 afs_termState;
 #endif /* AFS_AIX41_ENV */
 # include "../afsint/rxgen_consts.h"
 #else /* KERNEL */
-# include <afs/param.h>
-# include <afsconfig.h>
 # include <sys/types.h>
 # include <errno.h>
 #ifdef AFS_NT40_ENV
@@ -85,10 +90,11 @@ extern afs_int32 afs_termState;
 #endif
 #ifdef HAVE_STRING_H
 #include <string.h>
-#endif
+#else
 #ifdef HAVE_STRINGS_H
 #include <strings.h>
 #endif
+#endif
 # include "rx.h"
 # include "rx_user.h"
 # include "rx_clock.h"
@@ -221,8 +227,6 @@ assert(pthread_once(&rx_once_init, rxi_InitPthread)==0);
 #define INIT_PTHREAD_LOCKS
 #endif
 
-extern void rxi_DeleteCachedConnections(void);
-
 
 /* Variables for handling the minProcs implementation.  availProcs gives the
  * number of threads available in the pool at this moment (not counting dudes
@@ -246,11 +250,8 @@ extern void rxi_DeleteCachedConnections(void);
  * to manipulate the queue.
  */
 
-extern void rxi_Delay(int);
-
-static int rxi_ServerThreadSelectingCall;
-
 #ifdef RX_ENABLE_LOCKS
+static int rxi_ServerThreadSelectingCall;
 static afs_kmutex_t rx_rpc_stats;
 void rxi_StartUnlocked();
 #endif
@@ -300,8 +301,6 @@ void osirx_AssertMine(afs_kmutex_t *lockaddr, char *msg);
 #define CLEAR_CALL_QUEUE_LOCK(C)
 #endif /* RX_ENABLE_LOCKS */
 static void rxi_DestroyConnectionNoLock();
-void rxi_DestroyConnection();
-void rxi_CleanupConnection();
 struct rx_serverQueueEntry *rx_waitForPacket = 0;
 
 /* ------------Exported Interfaces------------- */
@@ -432,14 +431,14 @@ int rx_Init(u_int port)
     rxi_nCalls = 0;
     rx_connDeadTime = 12;
     rx_tranquil     = 0;       /* reset flag */
-    bzero((char *)&rx_stats, sizeof(struct rx_stats));
+    memset((char *)&rx_stats, 0, sizeof(struct rx_stats));
     htable = (char *)
        osi_Alloc(rx_hashTableSize*sizeof(struct rx_connection *));
     PIN(htable, rx_hashTableSize*sizeof(struct rx_connection *));  /* XXXXX */
-    bzero(htable, rx_hashTableSize*sizeof(struct rx_connection *));
+    memset(htable, 0, rx_hashTableSize*sizeof(struct rx_connection *));
     ptable =  (char *) osi_Alloc(rx_hashTableSize*sizeof(struct rx_peer *));   
     PIN(ptable, rx_hashTableSize*sizeof(struct rx_peer *));      /* XXXXX */
-    bzero(ptable, rx_hashTableSize*sizeof(struct rx_peer *));
+    memset(ptable, 0, rx_hashTableSize*sizeof(struct rx_peer *));
 
     /* Malloc up a bunch of packets & buffers */
     rx_nFreePackets = 0;
@@ -570,7 +569,7 @@ register struct rx_service *aservice;
 }
 
 #else /* RX_ENABLE_LOCKS */
-static QuotaOK(aservice)
+static int QuotaOK(aservice)
 register struct rx_service *aservice; {
     int rc=0;
     /* under min quota, we're OK */
@@ -666,14 +665,13 @@ void rx_StartServer(donateMe)
     if (donateMe) {
 #ifndef AFS_NT40_ENV
 #ifndef KERNEL
-       int code;
         char name[32];
 #ifdef AFS_PTHREAD_ENV
         pid_t pid;
         pid = (pid_t) pthread_self();
 #else /* AFS_PTHREAD_ENV */
         PROCESS pid;
-        code = LWP_CurrentProcess(&pid);
+        LWP_CurrentProcess(&pid);
 #endif /* AFS_PTHREAD_ENV */
 
         sprintf(name,"srv_%d", ++nProcs);
@@ -899,7 +897,12 @@ static void rxi_DestroyConnectionNoLock(conn)
                     * last reply packets */
                    rxevent_Cancel(call->delayedAckEvent, call,
                                   RX_CALL_REFCOUNT_DELAY);
-                   rxi_AckAll((struct rxevent *)0, call, 0);
+                   if (call->state == RX_STATE_PRECALL ||
+                       call->state == RX_STATE_ACTIVE) {
+                       rxi_SendDelayedAck(call->delayedAckEvent, call, 0);
+                   } else {
+                       rxi_AckAll((struct rxevent *)0, call, 0);
+                   }
                }
                MUTEX_EXIT(&call->lock);
            }
@@ -954,9 +957,10 @@ static void rxi_DestroyConnectionNoLock(conn)
 
     /* Make sure the connection is completely reset before deleting it. */
     /* get rid of pending events that could zap us later */
-    if (conn->challengeEvent) {
+    if (conn->challengeEvent)
        rxevent_Cancel(conn->challengeEvent, (struct rx_call*)0, 0);
-    }
+    if (conn->checkReachEvent)
+       rxevent_Cancel(conn->checkReachEvent, (struct rx_call*)0, 0);
  
     /* Add the connection to the list of destroyed connections that
      * need to be cleaned up. This is necessary to avoid deadlocks
@@ -1003,6 +1007,21 @@ struct rx_call *rx_NewCall(conn)
     clock_GetTime(&queueTime);
     AFS_RXGLOCK();
     MUTEX_ENTER(&conn->conn_call_lock);
+
+    /*
+     * Check if there are others waiting for a new call.
+     * If so, let them go first to avoid starving them.
+     * This is a fairly simple scheme, and might not be
+     * a complete solution for large numbers of waiters.
+     */
+    if (conn->makeCallWaiters) {
+#ifdef RX_ENABLE_LOCKS
+       CV_WAIT(&conn->conn_call_cv, &conn->conn_call_lock);
+#else
+       osi_rxSleep(conn);
+#endif
+    }
+
     for (;;) {
        for (i=0; i<RX_MAXCALLS; i++) {
            call = conn->call[i];
@@ -1017,7 +1036,6 @@ struct rx_call *rx_NewCall(conn)
            }
            else {
                call = rxi_NewCall(conn, i);
-               MUTEX_ENTER(&call->lock);
                break;
            }
        }
@@ -1027,12 +1045,24 @@ struct rx_call *rx_NewCall(conn)
        MUTEX_ENTER(&conn->conn_data_lock);
        conn->flags |= RX_CONN_MAKECALL_WAITING;
        MUTEX_EXIT(&conn->conn_data_lock);
+
+       conn->makeCallWaiters++;
 #ifdef RX_ENABLE_LOCKS
        CV_WAIT(&conn->conn_call_cv, &conn->conn_call_lock);
 #else
        osi_rxSleep(conn);
 #endif
+       conn->makeCallWaiters--;
     }
+    /*
+     * Wake up anyone else who might be giving us a chance to
+     * run (see code above that avoids resource starvation).
+     */
+#ifdef RX_ENABLE_LOCKS
+    CV_BROADCAST(&conn->conn_call_cv);
+#else
+    osi_rxWakeup(conn);
+#endif
 
     CALL_HOLD(call, RX_CALL_REFCOUNT_BEGIN);
 
@@ -1077,6 +1107,7 @@ struct rx_call *rx_NewCall(conn)
     return call;
 }
 
+int
 rxi_HasActiveCalls(aconn)
 register struct rx_connection *aconn; {
     register int i;
@@ -1097,6 +1128,7 @@ register struct rx_connection *aconn; {
     return 0;
 }
 
+int
 rxi_GetCallNumberVector(aconn, aint32s)
 register struct rx_connection *aconn;
 register afs_int32 *aint32s; {
@@ -1115,6 +1147,7 @@ register afs_int32 *aint32s; {
     return 0;
 }
 
+int
 rxi_SetCallNumberVector(aconn, aint32s)
 register struct rx_connection *aconn;
 register afs_int32 *aint32s; {
@@ -1380,12 +1413,12 @@ osi_socket *socketp;
 {
     struct rx_serverQueueEntry *sq;
     register struct rx_call *call = (struct rx_call *) 0, *choice2;
-    struct rx_service *service;
+    struct rx_service *service = NULL;
     SPLVAR;
 
     MUTEX_ENTER(&freeSQEList_lock);
 
-    if (sq = rx_FreeSQEList) {
+    if ((sq = rx_FreeSQEList)) {
        rx_FreeSQEList = *(struct rx_serverQueueEntry **)sq;
        MUTEX_EXIT(&freeSQEList_lock);
     } else {    /* otherwise allocate a new one and return that */
@@ -1917,7 +1950,7 @@ struct rx_service *rxi_FindService(socket, serviceId)
 
 /* Allocate a call structure, for the indicated channel of the
  * supplied connection.  The mode and state of the call must be set by
- * the caller. */
+ * the caller. Returns the call with mutex locked. */
 struct rx_call *rxi_NewCall(conn, channel)
     register struct rx_connection *conn;
     register int channel;
@@ -1999,7 +2032,6 @@ struct rx_call *rxi_NewCall(conn, channel)
        the call number is valid from the last time this channel was used */
     if (*call->callNumber == 0) *call->callNumber = 1;
 
-    MUTEX_EXIT(&call->lock);
     return call;
 }
 
@@ -2102,7 +2134,7 @@ register size_t size;
     p = (char *) osi_Alloc(size);
 #endif
     if (!p) osi_Panic("rxi_Alloc error");
-    bzero(p, size);
+    memset(p, 0, size);
     return p;
 }
 
@@ -2407,7 +2439,7 @@ struct rx_packet *rxi_ReceivePacket(np, socket, host, port, tnop, newcallp)
 
     MUTEX_ENTER(&conn->conn_data_lock);
     if (conn->maxSerial < np->header.serial)
-      conn->maxSerial = np->header.serial;
+       conn->maxSerial = np->header.serial;
     MUTEX_EXIT(&conn->conn_data_lock);
 
     /* If the connection is in an error state, send an abort packet and ignore
@@ -2524,8 +2556,9 @@ struct rx_packet *rxi_ReceivePacket(np, socket, host, port, tnop, newcallp)
            return np;
        }
        if (!call) {
+           MUTEX_ENTER(&conn->conn_call_lock);
            call = rxi_NewCall(conn, channel);
-           MUTEX_ENTER(&call->lock);
+           MUTEX_EXIT(&conn->conn_call_lock);
            *call->callNumber = np->header.callNumber;
            call->state = RX_STATE_PRECALL;
            clock_GetTime(&call->queueTime);
@@ -2835,20 +2868,102 @@ static TooLow(ap, acall)
 }
 #endif /* KERNEL */
 
+static void rxi_CheckReachEvent(event, conn, acall)
+    struct rxevent *event;
+    struct rx_connection *conn;
+    struct rx_call *acall;
+{
+    struct rx_call *call = acall;
+    struct clock when;
+    int i, waiting;
+
+    MUTEX_ENTER(&conn->conn_call_lock);
+    MUTEX_ENTER(&conn->conn_data_lock);
+    conn->checkReachEvent = (struct rxevent *) 0;
+    waiting = conn->flags & RX_CONN_ATTACHWAIT;
+    if (event) conn->refCount--;
+    MUTEX_EXIT(&conn->conn_data_lock);
+
+    if (waiting) {
+       if (!call)
+           for (i=0; i<RX_MAXCALLS; i++) {
+               struct rx_call *tc = conn->call[i];
+               if (tc && tc->state == RX_STATE_PRECALL) {
+                   call = tc;
+                   break;
+               }
+           }
+
+       if (call) {
+           if (call != acall) MUTEX_ENTER(&call->lock);
+           rxi_SendAck(call, NULL, 0, 0, 0, RX_ACK_PING, 0);
+           if (call != acall) MUTEX_EXIT(&call->lock);
+
+           MUTEX_ENTER(&conn->conn_data_lock);
+           conn->refCount++;
+           MUTEX_EXIT(&conn->conn_data_lock);
+           clock_GetTime(&when);
+           when.sec += RX_CHECKREACH_TIMEOUT;
+           conn->checkReachEvent =
+               rxevent_Post(&when, rxi_CheckReachEvent, conn, NULL);
+       }
+    }
+    MUTEX_EXIT(&conn->conn_call_lock);
+}
+
+static int rxi_CheckConnReach(conn, call)
+    struct rx_connection *conn;
+    struct rx_call *call;
+{
+    struct rx_service *service = conn->service;
+    struct rx_peer *peer = conn->peer;
+    afs_uint32 now, lastReach;
+
+    MUTEX_ENTER(&rx_serverPool_lock);
+    if (service->nRequestsRunning <= service->maxProcs/2) {
+       MUTEX_EXIT(&rx_serverPool_lock);
+       return 0;
+    }
+    MUTEX_EXIT(&rx_serverPool_lock);
+
+    now = clock_Sec();
+    MUTEX_ENTER(&peer->peer_lock);
+    lastReach = peer->lastReachTime;
+    MUTEX_EXIT(&peer->peer_lock);
+    if (now - lastReach < RX_CHECKREACH_TTL)
+       return 0;
+
+    MUTEX_ENTER(&conn->conn_data_lock);
+    if (conn->flags & RX_CONN_ATTACHWAIT) {
+       MUTEX_EXIT(&conn->conn_data_lock);
+       return 1;
+    }
+    conn->flags |= RX_CONN_ATTACHWAIT;
+    MUTEX_EXIT(&conn->conn_data_lock);
+    if (!conn->checkReachEvent)
+       rxi_CheckReachEvent((struct rxevent *)0, conn, call);
+
+    return 1;
+}
+
 /* try to attach call, if authentication is complete */
-static void TryAttach(acall, socket, tnop, newcallp)
-register struct rx_call *acall;
-register osi_socket socket;
-register int *tnop;
-register struct rx_call **newcallp; {
-    register struct rx_connection *conn;
-    conn = acall->conn;
-    if ((conn->type==RX_SERVER_CONNECTION) && (acall->state == RX_STATE_PRECALL)) {
+static void TryAttach(acall, socket, tnop, newcallp, reachOverride)
+    register struct rx_call *acall;
+    register osi_socket socket;
+    register int *tnop;
+    register struct rx_call **newcallp;
+    int reachOverride;
+{
+    struct rx_connection *conn = acall->conn;
+
+    if (conn->type==RX_SERVER_CONNECTION && acall->state==RX_STATE_PRECALL) {
        /* Don't attach until we have any req'd. authentication. */
        if (RXS_CheckAuthentication(conn->securityObject, conn) == 0) {
-           rxi_AttachServerProc(acall, socket, tnop, newcallp);
-           /* Note:  this does not necessarily succeed; there
-              may not any proc available */
+           if (reachOverride || rxi_CheckConnReach(conn, acall) == 0)
+               rxi_AttachServerProc(acall, socket, tnop, newcallp);
+               /* Note:  this does not necessarily succeed; there
+                * may not any proc available
+                */
        }
        else {
            rxi_ChallengeOn(acall->conn);
@@ -3023,7 +3138,7 @@ struct rx_packet *rxi_ReceiveDataPacket(call, np, istack, socket, host,
             * server thread is available, this thread becomes a server
             * thread and the server thread becomes a listener thread. */
            if (isFirst) {
-               TryAttach(call, socket, tnop, newcallp);
+               TryAttach(call, socket, tnop, newcallp, 0);
            }
        }       
        /* This is not the expected next packet. */
@@ -3211,6 +3326,37 @@ nextloop:;
 static void rxi_ComputeRate();
 #endif
 
+static void rxi_UpdatePeerReach(conn, acall)
+    struct rx_connection *conn;
+    struct rx_call *acall;
+{
+    struct rx_peer *peer = conn->peer;
+
+    MUTEX_ENTER(&peer->peer_lock);
+    peer->lastReachTime = clock_Sec();
+    MUTEX_EXIT(&peer->peer_lock);
+
+    MUTEX_ENTER(&conn->conn_call_lock);
+    MUTEX_ENTER(&conn->conn_data_lock);
+    if (conn->flags & RX_CONN_ATTACHWAIT) {
+       int i;
+
+       conn->flags &= ~RX_CONN_ATTACHWAIT;
+       MUTEX_EXIT(&conn->conn_data_lock);
+
+       for (i=0; i<RX_MAXCALLS; i++) {
+           struct rx_call *call = conn->call[i];
+           if (call) {
+               if (call != acall) MUTEX_ENTER(&call->lock);
+               TryAttach(call, -1, NULL, NULL, 1);
+               if (call != acall) MUTEX_EXIT(&call->lock);
+           }
+       }
+    } else
+       MUTEX_EXIT(&conn->conn_data_lock);
+    MUTEX_EXIT(&conn->conn_call_lock);
+}
+
 /* The real smarts of the whole thing.  */
 struct rx_packet *rxi_ReceiveAckPacket(call, np, istack)
     register struct rx_call *call;
@@ -3258,13 +3404,17 @@ struct rx_packet *rxi_ReceiveAckPacket(call, np, istack)
     if (np->header.flags & RX_SLOW_START_OK) {
        call->flags |= RX_CALL_SLOW_START_OK;
     }
+
+    if (ap->reason == RX_ACK_PING_RESPONSE)
+       rxi_UpdatePeerReach(conn, call);
     
 #ifdef RXDEBUG
     if (rx_Log) {
       fprintf( rx_Log, 
              "RACK: reason %x previous %u seq %u serial %u skew %d first %u",
-             ap->reason, ntohl(ap->previousPacket), np->header.seq, serial, 
-             skew, ntohl(ap->firstPacket));
+             ap->reason, ntohl(ap->previousPacket), 
+             (unsigned int) np->header.seq, (unsigned int) serial, 
+             (unsigned int) skew, ntohl(ap->firstPacket));
        if (nAcks) {
            int offset;
            for (offset = 0; offset < nAcks; offset++) 
@@ -3324,12 +3474,12 @@ struct rx_packet *rxi_ReceiveAckPacket(call, np, istack)
      * set the ack bits in the packets and have rxi_Start remove the packets
      * when it's done transmitting.
      */
-       if (!tp->acked) {
+       if (!(tp->flags & RX_PKTFLAG_ACKED)) {
            newAckCount++;
        }
        if (call->flags & RX_CALL_TQ_BUSY) {
 #ifdef RX_ENABLE_LOCKS
-           tp->acked = 1;
+           tp->flags |= RX_PKTFLAG_ACKED;
            call->flags |= RX_CALL_TQ_SOME_ACKED;
 #else /* RX_ENABLE_LOCKS */
            break;
@@ -3398,17 +3548,17 @@ struct rx_packet *rxi_ReceiveAckPacket(call, np, istack)
         * out of sequence. */
        if (tp->header.seq < first) {
            /* Implicit ack information */
-           if (!tp->acked) {
+           if (!(tp->flags & RX_PKTFLAG_ACKED)) {
                newAckCount++;
            }
-           tp->acked = 1;
+           tp->flags |= RX_PKTFLAG_ACKED;
        }
        else if (tp->header.seq < first + nAcks) {
            /* Explicit ack information:  set it in the packet appropriately */
            if (ap->acks[tp->header.seq - first] == RX_ACK_TYPE_ACK) {
-               if (!tp->acked) {
+               if (!(tp->flags & RX_PKTFLAG_ACKED)) {
                    newAckCount++;
-                   tp->acked = 1;
+                   tp->flags |= RX_PKTFLAG_ACKED;
                }
                if (missing) {
                    nNacked++;
@@ -3416,12 +3566,12 @@ struct rx_packet *rxi_ReceiveAckPacket(call, np, istack)
                    call->nSoftAcked++;
                }
            } else {
-               tp->acked = 0;
+               tp->flags &= ~RX_PKTFLAG_ACKED;
                missing = 1;
            }
        }
        else {
-           tp->acked = 0;
+           tp->flags &= ~RX_PKTFLAG_ACKED;
            missing = 1;
        }
 
@@ -3430,7 +3580,7 @@ struct rx_packet *rxi_ReceiveAckPacket(call, np, istack)
         * ie, this should readjust the retransmit timer for all outstanding 
         * packets...  So we don't just retransmit when we should know better*/
 
-       if (!tp->acked && !clock_IsZero(&tp->retryTime)) {
+       if (!(tp->flags & RX_PKTFLAG_ACKED) && !clock_IsZero(&tp->retryTime)) {
          tp->retryTime = tp->timeSent;
          clock_Add(&tp->retryTime, &peer->timeout);
          /* shift by eight because one quarter-sec ~ 256 milliseconds */
@@ -3458,7 +3608,7 @@ struct rx_packet *rxi_ReceiveAckPacket(call, np, istack)
 
     /* if the ack packet has a receivelen field hanging off it,
      * update our state */
-    if ( np->length >= rx_AckDataSize(ap->nAcks) +sizeof(afs_int32)) {
+    if ( np->length >= rx_AckDataSize(ap->nAcks) + 2*sizeof(afs_int32)) {
       afs_uint32 tSize;
 
       /* If the ack packet has a "recommended" size that is less than 
@@ -3623,10 +3773,10 @@ struct rx_packet *rxi_ReceiveAckPacket(call, np, istack)
         * so we will retransmit as soon as the window permits*/
        for(acked = 0, queue_ScanBackwards(&call->tq, tp, nxp, rx_packet)) {
            if (acked) {
-               if (!tp->acked) {
+               if (!(tp->flags & RX_PKTFLAG_ACKED)) {
                    clock_Zero(&tp->retryTime);
                }
-           } else if (tp->acked) {
+           } else if (tp->flags & RX_PKTFLAG_ACKED) {
                acked = 1;
            }
        }
@@ -3712,8 +3862,9 @@ struct rx_packet *rxi_ReceiveResponsePacket(conn, np, istack)
     }
     else {
        /* If the response is valid, any calls waiting to attach
-         * servers can now do so */
+        * servers can now do so */
        int i;
+
        for (i=0; i<RX_MAXCALLS; i++) {
            struct rx_call *call = conn->call[i];
            if (call) {
@@ -3723,6 +3874,12 @@ struct rx_packet *rxi_ReceiveResponsePacket(conn, np, istack)
                MUTEX_EXIT(&call->lock);
            }
        }
+
+       /* Update the peer reachability information, just in case
+        * some calls went into attach-wait while we were waiting
+        * for authentication..
+        */
+       rxi_UpdatePeerReach(conn, NULL);
     }
     return np;
 }
@@ -3773,10 +3930,10 @@ rxi_ReceiveChallengePacket(conn, np, istack)
  * call so it eventually gets one */
 void 
 rxi_AttachServerProc(call, socket, tnop, newcallp)
-register struct rx_call *call;
-register osi_socket socket;
-register int *tnop;
-register struct rx_call **newcallp;
+    register struct rx_call *call;
+    register osi_socket socket;
+    register int *tnop;
+    register struct rx_call **newcallp;
 {
     register struct rx_serverQueueEntry *sq;
     register struct rx_service *service = call->conn->service;
@@ -3936,7 +4093,7 @@ static void rxi_SetAcksInTransmitQueue(call)
      for (queue_Scan(&call->tq, p, tp, rx_packet)) {
         if (!p) 
             break;
-        p->acked = 1;
+        p->flags |= RX_PKTFLAG_ACKED;
         someAcked = 1;
      }
      if (someAcked) {
@@ -3973,7 +4130,7 @@ void rxi_ClearTransmitQueue(call, force)
        for (queue_Scan(&call->tq, p, tp, rx_packet)) {
          if (!p) 
             break;
-         p->acked = 1;
+         p->flags |= RX_PKTFLAG_ACKED;
          someAcked = 1;
        }
        if (someAcked) {
@@ -4130,6 +4287,10 @@ void rxi_ConnectionError(conn, error)
        register int i;
        if (conn->challengeEvent)
            rxevent_Cancel(conn->challengeEvent, (struct rx_call*)0, 0);
+       if (conn->checkReachEvent) {
+           rxevent_Cancel(conn->checkReachEvent, (struct rx_call*)0, 0);
+           conn->checkReachEvent = 0;
+       }
        for (i=0; i<RX_MAXCALLS; i++) {
            struct rx_call *call = conn->call[i];
            if (call) {
@@ -4450,8 +4611,8 @@ struct rx_packet *rxi_SendAck(call, optionalPacket, seq, serial, pflags, reason,
 #ifdef RXDEBUG
     if (rx_Log) {
        fprintf(rx_Log, "SACK: reason %x previous %u seq %u first %u",
-               ap->reason, ntohl(ap->previousPacket), p->header.seq, 
-               ntohl(ap->firstPacket));
+               ap->reason, ntohl(ap->previousPacket), 
+               (unsigned int) p->header.seq, ntohl(ap->firstPacket));
        if (ap->nAcks) {
            for (offset = 0; offset < ap->nAcks; offset++) 
                putc(ap->acks[offset] == RX_ACK_TYPE_NACK? '-' : '*', rx_Log);
@@ -4626,7 +4787,7 @@ static void rxi_SendXmitList(call, list, len, istack, now, retryTime, resending)
        /* Does the current packet force us to flush the current list? */
        if (cnt > 0
            && (list[i]->header.serial
-               || list[i]->acked
+               || (list[i]->flags & RX_PKTFLAG_ACKED)
                || list[i]->length > RX_JUMBOBUFFERSIZE)) {
            if (lastCnt > 0) {
                rxi_SendList(call, lastP, lastCnt, istack, 1, now, retryTime, resending);
@@ -4642,7 +4803,7 @@ static void rxi_SendXmitList(call, list, len, istack, now, retryTime, resending)
        }
        /* Add the current packet to the list if it hasn't been acked.
         * Otherwise adjust the list pointer to skip the current packet.  */
-       if (!list[i]->acked) {
+       if (!(list[i]->flags & RX_PKTFLAG_ACKED)) {
            cnt++;
            /* Do we need to flush the list? */
            if (cnt >= (int)peer->maxDgramPackets
@@ -4682,7 +4843,7 @@ static void rxi_SendXmitList(call, list, len, istack, now, retryTime, resending)
         * an acked packet. Since we always send retransmissions
         * in a separate packet, we only need to check the first
         * packet in the list */
-       if (cnt > 0 && !listP[0]->acked) {
+       if (cnt > 0 && !(listP[0]->flags & RX_PKTFLAG_ACKED)) {
            morePackets = 1;
        }
        if (lastCnt > 0) {
@@ -4787,7 +4948,7 @@ void rxi_Start(event, call, istack)
         * than recovery rates.
         */
        for(queue_Scan(&call->tq, p, nxp, rx_packet)) {
-           if (!p->acked) {
+           if (!(p->flags & RX_PKTFLAG_ACKED)) {
                clock_Zero(&p->retryTime);
            }
        }
@@ -4850,14 +5011,14 @@ void rxi_Start(event, call, istack)
             /* Only send one packet during fast recovery */
             break;
          }
-         if ((p->header.flags == RX_FREE_PACKET) ||
+         if ((p->flags & RX_PKTFLAG_FREE) ||
              (!queue_IsEnd(&call->tq, nxp)
-              && (nxp->header.flags == RX_FREE_PACKET)) ||
+              && (nxp->flags & RX_PKTFLAG_FREE)) ||
              (p == (struct rx_packet *)&rx_freePacketQueue) ||
              (nxp == (struct rx_packet *)&rx_freePacketQueue)) {
              osi_Panic("rxi_Start: xmit queue clobbered");
          }
-         if (p->acked) {
+         if (p->flags & RX_PKTFLAG_ACKED) {
            MUTEX_ENTER(&rx_stats_mutex);
            rx_stats.ignoreAckedPacket++;
            MUTEX_EXIT(&rx_stats_mutex);
@@ -4940,7 +5101,7 @@ void rxi_Start(event, call, istack)
             * the transmit queue.
             */
            for (missing = 0, queue_Scan(&call->tq, p, nxp, rx_packet)) {
-               if (p->header.seq < call->tfirst && p->acked) {
+               if (p->header.seq < call->tfirst && (p->flags & RX_PKTFLAG_ACKED)) {
                    queue_Remove(p);
                    rxi_FreePacket(p);
                }
@@ -4976,7 +5137,7 @@ void rxi_Start(event, call, istack)
                break;
            }
 
-           if (!p->acked && !clock_IsZero(&p->retryTime)) {
+           if (!(p->flags & RX_PKTFLAG_ACKED) && !clock_IsZero(&p->retryTime)) {
                haveEvent = 1;
                retryTime = p->retryTime;
                break;
@@ -5261,15 +5422,40 @@ void rxi_SendDelayedCallAbort(event, call, dummy)
  * seconds) to ask the client to authenticate itself.  The routine
  * issues a challenge to the client, which is obtained from the
  * security object associated with the connection */
-void rxi_ChallengeEvent(event, conn, dummy)
+void rxi_ChallengeEvent(event, conn, atries)
     struct rxevent *event;
     register struct rx_connection *conn;
-    char *dummy;
+    void *atries;
 {
+    int tries = (int) atries;
     conn->challengeEvent = (struct rxevent *) 0;
     if (RXS_CheckAuthentication(conn->securityObject, conn) != 0) {
        register struct rx_packet *packet;
        struct clock when;
+
+       if (tries <= 0) {
+           /* We've failed to authenticate for too long.
+            * Reset any calls waiting for authentication;
+            * they are all in RX_STATE_PRECALL.
+            */
+           int i;
+
+           MUTEX_ENTER(&conn->conn_call_lock);
+           for (i=0; i<RX_MAXCALLS; i++) {
+               struct rx_call *call = conn->call[i];
+               if (call) {
+                   MUTEX_ENTER(&call->lock);
+                   if (call->state == RX_STATE_PRECALL) {
+                       rxi_CallError(call, RX_CALL_DEAD);
+                       rxi_SendCallAbort(call, NULL, 0, 0);
+                   }
+                   MUTEX_EXIT(&call->lock);
+               }
+           }
+           MUTEX_EXIT(&conn->conn_call_lock);
+           return;
+       }
+
        packet = rxi_AllocPacket(RX_PACKET_CLASS_SPECIAL);
        if (packet) {
            /* If there's no packet available, do this later. */
@@ -5280,7 +5466,8 @@ void rxi_ChallengeEvent(event, conn, dummy)
        }
        clock_GetTime(&when);
        when.sec += RX_CHALLENGE_TIMEOUT;
-       conn->challengeEvent = rxevent_Post(&when, rxi_ChallengeEvent, conn, 0);
+       conn->challengeEvent =
+           rxevent_Post(&when, rxi_ChallengeEvent, conn, (void *) (tries-1));
     }
 }
 
@@ -5295,7 +5482,7 @@ void rxi_ChallengeOn(conn)
 {
     if (!conn->challengeEvent) {
        RXS_CreateChallenge(conn->securityObject, conn);
-       rxi_ChallengeEvent((struct rxevent *)0, conn, NULL);
+       rxi_ChallengeEvent(NULL, conn, (void *) RX_CHALLENGE_MAXTRIES);
     };
 }
 
@@ -5316,7 +5503,6 @@ void rxi_ComputeRoundTripTime(p, sentp, peer)
        struct timeval temptime;
 #endif
       register int rtt_timeout;
-      static char id[]="@(#)adaptive RTO";
 
 #if defined(AFS_ALPHA_LINUX20_ENV) && defined(AFS_PTHREAD_ENV) && !defined(KERNEL)
       /* yet again. This was the worst Heisenbug of the port - stroucki */
@@ -5746,7 +5932,7 @@ rxi_DebugPrint(format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
 {
     struct clock now;
     clock_GetTime(&now);
-    fprintf(rx_Log, " %u.%.3u:", now.sec, now.usec/1000);
+    fprintf(rx_Log, " %u.%.3u:", (unsigned int) now.sec, (unsigned int) now.usec/1000);
     fprintf(rx_Log, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15);
     putc('\n', rx_Log);
 }
@@ -5775,9 +5961,8 @@ void rx_PrintTheseStats (file, s, size, freePackets, version)
     }
 
     fprintf(file,
-           "rx stats: free packets %d, "
-           "allocs %d, ",
-           freePackets,
+           "rx stats: free packets %d, allocs %d, ",
+           (int) freePackets,
            s->packetRequests);
 
     if (version >= RX_DEBUGI_VERSION_W_NEWPACKETTYPES) {
@@ -5857,7 +6042,7 @@ void rx_PrintTheseStats (file, s, size, freePackets, version)
            "   \t(these should be small) sendFailed %d, "
            "fatalErrors %d\n", 
            s->netSendFailures,
-           s->fatalErrors);
+           (int) s->fatalErrors);
 
     if (s->nRttSamples) {
        fprintf(file,
@@ -5909,10 +6094,10 @@ struct rx_peer *peer;
            "Burst size %d, "
            "burst wait %u.%d.\n",
            ntohl(peer->host),
-           peer->port,
-           peer->burstSize,
-           peer->burstWait.sec,
-           peer->burstWait.usec);
+           (int) peer->port,
+           (int) peer->burstSize,
+           (int) peer->burstWait.sec,
+           (int) peer->burstWait.usec);
 
     fprintf(file,
            "   Rtt %d, "
@@ -5920,8 +6105,8 @@ struct rx_peer *peer;
            "total sent %d, "
            "resent %d\n",
            peer->rtt,
-           peer->timeout.sec,
-           peer->timeout.usec,
+           (int) peer->timeout.sec,
+           (int) peer->timeout.usec,
            peer->nSent,
            peer->reSends);
 
@@ -5930,8 +6115,8 @@ struct rx_peer *peer;
            "max in packet skew %d, "
            "max out packet skew %d\n",
            peer->ifMTU,
-           peer->inPacketSkew,
-           peer->outPacketSkew);
+           (int) peer->inPacketSkew,
+           (int) peer->outPacketSkew);
 }
 
 #ifdef AFS_PTHREAD_ENV
@@ -5988,8 +6173,8 @@ static int MakeDebugCall(
        theader.flags = RX_CLIENT_INITIATED | RX_LAST_PACKET;
        theader.serviceId = 0;
        
-       bcopy(&theader, tbuffer, sizeof(theader));
-       bcopy(inputData, tp, inputLength);
+       memcpy(tbuffer, &theader, sizeof(theader));
+       memcpy(tp, inputData, inputLength);
        code = sendto(socket, tbuffer, inputLength+sizeof(struct rx_header), 0,
                      (struct sockaddr *) &taddr, sizeof(struct sockaddr_in));
        
@@ -6005,7 +6190,7 @@ static int MakeDebugCall(
            code = recvfrom(socket, tbuffer, sizeof(tbuffer), 0,
                            (struct sockaddr *) &faddr, &faddrLen);
 
-           bcopy(tbuffer, &theader, sizeof(struct rx_header));
+           memcpy(&theader, tbuffer, sizeof(struct rx_header));
            if (counter == ntohl(theader.callNumber)) break;
        }
 
@@ -6014,7 +6199,7 @@ static int MakeDebugCall(
     }
     code -= sizeof(struct rx_header);
     if (code > outputLength) code = outputLength;
-    bcopy(tp, outputData, code);
+    memcpy(outputData, tp, code);
     return code;
 }