}
}
-/* SIGQUIT handler */
-static void ipc_reconnect_handler(int sig _U_)
-{
- if (reconnect_ipc(AFPobj) != 0) {
- LOG(log_error, logtype_afpd, "ipc_reconnect_handler: failed IPC reconnect");
- afp_dsi_close(AFPobj);
- exit(EXITERR_SYS);
- }
-
- if (ipc_child_write(AFPobj->ipc_fd, IPC_GETSESSION, AFPobj->sinfo.clientid_len, AFPobj->sinfo.clientid) != 0) {
- LOG(log_error, logtype_afpd, "ipc_reconnect_handler: failed IPC ID resend");
- afp_dsi_close(AFPobj);
- exit(EXITERR_SYS);
- }
- LOG(log_note, logtype_afpd, "ipc_reconnect_handler: IPC reconnect done");
-}
-
/* SIGURG handler (primary reconnect) */
static void afp_dsi_transfer_session(int sig _U_)
{
}
/* install SIGQUIT */
- action.sa_handler = ipc_reconnect_handler;
+ action.sa_handler = afp_dsi_die;
if ( sigaction(SIGQUIT, &action, NULL ) < 0 ) {
LOG(log_error, logtype_afpd, "afp_over_dsi: sigaction: %s", strerror(errno) );
afp_dsi_die(EXITERR_SYS);
unsigned char nologin = 0;
static AFPObj obj;
-static server_child *server_children;
+static server_child_t *server_children;
static sig_atomic_t reloadconfig = 0;
static sig_atomic_t gotsigchld = 0;
static struct polldata *polldata;
static int fdset_size; /* current allocated size */
static int fdset_used; /* number of used elements */
-static int disasociated_ipc_fd; /* disasociated sessions uses this fd for IPC */
-static afp_child_t *dsi_start(AFPObj *obj, DSI *dsi, server_child *server_children);
+static afp_child_t *dsi_start(AFPObj *obj, DSI *dsi, server_child_t *server_children);
static void afp_exit(int ret)
{
LISTEN_FD,
dsi);
}
-
- if (config->options.flags & OPTION_KEEPSESSIONS)
- fdset_add_fd(config->options.connections + AFP_LISTENERS + FDSET_SAFETY,
- &fdset,
- &polldata,
- &fdset_used,
- &fdset_size,
- disasociated_ipc_fd,
- DISASOCIATED_IPC_FD,
- NULL);
}
static void fd_reset_listening_sockets(const AFPObj *config)
for (dsi = config->dsi; dsi; dsi = dsi->next) {
fdset_del_fd(&fdset, &polldata, &fdset_used, &fdset_size, dsi->serversock);
}
-
- if (config->options.flags & OPTION_KEEPSESSIONS)
- fdset_del_fd(&fdset, &polldata, &fdset_used, &fdset_size, disasociated_ipc_fd);
}
/* ------------------ */
case SIGTERM:
case SIGQUIT:
- switch (sig) {
- case SIGTERM:
- LOG(log_note, logtype_afpd, "AFP Server shutting down on SIGTERM");
- break;
- case SIGQUIT:
- if (obj.options.flags & OPTION_KEEPSESSIONS) {
- LOG(log_note, logtype_afpd, "AFP Server shutting down on SIGQUIT, NOT disconnecting clients");
- } else {
- LOG(log_note, logtype_afpd, "AFP Server shutting down on SIGQUIT");
- sig = SIGTERM;
- }
- break;
- }
+ LOG(log_note, logtype_afpd, "AFP Server shutting down");
if (server_children)
- server_child_kill(server_children, CHILD_DSIFORK, sig);
-
+ server_child_kill(server_children, SIGTERM);
_exit(0);
break;
LOG(log_info, logtype_afpd, "disallowing logins");
if (server_children)
- server_child_kill(server_children, CHILD_DSIFORK, sig);
+ server_child_kill(server_children, sig);
break;
case SIGHUP :
#endif /* ! WAIT_ANY */
while ((pid = waitpid(WAIT_ANY, &status, WNOHANG)) > 0) {
- for (i = 0; i < server_children->nforks; i++) {
- if ((fd = server_child_remove(server_children, i, pid)) != -1) {
- fdset_del_fd(&fdset, &polldata, &fdset_used, &fdset_size, fd);
- break;
- }
+ if ((fd = server_child_remove(server_children, pid)) != -1) {
+ fdset_del_fd(&fdset, &polldata, &fdset_used, &fdset_size, fd);
+ break;
}
if (WIFEXITED(status)) {
/* install child handler for asp and dsi. we do this before afp_goaway
* as afp_goaway references stuff from here.
* XXX: this should really be setup after the initial connections. */
- if (!(server_children = server_child_alloc(obj.options.connections, CHILD_NFORKS))) {
+ if (!(server_children = server_child_alloc(obj.options.connections))) {
LOG(log_error, logtype_afpd, "main: server_child alloc: %s", strerror(errno) );
afp_exit(EXITERR_SYS);
}
cnid_init();
/* watch atp, dsi sockets and ipc parent/child file descriptor. */
-
- if (obj.options.flags & OPTION_KEEPSESSIONS) {
- LOG(log_note, logtype_afpd, "Activating continous service");
- disasociated_ipc_fd = ipc_server_uds(_PATH_AFP_IPC);
- }
-
fd_set_listening_sockets(&obj);
/* set limits */
&polldata,
&fdset_used,
&fdset_size,
- child->ipc_fd,
+ child->afpch_ipc_fd,
IPC_FD,
child);
}
case IPC_FD:
child = (afp_child_t *)polldata[i].data;
- LOG(log_debug, logtype_afpd, "main: IPC request from child[%u]", child->pid);
-
- if (ipc_server_read(server_children, child->ipc_fd) != 0) {
- fdset_del_fd(&fdset, &polldata, &fdset_used, &fdset_size, child->ipc_fd);
- close(child->ipc_fd);
- child->ipc_fd = -1;
- if ((obj.options.flags & OPTION_KEEPSESSIONS) && child->disasociated) {
- LOG(log_note, logtype_afpd, "main: removing reattached child[%u]", child->pid);
- server_child_remove(server_children, CHILD_DSIFORK, child->pid);
- }
- }
- break;
-
- case DISASOCIATED_IPC_FD:
- LOG(log_debug, logtype_afpd, "main: IPC reconnect request");
- if ((recon_ipc_fd = accept(disasociated_ipc_fd, NULL, NULL)) == -1) {
- LOG(log_error, logtype_afpd, "main: accept: %s", strerror(errno));
- break;
- }
- if (readt(recon_ipc_fd, &pid, sizeof(pid_t), 0, 1) != sizeof(pid_t)) {
- LOG(log_error, logtype_afpd, "main: readt: %s", strerror(errno));
- close(recon_ipc_fd);
- break;
- }
- LOG(log_note, logtype_afpd, "main: IPC reconnect from pid [%u]", pid);
+ LOG(log_debug, logtype_afpd, "main: IPC request from child[%u]", child->afpch_pid);
- if ((child = server_child_add(server_children, CHILD_DSIFORK, pid, recon_ipc_fd)) == NULL) {
- LOG(log_error, logtype_afpd, "main: server_child_add");
- close(recon_ipc_fd);
- break;
+ if (ipc_server_read(server_children, child->afpch_ipc_fd) != 0) {
+ fdset_del_fd(&fdset, &polldata, &fdset_used, &fdset_size, child->afpch_ipc_fd);
+ close(child->afpch_ipc_fd);
+ child->afpch_ipc_fd = -1;
}
- child->disasociated = 1;
- fdset_add_fd(obj.options.connections + AFP_LISTENERS + FDSET_SAFETY,
- &fdset,
- &polldata,
- &fdset_used,
- &fdset_size,
- recon_ipc_fd,
- IPC_FD,
- child);
break;
default:
return 0;
}
-static afp_child_t *dsi_start(AFPObj *obj, DSI *dsi, server_child *server_children)
+static afp_child_t *dsi_start(AFPObj *obj, DSI *dsi, server_child_t *server_children)
{
afp_child_t *child = NULL;
extern void dsi_free(DSI *dsi);
/* in dsi_getsess.c */
-extern int dsi_getsession (DSI *, server_child *, const int, afp_child_t **);
+extern int dsi_getsession (DSI *, server_child_t *, const int, afp_child_t **);
extern void dsi_kill (int);
#define OPTION_UUID (1 << 7)
#define OPTION_ACL2MACCESS (1 << 8)
#define OPTION_NOZEROCONF (1 << 9)
-#define OPTION_KEEPSESSIONS (1 << 10) /* preserve sessions across master afpd restart with SIGQUIT */
#define OPTION_SHARE_RESERV (1 << 11) /* whether to use Solaris fcntl F_SHARE locks */
#define PASSWD_NONE 0
* netatalk paths
*/
#define _PATH_AFPTKT "/tmp/AFPtktXXXXXX"
-#define _PATH_AFP_IPC ATALKPATHCAT(_PATH_LOCKDIR,"afpd_ipc")
#if defined (FHS_COMPATIBILITY) || defined (__NetBSD__) || defined (__OpenBSD__)
# define _PATH_NETATALK_LOCK ATALKPATHCAT(_PATH_LOCKDIR,"netatalk.pid")
#else
/* useful stuff for child processes. most of this is hidden in
* server_child.c to ease changes in implementation */
-#define CHILD_NFORKS 2
-#define CHILD_ASPFORK 0
-#define CHILD_PAPFORK 0
-#define CHILD_DSIFORK 1
-
-typedef struct server_child {
- void *fork;
- int count, nsessions, nforks;
-} server_child;
-
-typedef struct server_child_data {
- 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 */
- int killed; /* 1 if we already tried to kill the client */
- int disasociated; /* 1 if this is not a child, but a child from a previous afpd master */
- uint32_t time; /* client boot time (from the mac client) */
- uint32_t idlen; /* clientid len (from the Mac client) */
- char *clientid; /* clientid (from the Mac client) */
- int ipc_fd; /* socket for IPC bw afpd parent and childs */
- struct server_child_data **prevp, *next;
+#define CHILD_HASHSIZE 32
+
+/* One AFP session child process */
+typedef struct afp_child {
+ pid_t afpch_pid; /* afpd worker process pid (from the worker afpd process )*/
+ uid_t afpch_uid; /* user id of connected client (from the worker afpd process) */
+ int afpch_valid; /* 1 if we have a clientid */
+ int afpch_killed; /* 1 if we already tried to kill the client */
+ uint32_t afpch_time; /* client boot time (from the mac client) */
+ uint32_t afpch_idlen; /* clientid len (from the Mac client) */
+ char *afpch_clientid; /* clientid (from the Mac client) */
+ int afpch_ipc_fd; /* socket for IPC bw afpd parent and childs */
+ struct afp_child **afpch_prevp;
+ struct afp_child *afpch_next;
} afp_child_t;
+/* Info and table with all AFP session child processes */
+typedef struct {
+ pthread_mutex_t servch_lock; /* Lock */
+ int servch_count; /* Current count of active AFP sessions */
+ int servch_nsessions; /* Number of allowed AFP sessions */
+ afp_child_t *servch_table[CHILD_HASHSIZE]; /* Hashtable with data of AFP sesssions */
+ void (*servch_cleanup)(const pid_t); /* Cleanup handler */
+} server_child_t;
+
/* server_child.c */
-extern server_child *server_child_alloc (const int, const int);
-extern afp_child_t *server_child_add (server_child *, int, pid_t, int ipc_fd);
-extern int server_child_remove (server_child *, const int, const pid_t);
-extern void server_child_free (server_child *);
-
-extern void server_child_kill (server_child *, const int, const int);
-extern void server_child_kill_one_by_id (server_child *children, const int forkid, const pid_t pid, const uid_t,
- const uint32_t len, char *id, uint32_t boottime);
-extern int server_child_transfer_session(server_child *children, int forkid, pid_t, uid_t, int, uint16_t);
-extern void server_child_setup (server_child *, const int, void (*)(const pid_t));
-extern void server_child_handler (server_child *);
-extern void server_reset_signal (void);
+extern server_child_t *server_child_alloc(int);
+extern afp_child_t *server_child_add(server_child_t *, pid_t, int ipc_fd);
+extern int server_child_remove(server_child_t *, pid_t);
+extern void server_child_free(server_child_t *);
+
+extern void server_child_kill(server_child_t *, int);
+extern void server_child_kill_one_by_id(server_child_t *children, pid_t pid, uid_t,
+ uint32_t len, char *id, uint32_t boottime);
+extern int server_child_transfer_session(server_child_t *children, pid_t, uid_t, int, uint16_t);
+extern void server_child_handler(server_child_t *);
+extern void server_reset_signal(void);
#endif
#define IPC_DISCOLDSESSION 0
#define IPC_GETSESSION 1
-extern int ipc_server_uds(const char *name);
-extern int ipc_client_uds(const char *name);
-extern int reconnect_ipc(AFPObj *);
-extern int ipc_server_read(server_child *children, int fd);
+extern int ipc_server_read(server_child_t *children, int fd);
extern int ipc_child_write(int fd, uint16_t command, int len, void *token);
#endif /* IPC_GETSESSION_LOGIN */
extern int compare_ip(const struct sockaddr *sa1, const struct sockaddr *sa2);
/* Structures and functions dealing with dynamic pollfd arrays */
-enum fdtype {IPC_FD, LISTEN_FD, DISASOCIATED_IPC_FD};
+enum fdtype {IPC_FD, LISTEN_FD};
struct polldata {
enum fdtype fdtype; /* IPC fd or listening socket fd */
void *data; /* pointer to AFPconfig for listening socket and *
* @param childp (w) after fork: parent return pointer to child, child returns NULL
* @returns 0 on sucess, any other value denotes failure
*/
-int dsi_getsession(DSI *dsi, server_child *serv_children, int tickleval, afp_child_t **childp)
+int dsi_getsession(DSI *dsi, server_child_t *serv_children, int tickleval, afp_child_t **childp)
{
pid_t pid;
int ipc_fds[2];
/* using SIGKILL is hokey, but the child might not have
* re-established its signal handler for SIGTERM yet. */
close(ipc_fds[1]);
- if ((child = server_child_add(serv_children, CHILD_DSIFORK, pid, ipc_fds[0])) == NULL) {
+ if ((child = server_child_add(serv_children, pid, ipc_fds[0])) == NULL) {
LOG(log_error, logtype_dsi, "dsi_getsess: %s", strerror(errno));
close(ipc_fds[0]);
dsi->header.dsi_flags = DSIFL_REPLY;
/* child: check number of open connections. this is one off the
* actual count. */
- if ((serv_children->count >= serv_children->nsessions) &&
+ if ((serv_children->servch_count >= serv_children->servch_nsessions) &&
(dsi->header.dsi_command == DSIFUNC_OPEN)) {
LOG(log_info, logtype_dsi, "dsi_getsess: too many connections");
dsi->header.dsi_flags = DSIFL_REPLY;
options->flags |= OPTION_ANNOUNCESSH;
if (iniparser_getboolean(config, INISEC_GLOBAL, "map acls", 1))
options->flags |= OPTION_ACL2MACCESS;
- if (iniparser_getboolean(config, INISEC_GLOBAL, "keep sessions", 0))
- options->flags |= OPTION_KEEPSESSIONS;
if (iniparser_getboolean(config, INISEC_GLOBAL, "close vol", 0))
options->flags |= OPTION_CLOSEVOL;
if (!iniparser_getboolean(config, INISEC_GLOBAL, "client polling", 0))
/*
* Copyright (c) 1997 Adrian Sun (asun@zoology.washington.edu)
+ * Copyright (c) 2013 Frank Lahm <franklahm@gmail.com
* All rights reserved. See COPYRIGHT.
*
- *
* handle inserting, removing, and freeing of children.
* this does it via a hash table. it incurs some overhead over
* a linear append/remove in total removal and kills, but it makes
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/time.h>
+#include <pthread.h>
#include <atalk/logger.h>
#include <atalk/errchk.h>
#endif
/* hash/child functions: hash OR's pid */
-#define CHILD_HASHSIZE 32
#define HASH(i) ((((i) >> 8) ^ (i)) & (CHILD_HASHSIZE - 1))
-typedef struct server_child_fork {
- struct server_child_data *table[CHILD_HASHSIZE];
- void (*cleanup)(const pid_t);
-} server_child_fork;
-
-static inline void hash_child(struct server_child_data **htable,
- struct server_child_data *child)
+static inline void hash_child(afp_child_t **htable, afp_child_t *child)
{
- struct server_child_data **table;
+ afp_child_t **table;
- table = &htable[HASH(child->pid)];
- if ((child->next = *table) != NULL)
- (*table)->prevp = &child->next;
+ table = &htable[HASH(child->afpch_pid)];
+ if ((child->afpch_next = *table) != NULL)
+ (*table)->afpch_prevp = &child->afpch_next;
*table = child;
- child->prevp = table;
+ child->afpch_prevp = table;
}
-static inline void unhash_child(struct server_child_data *child)
+static inline void unhash_child(afp_child_t *child)
{
- if (child->prevp) {
- if (child->next)
- child->next->prevp = child->prevp;
- *(child->prevp) = child->next;
+ if (child->afpch_prevp) {
+ if (child->afpch_next)
+ child->afpch_next->afpch_prevp = child->afpch_prevp;
+ *(child->afpch_prevp) = child->afpch_next;
}
}
-static struct server_child_data *resolve_child(struct server_child_data **table, pid_t pid)
+static afp_child_t *resolve_child(afp_child_t **table, pid_t pid)
{
- struct server_child_data *child;
+ afp_child_t *child;
- for (child = table[HASH(pid)]; child; child = child->next) {
- if (child->pid == pid)
+ for (child = table[HASH(pid)]; child; child = child->afpch_next) {
+ if (child->afpch_pid == pid)
break;
}
}
/* initialize server_child structure */
-server_child *server_child_alloc(const int connections, const int nforks)
+server_child_t *server_child_alloc(int connections)
{
- server_child *children;
-
- children = (server_child *) calloc(1, sizeof(server_child));
- if (!children)
- return NULL;
-
- children->nsessions = connections;
- children->nforks = nforks;
- children->fork = (void *) calloc(nforks, sizeof(server_child_fork));
+ server_child_t *children;
- if (!children->fork) {
- free(children);
+ if (!(children = (server_child_t *)calloc(1, sizeof(server_child_t))))
return NULL;
- }
+ children->servch_nsessions = connections;
+ pthread_mutex_init(&children->servch_lock, NULL);
return children;
}
* add a child
* @return pointer to struct server_child_data on success, NULL on error
*/
-afp_child_t *server_child_add(server_child *children, int forkid, pid_t pid, int ipc_fd)
+afp_child_t *server_child_add(server_child_t *children, pid_t pid, int ipc_fd)
{
- server_child_fork *fork;
afp_child_t *child = NULL;
- sigset_t sig, oldsig;
- /* we need to prevent deletions from occuring before we get a
- * chance to add the child in. */
- sigemptyset(&sig);
- sigaddset(&sig, SIGCHLD);
- pthread_sigmask(SIG_BLOCK, &sig, &oldsig);
+ pthread_mutex_lock(&children->servch_lock);
/* it's possible that the child could have already died before the
* pthread_sigmask. we need to check for this. */
goto exit;
}
- fork = (server_child_fork *) children->fork + forkid;
-
/* if we already have an entry. just return. */
- if ((child = resolve_child(fork->table, pid)))
+ if ((child = resolve_child(children->servch_table, pid)))
goto exit;
if ((child = calloc(1, sizeof(afp_child_t))) == NULL)
goto exit;
- child->pid = pid;
- child->valid = 0;
- child->killed = 0;
- child->ipc_fd = ipc_fd;
+ child->afpch_pid = pid;
+ child->afpch_ipc_fd = ipc_fd;
- hash_child(fork->table, child);
- children->count++;
+ hash_child(children->servch_table, child);
+ children->servch_count++;
exit:
- pthread_sigmask(SIG_SETMASK, &oldsig, NULL);
+ pthread_mutex_unlock(&children->servch_lock);
return child;
}
/* remove a child and free it */
-int server_child_remove(server_child *children, const int forkid, pid_t pid)
+int server_child_remove(server_child_t *children, pid_t pid)
{
int fd;
- server_child_fork *fork;
- struct server_child_data *child;
+ afp_child_t *child;
- fork = (server_child_fork *) children->fork + forkid;
- if (!(child = resolve_child(fork->table, pid)))
+ if (!(child = resolve_child(children->servch_table, pid)))
return -1;
unhash_child(child);
- if (child->clientid) {
- free(child->clientid);
- child->clientid = NULL;
+ if (child->afpch_clientid) {
+ free(child->afpch_clientid);
+ child->afpch_clientid = NULL;
}
/* In main:child_handler() we need the fd in order to remove it from the pollfd set */
- fd = child->ipc_fd;
+ fd = child->afpch_ipc_fd;
if (fd != -1)
close(fd);
free(child);
- children->count--;
+ children->servch_count--;
- if (fork->cleanup)
- fork->cleanup(pid);
+ if (children->servch_cleanup)
+ children->servch_cleanup(pid);
return fd;
}
/* free everything: by using a hash table, this increases the cost of
* this part over a linked list by the size of the hash table */
-void server_child_free(server_child *children)
+void server_child_free(server_child_t *children)
{
- server_child_fork *fork;
- struct server_child_data *child, *tmp;
- int i, j;
-
- for (i = 0; i < children->nforks; i++) {
- fork = (server_child_fork *) children->fork + i;
- for (j = 0; j < CHILD_HASHSIZE; j++) {
- child = fork->table[j]; /* start at the beginning */
- while (child) {
- tmp = child->next;
- close(child->ipc_fd);
- if (child->clientid) {
- free(child->clientid);
- }
- free(child);
- child = tmp;
- }
+ afp_child_t *child, *tmp;
+ int j;
+
+ for (j = 0; j < CHILD_HASHSIZE; j++) {
+ child = children->servch_table[j]; /* start at the beginning */
+ while (child) {
+ tmp = child->afpch_next;
+ close(child->afpch_ipc_fd);
+ if (child->afpch_clientid)
+ free(child->afpch_clientid);
+ free(child);
+ child = tmp;
}
}
- free(children->fork);
+
free(children);
}
/* send signal to all child processes */
-void server_child_kill(server_child *children, int forkid, int sig)
+void server_child_kill(server_child_t *children, int sig)
{
- server_child_fork *fork;
- struct server_child_data *child, *tmp;
+ afp_child_t *child, *tmp;
int i;
- fork = (server_child_fork *) children->fork + forkid;
for (i = 0; i < CHILD_HASHSIZE; i++) {
- child = fork->table[i];
+ child = children->servch_table[i];
while (child) {
- tmp = child->next;
- kill(child->pid, sig);
+ tmp = child->afpch_next;
+ kill(child->afpch_pid, sig);
child = tmp;
}
}
}
-/* send kill to a child processes.
- * a plain-old linked list
- * FIXME use resolve_child ?
- */
-static int kill_child(struct server_child_data *child)
+/* send kill to a child processes */
+static int kill_child(afp_child_t *child)
{
- if (!child->killed) {
- kill(child->pid, SIGTERM);
+ if (!child->afpch_killed) {
+ kill(child->afpch_pid, SIGTERM);
/* we don't wait because there's no guarantee that we can really kill it */
- child->killed = 1;
+ child->afpch_killed = 1;
return 1;
} else {
- LOG(log_info, logtype_default, "Unresponsive child[%d], sending SIGKILL", child->pid);
- kill(child->pid, SIGKILL);
+ LOG(log_info, logtype_default, "Unresponsive child[%d], sending SIGKILL", child->afpch_pid);
+ kill(child->afpch_pid, SIGKILL);
}
return 1;
}
* Try to find an old session and pass socket
* @returns -1 on error, 0 if no matching session was found, 1 if session was found and socket passed
*/
-int server_child_transfer_session(server_child *children,
- int forkid,
+int server_child_transfer_session(server_child_t *children,
pid_t pid,
uid_t uid,
int afp_socket,
uint16_t DSI_requestID)
{
EC_INIT;
- server_child_fork *fork;
- struct server_child_data *child;
+ afp_child_t *child;
- fork = (server_child_fork *) children->fork + forkid;
- if ((child = resolve_child(fork->table, pid)) == NULL) {
+ if ((child = resolve_child(children->servch_table, pid)) == NULL) {
LOG(log_note, logtype_default, "Reconnect: no child[%u]", pid);
if (kill(pid, 0) == 0) {
LOG(log_note, logtype_default, "Reconnect: terminating old session[%u]", pid);
return 0;
}
- if (!child->valid) {
+ if (!child->afpch_valid) {
/* hmm, client 'guess' the pid, rogue? */
LOG(log_error, logtype_default, "Reconnect: invalidated child[%u]", pid);
return 0;
- } else if (child->uid != uid) {
+ } else if (child->afpch_uid != uid) {
LOG(log_error, logtype_default, "Reconnect: child[%u] not the same user", pid);
return 0;
}
LOG(log_note, logtype_default, "Reconnect: transfering session to child[%u]", pid);
- if (writet(child->ipc_fd, &DSI_requestID, 2, 0, 2) != 2) {
+ if (writet(child->afpch_ipc_fd, &DSI_requestID, 2, 0, 2) != 2) {
LOG(log_error, logtype_default, "Reconnect: error sending DSI id to child[%u]", pid);
EC_STATUS(-1);
goto EC_CLEANUP;
}
- EC_ZERO_LOG(send_fd(child->ipc_fd, afp_socket));
+ EC_ZERO_LOG(send_fd(child->afpch_ipc_fd, afp_socket));
EC_ZERO_LOG(kill(pid, SIGURG));
EC_STATUS(1);
/* 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, int forkid, pid_t pid,
+void server_child_kill_one_by_id(server_child_t *children, pid_t pid,
uid_t uid, uint32_t idlen, char *id, uint32_t boottime)
{
- server_child_fork *fork;
- struct server_child_data *child, *tmp;
+ afp_child_t *child, *tmp;
int i;
- fork = (server_child_fork *)children->fork + forkid;
-
for (i = 0; i < CHILD_HASHSIZE; i++) {
- child = fork->table[i];
+ child = children->servch_table[i];
while (child) {
- tmp = child->next;
- if ( child->pid != pid) {
- if (child->idlen == idlen && memcmp(child->clientid, id, idlen) == 0) {
- if ( child->time != boottime ) {
+ tmp = child->afpch_next;
+ if (child->afpch_pid != pid) {
+ if (child->afpch_idlen == idlen && memcmp(child->afpch_clientid, id, idlen) == 0) {
+ if ( child->afpch_time != boottime ) {
/* Client rebooted */
- if (uid == child->uid) {
+ if (uid == child->afpch_uid) {
kill_child(child);
LOG(log_warning, logtype_default,
"Terminated disconnected child[%u], client rebooted.",
- child->pid);
+ child->afpch_pid);
} else {
LOG(log_warning, logtype_default,
- "Session with different pid[%u]", child->pid);
+ "Session with different pid[%u]", child->afpch_pid);
}
} else {
/* One client with multiple sessions */
LOG(log_debug, logtype_default,
- "Found another session[%u] for client[%u]", child->pid, pid);
+ "Found another session[%u] for client[%u]", child->afpch_pid, pid);
}
}
} else {
/* update childs own slot */
- child->time = boottime;
- if (child->clientid)
- free(child->clientid);
- LOG(log_debug, logtype_default, "Setting client ID for %u", child->pid);
- child->uid = uid;
- child->valid = 1;
- child->idlen = idlen;
- child->clientid = id;
+ child->afpch_time = boottime;
+ if (child->afpch_clientid)
+ free(child->afpch_clientid);
+ LOG(log_debug, logtype_default, "Setting client ID for %u", child->afpch_pid);
+ child->afpch_uid = uid;
+ child->afpch_valid = 1;
+ child->afpch_idlen = idlen;
+ child->afpch_clientid = id;
}
child = tmp;
}
}
}
-/* for extra cleanup if necessary */
-void server_child_setup(server_child *children, const int forkid,
- void (*fcn)(const pid_t))
-{
- server_child_fork *fork;
-
- fork = (server_child_fork *) children->fork + forkid;
- fork->cleanup = fcn;
-}
-
-
/* ---------------------------
* reset children signals
*/
* Pass afp_socket to old disconnected session if one has a matching token (token = pid)
* @returns -1 on error, 0 if no matching session was found, 1 if session was found and socket passed
*/
-static int ipc_kill_token(struct ipc_header *ipc, server_child *children)
+static int ipc_kill_token(struct ipc_header *ipc, server_child_t *children)
{
pid_t pid;
memcpy (&pid, ipc->msg, sizeof(pid_t));
return server_child_transfer_session(children,
- CHILD_DSIFORK,
pid,
ipc->uid,
ipc->afp_socket,
}
/* ----------------- */
-static int ipc_get_session(struct ipc_header *ipc, server_child *children)
+static int ipc_get_session(struct ipc_header *ipc, server_child_t *children)
{
uint32_t boottime;
uint32_t idlen;
ipc->child_pid, ipc->uid, boottime);
server_child_kill_one_by_id(children,
- CHILD_DSIFORK,
ipc->child_pid,
ipc->uid,
idlen,
* Public functions
***********************************************************************************/
-/*!
- * 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
- */
-int ipc_server_uds(const char *name)
-{
- EC_INIT;
- struct sockaddr_un address;
- socklen_t address_length;
- int fd = -1;
-
- EC_NEG1_LOG( fd = socket(PF_UNIX, SOCK_STREAM, 0) );
- EC_ZERO_LOG( setnonblock(fd, 1) );
- unlink(name);
- address.sun_family = AF_UNIX;
- address_length = sizeof(address.sun_family) + sprintf(address.sun_path, "%s", name);
- EC_ZERO_LOG( bind(fd, (struct sockaddr *)&address, address_length) );
- EC_ZERO_LOG( listen(fd, 1024) );
-
-EC_CLEANUP:
- if (ret != 0) {
- return -1;
- }
-
- 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) );
- address.sun_family = AF_UNIX;
- address_length = sizeof(address.sun_family) + sprintf(address.sun_path, "%s", name);
-
- EC_ZERO_LOG( connect(fd, (struct sockaddr *)&address, address_length) ); /* 1 */
- LOG(log_debug, logtype_afpd, "ipc_client_uds: connected to master");
-
- EC_ZERO_LOG( setnonblock(fd, 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_debug, logtype_afpd, "ipc_client_uds: fd: %d", fd);
- return fd;
-}
-
-int reconnect_ipc(AFPObj *obj)
-{
- int retrycount = 0;
-
- LOG(log_debug, logtype_afpd, "reconnect_ipc: start");
-
- close(obj->ipc_fd);
- obj->ipc_fd = -1;
-
- sleep((getpid() % 5) + 15); /* give it enough time to start */
-
- while (retrycount++ < 10) {
- if ((obj->ipc_fd = ipc_client_uds(_PATH_AFP_IPC)) == -1) {
- LOG(log_error, logtype_afpd, "reconnect_ipc: cant reconnect to master");
- sleep(1);
- continue;
- }
- LOG(log_debug, logtype_afpd, "reconnect_ipc: succesfull IPC reconnect");
- return 0;
- }
- return -1;
-}
-
/* -----------------
* Ipc format
* command
*
* @returns -1 on error, 0 on success
*/
-int ipc_server_read(server_child *children, int fd)
+int ipc_server_read(server_child_t *children, int fd)
{
int ret;
struct ipc_header ipc;
\fIuser\*(Aqs home\fR\&.
.RE
.PP
-keep sessions = \fIBOOLEAN\fR (default: \fIno\fR) \fB(G)\fR
-.RS 4
-Enable "Continuous AFP Service"\&. This means restarting AFP and CNID service daemons master processes, but keeping the AFP session processes\&. This can be used to install (most) updates to Netatalk without interrupting active AFP sessions\&. Existing AFP sessions will still run the version from before updating, but new AFP sessions will run the updated code\&. After enabling this option when sending SIGQUIT to the
-\fInetatalk\fR
-service controller process, the AFP and CNID daemons will exit and then the service controller will restart them\&. AFP session processes are notified of the master afpd shutdown, they will then sleep 15\-20 seconds and then try to reconnect their IPC channel to the master afpd process\&. The IPC channel between the AFP master service daemon and the AFP session child is used for keeping session state of AFP sessions in the AFP master process\&. The session state is needed when AFP clients experience eg network outages and try to reconnect to the AFP server\&.
-.RE
-.PP
login message = \fImessage\fR \fB(G)/(V)\fR
.RS 4
Sets a message to be displayed when clients logon to the server\&. The message should be in
Stop Netatalk service, AFP and CNID daemons
.RE
.PP
-SIGQUIT
-.RS 4
-Restart AFP and CNID master daemons, but keep all session AFP processes running\&. Can be used to implement
-AFP service without downtime\&.
-.RE
-.PP
SIGHUP
.RS 4
Sending a