rx: Do not try to cancel nonexistent events
[openafs.git] / src / rx / rx.c
index fed35c8..68b7b02 100644 (file)
@@ -125,7 +125,8 @@ static void rxi_AckAll(struct rx_call *call);
 static struct rx_connection
        *rxi_FindConnection(osi_socket socket, afs_uint32 host, u_short port,
                            u_short serviceId, afs_uint32 cid,
-                           afs_uint32 epoch, int type, u_int securityIndex);
+                           afs_uint32 epoch, int type, u_int securityIndex,
+                            int *unknownService);
 static struct rx_packet
        *rxi_ReceiveDataPacket(struct rx_call *call, struct rx_packet *np,
                               int istack, osi_socket socket,
@@ -436,7 +437,6 @@ static int rxdb_fileID = RXDB_FILE_RX;
 #define CLEAR_CALL_QUEUE_LOCK(C)
 #endif /* RX_ENABLE_LOCKS */
 struct rx_serverQueueEntry *rx_waitForPacket = 0;
-struct rx_serverQueueEntry *rx_waitingForPacket = 0;
 
 /* ------------Exported Interfaces------------- */
 
@@ -477,19 +477,7 @@ rx_SetEpoch(afs_uint32 epoch)
 #ifndef AFS_NT40_ENV
 static
 #endif
-int rxinit_status = 1;
-#ifdef AFS_PTHREAD_ENV
-/*
- * This mutex protects the following global variables:
- * rxinit_status
- */
-
-#define LOCK_RX_INIT MUTEX_ENTER(&rx_init_mutex)
-#define UNLOCK_RX_INIT MUTEX_EXIT(&rx_init_mutex)
-#else
-#define LOCK_RX_INIT
-#define UNLOCK_RX_INIT
-#endif
+rx_atomic_t rxinit_status = RX_ATOMIC_INIT(1);
 
 int
 rx_InitHost(u_int host, u_int port)
@@ -500,17 +488,13 @@ rx_InitHost(u_int host, u_int port)
     struct timeval tv;
 #endif /* KERNEL */
     char *htable, *ptable;
-    int tmp_status;
 
     SPLVAR;
 
     INIT_PTHREAD_LOCKS;
-    LOCK_RX_INIT;
-    if (rxinit_status == 0) {
-       tmp_status = rxinit_status;
-       UNLOCK_RX_INIT;
-       return tmp_status;      /* Already started; return previous error code. */
-    }
+    if (!rx_atomic_test_and_clear_bit(&rxinit_status, 0))
+       return 0; /* already started */
+
 #ifdef RXDEBUG
     rxi_DebugInit();
 #endif
@@ -532,7 +516,6 @@ rx_InitHost(u_int host, u_int port)
 
     rx_socket = rxi_GetHostUDPSocket(host, (u_short) port);
     if (rx_socket == OSI_NULLSOCKET) {
-       UNLOCK_RX_INIT;
        return RX_ADDRINUSE;
     }
 #if defined(RX_ENABLE_LOCKS) && defined(KERNEL)
@@ -655,16 +638,13 @@ rx_InitHost(u_int host, u_int port)
     rx_GetIFInfo();
 #endif
 
-#if defined(RXK_LISTENER_ENV) || !defined(KERNEL)
     /* Start listener process (exact function is dependent on the
      * implementation environment--kernel or user space) */
     rxi_StartListener();
-#endif
 
     USERPRI;
-    tmp_status = rxinit_status = 0;
-    UNLOCK_RX_INIT;
-    return tmp_status;
+    rx_atomic_clear_bit(&rxinit_status, 0);
+    return 0;
 }
 
 int
@@ -730,8 +710,10 @@ rxi_rto_startTimer(struct rx_call *call, int lastPacket, int istack)
 static_inline void
 rxi_rto_cancel(struct rx_call *call)
 {
-    rxevent_Cancel(&call->resendEvent);
-    CALL_RELE(call, RX_CALL_REFCOUNT_RESEND);
+    if (call->resendEvent != NULL) {
+       rxevent_Cancel(&call->resendEvent);
+       CALL_RELE(call, RX_CALL_REFCOUNT_RESEND);
+    }
 }
 
 /*!
@@ -814,7 +796,7 @@ rx_rto_setPeerTimeoutSecs(struct rx_peer *peer, int secs) {
 void
 rx_SetBusyChannelError(afs_int32 onoff)
 {
-    osi_Assert(rxinit_status != 0);
+    osi_Assert(rx_atomic_test_bit(&rxinit_status, 0));
     rxi_busyChannelError = onoff ? 1 : 0;
 }
 
@@ -2147,8 +2129,6 @@ rx_GetCall(int tno, struct rx_service *cur_service, osi_socket * socketp)
            opr_queue_Append(&rx_idleServerQueue, &sq->entry);
 #ifndef AFS_AIX41_ENV
            rx_waitForPacket = sq;
-#else
-           rx_waitingForPacket = sq;
 #endif /* AFS_AIX41_ENV */
            do {
                CV_WAIT(&sq->cv, &rx_serverPool_lock);
@@ -2532,6 +2512,10 @@ rx_EndCall(struct rx_call *call, afs_int32 rc)
      * Map errors to the local host's errno.h format.
      */
     error = ntoh_syserr_conv(error);
+
+    /* If the caller said the call failed with some error, we had better
+     * return an error code. */
+    osi_Assert(!rc || error);
     return error;
 }
 
