summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Peach <jpeach@samba.org>2007-04-20 21:09:44 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 12:19:33 -0500
commit44f5211c170c0ddc2be23717f1ad08f5fc0b329a (patch)
tree36758905a0cdb7df1a63381d7380c77192ff78f1
parent8a22b1f0ea81f06616a2dc41a138c5126359f009 (diff)
downloadsamba-44f5211c170c0ddc2be23717f1ad08f5fc0b329a.tar.gz
samba-44f5211c170c0ddc2be23717f1ad08f5fc0b329a.tar.bz2
samba-44f5211c170c0ddc2be23717f1ad08f5fc0b329a.zip
r22418: Support running under launchd. We abstract the method of obtaining
sockets to listen on a little, because in the launchd case these are provided for us. We also add an idle timeout so that a daemon can exit after a period of inactivity. (This used to be commit fc8589a3371d396197fae508e563f814899c2beb)
-rw-r--r--source3/Makefile.in4
-rw-r--r--source3/configure.in29
-rw-r--r--source3/include/smb_launchd.h43
-rw-r--r--source3/lib/launchd.c242
-rw-r--r--source3/nsswitch/winbindd.c114
-rw-r--r--source3/nsswitch/winbindd_nss.h7
-rw-r--r--source3/smbd/connection.c42
-rw-r--r--source3/smbd/server.c175
8 files changed, 582 insertions, 74 deletions
diff --git a/source3/Makefile.in b/source3/Makefile.in
index 702bd63cd5..03ca7931d3 100644
--- a/source3/Makefile.in
+++ b/source3/Makefile.in
@@ -498,7 +498,7 @@ SMBD_OBJ_SRV = smbd/files.o smbd/chgpasswd.o smbd/connection.o \
smbd/change_trust_pw.o smbd/fake_file.o \
smbd/quotas.o smbd/ntquotas.o $(AFS_OBJ) smbd/msdfs.o \
$(AFS_SETTOKEN_OBJ) smbd/aio.o smbd/statvfs.o \
- smbd/dmapi.o $(MANGLE_OBJ) @VFS_STATIC@
+ smbd/dmapi.o lib/launchd.o $(MANGLE_OBJ) @VFS_STATIC@
SMBD_OBJ_BASE = $(PARAM_OBJ) $(SMBD_OBJ_SRV) $(LIBSMB_OBJ) \
$(RPC_SERVER_OBJ) $(RPC_PARSE_OBJ) $(SECRETS_OBJ) \
@@ -836,7 +836,7 @@ WINBINDD_OBJ = \
$(PROFILE_OBJ) $(SLCACHE_OBJ) $(SMBLDAP_OBJ) \
$(SECRETS_OBJ) $(LIBADS_OBJ) $(KRBCLIENT_OBJ) $(POPT_LIB_OBJ) \
$(DCUTIL_OBJ) $(IDMAP_OBJ) $(NSS_INFO_OBJ) \
- $(AFS_OBJ) $(AFS_SETTOKEN_OBJ) \
+ $(AFS_OBJ) $(AFS_SETTOKEN_OBJ) lib/launchd.o \
$(LIBADS_SERVER_OBJ) $(SERVER_MUTEX_OBJ) $(LDB_OBJ)
WBINFO_OBJ = nsswitch/wbinfo.o $(LIBSAMBA_OBJ) $(PARAM_OBJ) $(LIB_NONSMBD_OBJ) \
diff --git a/source3/configure.in b/source3/configure.in
index 1e9fca76f5..b467388947 100644
--- a/source3/configure.in
+++ b/source3/configure.in
@@ -348,6 +348,35 @@ AC_ARG_WITH(selftest-prefix,
esac
])
+AC_ARG_ENABLE(launchd,
+[ --enable-launchd Support running under launchd (default=auto)])
+
+if test x"$enable_launchd" != x"no" ; then
+ AC_CACHE_CHECK([whether to include launchd support],
+ samba_cv_launchd_support,
+ [
+ AC_TRY_COMPILE(
+ [
+#include <launch.h>
+ ],
+ [
+ launchd_msg(NULL);
+ launchd_data_get_fd(NULL);
+ ],
+ samba_cv_launchd_support=yes,
+ samba_cv_launchd_support=no)
+ ])
+
+ if test x"$samba_cv_launchd_support" = x"yes" ; then
+ AC_DEFINE(WITH_LAUNCHD_SUPPORT, 1,
+ [Whether launchd support should be enabled])
+ else
+ if test x"$enable_launchd" = x"yes" ; then
+ AC_ERROR(launchd support is not available)
+ fi
+ fi
+fi
+
#################################################
# set path of samba4's smbtorture
smbtorture4_path=""
diff --git a/source3/include/smb_launchd.h b/source3/include/smb_launchd.h
new file mode 100644
index 0000000000..2e758a4de1
--- /dev/null
+++ b/source3/include/smb_launchd.h
@@ -0,0 +1,43 @@
+/*
+ Unix SMB/CIFS implementation.
+ Launchd integration wrapper API
+
+ Copyright (C) James Peach 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+struct smb_launch_info
+{
+ int idle_timeout_secs;
+ int num_sockets;
+ int *socket_list;
+};
+
+/* Retrieve launchd configuration. Returns True if we are running under
+ * launchd, False otherwise. NOTE this does not guarantee to provide a list of
+ * sockets since this is a user configuration option.
+ */
+BOOL smb_launchd_checkin(struct smb_launch_info *linfo);
+
+/* Retrieve launchd configuration. The variadic arguments are a list of
+ * constant null-terminated strings. The strings are the names of the socket
+ * dictionaries to retrieve sockets from. The list of names is terminated by a
+ * NULL.
+ */
+BOOL smb_launchd_checkin_names(struct smb_launch_info *linfo, ...);
+
+/* Free any data or state associated with a successful launchd checkin. */
+void smb_launchd_checkout(struct smb_launch_info *linfo);
diff --git a/source3/lib/launchd.c b/source3/lib/launchd.c
new file mode 100644
index 0000000000..1fd5a33db0
--- /dev/null
+++ b/source3/lib/launchd.c
@@ -0,0 +1,242 @@
+/*
+ Unix SMB/CIFS implementation.
+ Launchd integration wrapper API
+
+ Copyright (C) 2007 James Peach
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "smb_launchd.h"
+
+/* launchd source code and documentation is available here:
+ * http://launchd.macosforge.org/
+ */
+
+#if defined(WITH_LAUNCHD_SUPPORT)
+
+#include <launch.h>
+#include <stdarg.h>
+
+typedef void (*launchd_iterator)(launch_data_t, const char*, void*);
+
+#define LAUNCHD_TRACE_LEVEL 10
+
+ void smb_launchd_checkout(struct smb_launch_info *linfo)
+{
+ talloc_free(linfo->socket_list);
+}
+
+static void pull_launch_sockets(launch_data_t key,
+ const char *name,
+ struct smb_launch_info *linfo)
+{
+ launch_data_type_t type;
+
+ type = launch_data_get_type(key);
+ DEBUG(LAUNCHD_TRACE_LEVEL,
+ ("Searching item name='%s' type=%d for sockets\n",
+ name ? name : "", (int)type));
+
+ switch (type) {
+ case LAUNCH_DATA_FD:
+ if (!linfo->socket_list) {
+ /* We are counting the number of sockets. */
+ linfo->num_sockets++;
+ } else {
+ /* We are collecting the socket fds. */
+ int fd = launch_data_get_fd(key);
+
+ linfo->socket_list[linfo->num_sockets] = fd;
+ linfo->num_sockets++;
+ DEBUG(LAUNCHD_TRACE_LEVEL,
+ ("Added fd=%d to launchd set\n", fd));
+ }
+ return;
+ case LAUNCH_DATA_ARRAY:
+ {
+ int i;
+ launch_data_t item;
+
+ for (i = 0; i < launch_data_array_get_count(key); ++i) {
+ item = launch_data_array_get_index(key, i);
+ pull_launch_sockets(item, name, linfo);
+ }
+ return;
+ }
+ case LAUNCH_DATA_DICTIONARY:
+ launch_data_dict_iterate(key,
+ (launchd_iterator)pull_launch_sockets, linfo);
+ return;
+ default:
+ return;
+ }
+}
+
+ BOOL smb_launchd_checkin_names(struct smb_launch_info *linfo, ...)
+{
+ launch_data_t msg;
+ launch_data_t resp;
+ launch_data_t item;
+ BOOL is_launchd = False;
+
+ ZERO_STRUCTP(linfo);
+
+ msg = launch_data_new_string(LAUNCH_KEY_CHECKIN);
+ resp = launch_msg(msg);
+ if (resp == NULL) {
+ /* IPC to launchd failed. */
+ launch_data_free(msg);
+ return is_launchd;
+ }
+
+ if (launch_data_get_type(resp) == LAUNCH_DATA_ERRNO) {
+ errno = launch_data_get_errno(resp);
+ goto done;
+ }
+
+ /* At this point, we know we are running under launchd. */
+ linfo->idle_timeout_secs = 600;
+ is_launchd = True;
+
+ if ((item = launch_data_dict_lookup(resp, LAUNCH_JOBKEY_TIMEOUT))) {
+ linfo->idle_timeout_secs = launch_data_get_integer(item);
+ }
+
+ if ((item = launch_data_dict_lookup(resp, LAUNCH_JOBKEY_SOCKETS))) {
+ int count = 0;
+ const char * sockname = NULL;
+ launch_data_t sockdata;
+ va_list args;
+
+ /* Figure out the maximum number of sockets. */
+ va_start(args, linfo);
+ while ((sockname = va_arg(args, const char *))) {
+ ++count;
+ }
+ va_end(args);
+
+ DEBUG(LAUNCHD_TRACE_LEVEL, ("Found %d launchd sockets\n",
+ linfo->num_sockets));
+
+ if (launch_data_dict_get_count(item) < count) {
+ DEBUG(0, ("%d launchd sockets requested, "
+ "but only %d are available\n",
+ count, launch_data_dict_get_count(item)));
+ }
+
+ linfo->socket_list = talloc_array(NULL, int, count);
+ if (linfo->socket_list == NULL) {
+ goto done;
+ }
+
+ linfo->num_sockets = 0;
+ va_start(args, linfo);
+ while ((sockname = va_arg(args, const char *))) {
+ sockdata = launch_data_dict_lookup(item, sockname);
+
+ pull_launch_sockets(sockdata, sockname, linfo);
+ DEBUG(LAUNCHD_TRACE_LEVEL,
+ ("Added launchd socket \"%s\"\n", sockname));
+ }
+
+ SMB_ASSERT(count >= linfo->num_sockets);
+ }
+
+done:
+ launch_data_free(msg);
+ launch_data_free(resp);
+ return is_launchd;
+}
+
+ BOOL smb_launchd_checkin(struct smb_launch_info *linfo)
+{
+ launch_data_t msg;
+ launch_data_t resp;
+ launch_data_t item;
+ BOOL is_launchd = False;
+
+ ZERO_STRUCTP(linfo);
+
+ msg = launch_data_new_string(LAUNCH_KEY_CHECKIN);
+ resp = launch_msg(msg);
+ if (resp == NULL) {
+ /* IPC to launchd failed. */
+ launch_data_free(msg);
+ return is_launchd;
+ }
+
+ if (launch_data_get_type(resp) == LAUNCH_DATA_ERRNO) {
+ errno = launch_data_get_errno(resp);
+ goto done;
+ }
+
+ /* At this point, we know we are running under launchd. */
+ linfo->idle_timeout_secs = 600;
+ is_launchd = True;
+
+ if ((item = launch_data_dict_lookup(resp, LAUNCH_JOBKEY_TIMEOUT))) {
+ linfo->idle_timeout_secs = launch_data_get_integer(item);
+ }
+
+ if ((item = launch_data_dict_lookup(resp, LAUNCH_JOBKEY_SOCKETS))) {
+ int count;
+
+ pull_launch_sockets(item, NULL, linfo);
+ DEBUG(LAUNCHD_TRACE_LEVEL, ("Found %d launchd sockets\n",
+ linfo->num_sockets));
+
+ count = linfo->num_sockets;
+ linfo->socket_list = talloc_array(NULL, int, count);
+ if (linfo->socket_list == NULL) {
+ goto done;
+ }
+
+ linfo->num_sockets = 0;
+ pull_launch_sockets(item, NULL, linfo);
+
+ DEBUG(LAUNCHD_TRACE_LEVEL, ("Added %d launchd sockets\n",
+ linfo->num_sockets));
+
+ SMB_ASSERT(count == linfo->num_sockets);
+ }
+
+done:
+ launch_data_free(msg);
+ launch_data_free(resp);
+ return is_launchd;
+}
+
+#else /* defined(WITH_LAUNCHD_SUPPORT) */
+
+ BOOL smb_launchd_checkin(struct smb_launch_info * UNUSED(linfo))
+{
+ ZERO_STRUCTP(linfo);
+ return False;
+}
+
+ BOOL smb_launchd_checkin_names(struct smb_launch_info * UNUSED(linfo), ...)
+{
+ ZERO_STRUCTP(linfo);
+ return False;
+}
+
+ void smb_launchd_checkout(struct smb_launch_info * UNUSED(linfo))
+{
+}
+
+#endif /* defined(WITH_LAUNCHD_SUPPORT) */
+
diff --git a/source3/nsswitch/winbindd.c b/source3/nsswitch/winbindd.c
index da0473583f..0dade53521 100644
--- a/source3/nsswitch/winbindd.c
+++ b/source3/nsswitch/winbindd.c
@@ -7,6 +7,7 @@
Copyright (C) Andrew Tridgell 2002
Copyright (C) Jelmer Vernooij 2003
Copyright (C) Volker Lendecke 2004
+ Copyright (C) James Peach 2007
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -25,6 +26,7 @@
#include "includes.h"
#include "winbindd.h"
+#include "smb_launchd.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_WINBIND
@@ -32,6 +34,7 @@
BOOL opt_nocache = False;
extern BOOL override_logfile;
+static BOOL unlink_winbindd_socket = True;
struct event_context *winbind_event_context(void)
{
@@ -121,9 +124,11 @@ static void terminate(void)
pstring path;
/* Remove socket file */
- pstr_sprintf(path, "%s/%s",
- WINBINDD_SOCKET_DIR, WINBINDD_SOCKET_NAME);
- unlink(path);
+ if (unlink_winbindd_socket) {
+ pstr_sprintf(path, "%s/%s",
+ WINBINDD_SOCKET_DIR, WINBINDD_SOCKET_NAME);
+ unlink(path);
+ }
idmap_close();
@@ -714,28 +719,56 @@ static BOOL remove_idle_client(void)
return False;
}
+static BOOL winbindd_init_sockets(int *public_sock, int *priv_sock,
+ int *idle_timeout_sec)
+{
+ struct smb_launch_info linfo;
+
+ if (smb_launchd_checkin_names(&linfo, "WinbindPublicPipe",
+ "WinbindPrivilegedPipe", NULL)) {
+ if (linfo.num_sockets != 2) {
+ DEBUG(0, ("invalid launchd configuration, "
+ "expected 2 sockets but got %d\n",
+ linfo.num_sockets));
+ return False;
+ }
+
+ *public_sock = linfo.socket_list[0];
+ *priv_sock = linfo.socket_list[1];
+ *idle_timeout_sec = linfo.idle_timeout_secs;
+
+ unlink_winbindd_socket = False;
+
+ smb_launchd_checkout(&linfo);
+ return True;
+ } else {
+ *public_sock = open_winbindd_socket();
+ *priv_sock = open_winbindd_priv_socket();
+ *idle_timeout_sec = -1;
+
+ if (*public_sock == -1 || *priv_sock == -1) {
+ DEBUG(0, ("failed to open winbindd pipes: %s\n",
+ errno ? strerror(errno) : "unknown error"));
+ return False;
+ }
+
+ return True;
+ }
+}
+
/* Process incoming clients on listen_sock. We use a tricky non-blocking,
non-forking, non-threaded model which allows us to handle many
simultaneous connections while remaining impervious to many denial of
service attacks. */
-static void process_loop(void)
+static int process_loop(int listen_sock, int listen_priv_sock)
{
struct winbindd_cli_state *state;
struct fd_event *ev;
fd_set r_fds, w_fds;
- int maxfd, listen_sock, listen_priv_sock, selret;
+ int maxfd, selret;
struct timeval timeout, ev_timeout;
- /* Open Sockets here to get stuff going ASAP */
- listen_sock = open_winbindd_socket();
- listen_priv_sock = open_winbindd_priv_socket();
-
- if (listen_sock == -1 || listen_priv_sock == -1) {
- perror("open_winbind_socket");
- exit(1);
- }
-
/* We'll be doing this a lot */
/* Handle messages */
@@ -903,6 +936,55 @@ static void process_loop(void)
winbind_child_died(pid);
}
}
+
+
+ return winbindd_num_clients();
+}
+
+static void winbindd_process_loop(enum smb_server_mode server_mode)
+{
+ int idle_timeout_sec;
+ struct timeval starttime;
+ int listen_public, listen_priv;
+
+ errno = 0;
+ if (!winbindd_init_sockets(&listen_public, &listen_priv,
+ &idle_timeout_sec)) {
+ terminate();
+ }
+
+ starttime = timeval_current();
+
+ if (listen_public == -1 || listen_priv == -1) {
+ DEBUG(0, ("failed to open winbindd pipes: %s\n",
+ errno ? strerror(errno) : "unknown error"));
+ terminate();
+ }
+
+ for (;;) {
+ int clients = process_loop(listen_public, listen_priv);
+
+ /* Don't bother figuring out the idle time if we won't be
+ * timing out anyway.
+ */
+ if (idle_timeout_sec < 0) {
+ continue;
+ }
+
+ if (clients == 0 && server_mode == SERVER_MODE_FOREGROUND) {
+ struct timeval now;
+
+ now = timeval_current();
+ if (timeval_elapsed2(&starttime, &now) >
+ (double)idle_timeout_sec) {
+ DEBUG(0, ("idle for %d secs, exitting\n",
+ idle_timeout_sec));
+ terminate();
+ }
+ } else {
+ starttime = timeval_current();
+ }
+ }
}
/* Main function */
@@ -1114,9 +1196,7 @@ int main(int argc, char **argv, char **envp)
smb_nscd_flush_group_cache();
/* Loop waiting for requests */
-
- while (1)
- process_loop();
+ winbindd_process_loop(server_mode);
return 0;
}
diff --git a/source3/nsswitch/winbindd_nss.h b/source3/nsswitch/winbindd_nss.h
index b6c262e466..96c4b1161c 100644
--- a/source3/nsswitch/winbindd_nss.h
+++ b/source3/nsswitch/winbindd_nss.h
@@ -28,7 +28,14 @@
#define _WINBINDD_NTDOM_H
#define WINBINDD_SOCKET_NAME "pipe" /* Name of PF_UNIX socket */
+
+/* Let the build environment override the public winbindd socket location. This
+ * is needed for launchd support -- jpeach.
+ */
+#ifndef WINBINDD_SOCKET_DIR
#define WINBINDD_SOCKET_DIR "/tmp/.winbindd" /* Name of PF_UNIX dir */
+#endif
+
#define WINBINDD_PRIV_SOCKET_SUBDIR "winbindd_privileged" /* name of subdirectory of lp_lockdir() to hold the 'privileged' pipe */
#define WINBINDD_DOMAIN_ENV "WINBINDD_DOMAIN" /* Environment variables */
#define WINBINDD_DONT_ENV "_NO_WINBINDD"
diff --git a/source3/smbd/connection.c b/source3/smbd/connection.c
index 5c31a5460b..e609b90a50 100644
--- a/source3/smbd/connection.c
+++ b/source3/smbd/connection.c
@@ -96,13 +96,15 @@ static int count_fn( TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *u
struct connections_data crec;
struct count_stat *cs = (struct count_stat *)udp;
- if (dbuf.dsize != sizeof(crec))
+ if (dbuf.dsize != sizeof(crec)) {
return 0;
+ }
memcpy(&crec, dbuf.dptr, sizeof(crec));
- if (crec.cnum == -1)
+ if (crec.cnum == -1) {
return 0;
+ }
/* If the pid was not found delete the entry from connections.tdb */
@@ -113,9 +115,19 @@ static int count_fn( TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *u
DEBUG(0,("count_fn: tdb_delete failed with error %s\n", tdb_errorstr(tdb) ));
return 0;
}
-
- if (strequal(crec.servicename, cs->name))
+
+ if (cs->name) {
+ /* We are counting all the connections to a given share. */
+ if (strequal(crec.servicename, cs->name)) {
+ cs->curr_connections++;
+ }
+ } else {
+ /* We are counting all the connections. Static registrations
+ * like the lpq backgroud process and the smbd daemon process
+ * have a cnum of -1, so won't be counted here.
+ */
cs->curr_connections++;
+ }
return 0;
}
@@ -139,15 +151,31 @@ int count_current_connections( const char *sharename, BOOL clear )
*/
if (tdb_traverse(tdb, count_fn, &cs) == -1) {
- DEBUG(0,("claim_connection: traverse of connections.tdb failed with error %s.\n",
+ DEBUG(0,("count_current_connections: traverse of connections.tdb failed with error %s\n",
tdb_errorstr(tdb) ));
- return False;
+ DEBUGADD(0, ("count_current_connections: connection count of %d might not be accurate",
+ cs.curr_connections));
}
-
+
+ /* If the traverse failed part-way through, we at least return
+ * as many connections as we had already counted. If it failed
+ * right at the start, we will return 0, which is about all we
+ * can do anywway.
+ */
+
return cs.curr_connections;
}
/****************************************************************************
+ Count the number of connections open across all shares.
+****************************************************************************/
+
+int count_all_current_connections(void)
+{
+ return count_current_connections(NULL, True /* clear stale entries */);
+}
+
+/****************************************************************************
Claim an entry in the connections database.
****************************************************************************/
diff --git a/source3/smbd/server.c b/source3/smbd/server.c
index 255f9d0c65..78f9779cfc 100644
--- a/source3/smbd/server.c
+++ b/source3/smbd/server.c
@@ -4,6 +4,7 @@
Copyright (C) Andrew Tridgell 1992-1998
Copyright (C) Martin Pool 2002
Copyright (C) Jelmer Vernooij 2002-2003
+ Copyright (C) James Peach 2007
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -21,6 +22,7 @@
*/
#include "includes.h"
+#include "smb_launchd.h"
static_decl_rpc;
@@ -296,39 +298,13 @@ static BOOL allowable_number_of_smbd_processes(void)
return num_children < max_processes;
}
-/****************************************************************************
- Open the socket communication.
-****************************************************************************/
-
-static BOOL open_sockets_smbd(enum smb_server_mode server_mode, const char *smb_ports)
+static int init_sockets_smbd(const char *smb_ports,
+ int fd_listenset[FD_SETSIZE])
{
int num_interfaces = iface_count();
+ char * ports;
int num_sockets = 0;
- int fd_listenset[FD_SETSIZE];
- fd_set listen_set;
- int s;
- int maxfd = 0;
- int i;
- char *ports;
-
- if (server_mode == SERVER_MODE_INETD) {
- return open_sockets_inetd();
- }
-
-#ifdef HAVE_ATEXIT
- {
- static int atexit_set;
- if(atexit_set == 0) {
- atexit_set=1;
- atexit(killkids);
- }
- }
-#endif
-
- /* Stop zombies */
- CatchSignal(SIGCLD, sig_cld);
-
- FD_ZERO(&listen_set);
+ int i, s;
/* use a reasonable default set of ports - listing on 445 and 139 */
if (!smb_ports) {
@@ -356,7 +332,7 @@ static BOOL open_sockets_smbd(enum smb_server_mode server_mode, const char *smb_
const char *ptr;
if(ifip == NULL) {
- DEBUG(0,("open_sockets_smbd: interface %d has NULL IP address !\n", i));
+ DEBUG(0,("init_sockets_smbd: interface %d has NULL IP address !\n", i));
continue;
}
@@ -367,7 +343,7 @@ static BOOL open_sockets_smbd(enum smb_server_mode server_mode, const char *smb_
}
s = fd_listenset[num_sockets] = open_socket_in(SOCK_STREAM, port, 0, ifip->s_addr, True);
if(s == -1)
- return False;
+ return 0;
/* ready to listen */
set_socket_options(s,"SO_KEEPALIVE");
@@ -379,15 +355,13 @@ static BOOL open_sockets_smbd(enum smb_server_mode server_mode, const char *smb_
if (listen(s, SMBD_LISTEN_BACKLOG) == -1) {
DEBUG(0,("listen: %s\n",strerror(errno)));
close(s);
- return False;
+ return 0;
}
- FD_SET(s,&listen_set);
- maxfd = MAX( maxfd, s);
num_sockets++;
if (num_sockets >= FD_SETSIZE) {
- DEBUG(0,("open_sockets_smbd: Too many sockets to bind to\n"));
- return False;
+ DEBUG(0,("init_sockets_smbd: Too many sockets to bind to\n"));
+ return 0;
}
}
}
@@ -407,7 +381,7 @@ static BOOL open_sockets_smbd(enum smb_server_mode server_mode, const char *smb_
s = open_socket_in(SOCK_STREAM, port, 0,
interpret_addr(lp_socket_address()),True);
if (s == -1)
- return(False);
+ return 0;
/* ready to listen */
set_socket_options(s,"SO_KEEPALIVE");
@@ -417,26 +391,122 @@ static BOOL open_sockets_smbd(enum smb_server_mode server_mode, const char *smb_
set_blocking(s,False);
if (listen(s, SMBD_LISTEN_BACKLOG) == -1) {
- DEBUG(0,("open_sockets_smbd: listen: %s\n",
+ DEBUG(0,("init_sockets_smbd: listen: %s\n",
strerror(errno)));
close(s);
- return False;
+ return 0;
}
fd_listenset[num_sockets] = s;
- FD_SET(s,&listen_set);
- maxfd = MAX( maxfd, s);
-
num_sockets++;
if (num_sockets >= FD_SETSIZE) {
- DEBUG(0,("open_sockets_smbd: Too many sockets to bind to\n"));
- return False;
+ DEBUG(0,("init_sockets_smbd: Too many sockets to bind to\n"));
+ return 0;
}
}
}
SAFE_FREE(ports);
+ return num_sockets;
+}
+
+static int init_sockets_launchd(const struct smb_launch_info *linfo,
+ const char * smb_ports,
+ int fd_listenset[FD_SETSIZE])
+{
+ int num_sockets;
+ int i;
+
+ /* The launchd service configuration does not have to provide sockets,
+ * even though it's basically useless without it.
+ */
+ if (!linfo->num_sockets) {
+ return init_sockets_smbd(smb_ports, fd_listenset);
+ }
+
+ /* Make sure we don't get more sockets than we can handle. */
+ num_sockets = MIN(FD_SETSIZE, linfo->num_sockets);
+ memcpy(fd_listenset, linfo->socket_list, num_sockets * sizeof(int));
+
+ /* Get the sockets ready. This could be hoisted into
+ * open_sockets_smbd(), but the order of socket operations might
+ * matter for some platforms, so this approach seems less risky.
+ * --jpeach
+ */
+ for (i = 0; i < num_sockets; ++i) {
+ set_socket_options(fd_listenset[i], "SO_KEEPALIVE");
+ set_socket_options(fd_listenset[i], user_socket_options);
+
+ /* Set server socket to non-blocking for the accept. */
+ set_blocking(fd_listenset[i], False);
+ }
+
+ return num_sockets;
+}
+
+/****************************************************************************
+ Open the socket communication.
+****************************************************************************/
+
+static BOOL open_sockets_smbd(enum smb_server_mode server_mode, const char *smb_ports)
+{
+ int num_sockets = 0;
+ int fd_listenset[FD_SETSIZE];
+ fd_set listen_set;
+ int s;
+ int maxfd = 0;
+ int i;
+ struct timeval idle_timeout = {0, 0};
+ struct smb_launch_info linfo;
+
+ if (server_mode == SERVER_MODE_INETD) {
+ return open_sockets_inetd();
+ }
+
+#ifdef HAVE_ATEXIT
+ {
+ static int atexit_set;
+ if(atexit_set == 0) {
+ atexit_set=1;
+ atexit(killkids);
+ }
+ }
+#endif
+
+ /* Stop zombies */
+ CatchSignal(SIGCLD, sig_cld);
+
+ FD_ZERO(&listen_set);
+
+ /* At this point, it doesn't matter what daemon mode we are in, we
+ * need some sockets to listen on. If we are in FOREGROUND mode,
+ * the launchd checkin might succeed. If we are in DAEMON or
+ * INTERACTIVE modes, it will fail and we will open the sockets
+ * ourselves.
+ */
+ if (smb_launchd_checkin(&linfo)) {
+ /* We are running under launchd and launchd has
+ * opened some sockets for us.
+ */
+ num_sockets = init_sockets_launchd(&linfo,
+ smb_ports,
+ fd_listenset);
+ idle_timeout.tv_sec = linfo.idle_timeout_secs;
+ smb_launchd_checkout(&linfo);
+ } else {
+ num_sockets = init_sockets_smbd(smb_ports,
+ fd_listenset);
+ }
+
+ if (num_sockets == 0) {
+ return False;
+ }
+
+ for (i = 0; i < num_sockets; ++i) {
+ FD_SET(fd_listenset[i], &listen_set);
+ maxfd = MAX(maxfd, fd_listenset[i]);
+ }
/* Listen to messages */
@@ -476,8 +546,9 @@ static BOOL open_sockets_smbd(enum smb_server_mode server_mode, const char *smb_
memcpy((char *)&lfds, (char *)&listen_set,
sizeof(listen_set));
-
- num = sys_select(maxfd+1,&lfds,NULL,NULL,NULL);
+
+ num = sys_select(maxfd+1,&lfds,NULL,NULL,
+ idle_timeout.tv_sec ? &idle_timeout : NULL);
if (num == -1 && errno == EINTR) {
if (got_sig_term) {
@@ -494,7 +565,15 @@ static BOOL open_sockets_smbd(enum smb_server_mode server_mode, const char *smb_
continue;
}
-
+
+ /* If the idle timeout fired and we don't have any connected
+ * users, exit gracefully. We should be running under a process
+ * controller that will restart us if necessry.
+ */
+ if (num == 0 && count_all_current_connections() == 0) {
+ exit_server_cleanly("idle timeout");
+ }
+
/* check if we need to reload services */
check_reload(time(NULL));