* \defgroup Webserver This contains a simple multithreaded TCP server manager. It sits around
* waiting on the specified port for incoming HTTP connections. When a
* connection is established, it calls context_loop() from context_loop.c.
- *
+ * \ingroup WebcitHttpServer
*/
/*@{*/
#include "webcit.h"
#include "webserver.h"
+#if HAVE_BACKTRACE
+#include <execinfo.h>
+#endif
+
#ifndef HAVE_SNPRINTF
int vsnprintf(char *buf, size_t max, const char *fmt, va_list argp);
#endif
int msock; /**< master listening socket */
int is_https = 0; /**< Nonzero if I am an HTTPS service */
int follow_xff = 0; /**< Follow X-Forwarded-For: header */
+int home_specified = 0; /**< did the user specify a homedir? */
extern void *context_loop(int);
extern void *housekeeping_loop(void);
extern pthread_mutex_t SessionListMutex;
extern pthread_key_t MyConKey;
+char socket_dir[PATH_MAX]; /**< where to talk to our citadel server */
+static const char editor_absolut_dir[PATH_MAX]=EDITORDIR; /**< nailed to what configure gives us. */
+static char static_dir[PATH_MAX]; /**< calculated on startup */
+char *static_dirs[]={ /**< needs same sort order as the web mapping */
+ (char*)static_dir, /** our templates on disk */
+ (char*)editor_absolut_dir /** the editor on disk */
+};
+int ndirs=2; //sizeof(static_content_dirs);//sizeof(char *);
+
+/**
+ * Subdirectories from which the client may request static content
+ */
+char *static_content_dirs[] = {
+ "static", /** static templates */
+ "tiny_mce" /** the JS editor */
+};
+
+
char *server_cookie = NULL; /**< our Cookie connection to the client */
+int http_port = PORT_NUM; /**< Port to listen on */
char *ctdlhost = DEFAULT_HOST; /**< our name */
char *ctdlport = DEFAULT_PORT; /**< our Port */
*/
ssize_t client_write(const void *buf, size_t count)
{
+ char *newptr;
+ size_t newalloc;
if (WC->burst != NULL) {
- WC->burst =
- realloc(WC->burst, (WC->burst_len + count + 2));
- memcpy(&WC->burst[WC->burst_len], buf, count);
- WC->burst_len += count;
- return (count);
+ if ((WC->burst_len + count) >= WC->burst_alloc) {
+ newalloc = (WC->burst_alloc * 2);
+ if ((WC->burst_len + count) >= newalloc) {
+ newalloc += count;
+ }
+ newptr = realloc(WC->burst, newalloc);
+ if (newptr != NULL) {
+ WC->burst = newptr;
+ WC->burst_alloc = newalloc;
+ }
+ }
+ if ((WC->burst_len + count) < WC->burst_alloc) {
+ memcpy(&WC->burst[WC->burst_len], buf, count);
+ WC->burst_len += count;
+ return (count);
+ }
+ else {
+ return(-1);
+ }
}
#ifdef HAVE_OPENSSL
if (is_https) {
WC->burst = NULL;
}
WC->burst_len = 0;
- WC->burst = malloc(SIZ);
+ WC->burst_alloc = 32768;
+ WC->burst = malloc(WC->burst_alloc);
}
the_data = WC->burst;
WC->burst_len = 0;
+ WC->burst_alloc = 0;
WC->burst = NULL;
#ifdef HAVE_ZLIB
if (retval != 1 || buf[i] == '\n' || i == (bufsiz-1))
break;
if ( (!isspace(buf[i])) && (!isprint(buf[i])) ) {
- lprintf(2, "Non printable character recieved from client\n");
+ /** Non printable character recieved from client */
return(-1);
}
}
-
- /** If we got a long line, discard characters until the newline. */
+ /** If we got a long line, discard characters until the newline. */
if (i == (bufsiz-1))
while (buf[i] != '\n' && retval == 1)
retval = client_read(sock, &buf[i], 1);
/**
- * \brief Start running as a daemon.
- * param do_close_stdio Only close stdio if set.
+ * \brief Start running as a daemon.
+ *
+ * param do_close_stdio Only close stdio if set.
*/
void start_daemon(int do_close_stdio)
{
signal(SIGHUP, SIG_IGN);
signal(SIGINT, SIG_IGN);
signal(SIGQUIT, SIG_IGN);
- if (fork() != 0)
+ if (fork() != 0) {
exit(0);
+ }
}
+/**
+ * \brief Spawn an additional worker thread into the pool.
+ */
void spawn_another_worker_thread()
{
pthread_t SessThread; /**< Thread descriptor */
pthread_t SessThread; /**< Thread descriptor */
pthread_attr_t attr; /**< Thread attributes */
int a, i; /**< General-purpose variables */
- int port = PORT_NUM; /**< Port to listen on */
char tracefile[PATH_MAX];
char ip_addr[256];
- char *webcitdir = WEBCITDIR;
+ char dirbuffer[PATH_MAX]="";
+ int relh=0;
+ int home=0;
+ int home_specified=0;
+ char relhome[PATH_MAX]="";
+ char webcitdir[PATH_MAX] = DATADIR;
+ char *hdir;
+ const char *basedir;
#ifdef ENABLE_NLS
char *locale = NULL;
char *mo = NULL;
#endif
switch (a) {
case 'h':
- webcitdir = strdup(optarg);
+ hdir = strdup(optarg);
+ relh=hdir[0]!='/';
+ if (!relh) safestrncpy(webcitdir, hdir,
+ sizeof webcitdir);
+ else
+ safestrncpy(relhome, relhome,
+ sizeof relhome);
+ /* free(hdir); TODO: SHOULD WE DO THIS? */
+ home_specified = 1;
+ home=1;
break;
case 'i':
safestrncpy(ip_addr, optarg, sizeof ip_addr);
break;
case 'p':
- port = atoi(optarg);
- if (port == 0) {
+ http_port = atoi(optarg);
+ if (http_port == 0) {
safestrncpy(uds_listen_path, optarg, sizeof uds_listen_path);
}
break;
}
/** Tell 'em who's in da house */
lprintf(1, SERVER "\n");
- lprintf(1, "Copyright (C) 1996-2005 by the Citadel development team.\n"
+ lprintf(1, "Copyright (C) 1996-2006 by the Citadel development team.\n"
"This software is distributed under the terms of the "
"GNU General Public License.\n\n"
);
- lprintf(9, "Changing directory to %s\n", webcitdir);
- if (chdir(webcitdir) != 0) {
- perror("chdir");
- }
/** initialize the International Bright Young Thing */
#ifdef ENABLE_NLS
-
initialize_locales();
-
locale = setlocale(LC_ALL, "");
-
mo = malloc(strlen(webcitdir) + 20);
- sprintf(mo, "%s/locale", webcitdir);
- lprintf(9, "Message catalog directory: %s\n",
- bindtextdomain("webcit", mo)
- );
+ lprintf(9, "Message catalog directory: %s\n", bindtextdomain("webcit", LOCALEDIR));
free(mo);
- lprintf(9, "Text domain: %s\n",
- textdomain("webcit")
- );
- lprintf(9, "Text domain Charset: %s\n",
- bind_textdomain_codeset("webcit","UTF8")
- );
+ lprintf(9, "Text domain: %s\n", textdomain("webcit"));
+ lprintf(9, "Text domain Charset: %s\n", bind_textdomain_codeset("webcit","UTF8"));
#endif
+
+ /* calculate all our path on a central place */
+ /* where to keep our config */
+
+#define COMPUTE_DIRECTORY(SUBDIR) memcpy(dirbuffer,SUBDIR, sizeof dirbuffer);\
+ snprintf(SUBDIR,sizeof SUBDIR, "%s%s%s%s%s%s%s", \
+ (home&!relh)?webcitdir:basedir, \
+ ((basedir!=webcitdir)&(home&!relh))?basedir:"/", \
+ ((basedir!=webcitdir)&(home&!relh))?"/":"", \
+ relhome, \
+ (relhome[0]!='\0')?"/":"",\
+ dirbuffer,\
+ (dirbuffer[0]!='\0')?"/":"");
+ basedir=RUNDIR;
+ COMPUTE_DIRECTORY(socket_dir);
+ basedir=DATADIR;
+ COMPUTE_DIRECTORY(static_dir);
+ /** we should go somewhere we can leave our coredump, if enabled... */
+ lprintf(9, "Changing directory to %s\n", socket_dir);
+ if (chdir(webcitdir) != 0) {
+ perror("chdir");
+ }
initialize_viewdefs();
initialize_axdefs();
msock = ig_uds_server(uds_listen_path, LISTEN_QUEUE_LENGTH);
}
else {
- lprintf(2, "Attempting to bind to port %d...\n", port);
- msock = ig_tcp_server(ip_addr, port, LISTEN_QUEUE_LENGTH);
+ lprintf(2, "Attempting to bind to port %d...\n", http_port);
+ msock = ig_tcp_server(ip_addr, http_port, LISTEN_QUEUE_LENGTH);
}
lprintf(2, "Listening on socket %d\n", msock);
#endif
if (fail_this_transaction == 0) {
+
/** Perform an HTTP transaction... */
context_loop(ssock);
+
+ /** Shut down SSL/TLS if required... */
+ if (is_https) {
+ endtls();
+ }
+
/** ...and close the socket. */
lingering_close(ssock);
}
}
+/**
+ * \brief print the actual stack frame.
+ */
+void wc_backtrace(void)
+{
+#ifdef HAVE_BACKTRACE
+ void *stack_frames[50];
+ size_t size, i;
+ char **strings;
+
+
+ size = backtrace(stack_frames, sizeof(stack_frames) / sizeof(void*));
+ strings = backtrace_symbols(stack_frames, size);
+ for (i = 0; i < size; i++) {
+ if (strings != NULL)
+ lprintf(1, "%s\n", strings[i]);
+ else
+ lprintf(1, "%p\n", stack_frames[i]);
+ }
+ free(strings);
+#endif
+}
+
/*@}*/