]> arthur.barton.de Git - netatalk.git/commitdiff
AFP 3.x add sleep timeout, add disconnect old session. Björn Fernhomberg and me
authordidg <didg>
Fri, 16 May 2003 15:29:25 +0000 (15:29 +0000)
committerdidg <didg>
Fri, 16 May 2003 15:29:25 +0000 (15:29 +0000)
config/afpd.conf.tmpl
etc/afpd/afp_dsi.c
etc/afpd/afp_options.c
etc/afpd/auth.c
etc/afpd/globals.h
etc/afpd/main.c
include/atalk/server_child.h
include/atalk/server_ipc.h [new file with mode: 0644]
libatalk/util/Makefile.am
libatalk/util/server_child.c
libatalk/util/server_ipc.c [new file with mode: 0644]

index d32d8347e345343bc299bd93949708621c53a29e..47d4b03a5e501faab629fe78526cd2cb202064c4 100644 (file)
 #                         Note: Depending on the number of simultaneously
 #                         connected clients and the network's speed, this can
 #                         lead to a significant higher load on your network!
+#     -sleep   <number>   AFP 3.x wait number hours before disconnecting
+#                         clients in sleep mode. Default 10 hours
 #     -tickleval <number> Specify the tickle timeout interval (in seconds).
 #                         Note, this defaults to 30 seconds, and really 
 #                         shouldn't be changed.  If you want to control
index 8d135e528430d5749fb5feb0b85305d1fcc722ff..230531644e099e431cb8b8055b7a765375b49bc8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: afp_dsi.c,v 1.27 2003-03-12 15:07:00 didg Exp $
+ * $Id: afp_dsi.c,v 1.28 2003-05-16 15:29:26 didg Exp $
  *
  * Copyright (c) 1999 Adrian Sun (asun@zoology.washington.edu)
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
@@ -47,6 +47,7 @@ extern struct oforks  *writtenfork;
 
 #define CHILD_DIE         (1 << 0)
 #define CHILD_RUNNING     (1 << 1)
+#define CHILD_SLEEPING    (1 << 2)
 
 static struct {
     AFPObj *obj;
@@ -87,6 +88,14 @@ static void afp_dsi_die(int sig)
     }
 }
 
