]> arthur.barton.de Git - netatalk.git/commitdiff
Better handling of connection errors and disconnect state
authorFrank Lahm <franklahm@googlemail.com>
Thu, 17 Feb 2011 16:07:19 +0000 (17:07 +0100)
committerFrank Lahm <franklahm@googlemail.com>
Thu, 17 Feb 2011 16:07:19 +0000 (17:07 +0100)
etc/afpd/afp_config.c
etc/afpd/afp_dsi.c
etc/afpd/afp_options.c
etc/afpd/globals.h
include/atalk/dsi.h
libatalk/dsi/dsi_attn.c
libatalk/dsi/dsi_close.c
libatalk/dsi/dsi_stream.c
libatalk/dsi/dsi_tickle.c

index 28fe7cbe8b09a1d6608321fbfb23496f21a95395..52592564cb84b1d9769f68696a5f015a32a581c8 100644 (file)
@@ -230,7 +230,6 @@ static afp_child_t *dsi_start(AFPConfig *config, AFPConfig *configs,
     /* we've forked. */
     if (parent_or_child == 1) {
         configfree(configs, config);
-        LOG(log_error, logtype_afpd, "dsi_start: IPC fd: %i", child->ipc_fds[1]);
         config->obj.ipc_fd = child->ipc_fds[1];
         close(child->ipc_fds[0]); /* Close parent IPC fd */
         free(child);
index c90c8a70f50364e5f9e957a181c98735b9db0858..3b4c01b097ea4d30876582e750c969c4fef7c1db 100644 (file)
 #include "uid.h"
 #endif /* FORCE_UIDGID */
 
-#define CHILD_DIE          (1 << 0)
-#define CHILD_RUNNING      (1 << 1)
-#define CHILD_SLEEPING     (1 << 2)
-#define CHILD_DATA         (1 << 3)
-#define CHILD_DISCONNECTED (1 << 4)
-
 /* 
  * We generally pass this from afp_over_dsi to all afp_* funcs, so it should already be
  * available everywhere. Unfortunately some funcs (eg acltoownermode) need acces to it
@@ -143,7 +137,7 @@ static void afp_dsi_transfer_session(int sig _U_)
     int socket;
     DSI *dsi = (DSI *)child.obj->handle;
 
-    LOG(log_note, logtype_afpd, "afp_dsi_transfer_session: got SIGURG, trying to receive session fd");
+    LOG(log_note, logtype_afpd, "afp_dsi_transfer_session: got SIGURG, trying to receive session");
 
     if (readt(child.obj->ipc_fd, &dsiID, 2, 0, 2) != 2) {
         LOG(log_error, logtype_afpd, "afp_dsi_transfer_session: couldn't receive DSI id, goodbye");
@@ -157,7 +151,8 @@ static void afp_dsi_transfer_session(int sig _U_)
         exit(EXITERR_SYS);
     }
 
-    close(dsi->socket);
+    if (dsi->socket != -1)
+        close(dsi->socket);
     dsi->socket = socket;
     dsi->header.dsi_requestID = dsiID;
     dsi->header.dsi_len = 0;
@@ -165,13 +160,16 @@ static void afp_dsi_transfer_session(int sig _U_)
     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
+     * have to send the reply now.
+     */
     if (!dsi_cmdreply(dsi, AFP_OK)) {
         LOG(log_error, logtype_afpd, "dsi_cmdreply: %s", strerror(errno) );
         afp_dsi_close(child.obj);
         exit(EXITERR_CLNT);
     }
 
-
     LOG(log_note, logtype_afpd, "afp_dsi_transfer_session: succesfull primary reconnect");
     /* 
      * Now returning from this signal handler return to dsi_receive which should start
@@ -183,7 +181,6 @@ static void afp_dsi_transfer_session(int sig _U_)
 /* */
 static void afp_dsi_sleep(void)
 {
-    child.flags |= CHILD_SLEEPING;
     dsi_sleep(child.obj->handle, 1);
 }
 
@@ -192,8 +189,8 @@ static void afp_dsi_timedown(int sig _U_)
 {
     struct sigaction   sv;
     struct itimerval   it;
-
-    child.flags |= CHILD_DIE;
+    DSI                 *dsi = (DSI *)child.obj->handle;
+    dsi->flags |= DSI_DIE;
     /* shutdown and don't reconnect. server going down in 5 minutes. */
     setmessage("The server is going down for maintenance.");
     if (dsi_attention(child.obj->handle, AFPATTN_SHUTDOWN | AFPATTN_NORECONNECT |
@@ -269,38 +266,46 @@ static void alarm_handler(int sig _U_)
     int err;
     DSI *dsi = (DSI *) child.obj->handle;
 
-    if (child.flags & CHILD_DISCONNECTED) {
-        LOG(log_note, logtype_afpd, "afp_alarm: no reconnect within 10 hours, goodbye");
-        afp_dsi_die(EXITERR_CLNT);
-    }
-
     /* we have to restart the timer because some libraries may use alarm() */
     setitimer(ITIMER_REAL, &dsi->timer, NULL);
 
-    /* we got some traffic from the client since the previous timer 
-     * tick. */
-    if ((child.flags & CHILD_DATA)) {
-        child.flags &= ~CHILD_DATA;
-        child.flags &= ~CHILD_DISCONNECTED;
+    /* we got some traffic from the client since the previous timer tick. */
+    if ((dsi->flags & DSI_DATA)) {
+        dsi->flags &= ~DSI_DATA;
+        dsi->flags &= ~DSI_DISCONNECTED;
        return;
     }
 
-    /* if we're in the midst of processing something,
-       don't die. */
-    if ((child.flags & CHILD_SLEEPING) && child.tickle++ < child.obj->options.sleep) {
+    child.tickle++;
+
+    if (dsi->flags & DSI_SLEEPING) {
+        if (child.tickle < child.obj->options.sleep) {
+            LOG(log_error, logtype_afpd, "afp_alarm: sleep time ended");
+            afp_dsi_die(EXITERR_CLNT);
+        }
         return;
     } 
-        
-    if ((child.flags & CHILD_RUNNING) || (child.tickle++ < child.obj->options.timeout)) {
-        if (!(err = pollvoltime(child.obj)))
-            err = dsi_tickle(child.obj->handle);
-        if (err <= 0) 
+
+    if (dsi->flags & DSI_DISCONNECTED) {
+        if (child.tickle > child.obj->options.disconnected) {
+             LOG(log_error, logtype_afpd, "afp_alarm: no reconnect within 10 minutes, goodbye");
             afp_dsi_die(EXITERR_CLNT);
-    } else { /* didn't receive a tickle, enter disconnected state */
+        }
+        return;
+    }
+
+    /* if we're in the midst of processing something, don't die. */        
+    if ( !(dsi->flags & DSI_RUNNING) && (child.tickle > child.obj->options.timeout)) {
         LOG(log_error, logtype_afpd, "afp_alarm: child timed out, entering disconnected state");
-        struct itimerval t = {{0, 60 * 60 * 10}, {0, 0}}; /* 10 hours */
-        setitimer(ITIMER_REAL, &t, NULL);
-        child.flags |= CHILD_DISCONNECTED;
+        dsi->flags |= DSI_DISCONNECTED;
+        return;
+    }
+
+    if ((err = pollvoltime(child.obj)) == 0)
+        err = dsi_tickle(child.obj->handle);
+    if (err <= 0) {
+        LOG(log_error, logtype_afpd, "afp_alarm: connection problem, entering disconnected state");
+        dsi->flags |= DSI_DISCONNECTED;
     }
 }
 
@@ -450,7 +455,7 @@ void afp_over_dsi(AFPObj *obj)
 #ifdef SERVERTEXT
     sigaddset(&action.sa_mask, SIGUSR2);
 #endif    
-    action.sa_flags = SA_RESTART;
+    action.sa_flags = SA_RESTART; /* dont restart, otherwi */
     if ((sigaction(SIGALRM, &action, NULL) < 0) ||
             (setitimer(ITIMER_REAL, &dsi->timer, NULL) < 0)) {
         afp_dsi_die(EXITERR_SYS);
@@ -461,9 +466,17 @@ void afp_over_dsi(AFPObj *obj)
         afp_dsi_die(EXITERR_SYS);
 
     /* get stuck here until the end */
-    while ((cmd = dsi_receive(dsi))) {
+    while (1) {
+        cmd = dsi_receive(dsi);
+        if (cmd == 0) {
+            /* 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  */
+        }
+
         child.tickle = 0;
-        child.flags &= ~CHILD_SLEEPING;
         dsi_sleep(dsi, 0); /* wake up */
 
         if (reload_request) {
@@ -494,13 +507,13 @@ void afp_over_dsi(AFPObj *obj)
 
         if (cmd == DSIFUNC_TICKLE) {
             /* timer is not every 30 seconds anymore, so we don't get killed on the client side. */
-            if ((child.flags & CHILD_DIE))
+            if ((dsi->flags & DSI_DIE))
                 dsi_tickle(dsi);
             pending_request(dsi);
             continue;
         } 
 
-        child.flags |= CHILD_DATA;
+        dsi->flags |= DSI_DATA;
         switch(cmd) {
         case DSIFUNC_CLOSE:
             afp_dsi_close(obj);
@@ -535,7 +548,7 @@ void afp_over_dsi(AFPObj *obj)
                  * of the fact that we're a stream-based protocol. */
                 if (afp_switch[function]) {
                     dsi->datalen = DSI_DATASIZ;
-                    child.flags |= CHILD_RUNNING;
+                    dsi->flags |= DSI_RUNNING;
 
                     LOG(log_debug, logtype_afpd, "<== Start AFP command: %s", AfpNum2name(function));
 
@@ -553,7 +566,7 @@ void afp_over_dsi(AFPObj *obj)
                     if (obj->force_uid)
                         restore_uidgid ( &obj->uidgid );
 #endif /* FORCE_UIDGID */
-                    child.flags &= ~CHILD_RUNNING;
+                    dsi->flags &= ~DSI_RUNNING;
 
                     /* Add result to the AFP replay cache */
                     replaycache[rc_idx].DSIreqID = dsi->clientID;
@@ -582,7 +595,7 @@ void afp_over_dsi(AFPObj *obj)
             function = (u_char) dsi->commands[0];
             if ( afp_switch[ function ] != NULL ) {
                 dsi->datalen = DSI_DATASIZ;
-                child.flags |= CHILD_RUNNING;
+                dsi->flags |= DSI_RUNNING;
 
                 LOG(log_debug, logtype_afpd, "<== Start AFP command: %s", AfpNum2name(function));
 
@@ -593,7 +606,7 @@ void afp_over_dsi(AFPObj *obj)
                 LOG(log_debug, logtype_afpd, "==> Finished AFP command: %s -> %s",
                     AfpNum2name(function), AfpErr2name(err));
 
-                child.flags &= ~CHILD_RUNNING;
+                dsi->flags &= ~DSI_RUNNING;
 #ifdef FORCE_UIDGID
                /* bring everything back to old euid, egid */
                if (obj->force_uid)
index 407a594a769511d4aa39c9cbde24aba75b3c23a7..b8e5130b67a6ccc58f5d0b3653a0d54cf523bbcb 100644 (file)
@@ -159,8 +159,9 @@ void afp_options_init(struct afp_options *options)
     options->transports = AFPTRANS_TCP; /*  TCP only */
     options->passwdfile = _PATH_AFPDPWFILE;
     options->tickleval = 30;
-    options->timeout = 4;
+    options->timeout = 4;       /* 4 tickles = 2 minutes */
     options->sleep = 10* 120; /* 10 h in 30 seconds tick */
+    options->disconnected = 20; /* 20 * 30 s (default tickleval) = 10 minutes */
     options->server_notif = 1;
     options->authprintdir = NULL;
     options->signatureopt = "auto";
index 0910c3514d667b5d5a7e8c5844c1dec0b633d912..ddd2393705a00cbfe95a0528f5aa08f79c56ee84 100644 (file)
@@ -57,6 +57,8 @@ struct afp_volume_name {
 
 struct afp_options {
     int connections, transports, tickleval, timeout, server_notif, flags, dircachesize;
+    int sleep;                  /* Maximum time allowed to sleep (in tickles) */
+    int disconnected;           /* Maximum time in disconnected state (in tickles) */
     unsigned char passwdbits, passwdminlen, loginmaxfail;
     u_int32_t server_quantum;
     char hostname[MAXHOSTNAMELEN + 1], *server, *ipaddr, *port, *configfile;
@@ -78,7 +80,6 @@ struct afp_options {
     charset_t maccharset, unixcharset; 
     mode_t umask;
     mode_t save_mask;
-    int    sleep;
 #ifdef ADMIN_GRP
     gid_t admingid;
 #endif /* ADMIN_GRP */
index f3a79e9fd881f6c0b310ebf6189741b7e8534faf..376e7fc6d058f1f8fc4c49f87ad0281116bf1001 100644 (file)
@@ -64,9 +64,8 @@ typedef struct DSI {
   
   struct itimerval timer;
 
-  int     in_write;      /* in the middle of writing multiple packets, signal handlers
-                          * can't write to the socket 
-                         */
+  int     in_write;      /* in the middle of writing multiple packets,
+                             signal handlers can't write to the socket */
   int      msg_request;   /* pending message to the client */
   int      down_request;  /* pending SIGUSR1 down in 5 mn */
 
@@ -77,7 +76,8 @@ typedef struct DSI {
   size_t statuslen;
   size_t datalen, cmdlen;
   off_t  read_count, write_count;
-  int asleep; /* client won't reply AFP 0x7a ? */
+//  int asleep; /* client won't reply AFP 0x7a ? */
+    uint32_t flags;             /* DSI flags like DSI_SLEEPING, DSI_DISCONNECTED */
   /* noreply = send reply? */
   char noreply;
   const char *program; 
@@ -149,6 +149,13 @@ typedef struct DSI {
 /* default port number */
 #define DSI_AFPOVERTCP_PORT 548
 
+/* DSI session State flags */
+#define DSI_DATA             (1 << 0) /* we have received a DSI command */
+#define DSI_RUNNING          (1 << 1) /* we have received a AFP command */
+#define DSI_SLEEPING         (1 << 2) /* we're sleeping after FPZzz */
+#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 */
+
 /* basic initialization: dsi_init.c */
 extern DSI *dsi_init (const dsi_proto /*protocol*/,
                          const char * /*program*/, 
index 8a9eaddedaac355cf484fc997ead9973da3311b8..9aef79b53534aeabd9598c622c001b7b8f4904bc 100644 (file)
@@ -34,7 +34,7 @@ int dsi_attention(DSI *dsi, AFPUserBytes flags)
   u_int32_t len, nlen;
   u_int16_t id;
 
-  if (dsi->asleep)
+  if (dsi->flags & DSI_SLEEPING)
       return 1;
 
   if (dsi->in_write) {
index 23c9cf46ce9898faf04b5b0a3dd19fe891d300b3..d409814f5f82c038e736368b8b2bad3ca3138f06 100644 (file)
@@ -17,7 +17,7 @@
 void dsi_close(DSI *dsi)
 {
   /* server generated. need to set all the fields. */
-  if (!dsi->asleep) {
+  if (!(dsi->flags & DSI_SLEEPING)) {
       dsi->header.dsi_flags = DSIFL_REQUEST;
       dsi->header.dsi_command = DSIFUNC_CLOSE;
       dsi->header.dsi_requestID = htons(dsi_serverID(dsi));
index ee595bbd3274a80ab02a09c70a7a4d215f80b3c4..87c559c7a28e672914586307d67461db0bf2c727 100644 (file)
@@ -313,7 +313,9 @@ size_t dsi_stream_read(DSI *dsi, void *data, const size_t length)
     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) {
-          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(%d): %s", len, (len < 0)?strerror(errno):"unexpected EOF");
       }
       break;
     }
@@ -357,7 +359,10 @@ static size_t dsi_buffered_stream_read(DSI *dsi, u_int8_t *data, const size_t le
 */
 void dsi_sleep(DSI *dsi, const int state)
 {
-    dsi->asleep = state;
+    if (state)
+        dsi->flags |= DSI_SLEEPING;
+    else
+        dsi->flags &= ~DSI_SLEEPING;
 }
 
 /* ---------------------------------------
index 02aa0536577e2126ad64256b80f0d3e079ceb69b..2a996539a968ba0201c8c19d1f62e9a53a8f7c25 100644 (file)
@@ -23,9 +23,8 @@ int dsi_tickle(DSI *dsi)
 {
   char block[DSI_BLOCKSIZ];
   u_int16_t id;
-  int ret;
   
-  if (dsi->asleep || dsi->in_write)
+  if ((dsi->flags & DSI_SLEEPING) || dsi->in_write)
       return 1;
 
   id = htons(dsi_serverID(dsi));
@@ -36,11 +35,6 @@ int dsi_tickle(DSI *dsi)
   memcpy(block + 2, &id, sizeof(id));
   /* code = len = reserved = 0 */
 
-  ret = dsi_stream_write(dsi, block, DSI_BLOCKSIZ, DSI_NOWAIT);
-  /* we don't really care if we can't send a tickle, it will fail
-   * elsewhere
-  */
-  ret = (ret == -1 || ret == DSI_BLOCKSIZ);
-  return ret;
+  return dsi_stream_write(dsi, block, DSI_BLOCKSIZ, DSI_NOWAIT);
 }