rx lowlevel nat ping
authorDerrick Brashear <shadow@dementia.org>
Thu, 25 Feb 2010 03:34:28 +0000 (22:34 -0500)
committerDerrick Brashear <shadow@dementia.org>
Sat, 27 Feb 2010 16:58:15 +0000 (08:58 -0800)
for rfc 4787, do a minimal impact nat ping. this uses an rx
"version request" reply debug packet, which will simply be discarded by the
receiver, to keep the port mapping open.

Change-Id: Ic2180bfa5c467e33c72e3f19d62488bd6a2dc61a
Reviewed-on: http://gerrit.openafs.org/1393
Reviewed-by: Simon Wilkinson <sxw@inf.ed.ac.uk>
Reviewed-by: Derrick Brashear <shadow@dementia.org>
Tested-by: Derrick Brashear <shadow@dementia.org>

src/afs/afs_conn.c
src/rx/rx.c
src/rx/rx.h
src/rx/rx_globals.h
src/rx/rx_prototypes.h

index d2091db..eae56ff 100644 (file)
@@ -294,6 +294,8 @@ afs_ConnBySA(struct srvAddr *sap, unsigned short aport, afs_int32 acell,
        }
        rx_SetConnIdleDeadTime(tc->id, afs_rx_idledead);
 
+       rx_SetConnSecondsUntilNatPing(tc->id, 20);
+
        tc->forceConnectFS = 0; /* apparently we're appropriately connected now */
        if (csec)
            rxs_Release(csec);
index 33c422b..1d0d922 100755 (executable)
@@ -828,6 +828,7 @@ rx_NewConnection(afs_uint32 shost, u_short sport, u_short sservice,
     conn->securityData = (void *) 0;
     conn->securityIndex = serviceSecurityIndex;
     rx_SetConnDeadTime(conn, rx_connDeadTime);
+    rx_SetConnSecondsUntilNatPing(conn, 0);
     conn->ackRate = RX_FAST_ACK_RATE;
     conn->nSpecific = 0;
     conn->specific = NULL;
@@ -1034,6 +1035,10 @@ rxi_DestroyConnectionNoLock(struct rx_connection *conn)
        return;
     }
 