+/* */
+static void afp_dsi_sleep(void)
+{
+    child.flags |= CHILD_SLEEPING;
+    dsi_sleep(child.obj->handle, 1);
+}
+
+/* ------------------- */
 static void afp_dsi_timedown()
 {
     struct sigaction   sv;
@@ -142,7 +151,9 @@ static void alarm_handler()
 int err;
     /* if we're in the midst of processing something,
        don't die. */
-    if ((child.flags & CHILD_RUNNING) || (child.tickle++ < child.obj->options.timeout)) {
+    if ((child.flags & CHILD_SLEEPING) && child.tickle++ < child.obj->options.sleep) {
+        return;
+    } else 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) 
@@ -182,7 +193,7 @@ void afp_over_dsi(AFPObj *obj)
     obj->exit = afp_dsi_die;
     obj->reply = (int (*)()) dsi_cmdreply;
     obj->attention = (int (*)(void *, AFPUserBytes)) dsi_attention;
-
+    obj->sleep = afp_dsi_sleep;
     child.obj = obj;
     child.tickle = child.flags = 0;
 
@@ -244,11 +255,12 @@ void afp_over_dsi(AFPObj *obj)
     /* get stuck here until the end */
     while ((cmd = dsi_receive(dsi))) {
         child.tickle = 0;
+        child.flags &= ~CHILD_SLEEPING;
         dsi_sleep(dsi, 0); /* wake up */
 
         if (cmd == DSIFUNC_TICKLE) {
             /* so we don't get killed on the client side. */
-            if (child.flags & CHILD_DIE)
+            if ((child.flags & CHILD_DIE))
                 dsi_tickle(dsi);
             continue;
         } else if (!(child.flags & CHILD_DIE)) { /* reset tickle timer */
index 0dabeae22dd4c7dfb2a42340cd870a233c801f1e..69ea78b3d237cf57b43d78d30eb3e50d8daad7a6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: afp_options.c,v 1.30 2003-04-16 22:45:08 samnoble Exp $
+ * $Id: afp_options.c,v 1.31 2003-05-16 15:29:26 didg Exp $
  *
  * Copyright (c) 1997 Adrian Sun (asun@zoology.washington.edu)
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
@@ -148,6 +148,7 @@ void afp_options_init(struct afp_options *options)
     options->passwdfile = _PATH_AFPDPWFILE;
     options->tickleval = 30;
     options->timeout = 4;
+    options->sleep = 10* 120; /* 10 h in 30 seconds tick */
     options->server_notif = 1;
     options->authprintdir = NULL;
     options->signature = "host";
@@ -253,6 +254,13 @@ int afp_options_parseline(char *buf, struct afp_options *options)
         }
     }
 
+    if ((c = getoption(buf, "-sleep"))) {
+        options->sleep = atoi(c) *120;
+        if (options->sleep <= 4) {
+            options->sleep = 4;
+        }
+    }
+
     if ((c = getoption(buf, "-server_quantum")))
         options->server_quantum = strtoul(c, NULL, 0);
 
index 16fc73761a9b2acf0c03b2d1820357f77472d49c..2991f0391c18356162e09f17fa5b9d9670f6d095 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: auth.c,v 1.45 2003-05-02 18:22:13 didg Exp $
+ * $Id: auth.c,v 1.46 2003-05-16 15:29:26 didg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -33,6 +33,7 @@
 #include <pwd.h>
 #include <grp.h>
 #include <atalk/logger.h>
+#include <atalk/server_ipc.h>
 
 #ifdef TRU64
 #include <netdb.h>
@@ -334,14 +335,15 @@ unsigned int ibuflen, *rbuflen;
 
     *rbuflen = 0;
 
-    retdata = 1;
+    retdata = obj->options.sleep /120;
+    if (!retdata) {
+       retdata = 1;
+    }
     *rbuflen = sizeof(retdata);
     retdata = htonl(retdata);
     memcpy(rbuf, &retdata, sizeof(retdata));
-    if (obj->proto == AFPPROTO_DSI) {
-        DSI *dsi = obj->handle;
-        dsi_sleep(dsi, 1);
-    }
+    if (obj->sleep)
+        obj->sleep();
     rbuf += sizeof(retdata);
     return AFP_OK;
 }
@@ -353,10 +355,12 @@ char           *ibuf, *rbuf;
 unsigned int ibuflen, *rbuflen;
 {
     u_int16_t           type;
-    u_int32_t           idlen;
+    u_int32_t           idlen = 0;
+    u_int32_t          boottime;
 
     u_int16_t           tklen; /* FIXME: spec  u_int32_t? */
     pid_t               token;
+    char               *p;
 
     *rbuflen = 0;
 
@@ -388,6 +392,19 @@ unsigned int ibuflen, *rbuflen;
         break;
     case 3: /* Jaguar */
     case 4:
+       if (ibuflen >= 8 ) {
+           p = ibuf;
+           memcpy( &idlen, ibuf, sizeof(idlen));
+           idlen = ntohl(idlen);
+           ibuf += sizeof(idlen);
+           ibuflen -= sizeof(idlen);
+           ibuf += sizeof(boottime);
+           ibuflen -= sizeof(boottime);
+           if (ibuflen < idlen || idlen > (90-10)) {
+               return AFPERR_PARAM;
+           }
+           server_ipc_write(IPC_GETSESSION, idlen+8, p ); 
+       }
        type = 0;
        break;
     }
@@ -434,6 +451,9 @@ int         ibuflen, *rbuflen;
     }   
     memcpy(&token, ibuf, tklen);
     /* killed old session, not easy */
+    server_ipc_write(IPC_KILLTOKEN, tklen, &token);
+    sleep(1);
+    
     return AFPERR_SESSCLOS;   /* was AFP_OK */
 }
 
@@ -509,7 +529,7 @@ int         ibuflen, *rbuflen;
     if (!len || len > ibuflen)
         return send_reply(obj, AFPERR_BADUAM);
 
-    if ((afp_uam = auth_uamfind(UAM_SERVER_LOGIN, ibuf, len)) == NULL)
+    if (NULL == (afp_uam = auth_uamfind(UAM_SERVER_LOGIN, ibuf, len)) )
         return send_reply(obj, AFPERR_BADUAM);
     ibuf += len;
     ibuflen -= len;
