]> arthur.barton.de Git - netatalk.git/commitdiff
Reconnection of disasociated afpd childs
authorFrank Lahm <franklahm@googlemail.com>
Wed, 25 May 2011 15:44:09 +0000 (17:44 +0200)
committerFrank Lahm <franklahm@googlemail.com>
Wed, 25 May 2011 15:44:09 +0000 (17:44 +0200)
etc/afpd/afp_dsi.c
etc/afpd/auth.c
include/atalk/server_ipc.h
include/atalk/uam.h
libatalk/util/server_ipc.c

index 29212b89eea2ea101b20ba844090668dd74187b2..e8bbc0174fad5551ed4a1a8843e31e78bab15b02 100644 (file)
@@ -32,6 +32,8 @@
 #include <atalk/compat.h>
 #include <atalk/util.h>
 #include <atalk/uuid.h>
+#include <atalk/paths.h>
+#include <atalk/server_ipc.h>
 
 #include "globals.h"
 #include "switch.h"
@@ -359,6 +361,7 @@ void afp_over_dsi(AFPObj *obj)
     u_int32_t err, cmd;
     u_int8_t function;
     struct sigaction action;
+    struct pollfd pollfds[1];
 
     AFPobj = obj;
     obj->exit = afp_dsi_die;
@@ -366,6 +369,9 @@ void afp_over_dsi(AFPObj *obj)
     obj->attention = (int (*)(void *, AFPUserBytes)) dsi_attention;
     dsi->tickle = 0;
 
+    pollfds[0].fd = obj->ipc_fd;
+    pollfds[0].events = POLLOUT;
+
     memset(&action, 0, sizeof(action));
 
     /* install SIGHUP */
@@ -517,6 +523,23 @@ void afp_over_dsi(AFPObj *obj)
                        * or a primary reconnect succeeds  */
         }
 
