* Citadel "system dependent" stuff.
*
* Here's where we (hopefully) have most parts of the Citadel server that
- * would need to be altered to run the server in a non-POSIX environment.
- *
- * If we ever port to a different platform and either have multiple
- * variants of this file or simply load it up with #ifdefs.
+ * might need tweaking when run on different operating system variants.
*
- * Copyright (c) 1987-2011 by the citadel.org team
+ * Copyright (c) 1987-2021 by the citadel.org team
*
* This program is open source software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 3.
#include "sysdep.h"
#include <stdlib.h>
#include <unistd.h>
-#include <stdio.h>
-#include <fcntl.h>
-#include <ctype.h>
-#include <signal.h>
-#include <sys/types.h>
#include <sys/stat.h>
-#include <sys/wait.h>
-#include <sys/socket.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
#include <syslog.h>
#include <sys/syslog.h>
-
-#if TIME_WITH_SYS_TIME
-# include <sys/time.h>
-# include <time.h>
-#else
-# if HAVE_SYS_TIME_H
-# include <sys/time.h>
-# else
-# include <time.h>
-# endif
-#endif
-
-#include <limits.h>
-#include <sys/resource.h>
+#include <netdb.h>
+#include <sys/un.h>
+#include <sys/types.h>
+#include <sys/socket.h>
#include <netinet/in.h>
+#include <arpa/inet.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
-#include <netdb.h>
-#include <sys/un.h>
-#include <string.h>
-#include <pwd.h>
-#include <errno.h>
-#include <stdarg.h>
-#include <grp.h>
#define SHOW_ME_VAPPEND_PRINTF
#include <libcitadel.h>
-#include "citadel.h"
-#include "server.h"
-#include "sysdep_decls.h"
#include "citserver.h"
-#include "support.h"
#include "config.h"
-#include "database.h"
-#include "housekeeping.h"
+#include "ctdl_module.h"
+#include "sysdep_decls.h"
#include "modules/crypto/serv_crypto.h" /* Needed for init_ssl, client_write_ssl, client_read_ssl, destruct_ssl */
-#include "ecrash.h"
+#include "housekeeping.h"
#include "context.h"
-#ifdef HAVE_SYS_SELECT_H
-#include <sys/select.h>
-#endif
-
-#include "ctdl_module.h"
-#include "threads.h"
-#include "user_ops.h"
-#include "control.h"
-
-
/*
* Signal handler to shut down the server.
*/
volatile int restart_server = 0;
volatile int running_as_daemon = 0;
+
static RETSIGTYPE signal_cleanup(int signum) {
- syslog(LOG_DEBUG, "Caught signal %d; shutting down.", signum);
+ syslog(LOG_DEBUG, "sysdep: caught signal %d; shutting down.", signum);
exit_signal = signum;
server_shutting_down = 1;
}
+
static RETSIGTYPE signal_exit(int signum) {
exit(1);
}
-
/*
* Some initialization stuff...
*/
init_ssl();
#endif
- /*
- * Set up a place to put thread-specific data.
- * We only need a single pointer per thread - it points to the
- * CitContext structure (in the ContextList linked list) of the
- * session to which the calling thread is currently bound.
- */
- if (pthread_key_create(&MyConKey, NULL) != 0) {
- syslog(LOG_CRIT, "Can't create TSD key: %s", strerror(errno));
+ if (pthread_key_create(&ThreadKey, NULL) != 0) { // TSD for threads
+ syslog(LOG_ERR, "pthread_key_create() : %m");
+ abort();
+ }
+
+ if (pthread_key_create(&MyConKey, NULL) != 0) { // TSD for sessions
+ syslog(LOG_CRIT, "sysdep: can't create TSD key: %m");
+ abort();
}
/*
* port_number port number to bind
* queue_len number of incoming connections to allow in the queue
*/
-int ctdl_tcp_server(char *ip_addr, int port_number, int queue_len, char *errormessage)
+int ctdl_tcp_server(char *ip_addr, int port_number, int queue_len)
{
struct protoent *p;
struct sockaddr_in6 sin6;
{
ip_version = 4;
if (inet_pton(AF_INET, ip_addr, &sin4.sin_addr) <= 0) {
- snprintf(errormessage, SIZ,
- "Error binding to [%s] : %s", ip_addr, strerror(errno)
- );
- syslog(LOG_ALERT, "%s", errormessage);
+ syslog(LOG_ALERT, "tcpserver: inet_pton: %m");
return (-1);
}
}
{
ip_version = 6;
if (inet_pton(AF_INET6, ip_addr, &sin6.sin6_addr) <= 0) {
- snprintf(errormessage, SIZ,
- "Error binding to [%s] : %s", ip_addr, strerror(errno)
- );
- syslog(LOG_ALERT, "%s", errormessage);
+ syslog(LOG_ALERT, "tcpserver: inet_pton: %m");
return (-1);
}
}
if (port_number == 0) {
- snprintf(errormessage, SIZ, "Can't start: no port number specified.");
- syslog(LOG_ALERT, "%s", errormessage);
+ syslog(LOG_ALERT, "tcpserver: no port number was specified");
return (-1);
}
sin6.sin6_port = htons((u_short) port_number);
sin4.sin_port = htons((u_short) port_number);
p = getprotobyname("tcp");
+ if (p == NULL) {
+ syslog(LOG_ALERT, "tcpserver: getprotobyname: %m");
+ return (-1);
+ }
s = socket( ((ip_version == 6) ? PF_INET6 : PF_INET), SOCK_STREAM, (p->p_proto));
if (s < 0) {
- snprintf(errormessage, SIZ,
- "Can't create a listening socket: %s", strerror(errno)
- );
- syslog(LOG_ALERT, "%s", errormessage);
+ syslog(LOG_ALERT, "tcpserver: socket: %m");
return (-1);
}
/* Set some socket options that make sense. */
}
if (b < 0) {
- snprintf(errormessage, SIZ,
- "Can't bind: %s", strerror(errno)
- );
- syslog(LOG_ALERT, "%s", errormessage);
+ syslog(LOG_ALERT, "tcpserver: bind: %m");
return (-1);
}
fcntl(s, F_SETFL, O_NONBLOCK);
if (listen(s, ((queue_len >= 5) ? queue_len : 5) ) < 0) {
- snprintf(errormessage, SIZ,
- "Can't listen: %s", strerror(errno)
- );
- syslog(LOG_ALERT, "%s", errormessage);
+ syslog(LOG_ALERT, "tcpserver: listen: %m");
return (-1);
}
return (s);
}
-
-
-
/*
* Create a Unix domain socket and listen on it
*/
-int ctdl_uds_server(char *sockpath, int queue_len, char *errormessage)
+int ctdl_uds_server(char *sockpath, int queue_len)
{
struct sockaddr_un addr;
int s;
i = unlink(sockpath);
if ((i != 0) && (errno != ENOENT)) {
- snprintf(errormessage, SIZ, "citserver: can't unlink %s: %s",
- sockpath, strerror(errno)
- );
- syslog(LOG_EMERG, "%s", errormessage);
+ syslog(LOG_ERR, "udsserver: %m");
return(-1);
}
s = socket(AF_UNIX, SOCK_STREAM, 0);
if (s < 0) {
- snprintf(errormessage, SIZ,
- "citserver: Can't create a socket: %s",
- strerror(errno));
- syslog(LOG_EMERG, "%s", errormessage);
+ syslog(LOG_ERR, "udsserver: socket: %m");
return(-1);
}
if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
- snprintf(errormessage, SIZ,
- "citserver: Can't bind: %s",
- strerror(errno));
- syslog(LOG_EMERG, "%s", errormessage);
+ syslog(LOG_ERR, "udsserver: bind: %m");
return(-1);
}
/* set to nonblock - we need this for some obscure situations */
if (fcntl(s, F_SETFL, O_NONBLOCK) < 0) {
- snprintf(errormessage, SIZ,
- "citserver: Can't set socket to non-blocking: %s",
- strerror(errno));
- syslog(LOG_EMERG, "%s", errormessage);
+ syslog(LOG_ERR, "udsserver: fcntl: %m");
close(s);
return(-1);
}
if (listen(s, actual_queue_len) < 0) {
- snprintf(errormessage, SIZ,
- "citserver: Can't listen: %s",
- strerror(errno));
- syslog(LOG_EMERG, "%s", errormessage);
+ syslog(LOG_ERR, "udsserver: listen: %m");
return(-1);
}
}
-
/*
* The following functions implement output buffering on operating systems which
* support it (such as Linux and various BSD flavors).
FlushStrBuf(CCC->ReadBuf);
CCC->RecvBuf->ReadWritePointer = NULL;
-
}
*/
if (!CCC) return;
if (CCC->client_socket <= 0) return;
- syslog(LOG_DEBUG, "Closing socket %d", CCC->client_socket);
-
+ syslog(LOG_DEBUG, "sysdep: closing socket %d", CCC->client_socket);
close(CCC->client_socket);
CCC->client_socket = -1 ;
}
-
-
/*
* client_write() ... Send binary data to the client.
*/
Ctx = CC;
-#ifdef BIGBAD_IODBG
- {
- int rv = 0;
- char fn [SIZ];
- FILE *fd;
-
- snprintf(fn, SIZ, "/tmp/foolog_%s.%d", Ctx->ServiceName, Ctx->cs_pid);
-
- fd = fopen(fn, "a+");
- if (fd)
- {
- fprintf(fd, "Sending: BufSize: %d BufContent: [",
- nbytes);
- rv = fwrite(buf, nbytes, 1, fd);
- fprintf(fd, "]\n");
- fclose(fd);
- }
- }
-#endif
-// flush_client_inbuf();
if (Ctx->redirect_buffer != NULL) {
StrBufAppendBufPlain(Ctx->redirect_buffer,
buf, nbytes, 0);
if (select(1, NULL, &wset, NULL, NULL) == -1) {
if (errno == EINTR)
{
- syslog(LOG_DEBUG, "client_write(%d bytes) select() interrupted.",
- nbytes-bytes_written
- );
+ syslog(LOG_DEBUG, "sysdep: client_write(%d bytes) select() interrupted.", nbytes-bytes_written);
if (server_shutting_down) {
CC->kill_me = KILLME_SELECT_INTERRUPTED;
return (-1);
continue;
}
} else {
- syslog(LOG_ERR,
- "client_write(%d bytes) select failed: %s (%d)",
- nbytes - bytes_written,
- strerror(errno), errno
- );
- cit_backtrace();
+ syslog(LOG_ERR, "sysdep: client_write(%d bytes) select failed: %m", nbytes - bytes_written);
client_close();
Ctx->kill_me = KILLME_SELECT_FAILED;
return -1;
retval = write(Ctx->client_socket, &buf[bytes_written], nbytes - bytes_written);
if (retval < 1) {
- syslog(LOG_ERR,
- "client_write(%d bytes) failed: %s (%d)",
- nbytes - bytes_written,
- strerror(errno), errno
- );
- cit_backtrace();
+ syslog(LOG_ERR, "sysdep: client_write(%d bytes) failed: %m", nbytes - bytes_written);
client_close();
Ctx->kill_me = KILLME_WRITE_FAILED;
return -1;
#ifdef HAVE_OPENSSL
if (CCC->redirect_ssl) {
-#ifdef BIGBAD_IODBG
- int rv = 0;
- char fn [SIZ];
- FILE *fd;
-
- snprintf(fn, SIZ, "/tmp/foolog_%s.%d", CCC->ServiceName, CCC->cs_pid);
-
- fd = fopen(fn, "a+");
- fprintf(fd, "Reading BLOB: BufSize: %d ",
- bytes);
- rv = fwrite(ChrPtr(Target), StrLength(Target), 1, fd);
- fprintf(fd, "]\n");
-
-
- fclose(fd);
-#endif
retval = client_read_sslblob(Target, bytes, timeout);
if (retval < 0) {
- syslog(LOG_CRIT, "client_read_blob() failed");
+ syslog(LOG_ERR, "sysdep: client_read_blob() failed");
}
-#ifdef BIGBAD_IODBG
- snprintf(fn, SIZ, "/tmp/foolog_%s.%d", CCC->ServiceName, CCC->cs_pid);
-
- fd = fopen(fn, "a+");
- fprintf(fd, "Read: %d BufContent: [",
- StrLength(Target));
- rv = fwrite(ChrPtr(Target), StrLength(Target), 1, fd);
- fprintf(fd, "]\n");
-
-
- fclose(fd);
-#endif
}
else
#endif
{
-#ifdef BIGBAD_IODBG
- int rv = 0;
- char fn [SIZ];
- FILE *fd;
-
- snprintf(fn, SIZ, "/tmp/foolog_%s.%d", CCC->ServiceName, CCC->cs_pid);
-
- fd = fopen(fn, "a+");
- fprintf(fd, "Reading BLOB: BufSize: %d ",
- bytes);
- rv = fwrite(ChrPtr(Target), StrLength(Target), 1, fd);
- fprintf(fd, "]\n");
-
-
- fclose(fd);
-#endif
retval = StrBufReadBLOBBuffered(Target,
CCC->RecvBuf.Buf,
&CCC->RecvBuf.ReadWritePointer,
1,
bytes,
O_TERM,
- &Error);
+ &Error
+ );
if (retval < 0) {
- syslog(LOG_CRIT, "client_read_blob() failed: %s", Error);
+ syslog(LOG_ERR, "sysdep: client_read_blob() failed: %s", Error);
client_close();
return retval;
}
-#ifdef BIGBAD_IODBG
- snprintf(fn, SIZ, "/tmp/foolog_%s.%d", CCC->ServiceName, CCC->cs_pid);
-
- fd = fopen(fn, "a+");
- fprintf(fd, "Read: %d BufContent: [",
- StrLength(Target));
- rv = fwrite(ChrPtr(Target), StrLength(Target), 1, fd);
- fprintf(fd, "]\n");
- fclose(fd);
-#endif
}
return retval;
}
StrBufAppendBufPlain(Target, pch, len, 0);
FlushStrBuf(CCC->RecvBuf.Buf);
CCC->RecvBuf.ReadWritePointer = NULL;
-#ifdef BIGBAD_IODBG
- {
- int rv = 0;
- char fn [SIZ];
- FILE *fd;
-
- snprintf(fn, SIZ, "/tmp/foolog_%s.%d", CCC->ServiceName, CCC->cs_pid);
-
- fd = fopen(fn, "a+");
- fprintf(fd, "Read: BufSize: %d BufContent: [",
- StrLength(Target));
- rv = fwrite(ChrPtr(Target), StrLength(Target), 1, fd);
- fprintf(fd, "]\n");
-
-
- fclose(fd);
- }
-#endif
-
return StrLength(Target);
}
return rc;
*/
INLINE int client_read(char *buf, int bytes)
{
- return(client_read_to(buf, bytes, config.c_sleeping));
+ return(client_read_to(buf, bytes, CtdlGetConfigInt("c_sleeping")));
}
int CtdlClientGetLine(StrBuf *Target)
FlushStrBuf(Target);
#ifdef HAVE_OPENSSL
if (CCC->redirect_ssl) {
-#ifdef BIGBAD_IODBG
- char fn [SIZ];
- FILE *fd;
- int len = 0;
- int rlen = 0;
- int nlen = 0;
- int nrlen = 0;
- const char *pch;
-
- snprintf(fn, SIZ, "/tmp/foolog_%s.%d", CCC->ServiceName, CCC->cs_pid);
-
- fd = fopen(fn, "a+");
- pch = ChrPtr(CCC->RecvBuf.Buf);
- len = StrLength(CCC->RecvBuf.Buf);
- if (CCC->RecvBuf.ReadWritePointer != NULL)
- rlen = CCC->RecvBuf.ReadWritePointer - pch;
- else
- rlen = 0;
-
-/* fprintf(fd, "\n\n\nBufSize: %d BufPos: %d \nBufContent: [%s]\n\n_____________________\n",
- len, rlen, pch);
-*/
- fprintf(fd, "\n\n\nSSL1: BufSize: %d BufPos: %d \n_____________________\n",
- len, rlen);
-#endif
- rc = client_readline_sslbuffer(Target,
- CCC->RecvBuf.Buf,
- &CCC->RecvBuf.ReadWritePointer,
- 1);
-#ifdef BIGBAD_IODBG
- pch = ChrPtr(CCC->RecvBuf.Buf);
- nlen = StrLength(CCC->RecvBuf.Buf);
- if (CCC->RecvBuf.ReadWritePointer != NULL)
- nrlen = CCC->RecvBuf.ReadWritePointer - pch;
- else
- nrlen = 0;
-/*
- fprintf(fd, "\n\n\nBufSize: was: %d is: %d BufPos: was: %d is: %d \nBufContent: [%s]\n\n_____________________\n",
- len, nlen, rlen, nrlen, pch);
-*/
- fprintf(fd, "\n\n\nSSL2: BufSize: was: %d is: %d BufPos: was: %d is: %d \n",
- len, nlen, rlen, nrlen);
-
- fprintf(fd, "SSL3: Read: BufSize: %d BufContent: [%s]\n\n*************\n",
- StrLength(Target), ChrPtr(Target));
- fclose(fd);
-
- if (rc < 0) {
- syslog(LOG_CRIT, "CtdlClientGetLine() failed");
- }
-#endif
+ rc = client_readline_sslbuffer(Target, CCC->RecvBuf.Buf, &CCC->RecvBuf.ReadWritePointer, 1);
return rc;
}
else
#endif
{
-#ifdef BIGBAD_IODBG
- char fn [SIZ];
- FILE *fd;
- int len, rlen, nlen, nrlen;
- const char *pch;
-
- snprintf(fn, SIZ, "/tmp/foolog_%s.%d", CCC->ServiceName, CCC->cs_pid);
-
- fd = fopen(fn, "a+");
- pch = ChrPtr(CCC->RecvBuf.Buf);
- len = StrLength(CCC->RecvBuf.Buf);
- if (CCC->RecvBuf.ReadWritePointer != NULL)
- rlen = CCC->RecvBuf.ReadWritePointer - pch;
- else
- rlen = 0;
-
-/* fprintf(fd, "\n\n\nBufSize: %d BufPos: %d \nBufContent: [%s]\n\n_____________________\n",
- len, rlen, pch);
-*/
- fprintf(fd, "\n\n\nBufSize: %d BufPos: %d \n_____________________\n",
- len, rlen);
-#endif
rc = StrBufTCP_read_buffered_line_fast(Target,
CCC->RecvBuf.Buf,
&CCC->RecvBuf.ReadWritePointer,
&CCC->client_socket,
5,
1,
- &Error);
-
-#ifdef BIGBAD_IODBG
- pch = ChrPtr(CCC->RecvBuf.Buf);
- nlen = StrLength(CCC->RecvBuf.Buf);
- if (CCC->RecvBuf.ReadWritePointer != NULL)
- nrlen = CCC->RecvBuf.ReadWritePointer - pch;
- else
- nrlen = 0;
-/*
- fprintf(fd, "\n\n\nBufSize: was: %d is: %d BufPos: was: %d is: %d \nBufContent: [%s]\n\n_____________________\n",
- len, nlen, rlen, nrlen, pch);
-*/
- fprintf(fd, "\n\n\nBufSize: was: %d is: %d BufPos: was: %d is: %d \n",
- len, nlen, rlen, nrlen);
-
- fprintf(fd, "Read: BufSize: %d BufContent: [%s]\n\n*************\n",
- StrLength(Target), ChrPtr(Target));
- fclose(fd);
-
- if ((rc < 0) && (Error != NULL)) {
- syslog(LOG_CRIT, "CtdlClientGetLine() failed: %s", Error);
- }
-#endif
+ &Error
+ );
return rc;
}
}
/*
* Cleanup any contexts that are left lying around
*/
-
-
-void close_masters (void)
-{
+void close_masters(void) {
struct ServiceFunctionHook *serviceptr;
const char *Text;
for (serviceptr = ServiceHookTable; serviceptr != NULL;
serviceptr = serviceptr->next ) {
- if (serviceptr->tcp_port > 0)
- {
- if (serviceptr->msock == -1)
+ if (serviceptr->tcp_port > 0) {
+ if (serviceptr->msock == -1) {
Text = "not closing again";
- else
+ }
+ else {
Text = "Closing";
-
- syslog(LOG_INFO, "%s %d listener on port %d\n",
+ }
+ syslog(LOG_INFO, "sysdep: %s %d listener on port %d",
Text,
serviceptr->msock,
- serviceptr->tcp_port);
+ serviceptr->tcp_port
+ );
serviceptr->tcp_port = 0;
}
- if (serviceptr->sockpath != NULL)
- {
- if (serviceptr->msock == -1)
+ if (serviceptr->sockpath != NULL) {
+ if (serviceptr->msock == -1) {
Text = "not closing again";
- else
+ }
+ else {
Text = "Closing";
-
- syslog(LOG_INFO, "%s %d listener on '%s'\n",
+ }
+ syslog(LOG_INFO, "sysdep: %s %d listener on '%s'",
Text,
serviceptr->msock,
- serviceptr->sockpath);
+ serviceptr->sockpath
+ );
}
- if (serviceptr->msock != -1)
- {
+ if (serviceptr->msock != -1) {
close(serviceptr->msock);
serviceptr->msock = -1;
}
* The system-dependent part of master_cleanup() - close the master socket.
*/
void sysdep_master_cleanup(void) {
-
close_masters();
-
context_cleanup();
-
#ifdef HAVE_OPENSSL
destruct_ssl();
#endif
- CtdlDestroyProtoHooks();
- CtdlDestroyDeleteHooks();
- CtdlDestroyXmsgHooks();
- CtdlDestroyNetprocHooks();
- CtdlDestroyUserHooks();
- CtdlDestroyMessageHook();
- CtdlDestroyCleanupHooks();
- CtdlDestroyFixedOutputHooks();
- CtdlDestroySessionHooks();
- CtdlDestroyServiceHook();
- CtdlDestroyRoomHooks();
- CtdlDestroySearchHooks();
- CtdlDestroyDebugTable();
- #ifdef HAVE_BACKTRACE
-/// eCrash_Uninit();
- #endif
}
pid_t child = 0;
FILE *fp;
int do_restart = 0;
-
current_child = 0;
+ //if (chdir(ctdl_run_dir) != 0) {
+ //syslog(LOG_ERR, "%s: %m", ctdl_run_dir);
+ //}
+
/* Close stdin/stdout/stderr and replace them with /dev/null.
* We don't just call close() because we don't want these fd's
* to be reused for other files.
*/
- if (chdir(ctdl_run_dir) != 0)
- syslog(LOG_EMERG,
- "unable to change into directory [%s]: %s",
- ctdl_run_dir, strerror(errno));
-
child = fork();
if (child != 0) {
exit(0);
setsid();
umask(0);
- if ((freopen("/dev/null", "r", stdin) != stdin) ||
- (freopen("/dev/null", "w", stdout) != stdout) ||
- (freopen("/dev/null", "w", stderr) != stderr))
- syslog(LOG_EMERG,
- "unable to reopen stdin/out/err %s",
- strerror(errno));
-
+ if ( (freopen("/dev/null", "r", stdin) != stdin) ||
+ (freopen("/dev/null", "w", stdout) != stdout) ||
+ (freopen("/dev/null", "w", stderr) != stderr)
+ ) {
+ syslog(LOG_ERR, "sysdep: unable to reopen stdio: %m");
+ }
do {
current_child = fork();
-
signal(SIGTERM, graceful_shutdown);
-
if (current_child < 0) {
perror("fork");
exit(errno);
}
-
else if (current_child == 0) {
return; /* continue starting citadel. */
}
-
else {
fp = fopen(file_pid_file, "w");
if (fp != NULL) {
}
waitpid(current_child, &status, 0);
}
-
nFireUpsNonRestart = nFireUps;
/* Exit code 0 means the watcher should exit */
}
-
-void checkcrash(void)
-{
- if (nFireUpsNonRestart != nFireUps)
- {
+void checkcrash(void) {
+ if (nFireUpsNonRestart != nFireUps) {
StrBuf *CrashMail;
-
CrashMail = NewStrBuf();
- syslog(LOG_ALERT, "Posting crash message\n");
+ syslog(LOG_ALERT, "sysdep: posting crash message");
StrBufPrintf(CrashMail,
" \n"
" The Citadel server process (citserver) terminated unexpectedly."
*/
int convert_login(char NameToConvert[]) {
struct passwd *pw;
- int a;
+ unsigned int a;
pw = getpwnam(NameToConvert);
if (pw == NULL) {
}
+void HuntBadSession(void) {
+ int highest;
+ CitContext *ptr;
+ fd_set readfds;
+ struct timeval tv;
+ struct ServiceFunctionHook *serviceptr;
+
+ /* Next, add all of the client sockets. */
+ begin_critical_section(S_SESSION_TABLE);
+ for (ptr = ContextList; ptr != NULL; ptr = ptr->next) {
+ if ((ptr->state == CON_SYS) && (ptr->client_socket == 0))
+ continue;
+ /* Initialize the fdset. */
+ FD_ZERO(&readfds);
+ highest = 0;
+ tv.tv_sec = 0; /* wake up every second if no input */
+ tv.tv_usec = 0;
+
+ /* Don't select on dead sessions, only truly idle ones */
+ if ( (ptr->state == CON_IDLE)
+ && (ptr->kill_me == 0)
+ && (ptr->client_socket > 0)
+ ) {
+ FD_SET(ptr->client_socket, &readfds);
+ if (ptr->client_socket > highest)
+ highest = ptr->client_socket;
+
+ if ((select(highest + 1, &readfds, NULL, NULL, &tv) < 0) && (errno == EBADF))
+ {
+ /* Gotcha! */
+ syslog(LOG_ERR,
+ "sysdep: killing session CC[%d] bad FD: [%d] User[%s] Host[%s:%s]",
+ ptr->cs_pid,
+ ptr->client_socket,
+ ptr->curr_user,
+ ptr->cs_host,
+ ptr->cs_addr
+ );
+ ptr->kill_me = 1;
+ ptr->client_socket = -1;
+ break;
+ }
+ }
+ }
+ end_critical_section(S_SESSION_TABLE);
+
+ /* First, add the various master sockets to the fdset. */
+ for (serviceptr = ServiceHookTable; serviceptr != NULL; serviceptr = serviceptr->next ) {
+
+ /* Initialize the fdset. */
+ highest = 0;
+ tv.tv_sec = 0; /* wake up every second if no input */
+ tv.tv_usec = 0;
+
+ FD_SET(serviceptr->msock, &readfds);
+ if (serviceptr->msock > highest) {
+ highest = serviceptr->msock;
+ }
+ if ((select(highest + 1, &readfds, NULL, NULL, &tv) < 0) &&
+ (errno == EBADF))
+ {
+ /* Gotcha! server socket dead? commit suicide! */
+ syslog(LOG_ERR, "sysdep: found bad FD: %d and its a server socket! Shutting Down!", serviceptr->msock);
+ server_shutting_down = 1;
+ break;
+ }
+ }
+}
+
/*
* This loop just keeps going and going and going...
CitContext *con = NULL; /* Temporary context pointer */
int i;
+ pthread_mutex_lock(&ThreadCountMutex);
++num_workers;
+ pthread_mutex_unlock(&ThreadCountMutex);
while (!server_shutting_down) {
- /* make doubly sure we're not holding any stale db handles
- * which might cause a deadlock.
- */
+ /* make doubly sure we're not holding any stale db handles * which might cause a deadlock */
cdb_check_handles();
do_select: force_purge = 0;
bind_me = NULL; /* Which session shall we handle? */
*/
if (retval < 0) {
if (errno == EBADF) {
- syslog(LOG_NOTICE, "select() failed: (%s)\n", strerror(errno));
+ syslog(LOG_ERR, "sysdep: select() failed: %m");
+ HuntBadSession();
goto do_select;
}
if (errno != EINTR) {
- syslog(LOG_EMERG, "Exiting (%s)\n", strerror(errno));
+ syslog(LOG_ERR, "sysdep: exiting: %m");
server_shutting_down = 1;
continue;
} else {
-#if 0
- syslog(LOG_DEBUG, "Interrupted select()\n");
-#endif
if (server_shutting_down) {
--num_workers;
return(NULL);
}
}
- /* Next, check to see if it's a new client connecting * on a master socket. */
+ /* Next, check to see if it's a new client connecting on a master socket. */
else if ((retval > 0) && (!server_shutting_down)) for (serviceptr = ServiceHookTable; serviceptr != NULL; serviceptr = serviceptr->next) {
if (FD_ISSET(serviceptr->msock, &readfds)) {
ssock = accept(serviceptr->msock, NULL, 0);
if (ssock >= 0) {
- syslog(LOG_DEBUG, "New client socket %d", ssock);
+ syslog(LOG_DEBUG, "sysdep: new client socket %d", ssock);
/* The master socket is non-blocking but the client
* sockets need to be blocking, otherwise certain
* operations barf on FreeBSD. Not a fatal error.
*/
if (fcntl(ssock, F_SETFL, 0) < 0) {
- syslog(LOG_EMERG,
- "citserver: Can't set socket to blocking: %s\n",
- strerror(errno));
+ syslog(LOG_ERR, "sysdep: Can't set socket to blocking: %m");
}
/* New context will be created already
con->h_greeting_function = serviceptr->h_greeting_function;
con->ServiceName = serviceptr->ServiceName;
- /* Determine whether it's a local socket */
+ /* Connections on a local client are always from the same host */
if (serviceptr->sockpath != NULL) {
- con->is_local_socket = 1;
+ con->is_local_client = 1;
}
/* Set the SO_REUSEADDR socket option */
SKIP_SELECT:
/* We're bound to a session */
+ pthread_mutex_lock(&ThreadCountMutex);
++active_workers;
+ pthread_mutex_unlock(&ThreadCountMutex);
+
if (bind_me != NULL) {
become_session(bind_me);
CC->input_waiting = 0;
}
- /* If there are asynchronous messages waiting and the
- * client supports it, do those now */
- if ((CC->is_async) && (CC->async_waiting)
- && (CC->h_async_function != NULL)) {
+ /* If there are asynchronous messages waiting and the client supports it, do those now */
+ if ((CC->is_async) && (CC->async_waiting) && (CC->h_async_function != NULL)) {
CC->h_async_function();
CC->async_waiting = 0;
}
-
+
force_purge = CC->kill_me;
become_session(NULL);
bind_me->state = CON_IDLE;
dead_session_purge(force_purge);
do_housekeeping();
+
+ pthread_mutex_lock(&ThreadCountMutex);
--active_workers;
+ if ((active_workers + CtdlGetConfigInt("c_min_workers") < num_workers) &&
+ (num_workers > CtdlGetConfigInt("c_min_workers")))
+ {
+ num_workers--;
+ pthread_mutex_unlock(&ThreadCountMutex);
+ return (NULL);
+ }
+ pthread_mutex_unlock(&ThreadCountMutex);
}
/* If control reaches this point, the server is shutting down */
+ pthread_mutex_lock(&ThreadCountMutex);
--num_workers;
+ pthread_mutex_unlock(&ThreadCountMutex);
return(NULL);
}
-
/*
* SyslogFacility()
* Translate text facility name to syslog.h defined value.