@@ -2549,11 +2533,9 @@ rx_Finalize(void)
     struct rx_connection **conn_ptr, **conn_end;
 
     INIT_PTHREAD_LOCKS;
-    LOCK_RX_INIT;
-    if (rxinit_status == 1) {
-       UNLOCK_RX_INIT;
+    if (rx_atomic_test_and_set_bit(&rxinit_status, 0))
        return;                 /* Already shutdown. */
-    }
+
     rxi_DeleteCachedConnections();
     if (rx_connHashTable) {
        MUTEX_ENTER(&rx_connHashTable_lock);
@@ -2593,8 +2575,6 @@ rx_Finalize(void)
     afs_winsockCleanup();
 #endif
 
-    rxinit_status = 1;
-    UNLOCK_RX_INIT;
 }
 #endif
 
@@ -3125,10 +3105,12 @@ rxi_FindPeer(afs_uint32 host, u_short port, int create)
 static struct rx_connection *
 rxi_FindConnection(osi_socket socket, afs_uint32 host,
                   u_short port, u_short serviceId, afs_uint32 cid,
-                  afs_uint32 epoch, int type, u_int securityIndex)
+                  afs_uint32 epoch, int type, u_int securityIndex,
+                   int *unknownService)
 {
     int hashindex, flag, i;
     struct rx_connection *conn;
+    *unknownService = 0;
     hashindex = CONN_HASH(host, port, cid, epoch, type);
     MUTEX_ENTER(&rx_connHashTable_lock);
     rxLastConn ? (conn = rxLastConn, flag = 0) : (conn =
@@ -3173,6 +3155,7 @@ rxi_FindConnection(osi_socket socket, afs_uint32 host,
        if (!service || (securityIndex >= service->nSecurityObjects)
            || (service->securityObjects[securityIndex] == 0)) {
            MUTEX_EXIT(&rx_connHashTable_lock);
+            *unknownService = 1;
            return (struct rx_connection *)0;
        }
        conn = rxi_AllocConnection();   /* This bzero's the connection */
@@ -3399,14 +3382,13 @@ rxi_ReceiveServerCall(osi_socket socket, struct rx_packet *np,
      * flag is cleared.
      */
 #ifdef RX_ENABLE_LOCKS
-    if (call->state == RX_STATE_ACTIVE) {
-       int old_error = call->error;
+    if (call->state == RX_STATE_ACTIVE && !call->error) {
        rxi_WaitforTQBusy(call);
         /* If we entered error state while waiting,
          * must call rxi_CallError to permit rxi_ResetCall
          * to processed when the tqWaiter count hits zero.
          */
-        if (call->error && call->error != old_error) {
+        if (call->error) {
            rxi_CallError(call, call->error);
            MUTEX_EXIT(&call->lock);
             return NULL;
@@ -3470,6 +3452,7 @@ rxi_ReceivePacket(struct rx_packet *np, osi_socket socket,
     struct rx_call *call;
     struct rx_connection *conn;
     int type;
+    int unknownService = 0;
 #ifdef RXDEBUG
     char *packetType;
 #endif
@@ -3550,12 +3533,12 @@ rxi_ReceivePacket(struct rx_packet *np, osi_socket socket,
     conn =
        rxi_FindConnection(socket, host, port, np->header.serviceId,
                           np->header.cid, np->header.epoch, type,
-                          np->header.securityIndex);
+                          np->header.securityIndex, &unknownService);
 
     /* To avoid having 2 connections just abort at each other,
        don't abort an abort. */
     if (!conn) {
-        if (np->header.type != RX_PACKET_TYPE_ABORT)
+        if (unknownService && (np->header.type != RX_PACKET_TYPE_ABORT))
             rxi_SendRawAbort(socket, host, port, RX_INVALID_OPERATION,
                              np, 0);
         return np;
@@ -4801,6 +4784,30 @@ rxi_ReceiveAckPacket(struct rx_call *call, struct rx_packet *np,
     return np;
 }
 
+/**
+ * Schedule a connection abort to be sent after some delay.
+ *
+ * @param[in] conn The connection to send the abort on.
+ * @param[in] msec The number of milliseconds to wait before sending.
+ *
+ * @pre conn_data_lock must be held
+ */
+static void
+rxi_SendConnectionAbortLater(struct rx_connection *conn, int msec)
+{
+    struct clock when, now;
+    if (!conn->error) {
+       return;
+    }
+    if (!conn->delayedAbortEvent) {
+       clock_GetTime(&now);
+       when = now;
+       clock_Addmsec(&when, msec);
+       conn->delayedAbortEvent =
+           rxevent_Post(&when, &now, rxi_SendDelayedConnAbort, conn, NULL, 0);
+    }
+}
+
 /* Received a response to a challenge packet */
 static struct rx_packet *
 rxi_ReceiveResponsePacket(struct rx_connection *conn,
@@ -4820,13 +4827,12 @@ rxi_ReceiveResponsePacket(struct rx_connection *conn,
     error = RXS_CheckResponse(conn->securityObject, conn, np);
     if (error) {
        /* If the response is invalid, reset the connection, sending
-        * an abort to the peer */
-#ifndef KERNEL
-       rxi_Delay(1);
-#endif
+        * an abort to the peer. Send the abort with a 1 second delay,
+        * to avoid a peer hammering us by constantly recreating a
+        * connection with bad credentials. */
        rxi_ConnectionError(conn, error);
        MUTEX_ENTER(&conn->conn_data_lock);
-       np = rxi_SendConnectionAbort(conn, np, istack, 0);
+       rxi_SendConnectionAbortLater(conn, 1000);
        MUTEX_EXIT(&conn->conn_data_lock);
        return np;
     } else {
@@ -5220,7 +5226,6 @@ rxi_SendConnectionAbort(struct rx_connection *conn,
                        struct rx_packet *packet, int istack, int force)
 {
     afs_int32 error;
-    struct clock when, now;
 
     if (!conn->error)
        return packet;
@@ -5241,12 +5246,8 @@ rxi_SendConnectionAbort(struct rx_connection *conn,
                            RX_PACKET_TYPE_ABORT, (char *)&error,
                            sizeof(error), istack);
        MUTEX_ENTER(&conn->conn_data_lock);
-    } else if (!conn->delayedAbortEvent) {
-       clock_GetTime(&now);
-       when = now;
-       clock_Addmsec(&when, rxi_connAbortDelay);
-       conn->delayedAbortEvent =
-           rxevent_Post(&when, &now, rxi_SendDelayedConnAbort, conn, NULL, 0);
+    } else {
+       rxi_SendConnectionAbortLater(conn, rxi_connAbortDelay);
     }
     return packet;
 }
@@ -6828,6 +6829,13 @@ rxi_ChallengeEvent(struct rxevent *event,
     if (event)
        rxevent_Put(&conn->challengeEvent);
 
+    /* If there are no active calls it is not worth re-issuing the
+     * challenge.  If the client issues another call on this connection
+     * the challenge can be requested at that time.
+     */
+    if (!rxi_HasActiveCalls(conn))
+        return;
+
     if (RXS_CheckAuthentication(conn->securityObject, conn) != 0) {
        struct rx_packet *packet;
        struct clock when, now;
@@ -7929,11 +7937,9 @@ shutdown_rx(void)
     struct rx_serverQueueEntry *sq;
 #endif /* KERNEL */
 
-    LOCK_RX_INIT;
-    if (rxinit_status == 1) {
-       UNLOCK_RX_INIT;
+    if (rx_atomic_test_and_set_bit(&rxinit_status, 0))
        return;                 /* Already shutdown. */
-    }
+
 #ifndef KERNEL
     rx_port = 0;
 #ifndef AFS_PTHREAD_ENV
@@ -8057,8 +8063,6 @@ shutdown_rx(void)
     rxi_dataQuota = RX_MAX_QUOTA;
     rxi_availProcs = rxi_totalMin = rxi_minDeficit = 0;
     MUTEX_EXIT(&rx_quota_mutex);
-    rxinit_status = 1;
-    UNLOCK_RX_INIT;
 }
 
 #ifndef KERNEL
@@ -9145,7 +9149,7 @@ rx_clearProcessRPCStats(afs_uint32 clearFlag)
     for (opr_queue_Scan(&processStats, cursor)) {
        unsigned int num_funcs = 0, i;
        struct rx_interface_stat *rpc_stat
-            = opr_queue_Entry(rpc_stat, struct rx_interface_stat, entry);
+            = opr_queue_Entry(cursor, struct rx_interface_stat, entry);
 
        num_funcs = rpc_stat->stats[0].func_total;
        for (i = 0; i < num_funcs; i++) {