+        static int saved_ipcfd = -1;
+        if (saved_ipcfd == -1)
+            saved_ipcfd = obj->ipc_fd;
+        if (poll(pollfds, 1, 0) == 1) {
+            if (pollfds[0].revents & (POLLHUP | POLLERR)) {
+                if (saved_ipcfd == obj->ipc_fd && getppid() == 1) {
+                    close(obj->ipc_fd);
+                    sleep(30);  /* give it enough time to start */
+                    if ((obj->ipc_fd = ipc_client_uds(_PATH_AFP_IPC)) == -1) {
+                        LOG(log_error, logtype_afpd, "afp_over_dsi: cant reconnect to master");
+                        afp_dsi_die(EXITERR_SYS);
+                    }
+                }
+            }
+        }
+
+
         if (!(dsi->flags & DSI_EXTSLEEP) && (dsi->flags & DSI_SLEEPING)) {
             LOG(log_debug, logtype_afpd, "afp_over_dsi: got data, ending normal sleep");
             dsi->flags &= ~DSI_SLEEPING;
index 566a8d0e05b1b838ddc5e2dceef29463e9c33d03..25ed6049c09f44ac3bc052371a7968ef0c63d7d3 100644 (file)
@@ -594,7 +594,13 @@ int afp_getsession(
             if (ibuflen < idlen || idlen > (90-10)) {
                 return AFPERR_PARAM;
             }
-            ipc_child_write(obj->ipc_fd, IPC_GETSESSION, idlen+8, p);
+            if (!obj->sinfo.clientid) {
+                obj->sinfo.clientid = malloc(idlen + 8);
+                memcpy(obj->sinfo.clientid, p, idlen + 8);
+            }
+            if (ipc_child_write(&obj->ipc_fd, IPC_GETSESSION, idlen+8, p) == -1) {
+                
+            }
             tklen = obj->sinfo.sessiontoken_len;
             token = obj->sinfo.sessiontoken;
         }
@@ -676,7 +682,7 @@ int afp_disconnect(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_,
     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)
+    if (ipc_child_write(&obj->ipc_fd, IPC_DISCOLDSESSION, tklen, &token) == -1)
         goto exit;
     /* write uint16_t DSI request ID */
     if (writet(obj->ipc_fd, &dsi->header.dsi_requestID, 2, 0, 2) != 2) {
index bdfc37a5ebc1228e5f029fbb1ba56e641cd15bc4..8704c6baae04e05ad2e7f9984c0d432b96730ab1 100644 (file)
@@ -7,7 +7,8 @@
 #define IPC_GETSESSION       1
 
 extern int ipc_server_uds(const char *name);
+extern int ipc_client_uds(const char *name);
 extern int ipc_server_read(server_child *children, int fd);
-extern int ipc_child_write(int fd, uint16_t command, int len, void *token);
+extern ssize_t ipc_child_write(int *fd, uint16_t command, int len, void *token);
 
 #endif /* IPC_GETSESSION_LOGIN */
index 0fb199b3962f9103fb839521120883112eff9a88..ba62783aa657aad332875986cbb6854897993c9f 100644 (file)
@@ -77,6 +77,8 @@ struct session_info {
   size_t  cryptedkey_len;
   void    *sessiontoken;        /* session token sent to the client on FPGetSessionToken*/
   size_t  sessiontoken_len;
+  void    *clientid;          /* whole buffer cotaining eg idlen, id and boottime */
+  size_t  clientid_len;
 };
 
 /* register and unregister uams with these functions */
index a78826c2920ad9a14c8a906c6689a9598627ba57..1060fde81f7f4be5af4ab4733f01b3e8a07ec6ab 100644 (file)
@@ -25,6 +25,7 @@
 #include <atalk/logger.h>
 #include <atalk/util.h>
 #include <atalk/errchk.h>
+#include <atalk/paths.h>
 
 #define IPC_HEADERLEN 14
 #define IPC_MAXMSGSIZE 90
@@ -109,7 +110,7 @@ static int ipc_get_session(struct ipc_header *ipc, server_child *children)
  ***********************************************************************************/
 
 /*!
- * Listen on UNIX domain socket "name" for IPD from old sesssion
+ * Listen on UNIX domain socket "name" for IPC from old sesssion
  *
  * @args name    (r) file name to use for UNIX domain socket
  * @returns      socket fd, -1 on error
@@ -131,13 +132,49 @@ int ipc_server_uds(const char *name)
 
 EC_CLEANUP:
     if (ret != 0) {
-
         return -1;
     }
     LOG(log_note, logtype_afpd, "ipc_server_uds: fd: %d", fd);
     return fd;
 }
 
+/*!
+ * Connect to UNIX domain socket "name" for IPC with new afpd master
+ *
+ * 1. Connect
+ * 2. send pid, which establishes a child structure for us in the master
+ *
+ * @args name    (r) file name to use for UNIX domain socket
+ * @returns      socket fd, -1 on error
+ */
+int ipc_client_uds(const char *name)
+{
+    EC_INIT;
+    struct sockaddr_un address;
+    socklen_t address_length;
+    int fd = -1;
+    pid_t pid = getpid();
+
+    EC_NEG1_LOG( fd = socket(PF_UNIX, SOCK_STREAM, 0) );
+    EC_ZERO_LOG( setnonblock(fd, 1) );
+    address.sun_family = AF_UNIX;
+    address_length = sizeof(address.sun_family) + sprintf(address.sun_path, name);
+
+    EC_ZERO_LOG( connect(fd, (struct sockaddr *)&address, address_length) ); /* 1 */
+
+    if (writet(fd, &pid, sizeof(pid_t), 0, 1) != sizeof(pid_t)) {
+        LOG(log_error, logtype_afpd, "ipc_client_uds: writet: %s", strerror(errno));
+        EC_FAIL;
+    }
+
+EC_CLEANUP:
+    if (ret != 0) {
+        return -1;
+    }
+    LOG(log_note, logtype_afpd, "ipc_client_uds: fd: %d", fd);
+    return fd;
+}
+
 /* ----------------- 
  * Ipc format
  * command
@@ -235,13 +272,19 @@ int ipc_server_read(server_child *children, int fd)
 }
 
 /* ----------------- */
-int ipc_child_write(int fd, uint16_t command, int len, void *msg)
+ssize_t ipc_child_write(int *fd, uint16_t command, int len, void *msg)
 {
+   static int fd_saved = -1;
    char block[IPC_MAXMSGSIZE], *p;
    pid_t pid;
    uid_t uid;
+   ssize_t ret;
+
    p = block;
 
+   if (fd_saved == -1)
+       fd_saved = *fd;
+
    memset ( p, 0 , IPC_MAXMSGSIZE);
    if (len + IPC_HEADERLEN > IPC_MAXMSGSIZE)
        return -1;
@@ -269,6 +312,16 @@ int ipc_child_write(int fd, uint16_t command, int len, void *msg)
 
    LOG(log_debug, logtype_afpd, "ipc_child_write(%s)", ipc_cmd_str[command]);
 
-   return write(fd, block, len+IPC_HEADERLEN );
+   if ((ret = writet(*fd, block, len+IPC_HEADERLEN, 0, 1)) == -1) {
+       if (*fd == fd_saved && getppid() == 1) {
+           /* still using original socketpair IPC fd, master was possibly restarted, try reestablish connection across uds */
+           if ((*fd = ipc_client_uds(_PATH_AFP_IPC)) == -1)
+               return -1;
+           /* now try again */
+           ret = writet(*fd, block, len+IPC_HEADERLEN, 0, 1);
+       }
+   }
+
+   return ret;
 }