Remove rx_SetEpoch, rx_SetConnectionEpoch, rx_SetConnectionId
[openafs.git] / src / rx / rx.c
index 7a50472..416ce07 100644 (file)
@@ -73,6 +73,7 @@ extern afs_int32 afs_termState;
 #endif /* KERNEL */
 
 #include <opr/queue.h>
+#include <hcrypto/rand.h>
 
 #include "rx.h"
 #include "rx_clock.h"
@@ -157,6 +158,7 @@ static void rxi_AckAllInTransmitQueue(struct rx_call *call);
 static void rxi_CancelKeepAliveEvent(struct rx_call *call);
 static void rxi_CancelDelayedAbortEvent(struct rx_call *call);
 static void rxi_CancelGrowMTUEvent(struct rx_call *call);
+static void update_nextCid(void);
 
 #ifdef RX_ENABLE_LOCKS
 struct rx_tq_debug {
@@ -394,6 +396,7 @@ struct rx_connection *rxLastConn = 0;
  * tiers:
  *
  * rx_connHashTable_lock - synchronizes conn creation, rx_connHashTable access
+ *                         also protects updates to rx_nextCid
  * conn_call_lock - used to synchonize rx_EndCall and rx_NewCall
  * call->lock - locks call data fields.
  * These are independent of each other:
@@ -440,34 +443,6 @@ struct rx_serverQueueEntry *rx_waitForPacket = 0;
 
 /* ------------Exported Interfaces------------- */
 
-/* This function allows rxkad to set the epoch to a suitably random number
- * which rx_NewConnection will use in the future.  The principle purpose is to
- * get rxnull connections to use the same epoch as the rxkad connections do, at
- * least once the first rxkad connection is established.  This is important now
- * that the host/port addresses aren't used in FindConnection: the uniqueness
- * of epoch/cid matters and the start time won't do. */
-
-#ifdef AFS_PTHREAD_ENV
-/*
- * This mutex protects the following global variables:
- * rx_epoch
- */
-
-#define LOCK_EPOCH MUTEX_ENTER(&epoch_mutex)
-#define UNLOCK_EPOCH MUTEX_EXIT(&epoch_mutex)
-#else
-#define LOCK_EPOCH
-#define UNLOCK_EPOCH
-#endif /* AFS_PTHREAD_ENV */
-
-void
-rx_SetEpoch(afs_uint32 epoch)
-{
-    LOCK_EPOCH;
-    rx_epoch = epoch;
-    UNLOCK_EPOCH;
-}
-
 /* Initialize rx.  A port number may be mentioned, in which case this
  * becomes the default port number for any service installed later.
  * If 0 is provided for the port number, a random port will be chosen
@@ -608,12 +583,12 @@ rx_InitHost(u_int host, u_int port)
 #endif
     }
     rx_stats.minRtt.sec = 9999999;
-#ifdef KERNEL
-    rx_SetEpoch(tv.tv_sec | 0x80000000);
-#else
-    rx_SetEpoch(tv.tv_sec);    /* Start time of this package, rxkad
-                                * will provide a randomer value. */
-#endif
+    if (RAND_bytes(&rx_epoch, sizeof(rx_epoch)) != 1)
+       return -1;
+    rx_epoch  = (rx_epoch & ~0x40000000) | 0x80000000;
+    if (RAND_bytes(&rx_nextCid, sizeof(rx_nextCid)) != 1)
+       return -1;
+    rx_nextCid &= RX_CIDMASK;
     MUTEX_ENTER(&rx_quota_mutex);
     rxi_dataQuota += rx_extraQuota; /* + extra pkts caller asked to rsrv */
     MUTEX_EXIT(&rx_quota_mutex);
@@ -710,8 +685,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);
+    }
 }
 
 /*!
@@ -1040,7 +1017,6 @@ rx_NewConnection(afs_uint32 shost, u_short sport, u_short sservice,
                 int serviceSecurityIndex)
 {
     int hashindex, i;
-    afs_int32 cid;
     struct rx_connection *conn;
 
     SPLVAR;
@@ -1061,10 +1037,10 @@ rx_NewConnection(afs_uint32 shost, u_short sport, u_short sservice,
 #endif
     NETPRI;
     MUTEX_ENTER(&rx_connHashTable_lock);
-    cid = (rx_nextCid += RX_MAXCALLS);
     conn->type = RX_CLIENT_CONNECTION;
-    conn->cid = cid;
     conn->epoch = rx_epoch;
+    conn->cid = rx_nextCid;
+    update_nextCid();
     conn->peer = rxi_FindPeer(shost, sport, 1);
     conn->serviceId = sservice;
     conn->securityObject = securityObject;
@@ -2510,6 +2486,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;
 }
 
@@ -4778,6 +4758,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,
@@ -4797,13 +4801,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 {
@@ -5197,7 +5200,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;
@@ -5218,12 +5220,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;
 }
@@ -6702,6 +6700,19 @@ rxi_CancelGrowMTUEvent(struct rx_call *call)
     }
 }
 
+/*
+ * Increment the counter for the next connection ID, handling overflow.
+ */
+static void
+update_nextCid(void)
+{
+    /* Overflow is technically undefined behavior; avoid it. */
+    if (rx_nextCid > MAX_AFS_INT32 - (1 << RX_CIDSHIFT))
+       rx_nextCid = -1 * ((MAX_AFS_INT32 / RX_CIDSHIFT) * RX_CIDSHIFT);
+    else
+       rx_nextCid += 1 << RX_CIDSHIFT;
+}
+
 static void
 rxi_KeepAliveOn(struct rx_call *call)
 {
@@ -7926,7 +7937,7 @@ shutdown_rx(void)
     rxi_StopListener();
 #endif /* AFS_PTHREAD_ENV */
     shutdown_rxevent();
-    rx_SetEpoch(0);
+    rx_epoch = 0;
 #ifndef AFS_PTHREAD_ENV
 #ifndef AFS_USE_GETTIMEOFDAY
     clock_UnInit();