index 7765c895d74ace138b944b10c1167161e7fb52c3..9c54349d8f0d5f72a2a37c7e2a590e1740680145 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: globals.h,v 1.18 2003-04-16 22:45:10 samnoble Exp $
+ * $Id: globals.h,v 1.19 2003-05-16 15:29:27 didg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -63,6 +63,7 @@ struct afp_options {
     char *k5service, *k5realm;
     mode_t umask;
     mode_t save_mask;
+    int    sleep;
 #ifdef ADMIN_GRP
     gid_t admingid;
 #endif /* ADMIN_GRP */
@@ -79,6 +80,7 @@ typedef struct AFPObj {
     void (*logout)(void), (*exit)(int);
     int (*reply)(void *, int);
     int (*attention)(void *, AFPUserBytes);
+    void (*sleep)(void);
     /* to prevent confusion, only use these in afp_* calls */
     char oldtmp[AFPOBJ_TMPSIZ + 1], newtmp[AFPOBJ_TMPSIZ + 1];
     void *uam_cookie; /* cookie for uams */
index 91ad85e9909afa52a0d31b2f8b7114fb1a1151a0..f31dd8440a84e76069fb26bce4a5f9ec285a8d29 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: main.c,v 1.20 2002-10-04 15:15:05 srittau Exp $
+ * $Id: main.c,v 1.21 2003-05-16 15:29:27 didg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -41,6 +41,7 @@
 #include <atalk/paths.h>
 #include <atalk/util.h>
 #include <atalk/server_child.h>
+#include <atalk/server_ipc.h>
 
 #include "globals.h"
 #include "afp_config.h"
@@ -63,6 +64,7 @@ struct afp_options default_options;
 static AFPConfig *configs;
 static server_child *server_children;
 static fd_set save_rfds;
+static int    Ipc_fd = -1;
 
 #ifdef TRU64
 void afp_get_cmdline( int *ac, char ***av)
@@ -78,6 +80,25 @@ static void afp_exit(const int i)
     exit(i);
 }
 
+/* ------------------ 
+   initialize fd set we are waiting for.
+*/
+static void set_fd(int ipc_fd)
+{
+    AFPConfig   *config;
+    
+    FD_ZERO(&save_rfds);
+    for (config = configs; config; config = config->next) {
+        if (config->fd < 0) /* for proxies */
+            continue;
+        FD_SET(config->fd, &save_rfds);
+    }
+    if (ipc_fd >= 0) {
+        FD_SET(ipc_fd, &save_rfds);
+    }
+}
+
+/* ------------------ */
 static void afp_goaway(int sig)
 {
 #ifndef NO_DDP
@@ -104,12 +125,7 @@ static void afp_goaway(int sig)
                 LOG(log_error, logtype_afpd, "config re-read: no servers configured");
                 afp_exit(1);
             }
-            FD_ZERO(&save_rfds);
-            for (config = configs; config; config = config->next) {
-                if (config->fd < 0)
-                    continue;
-                FD_SET(config->fd, &save_rfds);
-            }
+            set_fd(Ipc_fd);
         } else {
             LOG(log_info, logtype_afpd, "disallowing logins");
             auth_unload();
@@ -141,6 +157,7 @@ char        **av;
 {
     AFPConfig           *config;
     fd_set              rfds;
+    void                *ipc;
     struct sigaction   sv;
     sigset_t            sigs;
 
@@ -218,13 +235,11 @@ char      **av;
     }
     sigprocmask(SIG_UNBLOCK, &sigs, NULL);
 
-    /* watch atp and dsi sockets. */
-    FD_ZERO(&save_rfds);
-    for (config = configs; config; config = config->next) {
-        if (config->fd < 0) /* for proxies */
-            continue;
-        FD_SET(config->fd, &save_rfds);
+    /* watch atp, dsi sockets and ipc parent/child file descriptor. */
+    if ((ipc = server_ipc_create())) {
+        Ipc_fd = server_ipc_parent(ipc);
     }
+    set_fd(Ipc_fd);
 
     /* wait for an appleshare connection. parent remains in the loop
      * while the children get handled by afp_over_{asp,dsi}.  this is
@@ -240,7 +255,9 @@ char        **av;
             LOG(log_error, logtype_afpd, "main: can't wait for input: %s", strerror(errno));
             break;
         }
-
+        if (Ipc_fd >=0 && FD_ISSET(Ipc_fd, &rfds)) {
+            server_ipc_read(server_children);
+       }
         for (config = configs; config; config = config->next) {
             if (config->fd < 0)
                 continue;
index c983a863400a2b6d82b4624496244a89a5416e13..7112e06964ffbd6633f16000443d35ba0bd43725 100644 (file)
@@ -30,6 +30,10 @@ extern int server_child_remove __P((server_child *, const int, const pid_t));
 extern void server_child_free __P((server_child *));
 
 extern void server_child_kill __P((server_child *, const int, const int));
+extern void server_child_kill_one __P((server_child *children, const int forkid, const pid_t pid));
+extern void server_child_kill_one_by_id __P((server_child *children, const int forkid, const pid_t pid, 
+                                               const u_int32_t len, char *id, u_int32_t boottime));
+
 extern void server_child_setup __P((server_child *, const int, void (*)()));
 extern void server_child_handler __P((server_child *));
 
diff --git a/include/atalk/server_ipc.h b/include/atalk/server_ipc.h
new file mode 100644 (file)
index 0000000..b462c6f
--- /dev/null
@@ -0,0 +1,16 @@
+
+#include <atalk/server_child.h>
+
+#define IPC_KILLTOKEN   1
+#define IPC_GETSESSION  2
+
+void *server_ipc_create(void);
+int server_ipc_child(void *obj);
+int server_ipc_parent(void *obj);
+int server_ipc_read(server_child *children);
+int server_ipc_write(uint16_t command, int len, void *token);
+
+
+
+
+
index f3340ef75345a5bbfa0e5d0e1a8cc604be9f948b..8c4ffdae7d5ab116721792a56cbfb4a408efeeba 100644 (file)
@@ -12,5 +12,6 @@ libutil_la_SOURCES = \
        module.c        \
        server_child.c  \
        server_lock.c   \
+       server_ipc.c    \
        strcasestr.c    \
        strdicasecmp.c
index d443eb2b0876eed74482e8dd3c20ef8b9d621b3e..4fbacfb8d5c8bef2e56d5909042a41ab1c83909f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: server_child.c,v 1.7 2002-10-07 19:14:41 didg Exp $
+ * $Id: server_child.c,v 1.8 2003-05-16 15:29:27 didg Exp $
  *
  * Copyright (c) 1997 Adrian Sun (asun@zoology.washington.edu)
  * All rights reserved. See COPYRIGHT.
@@ -43,6 +43,9 @@
 #ifndef WIFSIGNALED
 #define WIFSIGNALED(status) (!WIFSTOPPED(status) && !WIFEXITED(status)) 
 #endif
+#ifndef WTERMSIG
+#define WTERMSIG(status)      ((status) & 0x7f)
+#endif
 
 #include <atalk/server_child.h>
 
 
 struct server_child_data {
   pid_t pid; 
+  u_int32_t  time;
+  u_int32_t idlen;
+  
+  char *clientid;
   struct server_child_data **prevp, *next;
 };
 
@@ -176,6 +183,9 @@ int server_child_remove(server_child *children, const int forkid,
     return 0;
   
   unhash_child(child);
+  if (child->clientid) {
+      free(child->clientid);
+  }
   free(child);
   children->count--;
   return 1;
@@ -195,6 +205,9 @@ void server_child_free(server_child *children)
       child = fork->table[j]; /* start at the beginning */
       while (child) {
        tmp = child->next;
+        if (child->clientid) {
+            free(child->clientid);
+        }
        free(child);
        child = tmp;
       }
@@ -224,6 +237,72 @@ void server_child_kill(server_child *children, const int forkid,
   }
 }
 
+/* send kill to a child processes.
+ * a plain-old linked list 
+ * FIXME use resolve_child ?
+ */
+void server_child_kill_one(server_child *children, const int forkid, const pid_t pid)
+{
+  server_child_fork *fork;
+  struct server_child_data *child, *tmp;
+  int i;
+
+  fork = (server_child_fork *) children->fork + forkid;
+  for (i = 0; i < CHILD_HASHSIZE; i++) {
+    child = fork->table[i];
+    while (child) {
+      tmp = child->next;
+      if (child->pid == pid) {
+          kill(child->pid, SIGTERM);
+      }
+      child = tmp;
+    }
+  }
+}
+
+
+/* see if there is a process for the same mac     */
+/* if the times don't match mac has been rebooted */
+void server_child_kill_one_by_id(server_child *children, const int forkid, const pid_t pid, 
+          const u_int32_t idlen, char *id, u_int32_t boottime)
+{
+  server_child_fork *fork;
+  struct server_child_data *child, *tmp;
+  int i;
+
+  fork = (server_child_fork *) children->fork + forkid;
+  for (i = 0; i < CHILD_HASHSIZE; i++) {
+    child = fork->table[i];
+    while (child) {
+      tmp = child->next;
+      if ( child->pid != pid) {
+          if ( child->idlen == idlen && !memcmp(child->clientid, id, idlen)) {
+            if ( child->time != boottime ) {
+                 kill(child->pid, SIGTERM);
+                 LOG(log_info, logtype_default, "Disconnecting old session %d, client rebooted.",  child->pid);
+            }
+            else {
+                 LOG(log_info, logtype_default, "WARNING: 2 connections (%d, %d), boottime identical, don't know if one needs to be disconnected.");
+            } 
+               
+         }
+      }
+      else 
+      {
+         child->time = boottime;
+         /* free old token if any */
+         if (child->clientid) {
+             free(child->clientid);
+         }
+         child->idlen = idlen;
+          child->clientid = id;
+         LOG(log_info, logtype_default, "Setting clientid (len %d) for %d, boottime %X", idlen, child->pid, boottime);
+      }
+      child = tmp;
+    }
+  }
+}
+
 /* for extra cleanup if necessary */
 void server_child_setup(server_child *children, const int forkid,
                          void (*fcn)(const pid_t))
@@ -266,7 +345,8 @@ void server_child_handler(server_child *children)
     } else {
       if (WIFSIGNALED(status))
       { 
-       LOG(log_info, logtype_default, "server_child[%d] %d killed", i, pid);
+       LOG(log_info, logtype_default, "server_child[%d] %d killed by signal %d", i, pid,  
+              WTERMSIG (status));
       }
       else
       {
diff --git a/libatalk/util/server_ipc.c b/libatalk/util/server_ipc.c
new file mode 100644 (file)
index 0000000..6881bb8
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * $Id: server_ipc.c,v 1.1 2003-05-16 15:29:28 didg Exp $
+ *
+ * All rights reserved. See COPYRIGHT.
+ *
+ *
+ * ipc between parent and children.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif 
+
+#include <sys/types.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif 
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <atalk/server_child.h>
+#include <atalk/server_ipc.h>
+#include <atalk/logger.h>
+
+typedef struct ipc_header {
+       u_int16_t command;
+        pid_t    child_pid;
+        u_int32_t len;
+       char      *msg;
+} ipc_header;
+
+static int pipe_fd[2];
+   
+void *server_ipc_create(void)
+{
+    if (pipe(pipe_fd)) {
+        return NULL;
+    }
+    return &pipe_fd;
+}
+
+/* ----------------- */
+int server_ipc_child(void *obj)
+{
+    /* close input */
+    close(pipe_fd[0]);
+    return pipe_fd[1];
+}
+
+/* ----------------- */
+int server_ipc_parent(void *obj)
+{
+    return pipe_fd[0];
+}
+
+/* ----------------- */
+int ipc_kill_token (struct ipc_header *ipc, server_child *children)
+{
+    pid_t pid;
+
+    if (ipc->len != sizeof(pid_t)) {
+        return -1;
+    }
+    /* assume signals SA_RESTART set */
+    memcpy (&pid, ipc->msg, sizeof(pid_t));
+
+    LOG(log_info, logtype_default, "child %d disconnected", pid); 
+    server_child_kill_one(children, CHILD_DSIFORK, pid);
+    return 0;
+}
+
+/* ----------------- */
+int ipc_get_session (struct ipc_header *ipc, server_child *children)
+{
+    u_int32_t boottime;
+    u_int32_t idlen;
+    char     *clientid, *p;
+
+
+    if (ipc->len < (sizeof(idlen) + sizeof(boottime)) ) {
+       return -1;
+    }
+    p = ipc->msg;
+    memcpy (&idlen, p, sizeof(idlen));
+    idlen = ntohl (idlen);
+    p += sizeof(idlen); 
+
+    memcpy (&boottime, p, sizeof(boottime));
+    p += sizeof(boottime);
+    
+    if (ipc->len < idlen + sizeof(idlen) + sizeof(boottime)) {
+       return -1;
+    }
+    if (NULL == (clientid = (char*) malloc(idlen)) ) {
+       return -1;
+    }
+    memcpy (clientid, p, idlen);
+  
+    server_child_kill_one_by_id (children, CHILD_DSIFORK, ipc->child_pid, idlen, clientid, boottime);
+    /* FIXME byte to ascii if we want to log clientid */
+    LOG (log_info, logtype_afpd, "ipc_get_session: len: %u, idlen %d, time %x", ipc->len, idlen, boottime); 
+    return 0;
+}
+
+#define IPC_HEADERLEN 10
+#define IPC_MAXMSGSIZE 90
+
+/* ----------------- */
+int server_ipc_read(server_child *children)
+{
+    int       ret = 0;
+    struct ipc_header ipc;
+    char      buf[IPC_MAXMSGSIZE], *p;
+
+    if ((ret = read(pipe_fd[0], buf, IPC_HEADERLEN)) != IPC_HEADERLEN) {
+       LOG (log_info, logtype_afpd, "Reading IPC header failed (%u of %u  bytes read)", ret, IPC_HEADERLEN);
+       return -1;
+    } 
+
+    p = buf;
+    memcpy(&ipc.command, p, sizeof(ipc.command));
+    p += sizeof(ipc.command);
+    memcpy(&ipc.child_pid, p, sizeof(ipc.child_pid));
+    p += sizeof(ipc.child_pid);
+    memcpy(&ipc.len, p, sizeof(ipc.len));
+
+    /* This should never happen */
+    if (ipc.len > (IPC_MAXMSGSIZE - IPC_HEADERLEN))
+    {
+       LOG (log_info, logtype_afpd, "IPC message exceeds allowed size (%u)", ipc.len);
+       return -1;
+    }
+
+    memset (buf, 0, IPC_MAXMSGSIZE);
+    if ( ipc.len != 0) {
+           if ((ret = read(pipe_fd[0], buf, ipc.len)) != ipc.len) {
+               LOG (log_info, logtype_afpd, "Reading IPC message failed (%u of %u  bytes read)", ret, ipc.len);
+               return -1;
+       }        
+    }
+    ipc.msg = buf;
+    
+    LOG (log_info, logtype_afpd, "ipc_read: command: %u, pid: %u, len: %u", ipc.command, ipc.child_pid, ipc.len); 
+
+    switch (ipc.command)
+    {
+       case IPC_KILLTOKEN:
+               return (ipc_kill_token(&ipc, children));
+               break;
+       case IPC_GETSESSION:
+               return (ipc_get_session(&ipc, children));
+               break;
+       default:
+               LOG (log_info, logtype_afpd, "ipc_read: unknown command: %d", ipc.command);
+               return -1;
+    }
+
+}
+
+/* ----------------- */
+int server_ipc_write( u_int16_t command, int len, void *msg)
+{
+   char block[IPC_MAXMSGSIZE], *p;
+   pid_t pid;
+   p = block;
+
+   memset ( p, 0 , IPC_MAXMSGSIZE);
+   if (len + IPC_HEADERLEN > IPC_MAXMSGSIZE)
+       return -1;
+
+   memcpy(p, &command, sizeof(command));
+   p   += sizeof(command);
+
+   pid = getpid();
+   memcpy(p, &pid, sizeof(pid_t));
+   p += sizeof(pid_t);
+
+   memcpy(p, &len, 4);
+   p += 4;
+
+   memcpy(p, msg, len);
+
+   LOG (log_info, logtype_afpd, "ipc_write: command: %u, pid: %u, msglen: %u", command, pid, len); 
+   return write(pipe_fd[1], block, len+IPC_HEADERLEN );
+}
+