# 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
/*
- * $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.
#define CHILD_DIE (1 << 0)
#define CHILD_RUNNING (1 << 1)
+#define CHILD_SLEEPING (1 << 2)
static struct {
AFPObj *obj;
}
}
+/* */
+static void afp_dsi_sleep(void)
+{
+ child.flags |= CHILD_SLEEPING;
+ dsi_sleep(child.obj->handle, 1);
+}
+
+/* ------------------- */
static void afp_dsi_timedown()
{
struct sigaction sv;
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)
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;
/* 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 */
/*
- * $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.
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";
}
}
+ 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);
/*
- * $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.
#include <pwd.h>
#include <grp.h>
#include <atalk/logger.h>
+#include <atalk/server_ipc.h>
#ifdef TRU64
#include <netdb.h>
*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;
}
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;
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;
}
}
memcpy(&token, ibuf, tklen);
/* killed old session, not easy */
+ server_ipc_write(IPC_KILLTOKEN, tklen, &token);
+ sleep(1);
+
return AFPERR_SESSCLOS; /* was AFP_OK */
}
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;
/*
- * $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.
char *k5service, *k5realm;
mode_t umask;
mode_t save_mask;
+ int sleep;
#ifdef ADMIN_GRP
gid_t admingid;
#endif /* ADMIN_GRP */
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 */
/*
- * $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.
#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"
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)
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
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();
{
AFPConfig *config;
fd_set rfds;
+ void *ipc;
struct sigaction sv;
sigset_t sigs;
}
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
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;
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 *));
--- /dev/null
+
+#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);
+
+
+
+
+
module.c \
server_child.c \
server_lock.c \
+ server_ipc.c \
strcasestr.c \
strdicasecmp.c
/*
- * $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.
#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;
};
return 0;
unhash_child(child);
+ if (child->clientid) {
+ free(child->clientid);
+ }
free(child);
children->count--;
return 1;
child = fork->table[j]; /* start at the beginning */
while (child) {
tmp = child->next;
+ if (child->clientid) {
+ free(child->clientid);
+ }
free(child);
child = tmp;
}
}
}
+/* 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))
} 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
{
--- /dev/null
+/*
+ * $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 );
+}
+