From e4238f86ca219675a2f56a156acec672106e5313 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Wilfried=20G=C3=B6esgens?= Date: Sun, 24 Jan 2010 11:11:37 +0000 Subject: [PATCH] * merge in much of the dav_rework branch: (the drift was becoming to big, no functional changes) * make configure search for cunit * rename struct floor to Floor, since floor was already taken by math.h * move over most of the functions from webserver.c to sysdep.c so main() is isolated and more easy to be replaced by another main in a test-suite-binary * add first unit test implementations - test the LANG header parser - start testing the floor evaluation --- webcit/configure.ac | 4 +- webcit/roomlist.c | 70 +++--- webcit/roomops.c | 2 +- webcit/roomops.h | 4 +- webcit/sysdep.c | 448 +++++++++++++++++++++++++++++++++++- webcit/tests/Makefile.in | 140 ++++++++++++ webcit/tests/test_main.c | 241 ++++++++++++++++++++ webcit/tests/test_tools.c | 320 ++++++++++++++++++++++++++ webcit/webcit.c | 2 +- webcit/webcit.h | 2 +- webcit/webserver.c | 465 +------------------------------------- webcit/webserver.h | 1 - 12 files changed, 1201 insertions(+), 498 deletions(-) create mode 100644 webcit/tests/Makefile.in create mode 100644 webcit/tests/test_main.c create mode 100644 webcit/tests/test_tools.c diff --git a/webcit/configure.ac b/webcit/configure.ac index 049571cdc..53a13c0d0 100644 --- a/webcit/configure.ac +++ b/webcit/configure.ac @@ -101,6 +101,8 @@ dnl Checks for library functions. AC_TYPE_SIGNAL dnl AC_FUNC_VPRINTF AC_REPLACE_FUNCS(snprintf) +AC_CHECK_HEADER(CUnit/CUnit.h, [AC_DEFINE(ENABLE_TESTS, [], [whether we should compile the test-suite])]) + AC_CHECK_HEADERS(fcntl.h limits.h sys/time.h unistd.h iconv.h xlocale.h) dnl Checks for the zlib compression library. @@ -471,7 +473,7 @@ if test "$abs_srcdir" != "$abs_builddir"; then CFLAGS="$CFLAGS -I $abs_builddir" fi AC_CONFIG_HEADER(sysdep.h) -AC_OUTPUT(Makefile po/Makefile ) +AC_OUTPUT(Makefile po/Makefile tests/Makefile) if test "$abs_srcdir" != "$abs_builddir"; then ln -s $abs_srcdir/static $abs_builddir diff --git a/webcit/roomlist.c b/webcit/roomlist.c index c440085f0..a53605893 100644 --- a/webcit/roomlist.c +++ b/webcit/roomlist.c @@ -9,16 +9,16 @@ void DeleteFloor(void *vFloor) { - floor *Floor; - Floor = (floor*) vFloor; - FreeStrBuf(&Floor->Name); - free(Floor); + Floor *pFloor; + pFloor = (Floor*) vFloor; + FreeStrBuf(&pFloor->Name); + free(pFloor); } int SortFloorsByNameOrder(const void *vfloor1, const void *vfloor2) { - floor *f1 = (floor*) GetSearchPayload(vfloor1); - floor *f2 = (floor*) GetSearchPayload(vfloor2); + Floor *f1 = (Floor*) GetSearchPayload(vfloor1); + Floor *f2 = (Floor*) GetSearchPayload(vfloor2); /* prefer My floor over alpabetical sort */ if (f1->ID == VIRTUAL_MY_FLOOR) @@ -36,7 +36,7 @@ HashList *GetFloorListHash(StrBuf *Target, WCTemplputParams *TP) StrBuf *Buf; HashList *floors; HashPos *it; - floor *Floor; + Floor *pFloor; void *vFloor; const char *Pos; int i; @@ -50,12 +50,12 @@ HashList *GetFloorListHash(StrBuf *Target, WCTemplputParams *TP) WCC->Floors = floors = NewHash(1, Flathash); Buf = NewStrBuf(); - Floor = malloc(sizeof(floor)); - Floor->ID = VIRTUAL_MY_FLOOR; - Floor->Name = NewStrBufPlain(_("My Folders"), -1); - Floor->NRooms = 0; + pFloor = (Floor*) malloc(sizeof(Floor)); + pFloor->ID = VIRTUAL_MY_FLOOR; + pFloor->Name = NewStrBufPlain(_("My Folders"), -1); + pFloor->NRooms = 0; - Put(floors, IKEY(Floor->ID), Floor, DeleteFloor); + Put(floors, IKEY(pFloor->ID), pFloor, DeleteFloor); serv_puts("LFLR"); /* get floors */ StrBufTCP_read_line(Buf, &WC->serv_sock, 0, &Err); /* '100', we hope */ @@ -72,13 +72,13 @@ HashList *GetFloorListHash(StrBuf *Target, WCTemplputParams *TP) Pos = NULL; - Floor = malloc(sizeof(floor)); - Floor->ID = StrBufExtractNext_int(Buf, &Pos, '|'); - Floor->Name = NewStrBufPlain(NULL, StrLength(Buf)); - StrBufExtract_NextToken(Floor->Name, Buf, &Pos, '|'); - Floor->NRooms = StrBufExtractNext_long(Buf, &Pos, '|'); + pFloor = (Floor*) malloc(sizeof(Floor)); + pFloor->ID = StrBufExtractNext_int(Buf, &Pos, '|'); + pFloor->Name = NewStrBufPlain(NULL, StrLength(Buf)); + StrBufExtract_NextToken(pFloor->Name, Buf, &Pos, '|'); + pFloor->NRooms = StrBufExtractNext_long(Buf, &Pos, '|'); - Put(floors, IKEY(Floor->ID), Floor, DeleteFloor); + Put(floors, IKEY(pFloor->ID), pFloor, DeleteFloor); } } FreeStrBuf(&Buf); @@ -88,7 +88,7 @@ HashList *GetFloorListHash(StrBuf *Target, WCTemplputParams *TP) SortByPayload(floors, SortFloorsByNameOrder); it = GetNewHashPos(floors, 0); while ( GetNextHashPos(floors, it, &HKLen, &HashKey, &vFloor)) - ((floor*) vFloor)->AlphaN = i++; + ((Floor*) vFloor)->AlphaN = i++; DeleteHashPos(&it); SortByHashKeyStr(floors); @@ -97,23 +97,23 @@ HashList *GetFloorListHash(StrBuf *Target, WCTemplputParams *TP) void tmplput_FLOOR_ID(StrBuf *Target, WCTemplputParams *TP) { - floor *Floor = (floor *)(TP->Context); + Floor *pFloor = (Floor *)(TP->Context); - StrBufAppendPrintf(Target, "%d", Floor->ID); + StrBufAppendPrintf(Target, "%d", pFloor->ID); } void tmplput_FLOOR_NAME(StrBuf *Target, WCTemplputParams *TP) { - floor *Floor = (floor *)(TP->Context); + Floor *pFloor = (Floor *)(TP->Context); - StrBufAppendTemplate(Target, TP, Floor->Name, 0); + StrBufAppendTemplate(Target, TP, pFloor->Name, 0); } void tmplput_FLOOR_NROOMS(StrBuf *Target, WCTemplputParams *TP) { - floor *Floor = (floor *)(TP->Context); + Floor *pFloor = (Floor *)(TP->Context); - StrBufAppendPrintf(Target, "%d", Floor->NRooms); + StrBufAppendPrintf(Target, "%d", pFloor->NRooms); } HashList *GetRoomListHashLKRA(StrBuf *Target, WCTemplputParams *TP) { @@ -233,7 +233,7 @@ HashList *GetRoomListHash(StrBuf *Target, WCTemplputParams *TP) } /* get a pointer to the floor we're on: */ GetHash(WCC->Floors, IKEY(room->floorid), &vFloor); - room->Floor = (const floor*) vFloor; + room->Floor = (const Floor*) vFloor; @@ -524,33 +524,33 @@ void tmplput_ROOM_LASTCHANGE(StrBuf *Target, WCTemplputParams *TP) void tmplput_ROOM_FLOOR_ID(StrBuf *Target, WCTemplputParams *TP) { folder *Folder = (folder *)(TP->Context); - const floor *Floor = Folder->Floor; + const Floor *pFloor = Folder->Floor; - if (Floor == NULL) + if (pFloor == NULL) return; - StrBufAppendPrintf(Target, "%d", Floor->ID); + StrBufAppendPrintf(Target, "%d", pFloor->ID); } void tmplput_ROOM_FLOOR_NAME(StrBuf *Target, WCTemplputParams *TP) { folder *Folder = (folder *)(TP->Context); - const floor *Floor = Folder->Floor; + const Floor *pFloor = Folder->Floor; - if (Floor == NULL) + if (pFloor == NULL) return; - StrBufAppendTemplate(Target, TP, Floor->Name, 0); + StrBufAppendTemplate(Target, TP, pFloor->Name, 0); } void tmplput_ROOM_FLOOR_NROOMS(StrBuf *Target, WCTemplputParams *TP) { folder *Folder = (folder *)(TP->Context); - const floor *Floor = Folder->Floor; + const Floor *pFloor = Folder->Floor; - if (Floor == NULL) + if (pFloor == NULL) return; - StrBufAppendPrintf(Target, "%d", Floor->NRooms); + StrBufAppendPrintf(Target, "%d", pFloor->NRooms); } diff --git a/webcit/roomops.c b/webcit/roomops.c index 783c1cb51..1ca41c288 100644 --- a/webcit/roomops.c +++ b/webcit/roomops.c @@ -893,7 +893,7 @@ void ParseGoto(folder *room, StrBuf *Line) } /* get a pointer to the floor we're on: */ GetHash(WCC->Floors, IKEY(room->floorid), &vFloor); - room->Floor = (const floor*) vFloor; + room->Floor = (const Floor*) vFloor; } diff --git a/webcit/roomops.h b/webcit/roomops.h index 8cdf095e0..13a96d3ce 100644 --- a/webcit/roomops.h +++ b/webcit/roomops.h @@ -33,7 +33,7 @@ typedef struct _floor { StrBuf *Name; long NRooms; long AlphaN; -} floor; +} Floor; /** * \brief Data structure for roomlist-to-folderlist conversion @@ -73,7 +73,7 @@ typedef struct _folder { long nRoomNameParts; StrBuf **RoomNameParts; - const floor *Floor; /* pint to the floor we're on.. */ + const Floor *Floor; /* pint to the floor we're on.. */ int hasnewmsgs; /* are there unread messages inside */ int is_inbox; /* is it a mailbox? */ diff --git a/webcit/sysdep.c b/webcit/sysdep.c index 36155ed84..b4db58f9e 100644 --- a/webcit/sysdep.c +++ b/webcit/sysdep.c @@ -11,7 +11,6 @@ * variants of this file or simply load it up with #ifdefs. * */ - #include "sysdep.h" #include #include @@ -62,12 +61,37 @@ #ifndef HAVE_SNPRINTF #include "snprintf.h" #endif - #include "webserver.h" +#include "modules_init.h" +#if HAVE_BACKTRACE +#include +#endif pthread_mutex_t Critters[MAX_SEMAPHORES]; /* Things needing locking */ pthread_key_t MyConKey; /* TSD key for MyContext() */ pthread_key_t MyReq; /* TSD key for MyReq() */ +int msock; /* master listening socket */ +int time_to_die = 0; /* Nonzero if server is shutting down */ +int verbosity = 9; /* Logging level */ + +extern void *context_loop(ParsedHttpHdrs *Hdr); +extern void *housekeeping_loop(void); + +char ctdl_key_dir[PATH_MAX]=SSL_DIR; +char file_crpt_file_key[PATH_MAX]=""; +char file_crpt_file_csr[PATH_MAX]=""; +char file_crpt_file_cer[PATH_MAX]=""; + +const char editor_absolut_dir[PATH_MAX]=EDITORDIR; /* nailed to what configure gives us. */ +char static_dir[PATH_MAX]; /* calculated on startup */ +char static_local_dir[PATH_MAX]; /* calculated on startup */ +char static_icon_dir[PATH_MAX]; /* where should we find our mime icons? */ +char *static_dirs[]={ /* needs same sort order as the web mapping */ + (char*)static_dir, /* our templates on disk */ + (char*)static_local_dir, /* user provided templates disk */ + (char*)editor_absolut_dir, /* the editor on disk */ + (char*)static_icon_dir /* our icons... */ +}; void InitialiseSemaphores(void) { @@ -96,6 +120,402 @@ void end_critical_section(int which_one) pthread_mutex_unlock(&Critters[which_one]); } + +void ShutDownWebcit(void) +{ + free_zone_directory (); + icaltimezone_release_zone_tab (); + icalmemory_free_ring (); + ShutDownLibCitadel (); + shutdown_modules (); +#ifdef HAVE_OPENSSL + if (is_https) { + shutdown_ssl(); + } +#endif +} + +/* + * Entry point for worker threads + */ +void worker_entry(void) +{ + int ssock; + int i = 0; + int fail_this_transaction = 0; + int ret; + struct timeval tv; + fd_set readset, tempset; + ParsedHttpHdrs Hdr; + + memset(&Hdr, 0, sizeof(ParsedHttpHdrs)); + Hdr.HR.eReqType = eGET; + http_new_modules(&Hdr); + tv.tv_sec = 0; + tv.tv_usec = 10000; + FD_ZERO(&readset); + FD_SET(msock, &readset); + + do { + /* Only one thread can accept at a time */ + fail_this_transaction = 0; + ssock = -1; + errno = EAGAIN; + do { + ret = -1; /* just one at once should select... */ + begin_critical_section(S_SELECT); + + FD_ZERO(&tempset); + if (msock > 0) FD_SET(msock, &tempset); + tv.tv_sec = 0; + tv.tv_usec = 10000; + if (msock > 0) ret = select(msock+1, &tempset, NULL, NULL, &tv); + end_critical_section(S_SELECT); + if ((ret < 0) && (errno != EINTR) && (errno != EAGAIN)) + {/* EINTR and EAGAIN are thrown but not of interest. */ + lprintf(2, "accept() failed:%d %s\n", + errno, strerror(errno)); + } + else if ((ret > 0) && (msock > 0) && FD_ISSET(msock, &tempset)) + {/* Successfully selected, and still not shutting down? Accept! */ + ssock = accept(msock, NULL, 0); + } + + } while ((msock > 0) && (ssock < 0) && (time_to_die == 0)); + + if ((msock == -1)||(time_to_die)) + {/* ok, we're going down. */ + int shutdown = 0; + + /* the first to come here will have to do the cleanup. + * make shure its realy just one. + */ + begin_critical_section(S_SHUTDOWN); + if (msock == -1) + { + msock = -2; + shutdown = 1; + } + end_critical_section(S_SHUTDOWN); + if (shutdown == 1) + {/* we're the one to cleanup the mess. */ + http_destroy_modules(&Hdr); + lprintf(2, "I'm master shutdown: tagging sessions to be killed.\n"); + shutdown_sessions(); + lprintf(2, "master shutdown: waiting for others\n"); + sleeeeeeeeeep(1); /* wait so some others might finish... */ + lprintf(2, "master shutdown: cleaning up sessions\n"); + do_housekeeping(); + lprintf(2, "master shutdown: cleaning up libical\n"); + + ShutDownWebcit(); + + lprintf(2, "master shutdown exiting!.\n"); + exit(0); + } + break; + } + if (ssock < 0 ) continue; + + if (msock < 0) { + if (ssock > 0) close (ssock); + lprintf(2, "inbetween."); + pthread_exit(NULL); + } else { /* Got it? do some real work! */ + /* Set the SO_REUSEADDR socket option */ + i = 1; + setsockopt(ssock, SOL_SOCKET, SO_REUSEADDR, + &i, sizeof(i)); + + /* If we are an HTTPS server, go crypto now. */ +#ifdef HAVE_OPENSSL + if (is_https) { + if (starttls(ssock) != 0) { + fail_this_transaction = 1; + close(ssock); + } + } + else +#endif + { + int fdflags; + fdflags = fcntl(ssock, F_GETFL); + if (fdflags < 0) + lprintf(1, "unable to get server socket flags! %s \n", + strerror(errno)); + fdflags = fdflags | O_NONBLOCK; + if (fcntl(ssock, F_SETFL, fdflags) < 0) + lprintf(1, "unable to set server socket nonblocking flags! %s \n", + strerror(errno)); + } + + if (fail_this_transaction == 0) { + Hdr.http_sock = ssock; + + /* Perform an HTTP transaction... */ + context_loop(&Hdr); + + /* Shut down SSL/TLS if required... */ +#ifdef HAVE_OPENSSL + if (is_https) { + endtls(); + } +#endif + + /* ...and close the socket. */ + if (Hdr.http_sock > 0) + lingering_close(ssock); + http_detach_modules(&Hdr); + + } + + } + + } while (!time_to_die); + + http_destroy_modules(&Hdr); + lprintf (1, "bye\n"); + pthread_exit(NULL); +} + +/* + * print log messages + * logs to stderr if loglevel is lower than the verbosity set at startup + * + * loglevel level of the message + * format the printf like format string + * ... the strings to put into format + */ +int lprintf(int loglevel, const char *format, ...) +{ + va_list ap; + + if (loglevel <= verbosity) { + va_start(ap, format); + vfprintf(stderr, format, ap); + va_end(ap); + fflush(stderr); + } + return 1; +} + +/* + * Shut us down the regular way. + * signum is the signal we want to forward + */ +pid_t current_child; +void graceful_shutdown_watcher(int signum) { + lprintf (1, "bye; shutting down watcher."); + kill(current_child, signum); + if (signum != SIGHUP) + exit(0); +} + + + + +/* + * Shut us down the regular way. + * signum is the signal we want to forward + */ +pid_t current_child; +void graceful_shutdown(int signum) { + FILE *FD; + int fd; + + lprintf (1, "WebCit is being shut down on signal %d.\n", signum); + fd = msock; + msock = -1; + time_to_die = 1; + FD=fdopen(fd, "a+"); + fflush (FD); + fclose (FD); + close(fd); +} + + +/* + * Start running as a daemon. + */ +void start_daemon(char *pid_file) +{ + int status = 0; + pid_t child = 0; + FILE *fp; + int do_restart = 0; + int rv; + FILE *rvfp = NULL; + + current_child = 0; + + /* 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. + */ + rv = chdir("/"); + + signal(SIGHUP, SIG_IGN); + signal(SIGINT, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + + child = fork(); + if (child != 0) { + exit(0); + } + + setsid(); + umask(0); + rvfp = freopen("/dev/null", "r", stdin); + rvfp = freopen("/dev/null", "w", stdout); + rvfp = freopen("/dev/null", "w", stderr); + signal(SIGTERM, graceful_shutdown_watcher); + signal(SIGHUP, graceful_shutdown_watcher); + + do { + current_child = fork(); + + + if (current_child < 0) { + perror("fork"); + ShutDownLibCitadel (); + exit(errno); + } + + else if (current_child == 0) { /* child process */ + signal(SIGHUP, graceful_shutdown); + + return; /* continue starting webcit. */ + } + else { /* watcher process */ + if (pid_file) { + fp = fopen(pid_file, "w"); + if (fp != NULL) { + fprintf(fp, "%d\n", getpid()); + fclose(fp); + } + } + waitpid(current_child, &status, 0); + } + + do_restart = 0; + + /* Did the main process exit with an actual exit code? */ + if (WIFEXITED(status)) { + + /* Exit code 0 means the watcher should exit */ + if (WEXITSTATUS(status) == 0) { + do_restart = 0; + } + + /* Exit code 101-109 means the watcher should exit */ + else if ( (WEXITSTATUS(status) >= 101) && (WEXITSTATUS(status) <= 109) ) { + do_restart = 0; + } + + /* Any other exit code means we should restart. */ + else { + do_restart = 1; + } + } + + /* Any other type of termination (signals, etc.) should also restart. */ + else { + do_restart = 1; + } + + } while (do_restart); + + if (pid_file) { + unlink(pid_file); + } + ShutDownLibCitadel (); + exit(WEXITSTATUS(status)); +} + +/* + * Spawn an additional worker thread into the pool. + */ +void spawn_another_worker_thread() +{ + pthread_t SessThread; /* Thread descriptor */ + pthread_attr_t attr; /* Thread attributes */ + int ret; + + lprintf(3, "Creating a new thread. Pool size is now %d\n", ++num_threads); + + /* set attributes for the new thread */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + + /* + * Our per-thread stacks need to be bigger than the default size, + * otherwise the MIME parser crashes on FreeBSD. + */ + if ((ret = pthread_attr_setstacksize(&attr, 1024 * 1024))) { + lprintf(1, "pthread_attr_setstacksize: %s\n", + strerror(ret)); + pthread_attr_destroy(&attr); + } + + /* now create the thread */ + if (pthread_create(&SessThread, &attr, + (void *(*)(void *)) worker_entry, NULL) + != 0) { + lprintf(1, "Can't create thread: %s\n", strerror(errno)); + } + + /* free up the attributes */ + pthread_attr_destroy(&attr); +} + + +void +webcit_calc_dirs_n_files(int relh, const char *basedir, int home, char *webcitdir, char *relhome) +{ + char dirbuffer[PATH_MAX]=""; + /* 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=WWWDIR "/static"; + COMPUTE_DIRECTORY(static_dir); + basedir=WWWDIR "/static/icons"; + COMPUTE_DIRECTORY(static_icon_dir); + basedir=WWWDIR "/static.local"; + COMPUTE_DIRECTORY(static_local_dir); + StripSlashes(static_dir, 1); + StripSlashes(static_icon_dir, 1); + StripSlashes(static_local_dir, 1); + + snprintf(file_crpt_file_key, + sizeof file_crpt_file_key, + "%s/citadel.key", + ctdl_key_dir); + snprintf(file_crpt_file_csr, + sizeof file_crpt_file_csr, + "%s/citadel.csr", + ctdl_key_dir); + snprintf(file_crpt_file_cer, + sizeof file_crpt_file_cer, + "%s/citadel.cer", + ctdl_key_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"); + } +} void drop_root(uid_t UID) { struct passwd pw, *pwp = NULL; @@ -135,3 +555,27 @@ void drop_root(uid_t UID) #endif } } + + +/* + * 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 +} diff --git a/webcit/tests/Makefile.in b/webcit/tests/Makefile.in new file mode 100644 index 000000000..17fa7afc2 --- /dev/null +++ b/webcit/tests/Makefile.in @@ -0,0 +1,140 @@ +# $Id: Makefile.in 7860 2009-10-05 20:25:07Z dothebart $ + +prefix=@prefix@ +srcdir=@srcdir@/../ +VPATH=$(srcdir) + +AUTOCONF=@AUTOCONF@ +CC=@CC@ +CFLAGS=@CFLAGS@ +DEFS=@DEFS@ +INSTALL=@INSTALL@ +LIBOBJS=@LIBOBJS@ +LIBS=@LIBS@ -lcunit +LDFLAGS=@LDFLAGS@ +SED=@SED@ +SETUP_LIBS=@SETUP_LIBS@ +PTHREAD_DEFS=@PTHREAD_DEFS@ +LIB_SUBDIRS= +PROG_SUBDIRS=@PROG_SUBDIRS@ +SUBDIRS=$(LIB_SUBDIRS) $(PROG_SUBDIRS) +LOCALEDIR=@LOCALEDIR@ +WWWDIR=@WWWDIR@ + +TEST_OBJECTS= \ + ../webcit.o \ + ../context_loop.o \ + ../modules_init.o \ + \ + ../cookie_conversion.o \ + \ + ../locate_host.o \ + ../sysdep.o \ + ../utils.o \ + ../decode.o \ + ../html2html.o \ + ../http_datestring.o \ + ../fmt_date.o \ + \ + ../subst.o \ + ../preferences.o \ + ../paramhandling.o \ + ../serv_func.o \ + ../tcp_sockets.o \ + ../crypto.o \ + ../gettext.o \ + ../tabs.o \ + \ + ../netconf.o \ + ../inetconf.o \ + ../siteconfig.o \ + ../smtpqueue.o \ + ../pushemail.o \ + ../sieve.o \ + \ + ../static.o \ + ../graphics.o \ + ../downloads.o \ + \ + ../auth.o \ + ../openid.o \ + ../who.o \ + ../userlist.o \ + ../useredit.o \ + ../sysmsgs.o \ + \ + ../listsub.o \ + \ + ../setup_wizard.o \ + ../summary.o \ + ../mainmenu.o \ + ../iconbar.o \ + \ + ../floors.o \ + ../roomops.o \ + ../roomlist.o \ + ../marchlist.o \ + \ + ../messages.o \ + ../msg_renderers.o \ + ../bbsview_renderer.o \ + ../wiki.o \ + \ + ../paging.o \ + \ + ../vcard_edit.o \ + ../addressbook_popup.o \ + ../autocompletion.o \ + \ + ../ical_maps.o \ + ../ical_subst.o \ + ../ical_dezonify.o \ + ../calendar.o \ + ../calendar_tools.o \ + ../calendar_view.o \ + ../tasks.o \ + ../event.o \ + ../availability.o \ + ../notes.o \ + \ + ../groupdav_main.o \ + ../groupdav_get.o \ + ../groupdav_propfind.o \ + ../groupdav_options.o \ + ../groupdav_delete.o \ + ../groupdav_put.o + +TEST_COMMON_OBJECTS = \ + test_tools.o + +# End of configuration section + +all: test + +.SUFFIXES: .cpp .c .o + +clean: + rm -f $(WEBCIT_OBJECTS) + + +test: $(TEST_OBJECTS) $(TEST_COMMON_OBJECTS) $(LIBOBJS) test_main.o + $(CC) $(LDFLAGS) -o test $(LIBOBJS) test_main.o \ + $(TEST_OBJECTS) $(TEST_COMMON_OBJECTS) $(LIBS) + +.c.o: + $(CC) $(CFLAGS) -I ../ $(DEFS) -c $(PTHREAD_DEFS) $< + +.cpp.o: + $(CC) $(CFLAGS) -I ../ $(DEFS) -c $(PTHREAD_DEFS) $< + +Makefile: $(srcdir)/Makefile.in $(srcdir)/config.status + CONFIG_FILES=Makefile CONFIG_HEADERS= $(SHELL) $(srcdir)/config.status + +config.status: $(srcdir)/configure + $(SHELL) $(srcdir)/config.status --recheck + +$(srcdir)/configure: $(srcdir)/configure.ac $(srcdir)/aclocal.m4 + cd $(srcdir) && $(AUTOCONF) + +$(srcdir)/aclocal.m4: $(srcdir)/acinclude.m4 + cd $(srcdir) && $(ACLOCAL) diff --git a/webcit/tests/test_main.c b/webcit/tests/test_main.c new file mode 100644 index 000000000..577a1dd3d --- /dev/null +++ b/webcit/tests/test_main.c @@ -0,0 +1,241 @@ +/* + * $Id: webserver.c 7847 2009-10-03 17:57:14Z dothebart $ + * + * 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. + * + * Copyright (c) 1996-2009 by the citadel.org developers. + * This program is released under the terms of the GNU General Public License v3. + * + */ + +#include "../webcit.h" +#include "../webserver.h" +#include "../modules_init.h" + + +#include +#include +#include + + +CU_EXPORT void CU_automated_run_tests(void); +CU_EXPORT CU_ErrorCode CU_list_tests_to_file(void); +CU_EXPORT void CU_set_output_filename(const char* szFilenameRoot); + +extern int msock; /* master listening socket */ +extern int verbosity; /* Logging level */ +extern char static_icon_dir[PATH_MAX]; /* where should we find our mime icons */ + +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? */ +int DisableGzip = 0; +extern pthread_mutex_t SessionListMutex; +extern pthread_key_t MyConKey; + +extern void run_tests(void); +extern int ig_tcp_server(char *ip_addr, int port_number, int queue_len); +extern int ig_uds_server(char *sockpath, int queue_len); +extern void webcit_calc_dirs_n_files(int relh, const char *basedir, int home, char *webcitdir, char *relhome); + + +char socket_dir[PATH_MAX]; /* where to talk to our citadel server */ + +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 */ +int running_as_daemon = 0; /* should we deamonize on startup? */ +char wizard_filename[PATH_MAX]; + +StrBuf *Username = NULL; /* the test user... */ +StrBuf *Passvoid = NULL; /* the test user... */ + + +extern int dbg_analyze_msg; +extern int dbg_bactrace_template_errors; +extern int DumpTemplateI18NStrings; +extern StrBuf *I18nDump; +void InitTemplateCache(void); +extern int LoadTemplates; + + + +/* + * Here's where it all begins. + */ +int main(int argc, char **argv) +{ + size_t basesize = 2; /* how big should strbufs be on creation? */ + pthread_attr_t attr; /* Thread attributes */ + int a; /* General-purpose variables */ + char tracefile[PATH_MAX]; + char ip_addr[256]="0.0.0.0"; + int relh=0; + int home=0; + int home_specified=0; + char relhome[PATH_MAX]=""; + char webcitdir[PATH_MAX] = DATADIR; + char *hdir; + const char *basedir = NULL; + char uds_listen_path[PATH_MAX]; /* listen on a unix domain socket? */ + FILE *rvfp = NULL; + + WildFireInitBacktrace(argv[0], 2); + + start_modules (); + + /* Ensure that we are linked to the correct version of libcitadel */ + if (libcitadel_version_number() < LIBCITADEL_VERSION_NUMBER) { + fprintf(stderr, " You are running libcitadel version %d.%02d\n", + (libcitadel_version_number() / 100), (libcitadel_version_number() % 100)); + fprintf(stderr, "WebCit was compiled against version %d.%02d\n", + (LIBCITADEL_VERSION_NUMBER / 100), (LIBCITADEL_VERSION_NUMBER % 100)); + return(1); + } + + strcpy(uds_listen_path, ""); + + /* Parse command line */ + while ((a = getopt(argc, argv, "h:i:p:t:T:B:x:U:P:cf:Z")) != EOF) + switch (a) { + case 'U': + Username = NewStrBufPlain(optarg, -1); + break; + case 'P': + Passvoid = NewStrBufPlain(optarg, -1); + break; + case 'h': + 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 'B': /* Basesize */ + basesize = atoi(optarg); + if (basesize > 2) + StartLibCitadel(basesize); + break; + case 'i': + safestrncpy(ip_addr, optarg, sizeof ip_addr); + break; + case 'p': + http_port = atoi(optarg); + if (http_port == 0) { + safestrncpy(uds_listen_path, optarg, sizeof uds_listen_path); + } + break; + case 't': + safestrncpy(tracefile, optarg, sizeof tracefile); + rvfp = freopen(tracefile, "w", stdout); + rvfp = freopen(tracefile, "w", stderr); + rvfp = freopen(tracefile, "r", stdin); + break; + case 'T': + LoadTemplates = atoi(optarg); + dbg_analyze_msg = (LoadTemplates && (1<<1)) != 0; + dbg_bactrace_template_errors = (LoadTemplates && (1<<2)) != 0; + break; + case 'Z': + DisableGzip = 1; + break; + case 'x': + verbosity = atoi(optarg); + break; + case 'f': + follow_xff = 1; + break; + case 'c': + server_cookie = malloc(256); + if (server_cookie != NULL) { + safestrncpy(server_cookie, + "Set-cookie: wcserver=", + 256); + if (gethostname + (&server_cookie[strlen(server_cookie)], + 200) != 0) { + lprintf(2, "gethostname: %s\n", + strerror(errno)); + free(server_cookie); + } + } + break; + default: + fprintf(stderr, "usage: webcit " + "[-i ip_addr] [-p http_port] " + "[-t tracefile] [-c] [-f] " + "[-T Templatedebuglevel] " + "[-Z] [-G i18ndumpfile] " +#ifdef HAVE_OPENSSL + "[-s] [-S cipher_suites]" +#endif + "[-U Username -P Password]" + "" + "[remotehost [remoteport]]\n"); + return 1; + } + + if (optind < argc) { + ctdlhost = argv[optind]; + if (++optind < argc) + ctdlport = argv[optind]; + } + + webcit_calc_dirs_n_files(relh, basedir, home, webcitdir, relhome); + LoadIconDir(static_icon_dir); + + /* Tell 'em who's in da house */ + lprintf(1, PACKAGE_STRING "\n"); + lprintf(1, "Copyright (C) 1996-2009 by the Citadel development team.\n" + "This software is distributed under the terms of the " + "GNU General Public License.\n\n" + ); + + + /* initialize the International Bright Young Thing */ + + initialise_modules(); + initialize_viewdefs(); + initialize_axdefs(); + + InitTemplateCache(); + + /* Use our own prefix on tzid's generated from system tzdata */ + icaltimezone_set_tzid_prefix("/citadel.org/"); + + /* + * Set up a place to put thread-specific data. + * We only need a single pointer per thread - it points to the + * wcsession struct to which the thread is currently bound. + */ + if (pthread_key_create(&MyConKey, NULL) != 0) { + lprintf(1, "Can't create TSD key: %s\n", strerror(errno)); + } + InitialiseSemaphores (); + + + /* + * Start up the housekeeping thread + */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + + run_tests(); + + ShutDownWebcit(); + FreeStrBuf(&Username); + FreeStrBuf(&Passvoid); + + return 0; +} + + diff --git a/webcit/tests/test_tools.c b/webcit/tests/test_tools.c new file mode 100644 index 000000000..6b3b31bd2 --- /dev/null +++ b/webcit/tests/test_tools.c @@ -0,0 +1,320 @@ +#include +#include +#include + + +#include "webcit.h" +#include "webserver.h" +#include "modules_init.h" +#include + + +wcsession *TestSessionList = NULL; + + +ParsedHttpHdrs Hdr; +wcsession *TheSession; + +extern StrBuf *Username; +extern StrBuf *Passvoid; + + +extern int ReadHttpSubject(ParsedHttpHdrs *Hdr, StrBuf *Line, StrBuf *Buf); +extern wcsession *CreateSession(int Lockable, wcsession **wclist, ParsedHttpHdrs *Hdr, pthread_mutex_t *ListMutex); + + + +void SetUpContext(void) +{ + memset(&Hdr, 0, sizeof(ParsedHttpHdrs)); + Hdr.HR.eReqType = eGET; + http_new_modules(&Hdr); + + + Hdr.http_sock = 1; /* STDOUT */ +/* Context loop */ + Hdr.HR.dav_depth = 32767; /* TODO: find a general way to have non-0 defaults */ + TheSession = CreateSession(1, &TestSessionList, &Hdr, NULL); + TheSession->lastreq = time(NULL); /* log */ + TheSession->Hdr = &Hdr; + Hdr.HTTPHeaders = NewHash(1, NULL); + session_attach_modules(TheSession); +} + +int SetUpConnection(void) +{ + StrBuf *Response; + if (!GetConnected ()) + { + Response = NewStrBuf(); + become_logged_in(Username, Passvoid, Response); + return 1; + + } + else { + CU_FAIL("Establishing session failed!"); + return 0; + } +} + +void SetHttpURL(ParsedHttpHdrs *Hdr, const char *Title, long tlen, StrBuf *Buf) +{ + StrBuf *Line = NewStrBufPlain (Title, tlen); + FreeStrBuf(&Line); +} + +/* from context_loop.c: */ +extern void DestroyHttpHeaderHandler(void *V); +extern int ReadHttpSubject(ParsedHttpHdrs *Hdr, StrBuf *Line, StrBuf *Buf); +void SetUpRequest(const char *UrlPath) +{ + OneHttpHeader *pHdr; + wcsession *WCC = WC; + StrBuf *Buf; + StrBuf *Line, *HeaderName; + + HeaderName = NewStrBuf(); + Buf = NewStrBuf(); + Line = NewStrBuf(); + StrBufPrintf(Line, "GET %s HTTP/1.0\r\n", UrlPath); + + WCC->Hdr->HTTPHeaders = NewHash(1, NULL); + pHdr = (OneHttpHeader*) malloc(sizeof(OneHttpHeader)); + memset(pHdr, 0, sizeof(OneHttpHeader)); + pHdr->Val = Line; + Put(Hdr.HTTPHeaders, HKEY("GET /"), pHdr, DestroyHttpHeaderHandler); + lprintf(9, "%s\n", ChrPtr(Line)); + + if (ReadHttpSubject(&Hdr, Line, HeaderName)) + CU_FAIL("Failed to parse Request line / me is bogus!"); + + FreeStrBuf(&Buf); +} + + + +void TearDownRequest(void) +{ +/* End Context loop */ + http_detach_modules(&Hdr); +} + +void TearDownContext(void) +{ + http_destroy_modules(&Hdr); +/* End Session Loop */ + session_detach_modules(TheSession); + session_destroy_modules(&TheSession); + +/* End Session loop */ +/* now shut it down clean. */ +// shutdown_sessions(); + do_housekeeping(); +} + +void test_worker_entry(StrBuf *UrlPath) +{ + + +} + + +void SetGroupdavHeaders(int DavDepth) +{ + Hdr.HR.dav_depth = DavDepth; +} + +void FlushHeaders(void) +{ + +} + +void test_groupdav_directorycommands(void) +{ + SetUpContext(); + if (SetUpConnection()) + { + SetUpRequest("/"); + SetGroupdavHeaders(0); + groupdav_main(); + FlushHeaders(); + TearDownRequest(); + + SetUpRequest("/"); + SetGroupdavHeaders(1); + groupdav_main(); + FlushHeaders(); + TearDownRequest(); + + + SetUpRequest("/groupdav"); + SetGroupdavHeaders(0); + groupdav_main(); + FlushHeaders(); + TearDownRequest(); + + SetUpRequest("/groupdav"); + SetGroupdavHeaders(1); + groupdav_main(); + FlushHeaders(); + TearDownRequest(); + + SetUpRequest("/groupdav/"); + SetGroupdavHeaders(0); + groupdav_main(); + FlushHeaders(); + TearDownRequest(); + + SetUpRequest("/groupdav/"); + SetGroupdavHeaders(1); + groupdav_main(); + FlushHeaders(); + TearDownRequest(); + + + SetUpRequest("/groupdav/My%20Folders"); + SetGroupdavHeaders(0); + groupdav_main(); + FlushHeaders(); + TearDownRequest(); + + SetUpRequest("/groupdav/My%20Folders"); + SetGroupdavHeaders(1); + groupdav_main(); + FlushHeaders(); + TearDownRequest(); + + SetUpRequest("/groupdav/My%20Folders/"); + SetGroupdavHeaders(0); + groupdav_main(); + FlushHeaders(); + TearDownRequest(); + + SetUpRequest("/groupdav/My%20Folders/"); + SetGroupdavHeaders(1); + groupdav_main(); + FlushHeaders(); + TearDownRequest(); + + SetUpRequest("/groupdav/My%20Folders/Calendar"); + SetGroupdavHeaders(0); + groupdav_main(); + FlushHeaders(); + TearDownRequest(); + + SetUpRequest("/groupdav/My%20Folders/Calendar"); + SetGroupdavHeaders(1); + groupdav_main(); + FlushHeaders(); + TearDownRequest(); + + SetUpRequest("/groupdav/My%20Folders/Calendar/"); + SetGroupdavHeaders(0); + groupdav_main(); + FlushHeaders(); + TearDownRequest(); + + SetUpRequest("/groupdav/My%20Folders/Calendar/"); + SetGroupdavHeaders(1); + groupdav_main(); + FlushHeaders(); + TearDownRequest(); + + + SetUpRequest("/"); + SetGroupdavHeaders(0); + groupdav_main(); + FlushHeaders(); + TearDownRequest(); + + SetUpRequest("/"); + SetGroupdavHeaders(1); + groupdav_main(); + FlushHeaders(); + TearDownRequest(); + } + + + TearDownContext(); +} + +extern void httplang_to_locale(StrBuf *LocaleString, wcsession *sess); + +static void test_gettext(const char *str, long len) +{ + StrBuf *Test = NewStrBufPlain(str, len); + + SetUpContext(); + httplang_to_locale(Test, TheSession); + TearDownContext(); + + FreeStrBuf(&Test); +} + +void test_gettext_headerevaluation_Opera(void) +{ + test_gettext(HKEY("sq;q=1.0,de;q=0.9,as;q=0.8,ar;q=0.7,bn;q=0.6,zh-cn;q=0.5,kn;q=0.4,ch;q=0.3,fo;q=0.2,gn;q=0.1,ce;q=0.1,ie;q=0.1")); +} + +void test_gettext_headerevaluation_firefox1(void) +{ + test_gettext(HKEY("de-de,en-us;q=0.7,en;q=0.3")); +} + +void test_gettext_headerevaluation_firefox2(void) +{ + test_gettext(HKEY("de,en-ph;q=0.8,en-us;q=0.5,de-at;q=0.3")); +} + +void test_gettext_headerevaluation_firefox3(void) +{ + test_gettext(HKEY("de,en-us;q=0.9,it;q=0.9,de-de;q=0.8,en-ph;q=0.7,de-at;q=0.7,zh-cn;q=0.6,cy;q=0.5,ar-om;q=0.5,en-tt;q=0.4,xh;q=0.3,nl-be;q=0.3,cs;q=0.2,sv;q=0.1,tk;q=0.1")); +} + +void test_gettext_headerevaluation_ie7(void) +{ +// ie7???? +// User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; FunWebProducts; FBSMTWB; GTB6.3; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.5.30729; .NET CLR 3.0.30618; Seekmo 10.3.86.0) + + test_gettext(HKEY("en-us,x-ns1MvoLpRxbNhu,x-ns2F0f0NnyPOPN")); +} + +static void AddTests(void) +{ + CU_pSuite pGroup = NULL; + CU_pTest pTest = NULL; +/* + pGroup = CU_add_suite("TestLocaleEvaluator", NULL, NULL); + pTest = CU_add_test(pGroup, "Test ie7", test_gettext_headerevaluation_ie7); + pTest = CU_add_test(pGroup, "Test Opera", test_gettext_headerevaluation_Opera); + pTest = CU_add_test(pGroup, "Test firefox1", test_gettext_headerevaluation_firefox1); + pTest = CU_add_test(pGroup, "Test firefox2", test_gettext_headerevaluation_firefox2); + pTest = CU_add_test(pGroup, "Test firefox3", test_gettext_headerevaluation_firefox3); +*/ + pGroup = CU_add_suite("TestUrlPatterns", NULL, NULL); + pTest = CU_add_test(pGroup, "Test", test_groupdav_directorycommands); + + +} + + + + + + + +void run_tests(void) +{ + setvbuf(stdout, NULL, _IONBF, 0); + + CU_set_output_filename("TestAutomated"); + if (CU_initialize_registry()) { + printf("\nInitialize of test Registry failed."); + } + + AddTests(); + + printf("\nTests completed with return value %d.\n", CU_basic_run_tests()); + CU_cleanup_registry(); + +} diff --git a/webcit/webcit.c b/webcit/webcit.c index e284f22ac..5912de4f7 100644 --- a/webcit/webcit.c +++ b/webcit/webcit.c @@ -536,7 +536,7 @@ void ParseREST_URL(void) if (Floors != NULL) { if (GetHash(Floors, SKEY(pFloor), &vFloor)) - WCC->CurrentFloor = (floor*) vFloor; + WCC->CurrentFloor = (Floor*) vFloor; } } } diff --git a/webcit/webcit.h b/webcit/webcit.h index b38a9c975..1217ab8f7 100644 --- a/webcit/webcit.h +++ b/webcit/webcit.h @@ -454,7 +454,7 @@ struct wcsession { char ImportantMessage[SIZ]; StrBuf *ImportantMsg; HashList *Directory; /* Parts of the directory URL in snippets */ - const floor *CurrentFloor; /**< when Parsing REST, which floor are we on? */ + const Floor *CurrentFloor; /**< when Parsing REST, which floor are we on? */ /* accounting */ StrBuf *wc_username; /* login name of current user */ diff --git a/webcit/webserver.c b/webcit/webserver.c index c70419b3b..e05dffddf 100644 --- a/webcit/webserver.c +++ b/webcit/webserver.c @@ -13,61 +13,34 @@ #include "webcit.h" #include "webserver.h" -#if HAVE_BACKTRACE -#include -#endif #include "modules_init.h" #ifndef HAVE_SNPRINTF int vsnprintf(char *buf, size_t max, const char *fmt, va_list argp); #endif -int verbosity = 9; /* Logging level */ -int msock; /* master listening socket */ + +extern int msock; /* master listening socket */ +extern int verbosity; /* Logging level */ +extern char static_icon_dir[PATH_MAX]; /* where should we find our mime icons */ + 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? */ -int time_to_die = 0; /* Nonzero if server is shutting down */ int DisableGzip = 0; -extern void *context_loop(ParsedHttpHdrs *Hdr); -extern void *housekeeping_loop(void); extern pthread_mutex_t SessionListMutex; extern pthread_key_t MyConKey; +extern void *housekeeping_loop(void); extern int ig_tcp_server(char *ip_addr, int port_number, int queue_len); extern int ig_uds_server(char *sockpath, int queue_len); +extern void graceful_shutdown_watcher(int signum); +extern void graceful_shutdown(int signum); +extern void start_daemon(char *pid_file); +extern void webcit_calc_dirs_n_files(int relh, const char *basedir, int home, char *webcitdir, char *relhome); extern void drop_root(uid_t UID); -char ctdl_key_dir[PATH_MAX]=SSL_DIR; -char file_crpt_file_key[PATH_MAX]=""; -char file_crpt_file_csr[PATH_MAX]=""; -char file_crpt_file_cer[PATH_MAX]=""; - char socket_dir[PATH_MAX]; /* where to talk to our citadel server */ -const char editor_absolut_dir[PATH_MAX]=EDITORDIR; /* nailed to what configure gives us. */ -char static_dir[PATH_MAX]; /* calculated on startup */ -char static_local_dir[PATH_MAX]; /* calculated on startup */ -char static_icon_dir[PATH_MAX]; /* where should we find our mime icons? */ -char *static_dirs[]={ /* needs same sort order as the web mapping */ - (char*)static_dir, /* our templates on disk */ - (char*)static_local_dir, /* user provided templates disk */ - (char*)editor_absolut_dir, /* the editor on disk */ - (char*)static_icon_dir /* our icons... */ -}; - -/* - * Subdirectories from which the client may request static content - * - * (If you add more, remember to increment 'ndirs' below) - */ -char *static_content_dirs[] = { - "static", /* static templates */ - "static.local", /* site local static templates */ - "tiny_mce" /* rich text editor */ -}; - -int ndirs=3; - char *server_cookie = NULL; /* our Cookie connection to the client */ int http_port = PORT_NUM; /* Port to listen on */ @@ -79,177 +52,9 @@ int running_as_daemon = 0; /* should we deamonize on startup? */ -/* - * Shut us down the regular way. - * signum is the signal we want to forward - */ -pid_t current_child; -void graceful_shutdown_watcher(int signum) { - lprintf (1, "bye; shutting down watcher."); - kill(current_child, signum); - if (signum != SIGHUP) - exit(0); -} - - - - -/* - * Shut us down the regular way. - * signum is the signal we want to forward - */ -pid_t current_child; -void graceful_shutdown(int signum) { - FILE *FD; - int fd; - - lprintf (1, "WebCit is being shut down on signal %d.\n", signum); - fd = msock; - msock = -1; - time_to_die = 1; - FD=fdopen(fd, "a+"); - fflush (FD); - fclose (FD); - close(fd); -} - - -/* - * Start running as a daemon. - */ -void start_daemon(char *pid_file) -{ - int status = 0; - pid_t child = 0; - FILE *fp; - int do_restart = 0; - int rv; - FILE *rvfp = NULL; - - current_child = 0; - - /* 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. - */ - rv = chdir("/"); - - signal(SIGHUP, SIG_IGN); - signal(SIGINT, SIG_IGN); - signal(SIGQUIT, SIG_IGN); - - child = fork(); - if (child != 0) { - exit(0); - } - - setsid(); - umask(0); - rvfp = freopen("/dev/null", "r", stdin); - rvfp = freopen("/dev/null", "w", stdout); - rvfp = freopen("/dev/null", "w", stderr); - signal(SIGTERM, graceful_shutdown_watcher); - signal(SIGHUP, graceful_shutdown_watcher); - - do { - current_child = fork(); - - - if (current_child < 0) { - perror("fork"); - ShutDownLibCitadel (); - exit(errno); - } - - else if (current_child == 0) { /* child process */ - signal(SIGHUP, graceful_shutdown); - - return; /* continue starting webcit. */ - } - else { /* watcher process */ - if (pid_file) { - fp = fopen(pid_file, "w"); - if (fp != NULL) { - fprintf(fp, "%d\n", getpid()); - fclose(fp); - } - } - waitpid(current_child, &status, 0); - } - - do_restart = 0; - - /* Did the main process exit with an actual exit code? */ - if (WIFEXITED(status)) { - - /* Exit code 0 means the watcher should exit */ - if (WEXITSTATUS(status) == 0) { - do_restart = 0; - } - - /* Exit code 101-109 means the watcher should exit */ - else if ( (WEXITSTATUS(status) >= 101) && (WEXITSTATUS(status) <= 109) ) { - do_restart = 0; - } - - /* Any other exit code means we should restart. */ - else { - do_restart = 1; - } - } - - /* Any other type of termination (signals, etc.) should also restart. */ - else { - do_restart = 1; - } - - } while (do_restart); - - if (pid_file) { - unlink(pid_file); - } - ShutDownLibCitadel (); - exit(WEXITSTATUS(status)); -} - -/* - * Spawn an additional worker thread into the pool. - */ -void spawn_another_worker_thread() -{ - pthread_t SessThread; /* Thread descriptor */ - pthread_attr_t attr; /* Thread attributes */ - int ret; - - lprintf(3, "Creating a new thread. Pool size is now %d\n", ++num_threads); - - /* set attributes for the new thread */ - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - - /* - * Our per-thread stacks need to be bigger than the default size, - * otherwise the MIME parser crashes on FreeBSD. - */ - if ((ret = pthread_attr_setstacksize(&attr, 1024 * 1024))) { - lprintf(1, "pthread_attr_setstacksize: %s\n", - strerror(ret)); - pthread_attr_destroy(&attr); - } - - /* now create the thread */ - if (pthread_create(&SessThread, &attr, - (void *(*)(void *)) worker_entry, NULL) - != 0) { - lprintf(1, "Can't create thread: %s\n", strerror(errno)); - } - - /* free up the attributes */ - pthread_attr_destroy(&attr); -} - /* #define DBG_PRINNT_HOOKS_AT_START */ #ifdef DBG_PRINNT_HOOKS_AT_START +extern HashList *HandlerHash; const char foobuf[32]; const char *nix(void *vptr) {snprintf(foobuf, 32, "%0x", (long) vptr); return foobuf;} #endif @@ -260,57 +65,9 @@ extern StrBuf *I18nDump; void InitTemplateCache(void); extern int LoadTemplates; -extern HashList *HandlerHash; -void -webcit_calc_dirs_n_files(int relh, const char *basedir, int home, char *webcitdir, char *relhome) -{ - char dirbuffer[PATH_MAX]=""; - /* 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=WWWDIR "/static"; - COMPUTE_DIRECTORY(static_dir); - basedir=WWWDIR "/static/icons"; - COMPUTE_DIRECTORY(static_icon_dir); - basedir=WWWDIR "/static.local"; - COMPUTE_DIRECTORY(static_local_dir); - StripSlashes(static_dir, 1); - StripSlashes(static_icon_dir, 1); - StripSlashes(static_local_dir, 1); - - snprintf(file_crpt_file_key, - sizeof file_crpt_file_key, - "%s/citadel.key", - ctdl_key_dir); - snprintf(file_crpt_file_csr, - sizeof file_crpt_file_csr, - "%s/citadel.csr", - ctdl_key_dir); - snprintf(file_crpt_file_cer, - sizeof file_crpt_file_cer, - "%s/citadel.cer", - ctdl_key_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"); - } -} /* * Here's where it all begins. */ @@ -599,207 +356,7 @@ int main(int argc, char **argv) } -void ShutDownWebcit(void) -{ - free_zone_directory (); - icaltimezone_release_zone_tab (); - icalmemory_free_ring (); - ShutDownLibCitadel (); - shutdown_modules (); -#ifdef HAVE_OPENSSL - if (is_https) { - shutdown_ssl(); - } -#endif -} - -/* - * Entry point for worker threads - */ -void worker_entry(void) -{ - int ssock; - int i = 0; - int fail_this_transaction = 0; - int ret; - struct timeval tv; - fd_set readset, tempset; - ParsedHttpHdrs Hdr; - - memset(&Hdr, 0, sizeof(ParsedHttpHdrs)); - Hdr.HR.eReqType = eGET; - http_new_modules(&Hdr); - tv.tv_sec = 0; - tv.tv_usec = 10000; - FD_ZERO(&readset); - FD_SET(msock, &readset); - - do { - /* Only one thread can accept at a time */ - fail_this_transaction = 0; - ssock = -1; - errno = EAGAIN; - do { - ret = -1; /* just one at once should select... */ - begin_critical_section(S_SELECT); - - FD_ZERO(&tempset); - if (msock > 0) FD_SET(msock, &tempset); - tv.tv_sec = 0; - tv.tv_usec = 10000; - if (msock > 0) ret = select(msock+1, &tempset, NULL, NULL, &tv); - end_critical_section(S_SELECT); - if ((ret < 0) && (errno != EINTR) && (errno != EAGAIN)) - {/* EINTR and EAGAIN are thrown but not of interest. */ - lprintf(2, "accept() failed:%d %s\n", - errno, strerror(errno)); - } - else if ((ret > 0) && (msock > 0) && FD_ISSET(msock, &tempset)) - {/* Successfully selected, and still not shutting down? Accept! */ - ssock = accept(msock, NULL, 0); - } - - } while ((msock > 0) && (ssock < 0) && (time_to_die == 0)); - - if ((msock == -1)||(time_to_die)) - {/* ok, we're going down. */ - int shutdown = 0; - - /* the first to come here will have to do the cleanup. - * make shure its realy just one. - */ - begin_critical_section(S_SHUTDOWN); - if (msock == -1) - { - msock = -2; - shutdown = 1; - } - end_critical_section(S_SHUTDOWN); - if (shutdown == 1) - {/* we're the one to cleanup the mess. */ - http_destroy_modules(&Hdr); - lprintf(2, "I'm master shutdown: tagging sessions to be killed.\n"); - shutdown_sessions(); - lprintf(2, "master shutdown: waiting for others\n"); - sleeeeeeeeeep(1); /* wait so some others might finish... */ - lprintf(2, "master shutdown: cleaning up sessions\n"); - do_housekeeping(); - lprintf(2, "master shutdown: cleaning up libical\n"); - - ShutDownWebcit(); - - lprintf(2, "master shutdown exiting!.\n"); - exit(0); - } - break; - } - if (ssock < 0 ) continue; - - if (msock < 0) { - if (ssock > 0) close (ssock); - lprintf(2, "inbetween."); - pthread_exit(NULL); - } else { /* Got it? do some real work! */ - /* Set the SO_REUSEADDR socket option */ - i = 1; - setsockopt(ssock, SOL_SOCKET, SO_REUSEADDR, - &i, sizeof(i)); - - /* If we are an HTTPS server, go crypto now. */ -#ifdef HAVE_OPENSSL - if (is_https) { - if (starttls(ssock) != 0) { - fail_this_transaction = 1; - close(ssock); - } - } - else -#endif - { - int fdflags; - fdflags = fcntl(ssock, F_GETFL); - if (fdflags < 0) - lprintf(1, "unable to get server socket flags! %s \n", - strerror(errno)); - fdflags = fdflags | O_NONBLOCK; - if (fcntl(ssock, F_SETFL, fdflags) < 0) - lprintf(1, "unable to set server socket nonblocking flags! %s \n", - strerror(errno)); - } - - if (fail_this_transaction == 0) { - Hdr.http_sock = ssock; - - /* Perform an HTTP transaction... */ - context_loop(&Hdr); - - /* Shut down SSL/TLS if required... */ -#ifdef HAVE_OPENSSL - if (is_https) { - endtls(); - } -#endif - - /* ...and close the socket. */ - if (Hdr.http_sock > 0) - lingering_close(ssock); - http_detach_modules(&Hdr); - - } - - } - - } while (!time_to_die); - - http_destroy_modules(&Hdr); - lprintf (1, "bye\n"); - pthread_exit(NULL); -} - -/* - * print log messages - * logs to stderr if loglevel is lower than the verbosity set at startup - * - * loglevel level of the message - * format the printf like format string - * ... the strings to put into format - */ -int lprintf(int loglevel, const char *format, ...) -{ - va_list ap; - - if (loglevel <= verbosity) { - va_start(ap, format); - vfprintf(stderr, format, ap); - va_end(ap); - fflush(stderr); - } - return 1; -} - -/* - * 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 -} diff --git a/webcit/webserver.h b/webcit/webserver.h index 291743e1f..1186e9c1c 100644 --- a/webcit/webserver.h +++ b/webcit/webserver.h @@ -1,7 +1,6 @@ /* $Id$ */ extern char *static_dirs[PATH_MAX]; /**< Web representation */ -extern char *static_content_dirs[PATH_MAX]; /**< Disk representation */ extern int ndirs; extern char socket_dir[PATH_MAX]; -- 2.30.2