+    if (conn->natKeepAliveEvent) {
+       rxi_NatKeepAliveOff(conn);
+    }
+
     if (conn->delayedAbortEvent) {
        rxevent_Cancel(conn->delayedAbortEvent, (struct rx_call *)0, 0);
        packet = rxi_AllocPacket(RX_PACKET_CLASS_SPECIAL);
@@ -1067,6 +1072,8 @@ rxi_DestroyConnectionNoLock(struct rx_connection *conn)
        rxevent_Cancel(conn->challengeEvent, (struct rx_call *)0, 0);
     if (conn->checkReachEvent)
        rxevent_Cancel(conn->checkReachEvent, (struct rx_call *)0, 0);
+    if (conn->natKeepAliveEvent)
+       rxevent_Cancel(conn->natKeepAliveEvent, (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
@@ -4602,6 +4609,8 @@ rxi_ConnectionError(struct rx_connection *conn,
        MUTEX_ENTER(&conn->conn_data_lock);
        if (conn->challengeEvent)
            rxevent_Cancel(conn->challengeEvent, (struct rx_call *)0, 0);
+       if (conn->natKeepAliveEvent)
+           rxevent_Cancel(conn->natKeepAliveEvent, (struct rx_call *)0, 0);
        if (conn->checkReachEvent) {
            rxevent_Cancel(conn->checkReachEvent, (struct rx_call *)0, 0);
            conn->checkReachEvent = 0;
@@ -5779,6 +5788,79 @@ rxi_CheckCall(struct rx_call *call)
     return 0;
 }
 
+void
+rxi_NatKeepAliveEvent(struct rxevent *event, void *arg1, void *dummy)
+{
+    struct rx_connection *conn = arg1;
+    struct rx_header theader;
+    char tbuffer[1500];
+    struct sockaddr_in taddr;
+    char *tp;
+    char a[1] = { 0 };
+    struct iovec tmpiov[2];
+    osi_socket socket =
+        (conn->type ==
+         RX_CLIENT_CONNECTION ? rx_socket : conn->service->socket);
+
+
+    MUTEX_ENTER(&conn->conn_data_lock);
+    conn->natKeepAliveEvent = NULL;
+    MUTEX_EXIT(&conn->conn_data_lock);
+
+    tp = &tbuffer[sizeof(struct rx_header)];
+    taddr.sin_family = AF_INET;
+    taddr.sin_port = rx_PortOf(rx_PeerOf(conn));
+    taddr.sin_addr.s_addr = rx_HostOf(rx_PeerOf(conn));
+#ifdef STRUCT_SOCKADDR_HAS_SA_LEN
+    taddr.sin_len = sizeof(struct sockaddr_in);
+#endif
+    memset(&theader, 0, sizeof(theader));
+    theader.epoch = htonl(999);
+    theader.cid = 0;
+    theader.callNumber = 0;
+    theader.seq = 0;
+    theader.serial = 0;
+    theader.type = RX_PACKET_TYPE_VERSION;
+    theader.flags = RX_LAST_PACKET;
+    theader.serviceId = 0;
+
+    memcpy(tbuffer, &theader, sizeof(theader));
+    memcpy(tp, &a, sizeof(a));
+    tmpiov[0].iov_base = tbuffer;
+    tmpiov[0].iov_len = 1 + sizeof(struct rx_header);
+
+    osi_NetSend(socket, &taddr, tmpiov, 1, 1 + sizeof(struct rx_header), 1);
+    rxi_ScheduleNatKeepAliveEvent(conn);
+}
+
+void
+rxi_ScheduleNatKeepAliveEvent(struct rx_connection *conn)
+{
+    MUTEX_ENTER(&conn->conn_data_lock);
+    if (!conn->natKeepAliveEvent && conn->secondsUntilNatPing) {
+       struct clock when, now;
+       clock_GetTime(&now);
+       when = now;
+       when.sec += conn->secondsUntilNatPing;
+       conn->natKeepAliveEvent =
+           rxevent_PostNow(&when, &now, rxi_NatKeepAliveEvent, conn, 0);
+    }
+    MUTEX_EXIT(&conn->conn_data_lock);
+}
+
+void
+rx_SetConnSecondsUntilNatPing(struct rx_connection *conn, afs_int32 seconds)
+{
+    conn->secondsUntilNatPing = seconds;
+    if (seconds != 0)
+       rxi_ScheduleNatKeepAliveEvent(conn);
+}
+
+void
+rxi_NatKeepAliveOn(struct rx_connection *conn)
+{
+    rxi_ScheduleNatKeepAliveEvent(conn);
+}
 
 /* When a call is in progress, this routine is called occasionally to
  * make sure that some traffic has arrived (or been sent to) the peer.
index 8f79086..9e3b111 100644 (file)
@@ -272,6 +272,8 @@ struct rx_connection {
     u_char ackRate;            /* how many packets between ack requests */
     u_char makeCallWaiters;    /* how many rx_NewCalls are waiting */
     afs_int32 idleDeadErr;
+    afs_int32 secondsUntilNatPing;     /* how often to ping conn */
+    struct rxevent *natKeepAliveEvent; /* Scheduled to keep connection open */
     int nSpecific;             /* number entries in specific data */
     void **specific;           /* pointer to connection specific data */
 };
index 78020fb..a265ba1 100644 (file)
@@ -531,6 +531,7 @@ EXT afs_kmutex_t rx_connHashTable_lock;
 /* Forward definitions of internal procedures */
 #define        rxi_ChallengeOff(conn)  rxevent_Cancel((conn)->challengeEvent, (struct rx_call*)0, 0);
 #define rxi_KeepAliveOff(call) rxevent_Cancel((call)->keepAliveEvent, call, RX_CALL_REFCOUNT_ALIVE)
+#define rxi_NatKeepAliveOff(conn) rxevent_Cancel((conn)->natKeepAliveEvent, (struct rx_call*)0, 0)
 
 #define rxi_AllocSecurityObject() (struct rx_securityClass *) rxi_Alloc(sizeof(struct rx_securityClass))
 #define        rxi_FreeSecurityObject(obj) rxi_Free(obj, sizeof(struct rx_securityClass))
index 35020be..f7f3b3a 100644 (file)
@@ -169,7 +169,10 @@ extern void rxi_KeepAliveEvent(struct rxevent *event,
                               void *call /* struct rx_call *call */, 
                               void *dummy);
 extern void rxi_ScheduleKeepAliveEvent(struct rx_call *call);
+extern void rxi_ScheduleNatKeepAliveEvent(struct rx_connection *conn);
 extern void rxi_KeepAliveOn(struct rx_call *call);
+extern void rxi_NatKeepAliveOn(struct rx_connection *conn);
+extern void rx_SetConnSecondsUntilNatPing(struct rx_connection *conn, afs_int32 seconds);
 extern void rxi_SendDelayedConnAbort(struct rxevent *event,
                                     void *conn, /* struct rx_connection *conn */
                                     void *dummy);