]> arthur.barton.de Git - netatalk.git/commitdiff
fix a race when a client very quickly reconnect and try to kill its old
authordidg <didg>
Thu, 31 Mar 2005 00:25:55 +0000 (00:25 +0000)
committerdidg <didg>
Thu, 31 Mar 2005 00:25:55 +0000 (00:25 +0000)
session.

etc/afpd/afp_dsi.c
libatalk/util/server_child.c

index b7ffd084aeea3ce6f93550fc1586f01f3dfb77b3..a34a664e3fc770b868a0b326b16050a329d0b755 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: afp_dsi.c,v 1.27.2.3.2.4 2004-05-04 15:38:24 didg Exp $
+ * $Id: afp_dsi.c,v 1.27.2.3.2.4.2.1 2005-03-31 00:25:55 didg Exp $
  *
  * Copyright (c) 1999 Adrian Sun (asun@zoology.washington.edu)
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
@@ -79,6 +79,17 @@ static __inline__ void afp_dsi_close(AFPObj *obj)
  */
 static void afp_dsi_die(int sig)
 {
+static volatile int in_handler;
+    
+    if (in_handler) {
+       return;
+    }
+    /* it's not atomic but we don't care because it's an exit function
+     * ie if a signal is received here, between the test and the affectation,
+     * it will not return.
+    */
+    in_handler = 1;
+
     dsi_attention(child.obj->handle, AFPATTN_SHUTDOWN);
     afp_dsi_close(child.obj);
     if (sig) /* if no signal, assume dieing because logins are disabled &
index 548388e7718b8cd60afac753e00991047589a989..9f96c4bebacc9ff599a44115fe7ebd4990e6f976 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: server_child.c,v 1.7.4.1.2.4 2004-07-01 01:27:34 didg Exp $
+ * $Id: server_child.c,v 1.7.4.1.2.4.2.1 2005-03-31 00:25:55 didg Exp $
  *
  * Copyright (c) 1997 Adrian Sun (asun@zoology.washington.edu)
  * All rights reserved. See COPYRIGHT.
 #define HASH(i) ((((i) >> 8) ^ (i)) & (CHILD_HASHSIZE - 1))
 
 struct server_child_data {
-  pid_t     pid; 
-  uid_t     uid;
-  int       valid;
-  u_int32_t time;
-  u_int32_t idlen;
-  
-  char *clientid;
+  pid_t     pid;               /* afpd worker process pid (from the worker afpd process )*/
+  uid_t     uid;               /* user id of connected client (from the worker afpd process) */
+  int       valid;             /* 1 if we have a clientid */
+  u_int32_t time;              /* client boot time (from the mac client) */
+  int       killed;            /* 1 if we already tried to kill the client */
+
+  u_int32_t idlen;             /* clientid len (from the Mac client) */
+  char *clientid;              /* clientid (from the Mac client) */
   struct server_child_data **prevp, *next;
 };
 
@@ -169,6 +170,7 @@ int server_child_add(server_child *children, const int forkid,
 
   child->pid = pid;
   child->valid = 0;
+  child->killed = 0;
   hash_child(fork->table, child);
   children->count++;
   sigprocmask(SIG_SETMASK, &oldsig, NULL);
@@ -246,6 +248,21 @@ void server_child_kill(server_child *children, const int forkid,
  * a plain-old linked list 
  * FIXME use resolve_child ?
  */
+static int kill_child(struct server_child_data *child)
+{
+  if (!child->killed) {
+     kill(child->pid, SIGTERM);
+     /* we don't wait because there's no guarantee that we can really kill it */
+     child->killed = 1;
+     return 1;
+  }
+  else {
+     LOG(log_info, logtype_default, "Already tried to kill (%d) before! Still there?",  child->pid);
+  }
+  return 0;
+}
+
+/* -------------------- */
 void server_child_kill_one(server_child *children, const int forkid, const pid_t pid, const uid_t uid)
 {
   server_child_fork *fork;
@@ -266,7 +283,7 @@ void server_child_kill_one(server_child *children, const int forkid, const pid_t
              LOG(log_info, logtype_default, "Disconnecting old session (%d) not the same user, bailout!",  child->pid);
           }
           else {
-              kill(child->pid, SIGTERM);
+              kill_child(child);
           }
       }
       child = tmp;
@@ -294,13 +311,21 @@ void server_child_kill_one_by_id(server_child *children, const int forkid, const
           if ( child->idlen == idlen && !memcmp(child->clientid, id, idlen)) {
             if ( child->time != boottime ) {
                  if (uid == child->uid) {
-                     kill(child->pid, SIGTERM);
-                     LOG(log_info, logtype_default, "Disconnecting old session %d, client rebooted.",  child->pid);
+                     if (kill_child(child)) {
+                         LOG(log_info, logtype_default, "Disconnecting old session %d, client rebooted.",  child->pid);
+                     }
                  }
                  else {
                      LOG(log_info, logtype_default, "Disconnecting old session not the same uid, bailout!");
                  }
             }
+            else if (child->killed) {
+                 /* there's case where a Mac close a connection and restart a new one before
+                  * the first is 'waited' by the master afpd process
+                 */
+                 LOG(log_info, logtype_default, 
+                     "WARNING: connection (%d) killed but still there.", child->pid);
+            }
             else {
                  LOG(log_info, logtype_default, 
                      "WARNING: 2 connections (%d, %d), boottime identical, don't know if one needs to be disconnected.",