]> arthur.barton.de Git - netatalk.git/commitdiff
Mege maste
authorFrank Lahm <franklahm@googlemail.com>
Mon, 21 Feb 2011 12:31:58 +0000 (13:31 +0100)
committerFrank Lahm <franklahm@googlemail.com>
Mon, 21 Feb 2011 12:31:58 +0000 (13:31 +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 8b15abf4dd014f767e16f23fbab6e0f9f0dfd3b3..d030d72570ac36571080239f6f3d4325dac2f198 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>
@@ -64,8 +65,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;
@@ -89,7 +92,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();
 
@@ -102,7 +105,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;
@@ -113,6 +117,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 &
@@ -146,14 +156,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
@@ -171,6 +181,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);
 }
 
 /* */
@@ -434,7 +445,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);
@@ -446,13 +457,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 2b1a99d77b92ae6bf1beac540fb2aa854b2f4426..e63a5a42c8bd8923aeb0d951e6520458809f52ec 100644 (file)
@@ -635,6 +635,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)
@@ -647,11 +652,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 0d4ccc34f1e48b3fc0dbc08ddfc35c844c66fcc8..988d2bbb3d7a1f19a7dd33a03d10508936df0e13 100644 (file)
@@ -148,6 +148,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 512d83ef2ff00d206e754765d07e2a1980b11a51..60e3c4f322e60a0e16598a6ad06b6aa936b4b8c6 100644 (file)
@@ -178,8 +178,9 @@ 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);
         }        
+        close(ipc.afp_socket);
         break;
 
        case IPC_GETSESSION: