mirror of
https://github.com/samba-team/samba.git
synced 2024-12-22 13:34:15 +03:00
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 fc8589a337
)
This commit is contained in:
parent
8a22b1f0ea
commit
44f5211c17
@ -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) \
|
||||
|
@ -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=""
|
||||
|
43
source3/include/smb_launchd.h
Normal file
43
source3/include/smb_launchd.h
Normal file
@ -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);
|
242
source3/lib/launchd.c
Normal file
242
source3/lib/launchd.c
Normal file
@ -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) */
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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"
|
||||
|
@ -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,14 +151,30 @@ 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.
|
||||
****************************************************************************/
|
||||
|
@ -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));
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user