]> arthur.barton.de Git - netatalk.git/commitdiff
Endless fiddling to find out that dsi->datalen had to be set to 0 in SIGURG handler
authorFrank Lahm <franklahm@googlemail.com>
Mon, 21 Feb 2011 11:07:19 +0000 (12:07 +0100)
committerFrank Lahm <franklahm@googlemail.com>
Mon, 21 Feb 2011 11:07:19 +0000 (12:07 +0100)
etc/afpd/afp_dsi.c
etc/afpd/auth.c
include/atalk/dsi.h
libatalk/dsi/dsi_stream.c
libatalk/util/server_ipc.c

index 690d0b3f24d1e29c2358c3aa23b9219c2591e49f..2f810a721e8a53d3fca96f833264671597dd00d4 100644 (file)
@@ -26,6 +26,7 @@
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <atalk/logger.h>
+#include <setjmp.h>
 
 #include <atalk/dsi.h>
 #include <atalk/compat.h>
@@ -63,8 +64,10 @@ typedef struct {
  * - fix sized array
  * - indexed just by taking DSIreqID mod REPLAYCACHE_SIZE
  */
-rc_elem_t replaycache[REPLAYCACHE_SIZE];
+static rc_elem_t replaycache[REPLAYCACHE_SIZE];
 
+static sigjmp_buf recon_jmp;
+static int oldsock = -1;
 static void afp_dsi_close(AFPObj *obj)
 {
     DSI *dsi = obj->handle;
@@ -88,7 +91,7 @@ static void afp_dsi_close(AFPObj *obj)
     if (obj->logout)
         (*obj->logout)();
 
-    LOG(log_info, logtype_afpd, "AFP statistics: %.2f KB read, %.2f KB written",
+    LOG(log_note, logtype_afpd, "AFP statistics: %.2f KB read, %.2f KB written",
         dsi->read_count/1024.0, dsi->write_count/1024.0);
     log_dircache_stat();
 
@@ -101,7 +104,8 @@ static void afp_dsi_close(AFPObj *obj)
  */
 static void afp_dsi_die(int sig)
 {
-static volatile int in_handler;
+    DSI *dsi = (DSI *)AFPobj->handle;
+    static volatile int in_handler;
     
     if (in_handler) {
        return;
@@ -112,6 +116,12 @@ static volatile int in_handler;
     */
     in_handler = 1;
 
+    if (dsi->flags & DSI_RECONINPROG) {
+        /* Primary reconnect succeeded, got SIGTERM from afpd parent */
+        dsi->flags &= ~DSI_RECONINPROG;
+        return; /* this returns to afp_disconnect */
+    }
+
     dsi_attention(AFPobj->handle, AFPATTN_SHUTDOWN);
     afp_dsi_close(AFPobj);
     if (sig) /* if no signal, assume dieing because logins are disabled &
@@ -145,14 +155,14 @@ static void afp_dsi_transfer_session(int sig _U_)
         exit(EXITERR_SYS);
     }
 
-    if (dsi->socket != -1)
-        close(dsi->socket);
+    LOG(log_note, logtype_afpd, "afp_dsi_transfer_session: received socket fd: %i", socket);
+
     dsi->socket = socket;
+    dsi->flags |= DSI_RECONSOCKET;
+    dsi->flags &= ~DSI_DISCONNECTED;
+    dsi->datalen = 0;
     dsi->header.dsi_requestID = dsiID;
-    dsi->header.dsi_len = 0;
-    dsi->header.dsi_code = AFP_OK;
     dsi->header.dsi_command = DSIFUNC_CMD;
-    dsi->header.dsi_flags = DSIFL_REPLY;
 
     /*
      * The session transfer happens in the middle of FPDisconnect old session, thus we
@@ -170,6 +180,7 @@ static void afp_dsi_transfer_session(int sig _U_)
      * reading/continuing from the connected socket that was passed via the parent from
      * another session. The parent will terminate that session.
      */
+    siglongjmp(recon_jmp, 1);
 }
 
 /* */
@@ -433,7 +444,7 @@ void afp_over_dsi(AFPObj *obj)
     sigaddset(&action.sa_mask, SIGUSR1);
     sigaddset(&action.sa_mask, SIGINT);
     sigaddset(&action.sa_mask, SIGUSR2);
-    action.sa_flags = SA_RESTART; /* dont restart, otherwi */
+    action.sa_flags = SA_RESTART;
     if ((sigaction(SIGALRM, &action, NULL) < 0) ||
             (setitimer(ITIMER_REAL, &dsi->timer, NULL) < 0)) {
         afp_dsi_die(EXITERR_SYS);
@@ -445,13 +456,32 @@ void afp_over_dsi(AFPObj *obj)
 
     /* get stuck here until the end */
     while (1) {
+        if (sigsetjmp(recon_jmp, 1) != 0) {
+            LOG(log_note, logtype_afpd, "Resuming operation after succesfull primary reconnect");
+            dsi->flags &= ~(DSI_RUNNING | DSI_DATA);
+            dsi->eof = dsi->start = dsi->buffer;
+            dsi->in_write = 0;
+            continue;
+        }
         cmd = dsi_receive(dsi);
         if (cmd == 0) {
+            if (dsi->flags & DSI_RECONSOCKET) {
+                /* we just got a reconnect so we immediately try again to receive on the new fd */
+                dsi->flags &= ~DSI_RECONSOCKET;
+                continue;
+            }
             /* Some error on the client connection, enter disconnected state */
             dsi->flags |= DSI_DISCONNECTED;
             pause(); /* gets interrupted by SIGALARM or SIGURG tickle */
             continue; /* continue receiving until disconnect timer expires
                        * or a primary reconnect succeeds  */
+        } else {
+            if (oldsock != -1) {
+                /* Now, after successfully reading from the new socket after a reconnect       *
+                 * we can close the old socket without taking the risk of confusing the client */
+                close(oldsock);
+                oldsock = -1;
+            }
         }
 
         dsi->tickle = 0;
index e9d658442c16c16b2506451ef501421dfcdb062f..ea774ee2f35fa9d6f899a35182b68780e528fe87 100644 (file)
@@ -637,6 +637,11 @@ int afp_disconnect(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_,
     }
 
     LOG(log_note, logtype_afpd, "afp_disconnect: trying primary reconnect");
+    dsi->flags |= DSI_RECONINPROG;
+
+    /* Deactivate tickle timer */
+    const struct itimerval none = {{0, 0}, {0, 0}};
+    setitimer(ITIMER_REAL, &none, NULL);
 
     /* check for old session, possibly transfering session from here to there */
     if (ipc_child_write(obj->ipc_fd, IPC_DISCOLDSESSION, tklen, &token) == -1)
@@ -649,11 +654,21 @@ int afp_disconnect(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_,
     /* now send our connected AFP client socket */
     if (send_fd(obj->ipc_fd, dsi->socket) != 0)
         goto exit;
-    /* Now see what happens: either afpd master kills us because our session */
+    /* Now see what happens: either afpd master sends us SIGTERM because our session */
     /* has been transfered to a old disconnected session, or we continue    */
-    sleep(2);
+    sleep(5);
+
+    if (!(dsi->flags & DSI_RECONINPROG)) { /* deleted in SIGTERM handler */
+        /* Reconnect succeeded, we exit now after sleeping some more */
+        sleep(2); /* sleep some more to give the recon. session time */
+        LOG(log_note, logtype_afpd, "afp_disconnect: primary reconnect succeeded");
+        exit(0);
+    }
 
 exit:
+    /* Reinstall tickle timer */
+    setitimer(ITIMER_REAL, &dsi->timer, NULL);
+
     LOG(log_error, logtype_afpd, "afp_disconnect: primary reconnect failed");
     return AFPERR_MISC;
 }
index d1d0cb3062739d12ee80421e5fc16b791fdd640c..6b53cfa7f9746bd2b7dd1a3d809f6bcae1059ef7 100644 (file)
@@ -152,6 +152,8 @@ typedef struct DSI {
 #define DSI_DISCONNECTED     (1 << 3) /* we're in diconnected state after a socket error */
 #define DSI_DIE              (1 << 4) /* SIGUSR1, going down in 5 minutes */
 #define DSI_NOREPLY          (1 << 5) /* in dsi_write we generate our own replies */
+#define DSI_RECONSOCKET      (1 << 6) /* we have a new socket from primary reconnect */
+#define DSI_RECONINPROG      (1 << 7) /* used in the new session in reconnect */
 
 /* basic initialization: dsi_init.c */
 extern DSI *dsi_init (const dsi_proto /*protocol*/,
index 87c559c7a28e672914586307d67461db0bf2c727..52209850988bf5c7e80749171cb18a5e2914052c 100644 (file)
@@ -302,20 +302,20 @@ size_t dsi_stream_read(DSI *dsi, void *data, const size_t length)
 {
   size_t stored;
   ssize_t len;
-  
+
   stored = 0;
   while (stored < length) {
     len = buf_read(dsi, (u_int8_t *) data + stored, length - stored);
-    if (len == -1 && errno == EINTR)
+    if (len == -1 && errno == EINTR) {
       continue;
-    else if (len > 0)
+    } else if (len > 0) {
       stored += len;
-    else { /* eof or error */
+    else { /* eof or error */
       /* don't log EOF error if it's just after connect (OSX 10.3 probe) */
       if (len || stored || dsi->read_count) {
-          if (! (dsi->flags & DSI_DISCONNECTED)
-)
-              LOG(log_error, logtype_dsi, "dsi_stream_read(%d): %s", len, (len < 0)?strerror(errno):"unexpected EOF");
+          if (! (dsi->flags & DSI_DISCONNECTED))
+              LOG(log_error, logtype_dsi, "dsi_stream_read(fd: %i): len:%d, %s",
+                  dsi->socket, len, (len < 0) ? strerror(errno) : "unexpected EOF");
       }
       break;
     }
index 76d3bc3b8a1f492433b77084ab6d207e0e5179ec..ec94be204b0082127effb526b01d132d872ae64b 100644 (file)
@@ -180,7 +180,7 @@ int ipc_server_read(server_child *children, int fd)
             /* Transfered session (ie afp_socket) to old disconnected child, now kill the new one */
             LOG(log_note, logtype_afpd, "Reconnect: killing new session child[%u] after transfer",
                 ipc.child_pid);
-            kill(ipc.child_pid, SIGKILL);
+            kill(ipc.child_pid, SIGTERM);
         }        
         break;