From: Ralph Boehme Date: Wed, 6 Feb 2013 07:30:17 +0000 (+0100) Subject: Remove continous service feature X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=netatalk.git;a=commitdiff_plain;h=fb751e80c0bc12c35675fbf1434ceecb4aad47cb Remove continous service feature --- diff --git a/etc/afpd/afp_dsi.c b/etc/afpd/afp_dsi.c index 8e1f90d2..77918c56 100644 --- a/etc/afpd/afp_dsi.c +++ b/etc/afpd/afp_dsi.c @@ -140,23 +140,6 @@ static void afp_dsi_die(int sig) } } -/* 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_) { @@ -407,7 +390,7 @@ void afp_over_dsi_sighandlers(AFPObj *obj) } /* 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); diff --git a/etc/afpd/main.c b/etc/afpd/main.c index 0e0a858e..a66e4a86 100644 --- a/etc/afpd/main.c +++ b/etc/afpd/main.c @@ -45,7 +45,7 @@ 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; @@ -54,9 +54,8 @@ static struct pollfd *fdset; 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) { @@ -81,16 +80,6 @@ static void fd_set_listening_sockets(const AFPObj *config) 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) @@ -100,9 +89,6 @@ 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); } /* ------------------ */ @@ -112,22 +98,9 @@ static void afp_goaway(int sig) 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; @@ -137,7 +110,7 @@ static void afp_goaway(int sig) 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 : @@ -167,11 +140,9 @@ static void child_handler(void) #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)) { @@ -232,7 +203,7 @@ int main(int ac, char **av) /* 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); } @@ -350,12 +321,6 @@ int main(int ac, char **av) 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 */ @@ -433,7 +398,7 @@ int main(int ac, char **av) &polldata, &fdset_used, &fdset_size, - child->ipc_fd, + child->afpch_ipc_fd, IPC_FD, child); } @@ -441,46 +406,13 @@ int main(int ac, char **av) 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: @@ -494,7 +426,7 @@ int main(int ac, char **av) 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; diff --git a/include/atalk/dsi.h b/include/atalk/dsi.h index 11fb59b2..4197dba5 100644 --- a/include/atalk/dsi.h +++ b/include/atalk/dsi.h @@ -165,7 +165,7 @@ extern int dsi_tcp_init(DSI *dsi, const char *hostname, const char *address, con 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); diff --git a/include/atalk/globals.h b/include/atalk/globals.h index 75d4041b..925f4560 100644 --- a/include/atalk/globals.h +++ b/include/atalk/globals.h @@ -41,7 +41,6 @@ #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 diff --git a/include/atalk/paths.h b/include/atalk/paths.h index 1aab9690..ba4d2f23 100644 --- a/include/atalk/paths.h +++ b/include/atalk/paths.h @@ -36,7 +36,6 @@ * 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 diff --git a/include/atalk/server_child.h b/include/atalk/server_child.h index ad41bcec..6f8f18a0 100644 --- a/include/atalk/server_child.h +++ b/include/atalk/server_child.h @@ -12,41 +12,42 @@ /* 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 diff --git a/include/atalk/server_ipc.h b/include/atalk/server_ipc.h index aca04f80..0765c73c 100644 --- a/include/atalk/server_ipc.h +++ b/include/atalk/server_ipc.h @@ -7,10 +7,7 @@ #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 */ diff --git a/include/atalk/util.h b/include/atalk/util.h index 08c37394..facc7763 100644 --- a/include/atalk/util.h +++ b/include/atalk/util.h @@ -149,7 +149,7 @@ extern void apply_ip_mask(struct sockaddr *ai, int maskbits); 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 * diff --git a/libatalk/dsi/dsi_getsess.c b/libatalk/dsi/dsi_getsess.c index cde5def7..38477be9 100644 --- a/libatalk/dsi/dsi_getsess.c +++ b/libatalk/dsi/dsi_getsess.c @@ -32,7 +32,7 @@ * @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]; @@ -61,7 +61,7 @@ int dsi_getsession(DSI *dsi, server_child *serv_children, int tickleval, afp_chi /* 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; @@ -77,7 +77,7 @@ int dsi_getsession(DSI *dsi, server_child *serv_children, int tickleval, afp_chi /* 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; diff --git a/libatalk/util/netatalk_conf.c b/libatalk/util/netatalk_conf.c index b1ca02d1..1bfa3a94 100644 --- a/libatalk/util/netatalk_conf.c +++ b/libatalk/util/netatalk_conf.c @@ -1641,8 +1641,6 @@ int afp_config_parse(AFPObj *AFPObj, char *processname) 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)) diff --git a/libatalk/util/server_child.c b/libatalk/util/server_child.c index 547d68d9..6c86f483 100644 --- a/libatalk/util/server_child.c +++ b/libatalk/util/server_child.c @@ -1,8 +1,8 @@ /* * Copyright (c) 1997 Adrian Sun (asun@zoology.washington.edu) + * Copyright (c) 2013 Frank Lahm #include #include +#include #include #include @@ -47,41 +48,34 @@ #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; } @@ -89,23 +83,15 @@ static struct server_child_data *resolve_child(struct server_child_data **table, } /* 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; } @@ -113,17 +99,11 @@ server_child *server_child_alloc(const int connections, const int nforks) * 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. */ @@ -132,118 +112,102 @@ afp_child_t *server_child_add(server_child *children, int forkid, pid_t pid, int 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; } @@ -252,19 +216,16 @@ static int kill_child(struct server_child_data *child) * 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); @@ -279,23 +240,23 @@ int server_child_transfer_session(server_child *children, 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); @@ -307,65 +268,51 @@ EC_CLEANUP: /* 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 */ diff --git a/libatalk/util/server_ipc.c b/libatalk/util/server_ipc.c index 815c58d8..838cece7 100644 --- a/libatalk/util/server_ipc.c +++ b/libatalk/util/server_ipc.c @@ -48,7 +48,7 @@ static char *ipc_cmd_str[] = { "IPC_DISCOLDSESSION", * 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; @@ -59,7 +59,6 @@ static int ipc_kill_token(struct ipc_header *ipc, server_child *children) memcpy (&pid, ipc->msg, sizeof(pid_t)); return server_child_transfer_session(children, - CHILD_DSIFORK, pid, ipc->uid, ipc->afp_socket, @@ -67,7 +66,7 @@ static int ipc_kill_token(struct ipc_header *ipc, server_child *children) } /* ----------------- */ -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; @@ -96,7 +95,6 @@ static int ipc_get_session(struct ipc_header *ipc, server_child *children) ipc->child_pid, ipc->uid, boottime); server_child_kill_one_by_id(children, - CHILD_DSIFORK, ipc->child_pid, ipc->uid, idlen, @@ -110,97 +108,6 @@ static int ipc_get_session(struct ipc_header *ipc, server_child *children) * 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 @@ -219,7 +126,7 @@ int reconnect_ipc(AFPObj *obj) * * @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; diff --git a/man/man5/afp.conf.5.tmpl b/man/man5/afp.conf.5.tmpl index 4f2472c3..c03ad30a 100644 --- a/man/man5/afp.conf.5.tmpl +++ b/man/man5/afp.conf.5.tmpl @@ -549,13 +549,6 @@ AFP user home volume name\&. The default is \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 diff --git a/man/man8/netatalk.8.tmpl b/man/man8/netatalk.8.tmpl index 88cb179e..06878da5 100644 --- a/man/man8/netatalk.8.tmpl +++ b/man/man8/netatalk.8.tmpl @@ -48,12 +48,6 @@ SIGTERM 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