From 5c39ca8a3c875df98163fed8923c258f21bb3f66 Mon Sep 17 00:00:00 2001 From: Art Cancro Date: Tue, 4 Apr 2017 16:26:47 -0400 Subject: [PATCH] Initial version of new room sharing poller. I don't really like this because it resembles a Gen 1 poller more than a Gen 3 poller, but this is going to be an intermediate step. --- citadel/Makefile.in | 4 +- citadel/citserver.c | 3 + citadel/citserver.h | 3 + citadel/clientsocket.c | 24 +- citadel/config.c | 3 + citadel/configure.ac | 53 - citadel/context.c | 65 +- citadel/context.h | 15 +- citadel/control.c | 2 +- citadel/database.c | 4 +- citadel/event_client.c | 1332 ----------------- citadel/event_client.h | 343 ----- citadel/housekeeping.c | 2 +- citadel/modules/c-ares-dns/serv_c-ares-dns.c | 626 -------- citadel/modules/calendar/serv_calendar.c | 2 +- citadel/modules/ctdlproto/serv_file.c | 6 +- citadel/modules/ctdlproto/serv_rooms.c | 4 + citadel/modules/dspam/.gitignore | 1 - citadel/modules/dspam/serv_dspam.c | 268 ---- citadel/modules/eventclient/serv_curl.h | 0 .../modules/eventclient/serv_eventclient.c | 917 ------------ citadel/modules/extnotify/.gitignore | 1 - citadel/modules/extnotify/extnotify.h | 53 - citadel/modules/extnotify/extnotify_main.c | 518 ------- citadel/modules/extnotify/funambol65.c | 315 ---- citadel/modules/network/serv_netmail.c | 17 +- citadel/modules/network/serv_netspool.c | 6 +- .../networkclient/serv_networkclient.c | 973 ++---------- citadel/modules/rwho/serv_rwho.c | 5 +- citadel/modules/sieve/serv_sieve.c | 4 +- citadel/modules/smtp/serv_smtp.c | 2 +- citadel/msgbase.c | 200 +-- citadel/msgbase.h | 71 +- citadel/serv_extensions.c | 5 +- citadel/server_main.c | 20 +- citadel/sysdep.c | 19 +- citadel/threads.c | 9 - citadel/user_ops.c | 4 +- 38 files changed, 263 insertions(+), 5636 deletions(-) delete mode 100644 citadel/event_client.c delete mode 100644 citadel/event_client.h delete mode 100644 citadel/modules/c-ares-dns/serv_c-ares-dns.c delete mode 100644 citadel/modules/dspam/.gitignore delete mode 100644 citadel/modules/dspam/serv_dspam.c delete mode 100644 citadel/modules/eventclient/serv_curl.h delete mode 100644 citadel/modules/eventclient/serv_eventclient.c delete mode 100644 citadel/modules/extnotify/.gitignore delete mode 100644 citadel/modules/extnotify/extnotify.h delete mode 100644 citadel/modules/extnotify/extnotify_main.c delete mode 100644 citadel/modules/extnotify/funambol65.c diff --git a/citadel/Makefile.in b/citadel/Makefile.in index 7586e782e..912052c24 100644 --- a/citadel/Makefile.in +++ b/citadel/Makefile.in @@ -81,7 +81,7 @@ SOURCES=utils/aidepost.c utils/citmail.c \ locate_host.c auth.c msgbase.c parsedate.c \ room_ops.c euidindex.c server_main.c ldap.c \ support.c sysdep.c user_ops.c journaling.c threads.c \ - context.c event_client.c netconfig.c nttlist.c md5.c + context.c netconfig.c nttlist.c md5.c include Make_sources @@ -127,7 +127,7 @@ Make_modules: modules_init.c modules_upgrade.c: modules_init.c -SERV_OBJS = server_main.o utillib/citadel_dirs.o event_client.o \ +SERV_OBJS = server_main.o utillib/citadel_dirs.o \ user_ops.o citserver.o sysdep.o serv_extensions.o \ $(DATABASE:.c=.o) domain.o \ control.o config.o support.o room_ops.o \ diff --git a/citadel/citserver.c b/citadel/citserver.c index f389ac9f0..447d68f06 100644 --- a/citadel/citserver.c +++ b/citadel/citserver.c @@ -12,7 +12,10 @@ * GNU General Public License for more details. */ +#include +#include #include +#include #include "sysdep.h" #include #if HAVE_BACKTRACE diff --git a/citadel/citserver.h b/citadel/citserver.h index 61f1964b7..cce5c51a2 100644 --- a/citadel/citserver.h +++ b/citadel/citserver.h @@ -10,6 +10,9 @@ * GNU General Public License for more details. */ +/* I fucking hate const and want it to die. */ +#pragma GCC diagnostic ignored "-Wcast-qual" + #include "serv_extensions.h" #include "context.h" #include "ctdl_module.h" diff --git a/citadel/clientsocket.c b/citadel/clientsocket.c index 91485bedc..ed54c2f77 100644 --- a/citadel/clientsocket.c +++ b/citadel/clientsocket.c @@ -15,6 +15,9 @@ * GNU General Public License for more details. */ +#include +#include +#include #include #include #include "ctdl_module.h" @@ -101,18 +104,12 @@ int sock_connect(char *host, char *service) * 0 Request timed out. * -1 Connection is broken, or other error. */ -int socket_read_blob(int *Socket, StrBuf * Target, int bytes, int timeout) +int socket_read_blob(int *Socket, StrBuf *Target, int bytes, int timeout) { - CitContext *CCC = MyContext(); const char *Error; int retval = 0; - - retval = StrBufReadBLOBBuffered(Target, - CCC->SBuf.Buf, - &CCC->SBuf.ReadWritePointer, - Socket, 1, bytes, O_TERM, &Error); - + retval = StrBufReadBLOBBuffered(Target, CC->SBuf.Buf, &CC->SBuf.ReadWritePointer, Socket, 1, bytes, O_TERM, &Error); if (retval < 0) { syslog(LOG_CRIT, "socket_read_blob() failed: %s", Error); } @@ -120,7 +117,7 @@ int socket_read_blob(int *Socket, StrBuf * Target, int bytes, int timeout) } -int CtdlSockGetLine(int *sock, StrBuf * Target, int nSec) +int CtdlSockGetLine(int *sock, StrBuf *Target, int nSec) { CitContext *CCC = MyContext(); const char *Error; @@ -131,16 +128,15 @@ int CtdlSockGetLine(int *sock, StrBuf * Target, int nSec) CCC->SBuf.Buf, &CCC->SBuf.ReadWritePointer, sock, nSec, 1, &Error); - if ((rc < 0) && (Error != NULL)) + if ((rc < 0) && (Error != NULL)) { syslog(LOG_CRIT, "CtdlSockGetLine() failed: %s", Error); + } return rc; } /* * client_getln() ... Get a LF-terminated line of text from the client. - * (This is implemented in terms of client_read() and could be - * justifiably moved out of sysdep.c) */ int sock_getln(int *sock, char *buf, int bufsize) { @@ -232,11 +228,8 @@ int sock_write_timeout(int *sock, const char *buf, int nbytes, int timeout) } - /* * client_getln() ... Get a LF-terminated line of text from the client. - * (This is implemented in terms of client_read() and could be - * justifiably moved out of sysdep.c) */ int sock_getln_err(int *sock, char *buf, int bufsize, int *rc, int nSec) { @@ -260,6 +253,7 @@ int sock_getln_err(int *sock, char *buf, int bufsize, int *rc, int nSec) return i; } + /* * Multiline version of sock_gets() ... this is a convenience function for * client side protocol implementations. It only returns the first line of diff --git a/citadel/config.c b/citadel/config.c index 46105383b..9cc1b3a3d 100644 --- a/citadel/config.c +++ b/citadel/config.c @@ -13,7 +13,10 @@ */ #include "sysdep.h" +#include +#include #include +#include #include #include #include diff --git a/citadel/configure.ac b/citadel/configure.ac index 0e0247f3d..39fe88db2 100644 --- a/citadel/configure.ac +++ b/citadel/configure.ac @@ -565,59 +565,6 @@ AC_CHECK_HEADER(libcitadel.h, CFLAGS="$saved_CFLAGS" -AC_CHECK_LIB(cares, ares_parse_mx_reply, - [ - C_ARES_LIBS=-lcares - AC_DEFINE(HAVE_C_ARES, 1, [Define to use c-ares library]) - have_good_c_ares=yes - ],, $SOCKET_LIBS $NSL_LIBS -) - - - -saved_CFLAGS="$CFLAGS" -CFLAGS="$CFLAGS $SERVER_LIBS" -dnl Check for c-ares -AC_CHECK_HEADER(ares.h, - [AC_CHECK_LIB(cares, ares_parse_mx_reply, - [ - LIBS="-lcares $LIBS $SERVER_LIBS" - ], - [ - AC_MSG_ERROR(libc-ares was not found or is not usable. Please install libc-ares.) - ] - )], - [ - AC_MSG_ERROR(ares.h was not found or is not usable. Please install libc-ares.) - ] -) -CFLAGS="$saved_CFLAGS" - -saved_CFLAGS="$CFLAGS" -CFLAGS="$CFLAGS $SERVER_LIBS" -dnl Check for libev -AC_CHECK_HEADER(ev.h, - [AC_TRY_COMPILE([#include -#include ], - [ - ev_cleanup abort_by_shutdown; - struct ev_loop *event_base; - ev_cleanup_start(event_base, &abort_by_shutdown); - ], - [ - LIBS="-lev -lm $LIBS $SERVER_LIBS" - ], - [ - AC_MSG_ERROR(libev was not found or is not usable. Please install libev.) - ]) - ], - [ - AC_MSG_ERROR(ev.h was not found or is not usable. Please install libev.) - ] -) -CFLAGS="$saved_CFLAGS" - - # The big search for OpenSSL if test "$with_ssl" != "no"; then saved_LIBS="$LIBS" diff --git a/citadel/context.c b/citadel/context.c index 82ab97b43..a9ba4fbb4 100644 --- a/citadel/context.c +++ b/citadel/context.c @@ -102,7 +102,7 @@ int CtdlTerminateOtherSession (int session_num) aide = ( (CCC->user.axlevel >= AxAideU) || (CCC->internal_pgm) ) ; - syslog(LOG_DEBUG, "Locating session to kill\n"); + syslog(LOG_DEBUG, "context: locating session to kill"); begin_critical_section(S_SESSION_TABLE); for (ccptr = ContextList; ccptr != NULL; ccptr = ccptr->next) { if (session_num == ccptr->cs_pid) { @@ -116,19 +116,11 @@ int CtdlTerminateOtherSession (int session_num) if (((ret & TERM_FOUND) != 0) && ((ret & TERM_ALLOWED) != 0)) { - if (ccptr->IO != NULL) { - AsyncIO *IO = ccptr->IO; - end_critical_section(S_SESSION_TABLE); - KillAsyncIOContext(IO); - } + if (ccptr->user.usernum == CCC->user.usernum) + ccptr->kill_me = KILLME_ADMIN_TERMINATE; else - { - if (ccptr->user.usernum == CCC->user.usernum) - ccptr->kill_me = KILLME_ADMIN_TERMINATE; - else - ccptr->kill_me = KILLME_IDLE; - end_critical_section(S_SESSION_TABLE); - } + ccptr->kill_me = KILLME_IDLE; + end_critical_section(S_SESSION_TABLE); } else end_critical_section(S_SESSION_TABLE); @@ -258,10 +250,12 @@ void terminate_idle_sessions(void) } } end_critical_section(S_SESSION_TABLE); - if (killed > 0) - syslog(LOG_INFO, "Scheduled %d idle sessions for termination\n", killed); - if (longrunners > 0) - syslog(LOG_INFO, "Didn't terminate %d protected idle sessions", longrunners); + if (killed > 0) { + syslog(LOG_INFO, "context: scheduled %d idle sessions for termination", killed); + } + if (longrunners > 0) { + syslog(LOG_INFO, "context: did not terminate %d protected idle sessions", longrunners); + } } @@ -277,12 +271,7 @@ void terminate_all_sessions(void) for (ccptr = ContextList; ccptr != NULL; ccptr = ccptr->next) { if (ccptr->client_socket != -1) { - if (ccptr->IO != NULL) { - syslog(LOG_INFO, "terminate_all_sessions() is murdering %s IO[%ld]CC[%d]", ccptr->curr_user, ccptr->IO->ID, ccptr->cs_pid); - } - else { - syslog(LOG_INFO, "terminate_all_sessions() is murdering %s CC[%d]", ccptr->curr_user, ccptr->cs_pid); - } + syslog(LOG_INFO, "context: terminate_all_sessions() is murdering %s CC[%d]", ccptr->curr_user, ccptr->cs_pid); close(ccptr->client_socket); ccptr->client_socket = -1; killed++; @@ -290,7 +279,7 @@ void terminate_all_sessions(void) } end_critical_section(S_SESSION_TABLE); if (killed > 0) { - syslog(LOG_INFO, "Flushed %d stuck sessions\n", killed); + syslog(LOG_INFO, "context: flushed %d stuck sessions", killed); } } @@ -303,14 +292,14 @@ void RemoveContext (CitContext *con) { const char *c; if (con == NULL) { - syslog(LOG_ERR, "WARNING: RemoveContext() called with NULL!"); + syslog(LOG_ERR, "context: RemoveContext() called with NULL, this should not happen"); return; } c = con->ServiceName; if (c == NULL) { c = "WTF?"; } - syslog(LOG_DEBUG, "RemoveContext(%s) session %d", c, con->cs_pid); + syslog(LOG_DEBUG, "context: RemoveContext(%s) session %d", c, con->cs_pid); /// cit_backtrace(); /* Run any cleanup routines registered by loadable modules. @@ -323,7 +312,7 @@ void RemoveContext (CitContext *con) client_close(); /* If the client is still connected, blow 'em away. */ become_session(NULL); - syslog(LOG_NOTICE, "[%3d]SRV[%s] Session ended.", con->cs_pid, c); + syslog(LOG_INFO, "context: [%3d]SRV[%s] Session ended.", con->cs_pid, c); /* * If the client is still connected, blow 'em away. @@ -331,7 +320,7 @@ void RemoveContext (CitContext *con) */ if (con->client_socket > 0) { - syslog(LOG_NOTICE, "Closing socket %d", con->client_socket); + syslog(LOG_INFO, "context: closing socket %d", con->client_socket); close(con->client_socket); } @@ -347,7 +336,7 @@ void RemoveContext (CitContext *con) free(con->cached_msglist); } - syslog(LOG_DEBUG, "Done with RemoveContext()"); + syslog(LOG_DEBUG, "context: done with RemoveContext()"); } @@ -363,7 +352,7 @@ CitContext *CreateNewContext(void) { me = (CitContext *) malloc(sizeof(CitContext)); if (me == NULL) { - syslog(LOG_ALERT, "citserver: can't allocate memory!!\n"); + syslog(LOG_ERR, "citserver: malloc() failed: %s", strerror(errno)); return NULL; } memset(me, 0, sizeof(CitContext)); @@ -412,7 +401,7 @@ CitContext *CloneContext(CitContext *CloneMe) { me = (CitContext *) malloc(sizeof(CitContext)); if (me == NULL) { - syslog(LOG_ALERT, "citserver: can't allocate memory!!\n"); + syslog(LOG_ERR, "citserver: malloc() failed: %s", strerror(errno)); return NULL; } memcpy(me, CloneMe, sizeof(CitContext)); @@ -536,7 +525,7 @@ void begin_session(CitContext *con) /*fill in the user data structure */ if(getsockopt(con->client_socket, SOL_SOCKET, SO_PEERCRED, &credentials, &ucred_length)) { - syslog(LOG_NOTICE, "could obtain credentials from unix domain socket"); + syslog(LOG_ERR, "context: could obtain credentials from unix domain socket"); } else { @@ -572,10 +561,10 @@ void begin_session(CitContext *con) } if (!CC->is_local_socket) { - syslog(LOG_NOTICE, "Session (%s) started from %s (%s).\n", con->ServiceName, con->cs_host, con->cs_addr); + syslog(LOG_INFO, "context: session (%s) started from %s (%s)", con->ServiceName, con->cs_host, con->cs_addr); } else { - syslog(LOG_NOTICE, "Session (%s) started via local socket UID:%d.\n", con->ServiceName, con->cs_UDSclientUID); + syslog(LOG_INFO, "context: session (%s) started via local socket with uid=%d", con->ServiceName, con->cs_UDSclientUID); } /* Run any session startup routines registered by loadable modules */ @@ -612,7 +601,7 @@ void CtdlFillSystemContext(CitContext *context, char *name) if (context->user.usernum == 0) { /* old system user with number 0, upgrade it */ context->user.usernum = get_new_user_number(); - syslog(LOG_INFO, "Upgrading system user \"%s\" from user number 0 to user number %ld\n", context->user.fullname, context->user.usernum); + syslog(LOG_INFO, "context: upgrading system user \"%s\" from user number 0 to user number %ld", context->user.fullname, context->user.usernum); /* add user to the database */ CtdlPutUser(&(context->user)); cdb_store(CDB_USERSBYNUMBER, &(context->user.usernum), sizeof(long), context->user.fullname, strlen(context->user.fullname)+1); @@ -646,7 +635,7 @@ void context_cleanup(void) rem = ptr->next; --num_sessions; - syslog(LOG_DEBUG, "context_cleanup(): purging session %d\n", ptr->cs_pid); + syslog(LOG_DEBUG, "context: context_cleanup() purging session %d", ptr->cs_pid); RemoveContext(ptr); free (ptr); ptr = rem; @@ -706,7 +695,7 @@ void dead_session_purge(int force) { * is allocated privately on this thread's stack. */ while (rem != NULL) { - syslog(LOG_DEBUG, "dead_session_purge(): purging session %d, reason=%d\n", rem->cs_pid, rem->kill_me); + syslog(LOG_DEBUG, "context: dead_session_purge() purging session %d, reason=%d", rem->cs_pid, rem->kill_me); RemoveContext(rem); ptr = rem; rem = rem->next; @@ -737,7 +726,7 @@ void InitializeMasterCC(void) { */ void set_async_waiting(struct CitContext *ccptr) { - syslog(LOG_DEBUG, "Setting async_waiting flag for session %d\n", ccptr->cs_pid); + syslog(LOG_DEBUG, "context: setting async_waiting flag for session %d", ccptr->cs_pid); if (ccptr->is_async) { ccptr->async_waiting++; if (ccptr->state == CON_IDLE) { diff --git a/citadel/context.h b/citadel/context.h index 755d1998b..76d2a9191 100644 --- a/citadel/context.h +++ b/citadel/context.h @@ -28,10 +28,12 @@ typedef enum __CCState { CON_SYS /* This is a system context and mustn't be purged */ } CCState; -#ifndef __ASYNCIO__ -#define __ASYNCIO__ -typedef struct AsyncIO AsyncIO; /* forward declaration for event_client.h */ -#endif +//#ifndef __ASYNCIO__ +//#define __ASYNCIO__ +//typedef struct AsyncIO AsyncIO; /* forward declaration for event_client.h */ +//#endif + + #ifndef __CIT_CONTEXT__ #define __CIT_CONTEXT__ typedef struct CitContext CitContext; @@ -151,14 +153,11 @@ struct CitContext { char vcard_updated_by_ldap; /* !0 iff ldap changed the vcard, treat as aide update */ - AsyncIO *IO; /* if this session has AsyncIO going on... */ + //AsyncIO *IO; /* if this session has AsyncIO going on... */ }; - - #define CC MyContext() - extern pthread_key_t MyConKey; /* TSD key for MyContext() */ extern int num_sessions; extern CitContext masterCC; diff --git a/citadel/control.c b/citadel/control.c index fce46a00c..077809178 100644 --- a/citadel/control.c +++ b/citadel/control.c @@ -619,7 +619,7 @@ void cmd_conf(char *argbuf) extract_token(confname, argbuf, 1, '|', sizeof confname); unbuffer_output(); cprintf("%d %s\n", SEND_LISTING, confname); - confptr = CtdlReadMessageBody(HKEY("000"), CtdlGetConfigLong("c_maxmsglen"), NULL, 0, 0); + confptr = CtdlReadMessageBody(HKEY("000"), CtdlGetConfigLong("c_maxmsglen"), NULL, 0); CtdlPutSysConfig(confname, confptr); free(confptr); } diff --git a/citadel/database.c b/citadel/database.c index bc36e6f04..ea47a169e 100644 --- a/citadel/database.c +++ b/citadel/database.c @@ -27,6 +27,9 @@ /*****************************************************************************/ #include "sysdep.h" +#include +#include +#include #include #include #include @@ -49,7 +52,6 @@ #include "control.h" #include "citserver.h" #include "config.h" -#pragma GCC diagnostic ignored "-Wcast-qual" static DB *dbp[MAXCDB]; /* One DB handle for each Citadel database */ static DB_ENV *dbenv; /* The DB environment (global) */ diff --git a/citadel/event_client.c b/citadel/event_client.c deleted file mode 100644 index 1d0fad542..000000000 --- a/citadel/event_client.c +++ /dev/null @@ -1,1332 +0,0 @@ -/* - * Copyright (c) 1998-2017 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. - * - * 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. - */ -#include "sysdep.h" - -#include -#include -#include -#include -#include -#include -#include -#if HAVE_BACKTRACE -#include -#endif - -#include - -#include "ctdl_module.h" -#include "event_client.h" -#include "citserver.h" -#include "config.h" - -ConstStr IOStates[] = { - {HKEY("DB Queue")}, - {HKEY("DB Q Next")}, - {HKEY("DB Attach")}, - {HKEY("DB Next")}, - {HKEY("DB Stop")}, - {HKEY("DB Exit")}, - {HKEY("DB Terminate")}, - {HKEY("IO Queue")}, - {HKEY("IO Attach")}, - {HKEY("IO Connect Socket")}, - {HKEY("IO Abort")}, - {HKEY("IO Timeout")}, - {HKEY("IO ConnFail")}, - {HKEY("IO ConnFail Now")}, - {HKEY("IO Conn Now")}, - {HKEY("IO Conn Wait")}, - {HKEY("Curl Q")}, - {HKEY("Curl Start")}, - {HKEY("Curl Shotdown")}, - {HKEY("Curl More IO")}, - {HKEY("Curl Got IO")}, - {HKEY("Curl Got Data")}, - {HKEY("Curl Got Status")}, - {HKEY("C-Ares Start")}, - {HKEY("C-Ares IO Done")}, - {HKEY("C-Ares Finished")}, - {HKEY("C-Ares exit")}, - {HKEY("Killing")}, - {HKEY("Exit")} -}; - -void SetEVState(AsyncIO *IO, eIOState State) -{ - - CitContext* CCC = IO->CitContext; - if (CCC != NULL) - memcpy(CCC->lastcmdname, IOStates[State].Key, IOStates[State].len + 1); - -} - -eNextState QueueAnEventContext(AsyncIO *IO); -static void IO_Timeout_callback(struct ev_loop *loop, ev_timer *watcher, int revents); -static void IO_abort_shutdown_callback(struct ev_loop *loop, - ev_cleanup *watcher, - int revents); - - -/*------------------------------------------------------------------------------ - * Server DB IO - *----------------------------------------------------------------------------*/ -extern int evdb_count; -extern pthread_mutex_t DBEventQueueMutex; -extern pthread_mutex_t DBEventExitQueueMutex; -extern HashList *DBInboundEventQueue; -extern struct ev_loop *event_db; -extern ev_async DBAddJob; -extern ev_async DBExitEventLoop; - -eNextState QueueAnDBOperation(AsyncIO *IO) -{ - IOAddHandler *h; - int i; - - SetEVState(IO, eDBQ); - h = (IOAddHandler*)malloc(sizeof(IOAddHandler)); - h->IO = IO; - - assert(IO->ReAttachCB != NULL); - - h->EvAttch = IO->ReAttachCB; - ev_cleanup_init(&IO->db_abort_by_shutdown, - IO_abort_shutdown_callback); - IO->db_abort_by_shutdown.data = IO; - - pthread_mutex_lock(&DBEventQueueMutex); - if (DBInboundEventQueue == NULL) - { - /* shutting down... */ - free(h); - syslog(LOG_DEBUG, "DBEVENT Q exiting.\n"); - pthread_mutex_unlock(&DBEventQueueMutex); - return eAbort; - } - syslog(LOG_DEBUG, "DBEVENT Q\n"); - i = ++evdb_count ; - Put(DBInboundEventQueue, IKEY(i), h, NULL); - pthread_mutex_unlock(&DBEventQueueMutex); - - pthread_mutex_lock(&DBEventExitQueueMutex); - if (event_db == NULL) - { - pthread_mutex_unlock(&DBEventExitQueueMutex); - return eAbort; - } - ev_async_send (event_db, &DBAddJob); - pthread_mutex_unlock(&DBEventExitQueueMutex); - - syslog(LOG_DEBUG, "DBEVENT Q Done.\n"); - return eDBQuery; -} - -void StopDBWatchers(AsyncIO *IO) -{ - SetEVState(IO, eDBStop); - ev_cleanup_stop(event_db, &IO->db_abort_by_shutdown); - ev_idle_stop(event_db, &IO->db_unwind_stack); -} - -void ShutDownDBCLient(AsyncIO *IO) -{ - CitContext *Ctx =IO->CitContext; - become_session(Ctx); - - SetEVState(IO, eDBTerm); - syslog(LOG_DEBUG, "DBEVENT Terminating.\n"); - StopDBWatchers(IO); - - assert(IO->DBTerminate); - IO->DBTerminate(IO); -} - -void -DB_PerformNext(struct ev_loop *loop, ev_idle *watcher, int revents) -{ - AsyncIO *IO = watcher->data; - - SetEVState(IO, eDBNext); - SET_EV_TIME(IO, event_db); - syslog(LOG_DEBUG, "%s()", __FUNCTION__); - become_session(IO->CitContext); - - ev_idle_stop(event_db, &IO->db_unwind_stack); - - assert(IO->NextDBOperation); - switch (IO->NextDBOperation(IO)) - { - case eSendReply: - ev_cleanup_stop(loop, &IO->db_abort_by_shutdown); - QueueAnEventContext(IO); - break; - case eDBQuery: - break; - case eSendDNSQuery: - case eReadDNSReply: - case eConnect: - case eSendMore: - case eSendFile: - case eReadMessage: - case eReadMore: - case eReadPayload: - case eReadFile: - ev_cleanup_stop(loop, &IO->db_abort_by_shutdown); - break; - case eTerminateConnection: - case eAbort: - ev_idle_stop(event_db, &IO->db_unwind_stack); - ev_cleanup_stop(loop, &IO->db_abort_by_shutdown); - ShutDownDBCLient(IO); - } -} - -eNextState NextDBOperation(AsyncIO *IO, IO_CallBack CB) -{ - SetEVState(IO, eQDBNext); - IO->NextDBOperation = CB; - ev_idle_init(&IO->db_unwind_stack, - DB_PerformNext); - IO->db_unwind_stack.data = IO; - ev_idle_start(event_db, &IO->db_unwind_stack); - return eDBQuery; -} - -/*------------------------------------------------------------------------------ - * Client IO - *----------------------------------------------------------------------------*/ -extern int evbase_count; -extern pthread_mutex_t EventQueueMutex; -extern pthread_mutex_t EventExitQueueMutex; -extern HashList *InboundEventQueue; -extern struct ev_loop *event_base; -extern ev_async AddJob; -extern ev_async ExitEventLoop; - -static void IO_abort_shutdown_callback(struct ev_loop *loop, - ev_cleanup *watcher, - int revents) -{ - AsyncIO *IO = watcher->data; - - SetEVState(IO, eIOAbort); - syslog(LOG_DEBUG, "EVENT Q: %s\n", __FUNCTION__); - SET_EV_TIME(IO, event_base); - assert(IO->ShutdownAbort); - IO->ShutdownAbort(IO); -} - - -eNextState QueueAnEventContext(AsyncIO *IO) -{ - IOAddHandler *h; - int i; - - SetEVState(IO, eIOQ); - h = (IOAddHandler*)malloc(sizeof(IOAddHandler)); - h->IO = IO; - - assert(IO->ReAttachCB != NULL); - - h->EvAttch = IO->ReAttachCB; - - ev_cleanup_init(&IO->abort_by_shutdown, - IO_abort_shutdown_callback); - IO->abort_by_shutdown.data = IO; - - pthread_mutex_lock(&EventQueueMutex); - if (InboundEventQueue == NULL) - { - free(h); - /* shutting down... */ - syslog(LOG_DEBUG, "EVENT Q exiting.\n"); - pthread_mutex_unlock(&EventQueueMutex); - return eAbort; - } - syslog(LOG_DEBUG, "EVENT Q\n"); - i = ++evbase_count; - Put(InboundEventQueue, IKEY(i), h, NULL); - pthread_mutex_unlock(&EventQueueMutex); - - pthread_mutex_lock(&EventExitQueueMutex); - if (event_base == NULL) { - pthread_mutex_unlock(&EventExitQueueMutex); - return eAbort; - } - ev_async_send (event_base, &AddJob); - pthread_mutex_unlock(&EventExitQueueMutex); - syslog(LOG_DEBUG, "EVENT Q Done.\n"); - return eSendReply; -} - -eNextState EventQueueDBOperation(AsyncIO *IO, IO_CallBack CB, int CloseFDs) -{ - StopClientWatchers(IO, CloseFDs); - IO->ReAttachCB = CB; - return eDBQuery; -} -eNextState DBQueueEventContext(AsyncIO *IO, IO_CallBack CB) -{ - StopDBWatchers(IO); - IO->ReAttachCB = CB; - return eSendReply; -} - -eNextState QueueEventContext(AsyncIO *IO, IO_CallBack CB) -{ - IO->ReAttachCB = CB; - return QueueAnEventContext(IO); -} - -extern eNextState evcurl_handle_start(AsyncIO *IO); - -eNextState QueueCurlContext(AsyncIO *IO) -{ - IOAddHandler *h; - int i; - - SetEVState(IO, eCurlQ); - h = (IOAddHandler*)malloc(sizeof(IOAddHandler)); - h->IO = IO; - h->EvAttch = evcurl_handle_start; - - pthread_mutex_lock(&EventQueueMutex); - if (InboundEventQueue == NULL) - { - /* shutting down... */ - free(h); - syslog(LOG_DEBUG, "EVENT Q exiting.\n"); - pthread_mutex_unlock(&EventQueueMutex); - return eAbort; - } - - syslog(LOG_DEBUG, "EVENT Q\n"); - i = ++evbase_count; - Put(InboundEventQueue, IKEY(i), h, NULL); - pthread_mutex_unlock(&EventQueueMutex); - - pthread_mutex_lock(&EventExitQueueMutex); - if (event_base == NULL) { - pthread_mutex_unlock(&EventExitQueueMutex); - return eAbort; - } - ev_async_send (event_base, &AddJob); - pthread_mutex_unlock(&EventExitQueueMutex); - - syslog(LOG_DEBUG, "EVENT Q Done.\n"); - return eSendReply; -} - -eNextState CurlQueueDBOperation(AsyncIO *IO, IO_CallBack CB) -{ - StopCurlWatchers(IO); - IO->ReAttachCB = CB; - return eDBQuery; -} - - -void FreeAsyncIOContents(AsyncIO *IO) -{ - CitContext *Ctx = IO->CitContext; - - FreeStrBuf(&IO->IOBuf); - FreeStrBuf(&IO->SendBuf.Buf); - FreeStrBuf(&IO->RecvBuf.Buf); - - FreeURL(&IO->ConnectMe); - FreeStrBuf(&IO->HttpReq.ReplyData); - - if (Ctx) { - Ctx->state = CON_IDLE; - Ctx->kill_me = 1; - IO->CitContext = NULL; - } -} - - -void DestructCAres(AsyncIO *IO); -void StopClientWatchers(AsyncIO *IO, int CloseFD) -{ - syslog(LOG_DEBUG, "EVENT StopClientWatchers"); - - DestructCAres(IO); - - ev_timer_stop (event_base, &IO->rw_timeout); - ev_timer_stop(event_base, &IO->conn_fail); - ev_idle_stop(event_base, &IO->unwind_stack); - ev_cleanup_stop(event_base, &IO->abort_by_shutdown); - - ev_io_stop(event_base, &IO->conn_event); - ev_io_stop(event_base, &IO->send_event); - ev_io_stop(event_base, &IO->recv_event); - - if (CloseFD && (IO->SendBuf.fd > 0)) { - close(IO->SendBuf.fd); - IO->SendBuf.fd = 0; - IO->RecvBuf.fd = 0; - } -} - -void StopCurlWatchers(AsyncIO *IO) -{ - syslog(LOG_DEBUG, "EVENT StopCurlWatchers \n"); - - ev_timer_stop (event_base, &IO->rw_timeout); - ev_timer_stop(event_base, &IO->conn_fail); - ev_idle_stop(event_base, &IO->unwind_stack); - ev_cleanup_stop(event_base, &IO->abort_by_shutdown); - - ev_io_stop(event_base, &IO->conn_event); - ev_io_stop(event_base, &IO->send_event); - ev_io_stop(event_base, &IO->recv_event); - - curl_easy_cleanup(IO->HttpReq.chnd); - IO->HttpReq.chnd = NULL; - - if (IO->SendBuf.fd != 0) { - close(IO->SendBuf.fd); - } - IO->SendBuf.fd = 0; - IO->RecvBuf.fd = 0; -} - -eNextState ShutDownCLient(AsyncIO *IO) -{ - CitContext *Ctx =IO->CitContext; - - SetEVState(IO, eExit); - become_session(Ctx); - - syslog(LOG_DEBUG, "EVENT Terminating \n"); - - StopClientWatchers(IO, 1); - - if (IO->DNS.Channel != NULL) { - ares_destroy(IO->DNS.Channel); - EV_DNS_LOG_STOP(DNS.recv_event); - EV_DNS_LOG_STOP(DNS.send_event); - ev_io_stop(event_base, &IO->DNS.recv_event); - ev_io_stop(event_base, &IO->DNS.send_event); - IO->DNS.Channel = NULL; - } - assert(IO->Terminate); - return IO->Terminate(IO); -} - -void PostInbound(AsyncIO *IO) -{ - - switch (IO->NextState) { - case eSendFile: - ev_io_start(event_base, &IO->send_event); - break; - case eSendReply: - case eSendMore: - assert(IO->SendDone); - IO->NextState = IO->SendDone(IO); - switch (IO->NextState) - { - case eSendFile: - case eSendReply: - case eSendMore: - case eReadMessage: - case eReadPayload: - case eReadMore: - case eReadFile: - ev_io_start(event_base, &IO->send_event); - break; - case eDBQuery: - StopClientWatchers(IO, 0); - QueueAnDBOperation(IO); - default: - break; - } - break; - case eReadPayload: - case eReadMore: - case eReadFile: - ev_io_start(event_base, &IO->recv_event); - break; - case eTerminateConnection: - case eAbort: - if (ShutDownCLient(IO) == eDBQuery) { - QueueAnDBOperation(IO); - } - break; - case eSendDNSQuery: - case eReadDNSReply: - case eConnect: - case eReadMessage: - break; - case eDBQuery: - QueueAnDBOperation(IO); - } -} -eReadState HandleInbound(AsyncIO *IO) -{ - const char *Err = NULL; - eReadState Finished = eBufferNotEmpty; - - become_session(IO->CitContext); - - while ((Finished == eBufferNotEmpty) && - ((IO->NextState == eReadMessage)|| - (IO->NextState == eReadMore)|| - (IO->NextState == eReadFile)|| - (IO->NextState == eReadPayload))) - { - /* Reading lines... - * lex line reply in callback, - * or do it ourselves. - * i.e. as nnn-blabla means continue reading in SMTP - */ - if ((IO->NextState == eReadFile) && - (Finished == eBufferNotEmpty)) - { - Finished = WriteIOBAlreadyRead(&IO->IOB, &Err); - if (Finished == eReadSuccess) - { - IO->NextState = eSendReply; - } - } - else if (IO->LineReader) - Finished = IO->LineReader(IO); - else - Finished = StrBufChunkSipLine(IO->IOBuf, - &IO->RecvBuf); - - switch (Finished) { - case eMustReadMore: /// read new from socket... - break; - case eBufferNotEmpty: /* shouldn't happen... */ - case eReadSuccess: /// done for now... - break; - case eReadFail: /// WHUT? - ///todo: shut down! - break; - } - - if (Finished != eMustReadMore) { - ev_io_stop(event_base, &IO->recv_event); - IO->NextState = IO->ReadDone(IO); - if (IO->NextState == eDBQuery) { - if (QueueAnDBOperation(IO) == eAbort) - return eReadFail; - else - return eReadSuccess; - } - else { - Finished = StrBufCheckBuffer(&IO->RecvBuf); - } - } - } - - PostInbound(IO); - - return Finished; -} - - -static void -IO_send_callback(struct ev_loop *loop, ev_io *watcher, int revents) -{ - int rc; - AsyncIO *IO = watcher->data; - const char *errmsg = NULL; - - SET_EV_TIME(IO, event_base); - become_session(IO->CitContext); -#ifdef BIGBAD_IODBG - { - int rv = 0; - char fn [SIZ]; - FILE *fd; - const char *pch = ChrPtr(IO->SendBuf.Buf); - const char *pchh = IO->SendBuf.ReadWritePointer; - long nbytes; - - if (pchh == NULL) - pchh = pch; - - nbytes = StrLength(IO->SendBuf.Buf) - (pchh - pch); - snprintf(fn, SIZ, "/tmp/foolog_ev_%s.%d", - ((CitContext*)(IO->CitContext))->ServiceName, - IO->SendBuf.fd); - - fd = fopen(fn, "a+"); - if (fd == NULL) { - syslog(LOG_EMERG, "failed to open file %s: %s", fn, strerror(errno)); - cit_backtrace(); - exit(1); - } - fprintf(fd, "Send: BufSize: %ld BufContent: [", - nbytes); - rv = fwrite(pchh, nbytes, 1, fd); - if (!rv) printf("failed to write debug to %s!\n", fn); - fprintf(fd, "]\n"); -#endif - switch (IO->NextState) { - case eSendFile: - rc = FileSendChunked(&IO->IOB, &errmsg); - if (rc < 0) - StrBufPlain(IO->ErrMsg, errmsg, -1); - break; - default: - rc = StrBuf_write_one_chunk_callback(IO->SendBuf.fd, - 0, - &IO->SendBuf); - } - -#ifdef BIGBAD_IODBG - fprintf(fd, "Sent: BufSize: %d bytes.\n", rc); - fclose(fd); - } -#endif - if (rc == 0) - { - ev_io_stop(event_base, &IO->send_event); - switch (IO->NextState) { - case eSendMore: - assert(IO->SendDone); - IO->NextState = IO->SendDone(IO); - - if ((IO->NextState == eTerminateConnection) || - (IO->NextState == eAbort) ) - ShutDownCLient(IO); - else { - ev_io_start(event_base, &IO->send_event); - } - break; - case eSendFile: - if (IO->IOB.ChunkSendRemain > 0) { - ev_io_start(event_base, &IO->recv_event); - SetNextTimeout(IO, 100.0); - - } else { - assert(IO->ReadDone); - IO->NextState = IO->ReadDone(IO); - switch(IO->NextState) { - case eSendDNSQuery: - case eReadDNSReply: - case eDBQuery: - case eConnect: - break; - case eSendReply: - case eSendMore: - case eSendFile: - ev_io_start(event_base, - &IO->send_event); - break; - case eReadMessage: - case eReadMore: - case eReadPayload: - case eReadFile: - break; - case eTerminateConnection: - case eAbort: - break; - } - } - break; - case eSendReply: - if (StrBufCheckBuffer(&IO->SendBuf) != eReadSuccess) - break; - IO->NextState = eReadMore; - case eReadMore: - case eReadMessage: - case eReadPayload: - case eReadFile: - if (StrBufCheckBuffer(&IO->RecvBuf) == eBufferNotEmpty) - { - HandleInbound(IO); - } - else { - ev_io_start(event_base, &IO->recv_event); - } - - break; - case eDBQuery: - /* - * we now live in another queue, - * so we have to unregister. - */ - ev_cleanup_stop(loop, &IO->abort_by_shutdown); - break; - case eSendDNSQuery: - case eReadDNSReply: - case eConnect: - case eTerminateConnection: - case eAbort: - break; - } - } - else if (rc < 0) { - if (errno != EAGAIN) { - StopClientWatchers(IO, 1); - syslog(LOG_DEBUG, - "IO_send_callback(): Socket Invalid! [%d] [%s] [%d]\n", - errno, strerror(errno), IO->SendBuf.fd); - StrBufPrintf(IO->ErrMsg, - "Socket Invalid! [%s]", - strerror(errno)); - SetNextTimeout(IO, 0.01); - } - } - /* else : must write more. */ -} -static void -set_start_callback(struct ev_loop *loop, AsyncIO *IO, int revents) -{ - ev_timer_stop(event_base, &IO->conn_fail); - ev_timer_start(event_base, &IO->rw_timeout); - - switch(IO->NextState) { - case eReadMore: - case eReadMessage: - case eReadFile: - StrBufAppendBufPlain(IO->ErrMsg, HKEY("[while waiting for greeting]"), 0); - ev_io_start(event_base, &IO->recv_event); - break; - case eSendReply: - case eSendMore: - case eReadPayload: - case eSendFile: - become_session(IO->CitContext); - IO_send_callback(loop, &IO->send_event, revents); - break; - case eDBQuery: - case eSendDNSQuery: - case eReadDNSReply: - case eConnect: - case eTerminateConnection: - case eAbort: - /// TODO: WHUT? - break; - } -} - -static void -IO_Timeout_callback(struct ev_loop *loop, ev_timer *watcher, int revents) -{ - AsyncIO *IO = watcher->data; - - SetEVState(IO, eIOTimeout); - SET_EV_TIME(IO, event_base); - ev_timer_stop (event_base, &IO->rw_timeout); - become_session(IO->CitContext); - - if (IO->SendBuf.fd != 0) - { - ev_io_stop(event_base, &IO->send_event); - ev_io_stop(event_base, &IO->recv_event); - ev_timer_stop (event_base, &IO->rw_timeout); - close(IO->SendBuf.fd); - IO->SendBuf.fd = IO->RecvBuf.fd = 0; - } - - assert(IO->Timeout); - switch (IO->Timeout(IO)) - { - case eAbort: - ShutDownCLient(IO); - default: - break; - } -} - -static void -IO_connfail_callback(struct ev_loop *loop, ev_timer *watcher, int revents) -{ - AsyncIO *IO = watcher->data; - - SetEVState(IO, eIOConnfail); - SET_EV_TIME(IO, event_base); - ev_timer_stop (event_base, &IO->conn_fail); - - if (IO->SendBuf.fd != 0) - { - ev_io_stop(loop, &IO->conn_event); - ev_io_stop(event_base, &IO->send_event); - ev_io_stop(event_base, &IO->recv_event); - ev_timer_stop (event_base, &IO->rw_timeout); - close(IO->SendBuf.fd); - IO->SendBuf.fd = IO->RecvBuf.fd = 0; - } - become_session(IO->CitContext); - - assert(IO->ConnFail); - switch (IO->ConnFail(IO)) - { - case eAbort: - ShutDownCLient(IO); - default: - break; - - } -} - -static void -IO_connfailimmediate_callback(struct ev_loop *loop, - ev_idle *watcher, - int revents) -{ - AsyncIO *IO = watcher->data; - - SetEVState(IO, eIOConnfailNow); - SET_EV_TIME(IO, event_base); - ev_idle_stop (event_base, &IO->conn_fail_immediate); - - if (IO->SendBuf.fd != 0) - { - close(IO->SendBuf.fd); - IO->SendBuf.fd = IO->RecvBuf.fd = 0; - } - become_session(IO->CitContext); - - assert(IO->ConnFail); - switch (IO->ConnFail(IO)) - { - case eAbort: - ShutDownCLient(IO); - default: - break; - - } -} - -static void -IO_connestd_callback(struct ev_loop *loop, ev_io *watcher, int revents) -{ - AsyncIO *IO = watcher->data; - int so_err = 0; - socklen_t lon = sizeof(so_err); - int err; - - SetEVState(IO, eIOConnNow); - SET_EV_TIME(IO, event_base); - syslog(LOG_DEBUG, "connect() succeeded.\n"); - - ev_io_stop(loop, &IO->conn_event); - ev_timer_stop(event_base, &IO->conn_fail); - - err = getsockopt(IO->SendBuf.fd, - SOL_SOCKET, - SO_ERROR, - (void*)&so_err, - &lon); - - if ((err == 0) && (so_err != 0)) - { - syslog(LOG_DEBUG, "connect() failed [%d][%s]\n", - so_err, - strerror(so_err)); - IO_connfail_callback(loop, &IO->conn_fail, revents); - - } - else - { - syslog(LOG_DEBUG, "connect() succeeded\n"); - set_start_callback(loop, IO, revents); - } -} - -static void -IO_recv_callback(struct ev_loop *loop, ev_io *watcher, int revents) -{ - const char *errmsg; - ssize_t nbytes; - AsyncIO *IO = watcher->data; - - SET_EV_TIME(IO, event_base); - switch (IO->NextState) { - case eReadFile: - nbytes = FileRecvChunked(&IO->IOB, &errmsg); - if (nbytes < 0) - StrBufPlain(IO->ErrMsg, errmsg, -1); - else - { - if (IO->IOB.ChunkSendRemain == 0) - { - IO->NextState = eSendReply; - assert(IO->ReadDone); - ev_io_stop(event_base, &IO->recv_event); - PostInbound(IO); - return; - } - else - return; - } - break; - default: - nbytes = StrBuf_read_one_chunk_callback(IO->RecvBuf.fd, - 0, - &IO->RecvBuf); - break; - } - -#ifdef BIGBAD_IODBG - { - long nbytes; - int rv = 0; - char fn [SIZ]; - FILE *fd; - const char *pch = ChrPtr(IO->RecvBuf.Buf); - const char *pchh = IO->RecvBuf.ReadWritePointer; - - if (pchh == NULL) - pchh = pch; - - nbytes = StrLength(IO->RecvBuf.Buf) - (pchh - pch); - snprintf(fn, SIZ, "/tmp/foolog_ev_%s.%d", - ((CitContext*)(IO->CitContext))->ServiceName, - IO->SendBuf.fd); - - fd = fopen(fn, "a+"); - if (fd == NULL) { - syslog(LOG_EMERG, "failed to open file %s: %s", fn, strerror(errno)); - cit_backtrace(); - exit(1); - } - fprintf(fd, "Read: BufSize: %ld BufContent: [", - nbytes); - rv = fwrite(pchh, nbytes, 1, fd); - if (!rv) printf("failed to write debug to %s!\n", fn); - fprintf(fd, "]\n"); - fclose(fd); - } -#endif - if (nbytes > 0) { - HandleInbound(IO); - } else if (nbytes == 0) { - StopClientWatchers(IO, 1); - SetNextTimeout(IO, 0.01); - return; - } else if (nbytes == -1) { - if (errno != EAGAIN) { - // FD is gone. kick it. - StopClientWatchers(IO, 1); - syslog(LOG_DEBUG, - "IO_recv_callback(): Socket Invalid! [%d] [%s] [%d]\n", - errno, strerror(errno), IO->SendBuf.fd); - StrBufPrintf(IO->ErrMsg, - "Socket Invalid! [%s]", - strerror(errno)); - SetNextTimeout(IO, 0.01); - } - return; - } -} - -void -IO_postdns_callback(struct ev_loop *loop, ev_idle *watcher, int revents) -{ - AsyncIO *IO = watcher->data; - - SetEVState(IO, eCaresFinished); - SET_EV_TIME(IO, event_base); - syslog(LOG_DEBUG, "event: %s\n", __FUNCTION__); - become_session(IO->CitContext); - assert(IO->DNS.Query->PostDNS); - switch (IO->DNS.Query->PostDNS(IO)) - { - case eAbort: - assert(IO->DNS.Fail); - switch (IO->DNS.Fail(IO)) { - case eAbort: -//// StopClientWatchers(IO); - ShutDownCLient(IO); - break; - case eDBQuery: - StopClientWatchers(IO, 0); - QueueAnDBOperation(IO); - break; - default: - break; - } - case eDBQuery: - StopClientWatchers(IO, 0); - QueueAnDBOperation(IO); - break; - default: - break; - } -} - - -eNextState EvConnectSock(AsyncIO *IO, - double conn_timeout, - double first_rw_timeout, - int ReadFirst) -{ - struct sockaddr_in egress_sin; - int fdflags; - int rc = -1; - - SetEVState(IO, eIOConnectSock); - become_session(IO->CitContext); - - if (ReadFirst) { - IO->NextState = eReadMessage; - } - else { - IO->NextState = eSendReply; - } - - IO->SendBuf.fd = IO->RecvBuf.fd = - socket( - (IO->ConnectMe->IPv6)?PF_INET6:PF_INET, - SOCK_STREAM, - IPPROTO_TCP); - - if (IO->SendBuf.fd < 0) { - syslog(LOG_ERR, - "EVENT: socket() failed: %s\n", - strerror(errno)); - - StrBufPrintf(IO->ErrMsg, - "Failed to create socket: %s", - strerror(errno)); - IO->SendBuf.fd = IO->RecvBuf.fd = 0; - return eAbort; - } - fdflags = fcntl(IO->SendBuf.fd, F_GETFL); - if (fdflags < 0) { - syslog(LOG_ERR, - "EVENT: unable to get socket %d flags! %s \n", - IO->SendBuf.fd, - strerror(errno)); - StrBufPrintf(IO->ErrMsg, - "Failed to get socket %d flags: %s", - IO->SendBuf.fd, - strerror(errno)); - close(IO->SendBuf.fd); - IO->SendBuf.fd = IO->RecvBuf.fd = 0; - return eAbort; - } - fdflags = fdflags | O_NONBLOCK; - if (fcntl(IO->SendBuf.fd, F_SETFL, fdflags) < 0) { - syslog( - LOG_ERR, - "EVENT: unable to set socket %d nonblocking flags! %s \n", - IO->SendBuf.fd, - strerror(errno)); - StrBufPrintf(IO->ErrMsg, - "Failed to set socket flags: %s", - strerror(errno)); - close(IO->SendBuf.fd); - IO->SendBuf.fd = IO->RecvBuf.fd = 0; - return eAbort; - } -/* TODO: maye we could use offsetof() to calc the position of data... - * http://doc.dvgu.ru/devel/ev.html#associating_custom_data_with_a_watcher - */ - ev_io_init(&IO->recv_event, IO_recv_callback, IO->RecvBuf.fd, EV_READ); - IO->recv_event.data = IO; - ev_io_init(&IO->send_event, IO_send_callback, IO->SendBuf.fd, EV_WRITE); - IO->send_event.data = IO; - - ev_timer_init(&IO->conn_fail, IO_connfail_callback, conn_timeout, 0); - IO->conn_fail.data = IO; - ev_timer_init(&IO->rw_timeout, IO_Timeout_callback, first_rw_timeout,0); - IO->rw_timeout.data = IO; - - - - - /* for debugging you may bypass it like this: - * IO->Addr.sin_addr.s_addr = inet_addr("127.0.0.1"); - * ((struct sockaddr_in)IO->ConnectMe->Addr).sin_addr.s_addr = - * inet_addr("127.0.0.1"); - */ - if (IO->ConnectMe->IPv6) { - rc = connect(IO->SendBuf.fd, - &IO->ConnectMe->Addr, - sizeof(struct sockaddr_in6)); - } - else { - /* If citserver is bound to a specific IP address on the host, make - * sure we use that address for outbound connections. - */ - - memset(&egress_sin, 0, sizeof(egress_sin)); - egress_sin.sin_family = AF_INET; - if (!IsEmptyStr(CtdlGetConfigStr("c_ip_addr"))) { - egress_sin.sin_addr.s_addr = inet_addr(CtdlGetConfigStr("c_ip_addr")); - if (egress_sin.sin_addr.s_addr == !INADDR_ANY) { - egress_sin.sin_addr.s_addr = INADDR_ANY; - } - - /* If this bind fails, no problem; we can still use INADDR_ANY */ - bind(IO->SendBuf.fd, (struct sockaddr *)&egress_sin, sizeof(egress_sin)); - } - rc = connect(IO->SendBuf.fd, - (struct sockaddr_in *)&IO->ConnectMe->Addr, - sizeof(struct sockaddr_in)); - } - - if (rc >= 0){ - SetEVState(IO, eIOConnNow); - syslog(LOG_DEBUG, "connect() = %d immediate success.\n", IO->SendBuf.fd); - set_start_callback(event_base, IO, 0); - return IO->NextState; - } - else if (errno == EINPROGRESS) { - SetEVState(IO, eIOConnWait); - syslog(LOG_DEBUG, "connect() = %d have to wait now.\n", IO->SendBuf.fd); - - ev_io_init(&IO->conn_event, - IO_connestd_callback, - IO->SendBuf.fd, - EV_READ|EV_WRITE); - - IO->conn_event.data = IO; - - ev_io_start(event_base, &IO->conn_event); - ev_timer_start(event_base, &IO->conn_fail); - return IO->NextState; - } - else { - SetEVState(IO, eIOConnfail); - ev_idle_init(&IO->conn_fail_immediate, - IO_connfailimmediate_callback); - IO->conn_fail_immediate.data = IO; - ev_idle_start(event_base, &IO->conn_fail_immediate); - - syslog(LOG_ERR, - "connect() = %d failed: %s\n", - IO->SendBuf.fd, - strerror(errno)); - - StrBufPrintf(IO->ErrMsg, - "Failed to connect: %s", - strerror(errno)); - return IO->NextState; - } - return IO->NextState; -} - -void SetNextTimeout(AsyncIO *IO, double timeout) -{ - IO->rw_timeout.repeat = timeout; - ev_timer_again (event_base, &IO->rw_timeout); -} - - -eNextState ReAttachIO(AsyncIO *IO, - void *pData, - int ReadFirst) -{ - SetEVState(IO, eIOAttach); - IO->Data = pData; - become_session(IO->CitContext); - ev_cleanup_start(event_base, &IO->abort_by_shutdown); - if (ReadFirst) { - IO->NextState = eReadMessage; - } - else { - IO->NextState = eSendReply; - } - set_start_callback(event_base, IO, 0); - - return IO->NextState; -} - -void InitIOStruct(AsyncIO *IO, - void *Data, - eNextState NextState, - IO_LineReaderCallback LineReader, - IO_CallBack DNS_Fail, - IO_CallBack SendDone, - IO_CallBack ReadDone, - IO_CallBack Terminate, - IO_CallBack DBTerminate, - IO_CallBack ConnFail, - IO_CallBack Timeout, - IO_CallBack ShutdownAbort) -{ - IO->Data = Data; - - IO->CitContext = CloneContext(CC); - IO->CitContext->session_specific_data = Data; - IO->CitContext->IO = IO; - - IO->NextState = NextState; - - IO->SendDone = SendDone; - IO->ReadDone = ReadDone; - IO->Terminate = Terminate; - IO->DBTerminate = DBTerminate; - IO->LineReader = LineReader; - IO->ConnFail = ConnFail; - IO->Timeout = Timeout; - IO->ShutdownAbort = ShutdownAbort; - - IO->DNS.Fail = DNS_Fail; - - IO->SendBuf.Buf = NewStrBufPlain(NULL, 1024); - IO->RecvBuf.Buf = NewStrBufPlain(NULL, 1024); - IO->IOBuf = NewStrBuf(); - syslog(LOG_DEBUG, - "EVENT: Session lives at %p IO at %p \n", - Data, IO); - -} - -extern int evcurl_init(AsyncIO *IO); - -int InitcURLIOStruct(AsyncIO *IO, - void *Data, - const char* Desc, - IO_CallBack SendDone, - IO_CallBack Terminate, - IO_CallBack DBTerminate, - IO_CallBack ShutdownAbort) -{ - IO->Data = Data; - - IO->CitContext = CloneContext(CC); - IO->CitContext->session_specific_data = Data; - IO->CitContext->IO = IO; - - IO->SendDone = SendDone; - IO->Terminate = Terminate; - IO->DBTerminate = DBTerminate; - IO->ShutdownAbort = ShutdownAbort; - - strcpy(IO->HttpReq.errdesc, Desc); - - - return evcurl_init(IO); - -} - - -typedef struct KillOtherSessionContext { - AsyncIO IO; - AsyncIO *OtherOne; -}KillOtherSessionContext; - -eNextState KillTerminate(AsyncIO *IO) -{ - long id; - KillOtherSessionContext *Ctx = (KillOtherSessionContext*)IO->Data; - syslog(LOG_DEBUG, "%s Exit\n", __FUNCTION__); - id = IO->ID; - FreeAsyncIOContents(IO); - memset(Ctx, 0, sizeof(KillOtherSessionContext)); - IO->ID = id; /* just for the case we want to analyze it in a coredump */ - free(Ctx); - return eAbort; - -} - -eNextState KillShutdown(AsyncIO *IO) -{ - return eTerminateConnection; -} - -eNextState KillOtherContextNow(AsyncIO *IO) -{ - KillOtherSessionContext *Ctx = IO->Data; - - SetEVState(IO, eKill); - - if (Ctx->OtherOne->ShutdownAbort != NULL) { - Ctx->OtherOne->NextState = eAbort; - if (Ctx->OtherOne->ShutdownAbort(Ctx->OtherOne) == eDBQuery) { - StopClientWatchers(Ctx->OtherOne, 0); - QueueAnDBOperation(Ctx->OtherOne); - } - } - return eTerminateConnection; -} - -void KillAsyncIOContext(AsyncIO *IO) -{ - KillOtherSessionContext *Ctx; - - Ctx = (KillOtherSessionContext*) malloc(sizeof(KillOtherSessionContext)); - memset(Ctx, 0, sizeof(KillOtherSessionContext)); - - InitIOStruct(&Ctx->IO, - Ctx, - eReadMessage, - NULL, - NULL, - NULL, - NULL, - KillTerminate, - NULL, - NULL, - NULL, - KillShutdown); - - Ctx->OtherOne = IO; - - switch(IO->NextState) { - case eSendDNSQuery: - case eReadDNSReply: - - case eConnect: - case eSendReply: - case eSendMore: - case eSendFile: - - case eReadMessage: - case eReadMore: - case eReadPayload: - case eReadFile: - Ctx->IO.ReAttachCB = KillOtherContextNow; - QueueAnEventContext(&Ctx->IO); - break; - case eDBQuery: - Ctx->IO.ReAttachCB = KillOtherContextNow; - QueueAnDBOperation(&Ctx->IO); - break; - case eTerminateConnection: - case eAbort: - /*hm, its already dying, dunno which Queue its in... */ - free(Ctx); - } - -} - -extern int DebugEventLoopBacktrace; -void EV_backtrace(AsyncIO *IO) -{ -#ifdef HAVE_BACKTRACE - void *stack_frames[50]; - size_t size, i; - char **strings; - - if ((IO == NULL) || (DebugEventLoopBacktrace == 0)) - return; - size = backtrace(stack_frames, sizeof(stack_frames) / sizeof(void*)); - strings = backtrace_symbols(stack_frames, size); - for (i = 0; i < size; i++) { - if (strings != NULL) { - syslog(LOG_ALERT, " BT %s\n", strings[i]); - } - else { - syslog(LOG_ALERT, " BT %p\n", stack_frames[i]); - } - } - free(strings); -#endif -} - - -ev_tstamp ctdl_ev_now (void) -{ - return ev_now(event_base); -} diff --git a/citadel/event_client.h b/citadel/event_client.h deleted file mode 100644 index 2b5b698bd..000000000 --- a/citadel/event_client.h +++ /dev/null @@ -1,343 +0,0 @@ -/* - * - * Copyright (c) 1998-2012 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. - * - * 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. - */ - -#ifndef __EVENT_CLIENT_H__ -#define __EVENT_CLIENT_H__ -#define EV_COMPAT3 0 -#include "sysconfig.h" -#include -#include -#include -#include -#include -#include -#include - -#ifndef __ASYNCIO__ -#define __ASYNCIO__ -typedef struct AsyncIO AsyncIO; -#endif -#ifndef __CIT_CONTEXT__ -#define __CIT_CONTEXT__ -typedef struct CitContext CitContext; -#endif - -extern pthread_key_t evConKey; - -typedef enum __eIOState { - eDBQ, - eQDBNext, - eDBAttach, - eDBNext, - eDBStop, - eDBX, - eDBTerm, - eIOQ, - eIOAttach, - eIOConnectSock, - eIOAbort, - eIOTimeout, - eIOConnfail, - eIOConnfailNow, - eIOConnNow, - eIOConnWait, - eCurlQ, - eCurlStart, - eCurlShutdown, - eCurlNewIO, - eCurlGotIO, - eCurlGotData, - eCurlGotStatus, - eCaresStart, - eCaresDoneIO, - eCaresFinished, - eCaresX, - eKill, - eExit -}eIOState; - -typedef enum _eNextState { - eSendDNSQuery, - eReadDNSReply, - - eDBQuery, - - eConnect, - eSendReply, - eSendMore, - eSendFile, - - eReadMessage, - eReadMore, - eReadPayload, - eReadFile, - - eTerminateConnection, - eAbort -}eNextState; - -void SetEVState(AsyncIO *IO, eIOState State); - -typedef eNextState (*IO_CallBack)(AsyncIO *IO); -typedef eReadState (*IO_LineReaderCallback)(AsyncIO *IO); -typedef void (*ParseDNSAnswerCb)(AsyncIO*, unsigned char*, int); -typedef void (*FreeDNSReply)(void *DNSData); - - -typedef struct __ReadAsyncMsg { - StrBuf *MsgBuf; - size_t maxlen; /* maximum message length */ - - const char *terminator; /* token signalling EOT */ - long tlen; - int dodot; - - int flushing; -/* if we read maxlen, read until nothing more arives and ignore this. */ - - int crlf; /* CRLF newlines instead of LF */ -} ReadAsyncMsg; - - -typedef struct _DNSQueryParts { - ParseDNSAnswerCb DNS_CB; - IO_CallBack PostDNS; - - const char *QueryTYPE; - const char *QStr; - int DNSStatus; - void *VParsedDNSReply; - FreeDNSReply DNSReplyFree; - void *Data; -} DNSQueryParts; - -typedef struct _evcurl_request_data -{ - CURL *chnd; - struct curl_slist *headers; - char errdesc[CURL_ERROR_SIZE]; - const char *CurlError; - - int attached; - - char *PlainPostData; - long PlainPostDataLen; - StrBuf *PostData; - - StrBuf *ReplyData; - long httpcode; -} evcurl_request_data; - -/* DNS Related */ -typedef struct __evcares_data { - ev_tstamp Start; - ev_io recv_event, - send_event; - ev_timer timeout; /* timeout while requesting ips */ - short int SourcePort; - - struct ares_options Options; - ares_channel Channel; - DNSQueryParts *Query; - - IO_CallBack Fail; /* the dns lookup didn't work out. */ -} evcares_data; - - -struct AsyncIO { - long ID; - ev_tstamp Now; - ev_tstamp StartIO; - ev_tstamp StartDB; - eNextState NextState; - - /* connection related */ - ParsedURL *ConnectMe; - - /* read/send related... */ - StrBuf *IOBuf; - IOBuffer SendBuf, - RecvBuf; - - FDIOBuffer IOB; - /* when sending from / reading into files, this is used. */ - - /* our events... */ - ev_cleanup abort_by_shutdown, /* server wants to go down... */ - db_abort_by_shutdown; /* server wants to go down... */ - ev_timer conn_fail, /* connection establishing timed out */ - rw_timeout; /* timeout while sending data */ - ev_idle unwind_stack, /* get c-ares out of the stack */ - db_unwind_stack, /* wait for next db operation... */ - conn_fail_immediate; /* unwind stack, but fail immediately. */ - ev_io recv_event, /* receive data from the client */ - send_event, /* send more data to the client */ - conn_event; /* Connection successfully established */ - - StrBuf *ErrMsg; /* if we fail to connect, or lookup, error goes here. */ - - /* Citadel application callbacks... */ - IO_CallBack ReadDone, /* Theres new data to read... */ - SendDone, /* we may send more data */ - Terminate, /* shutting down... */ - DBTerminate, /* shutting down... */ - Timeout, /* Timeout handler;may also be conn. timeout */ - ConnFail, /* What to do when one connection failed? */ - ShutdownAbort,/* we're going down. make your piece. */ - NextDBOperation, /* Perform Database IO */ - ReAttachCB; /* on the hop from one Q to the other, this is the next CB */ - - /* if we have linereaders, maybe we want to read more lines before - * the real application logic is called? */ - IO_LineReaderCallback LineReader; - - evcares_data DNS; - - evcurl_request_data HttpReq; - - /* Saving / loading a message async from / to disk */ - ReadAsyncMsg *ReadMsg; - struct CtdlMessage *AsyncMsg; - recptypes *AsyncRcp; - - /* Context specific data; Hint: put AsyncIO in there */ - void *Data; /* application specific data */ - CitContext *CitContext; /* Citadel Session context... */ -}; - -typedef struct _IOAddHandler { - AsyncIO *IO; - IO_CallBack EvAttch; -} IOAddHandler; - - -inline static time_t EvGetNow(AsyncIO *IO) { return (time_t) IO->Now;} - -extern int DebugEventLoop; -extern int DebugCAres; - -#define IOSTR (const char *) pthread_getspecific(evConKey) - -#define EDBGLOG(LEVEL) if ((LEVEL != LOG_DEBUG) || (DebugEventLoop != 0)) - -#define CCID ((CitContext*)IO->CitContext)?((CitContext*)IO->CitContext)->cs_pid:-1 - -#define CDBGLOG() if (DebugCAres != 0) -#define CEDBGLOG(LEVEL) if ((LEVEL != LOG_DEBUG) || (DebugCAres != 0)) -#define EV_DNS_LOG_START(a) \ - CDBGLOG () {syslog(LOG_DEBUG, "%s[%ld]CC[%d] + Starting " #a " %s %p FD %d", IOSTR, IO->ID, CCID, __FUNCTION__, &IO->a, IO->a.fd); \ - EV_backtrace(IO);} - -#define EV_DNS_LOG_STOP(a) \ - CDBGLOG () { syslog(LOG_DEBUG, "%s[%ld]CC[%d] - Stopping " #a " %s %p FD %d", IOSTR, IO->ID, CCID, __FUNCTION__, &IO->a, IO->a.fd); \ - EV_backtrace(IO);} - -#define EV_DNS_LOG_INIT(a) \ - CDBGLOG () { syslog(LOG_DEBUG, "%s[%ld]CC[%d] * Init " #a " %s %p FD %d", IOSTR, IO->ID, CCID, __FUNCTION__, &IO->a, IO->a.fd); \ - EV_backtrace(IO);} - -#define EV_DNS_LOGT_START(a) \ - CDBGLOG () { syslog(LOG_DEBUG, "%s[%ld]CC[%d] + Starting " #a " %s %p", IOSTR, IO->ID, CCID, __FUNCTION__, &IO->a); \ - EV_backtrace(IO);} - -#define EV_DNS_LOGT_STOP(a) \ - CDBGLOG () { syslog(LOG_DEBUG, "%s[%ld]CC[%d] - Stopping " #a " %s %p", IOSTR, IO->ID, CCID, __FUNCTION__, &IO->a); \ - EV_backtrace(IO); } - -#define EV_DNS_LOGT_INIT(a) \ - CDBGLOG () { syslog(LOG_DEBUG, "%s[%ld]CC[%d] * Init " #a " %p", IOSTR, IO->ID, CCID, &IO->a); \ - EV_backtrace(IO);} - -void FreeAsyncIOContents(AsyncIO *IO); - -eNextState NextDBOperation(AsyncIO *IO, IO_CallBack CB); -eNextState EventQueueDBOperation(AsyncIO *IO, IO_CallBack CB, int CloseFDs); -void StopDBWatchers(AsyncIO *IO); -eNextState QueueEventContext(AsyncIO *IO, IO_CallBack CB); -eNextState QueueCurlContext(AsyncIO *IO); -eNextState DBQueueEventContext(AsyncIO *IO, IO_CallBack CB); - -eNextState EvConnectSock(AsyncIO *IO, - double conn_timeout, - double first_rw_timeout, - int ReadFirst); -void IO_postdns_callback(struct ev_loop *loop, ev_idle *watcher, int revents); - -int QueueQuery(ns_type Type, - const char *name, - AsyncIO *IO, - DNSQueryParts *QueryParts, - IO_CallBack PostDNS); - -void QueueGetHostByName(AsyncIO *IO, - const char *Hostname, - DNSQueryParts *QueryParts, - IO_CallBack PostDNS); - -void QueryCbDone(AsyncIO *IO); - -void StopClient(AsyncIO *IO); - -void StopClientWatchers(AsyncIO *IO, int CloseFD); - -void SetNextTimeout(AsyncIO *IO, double timeout); - -#include - -#define OPT(s, v) \ - do { \ - sta = curl_easy_setopt(chnd, (CURLOPT_##s), (v)); \ - if (sta) { \ - syslog(LOG_ERR, \ - "error setting option " #s \ - " on curl handle: %s", \ - curl_easy_strerror(sta)); \ - } } while (0) - -#define SET_EV_TIME(IO, BASE) \ - IO->Now = ev_now(BASE); \ - if (IO->CitContext != NULL) IO->CitContext->lastcmd = IO->Now; - -void InitIOStruct(AsyncIO *IO, - void *Data, - eNextState NextState, - IO_LineReaderCallback LineReader, - IO_CallBack DNS_Fail, - IO_CallBack SendDone, - IO_CallBack ReadDone, - IO_CallBack Terminate, - IO_CallBack DBTerminate, - IO_CallBack ConnFail, - IO_CallBack Timeout, - IO_CallBack ShutdownAbort); - -int InitcURLIOStruct(AsyncIO *IO, - void *Data, - const char* Desc, - IO_CallBack SendDone, - IO_CallBack Terminate, - IO_CallBack DBTerminate, - IO_CallBack ShutdownAbort); -void KillAsyncIOContext(AsyncIO *IO); -void StopCurlWatchers(AsyncIO *IO); - -eNextState CurlQueueDBOperation(AsyncIO *IO, IO_CallBack CB); - -eNextState ReAttachIO(AsyncIO *IO, - void *pData, - int ReadFirst); - -void EV_backtrace(AsyncIO *IO); -ev_tstamp ctdl_ev_now (void); - -#endif /* __EVENT_CLIENT_H__ */ diff --git a/citadel/housekeeping.c b/citadel/housekeeping.c index 139ada05e..b685c701a 100644 --- a/citadel/housekeeping.c +++ b/citadel/housekeeping.c @@ -164,7 +164,7 @@ retry_wait_for_contexts: { for (i=0; i -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if TIME_WITH_SYS_TIME -# include -# include -#else -# if HAVE_SYS_TIME_H -# include -# else -# include -# endif -#endif -#include -#include -#include -#include -#include -#include -#include - -#include -#include "citadel.h" -#include "server.h" -#include "citserver.h" -#include "support.h" - -#include "ctdl_module.h" -#include "event_client.h" - -int DebugCAres = 0; - -extern struct ev_loop *event_base; - -void SockStateCb(void *data, int sock, int read, int write); - - -static void HostByAddrCb(void *data, - int status, - int timeouts, - struct hostent *hostent) -{ - AsyncIO *IO = data; - - syslog(LOG_DEBUG, "c-ares: %s", __FUNCTION__); - - EV_DNS_LOGT_STOP(DNS.timeout); - ev_timer_stop (event_base, &IO->DNS.timeout); - - IO->DNS.Query->DNSStatus = status; - if (status != ARES_SUCCESS) { - StrBufPlain(IO->ErrMsg, ares_strerror(status), -1); - return; - } - IO->DNS.Query->Data = hostent; -} - -static void ParseAnswerA(AsyncIO *IO, unsigned char* abuf, int alen) -{ - struct hostent* host = NULL; - - syslog(LOG_DEBUG, "c-ares: %s", __FUNCTION__); - - if (IO->DNS.Query->VParsedDNSReply != NULL) - IO->DNS.Query->DNSReplyFree(IO->DNS.Query->VParsedDNSReply); - IO->DNS.Query->VParsedDNSReply = NULL; - - IO->DNS.Query->DNSStatus = ares_parse_a_reply(abuf, - alen, - &host, - NULL, - NULL); - if (IO->DNS.Query->DNSStatus != ARES_SUCCESS) { - if (host != NULL) - ares_free_hostent(host); - StrBufPlain(IO->ErrMsg, - ares_strerror(IO->DNS.Query->DNSStatus), -1); - return; - } - IO->DNS.Query->VParsedDNSReply = host; - IO->DNS.Query->DNSReplyFree = (FreeDNSReply) ares_free_hostent; -} - - -static void ParseAnswerAAAA(AsyncIO *IO, unsigned char* abuf, int alen) -{ - struct hostent* host = NULL; - - syslog(LOG_DEBUG, "c-ares: %s", __FUNCTION__); - - if (IO->DNS.Query->VParsedDNSReply != NULL) - IO->DNS.Query->DNSReplyFree(IO->DNS.Query->VParsedDNSReply); - IO->DNS.Query->VParsedDNSReply = NULL; - - IO->DNS.Query->DNSStatus = ares_parse_aaaa_reply(abuf, - alen, - &host, - NULL, - NULL); - if (IO->DNS.Query->DNSStatus != ARES_SUCCESS) { - if (host != NULL) - ares_free_hostent(host); - StrBufPlain(IO->ErrMsg, - ares_strerror(IO->DNS.Query->DNSStatus), -1); - return; - } - IO->DNS.Query->VParsedDNSReply = host; - IO->DNS.Query->DNSReplyFree = (FreeDNSReply) ares_free_hostent; -} - - -static void ParseAnswerCNAME(AsyncIO *IO, unsigned char* abuf, int alen) -{ - struct hostent* host = NULL; - - syslog(LOG_DEBUG, "c-ares: %s", __FUNCTION__); - - if (IO->DNS.Query->VParsedDNSReply != NULL) - IO->DNS.Query->DNSReplyFree(IO->DNS.Query->VParsedDNSReply); - IO->DNS.Query->VParsedDNSReply = NULL; - - IO->DNS.Query->DNSStatus = ares_parse_a_reply(abuf, - alen, - &host, - NULL, - NULL); - if (IO->DNS.Query->DNSStatus != ARES_SUCCESS) { - if (host != NULL) - ares_free_hostent(host); - StrBufPlain(IO->ErrMsg, - ares_strerror(IO->DNS.Query->DNSStatus), -1); - return; - } - - // a CNAME lookup always returns a single record but - IO->DNS.Query->VParsedDNSReply = host; - IO->DNS.Query->DNSReplyFree = (FreeDNSReply) ares_free_hostent; -} - - -static void ParseAnswerMX(AsyncIO *IO, unsigned char* abuf, int alen) -{ - struct ares_mx_reply *mx_out = NULL; - - syslog(LOG_DEBUG, "c-ares: %s", __FUNCTION__); - - if (IO->DNS.Query->VParsedDNSReply != NULL) - IO->DNS.Query->DNSReplyFree(IO->DNS.Query->VParsedDNSReply); - IO->DNS.Query->VParsedDNSReply = NULL; - - IO->DNS.Query->DNSStatus = ares_parse_mx_reply(abuf, alen, &mx_out); - if (IO->DNS.Query->DNSStatus != ARES_SUCCESS) { - if (mx_out != NULL) - ares_free_data(mx_out); - StrBufPlain(IO->ErrMsg, - ares_strerror(IO->DNS.Query->DNSStatus), -1); - return; - } - - IO->DNS.Query->VParsedDNSReply = mx_out; - IO->DNS.Query->DNSReplyFree = (FreeDNSReply) ares_free_data; -} - - -static void ParseAnswerNS(AsyncIO *IO, unsigned char* abuf, int alen) -{ - struct hostent* host = NULL; - - syslog(LOG_DEBUG, "c-ares: %s", __FUNCTION__); - - if (IO->DNS.Query->VParsedDNSReply != NULL) - IO->DNS.Query->DNSReplyFree(IO->DNS.Query->VParsedDNSReply); - IO->DNS.Query->VParsedDNSReply = NULL; - - IO->DNS.Query->DNSStatus = ares_parse_ns_reply(abuf, alen, &host); - if (IO->DNS.Query->DNSStatus != ARES_SUCCESS) { - if (host != NULL) - ares_free_hostent(host); - StrBufPlain(IO->ErrMsg, - ares_strerror(IO->DNS.Query->DNSStatus), -1); - return; - } - IO->DNS.Query->VParsedDNSReply = host; - IO->DNS.Query->DNSReplyFree = (FreeDNSReply) ares_free_hostent; -} - - -static void ParseAnswerSRV(AsyncIO *IO, unsigned char* abuf, int alen) -{ - struct ares_srv_reply *srv_out = NULL; - - syslog(LOG_DEBUG, "c-ares: %s", __FUNCTION__); - - if (IO->DNS.Query->VParsedDNSReply != NULL) - IO->DNS.Query->DNSReplyFree(IO->DNS.Query->VParsedDNSReply); - IO->DNS.Query->VParsedDNSReply = NULL; - - IO->DNS.Query->DNSStatus = ares_parse_srv_reply(abuf, alen, &srv_out); - if (IO->DNS.Query->DNSStatus != ARES_SUCCESS) { - if (srv_out != NULL) - ares_free_data(srv_out); - StrBufPlain(IO->ErrMsg, - ares_strerror(IO->DNS.Query->DNSStatus), -1); - return; - } - - IO->DNS.Query->VParsedDNSReply = srv_out; - IO->DNS.Query->DNSReplyFree = (FreeDNSReply) ares_free_data; -} - - -static void ParseAnswerTXT(AsyncIO *IO, unsigned char* abuf, int alen) -{ - struct ares_txt_reply *txt_out; - - syslog(LOG_DEBUG, "c-ares: %s", __FUNCTION__); - - if (IO->DNS.Query->VParsedDNSReply != NULL) - IO->DNS.Query->DNSReplyFree(IO->DNS.Query->VParsedDNSReply); - IO->DNS.Query->VParsedDNSReply = NULL; - - IO->DNS.Query->DNSStatus = ares_parse_txt_reply(abuf, alen, &txt_out); - if (IO->DNS.Query->DNSStatus != ARES_SUCCESS) { - if (txt_out != NULL) - ares_free_data(txt_out); - StrBufPlain(IO->ErrMsg, - ares_strerror(IO->DNS.Query->DNSStatus), -1); - return; - } - IO->DNS.Query->VParsedDNSReply = txt_out; - IO->DNS.Query->DNSReplyFree = (FreeDNSReply) ares_free_data; -} - -void QueryCb(void *arg, - int status, - int timeouts, - unsigned char* abuf, - int alen) -{ - AsyncIO *IO = arg; - - SetEVState(IO, eCaresStart); - syslog(LOG_DEBUG, "c-ares: %s", __FUNCTION__); - - EV_DNS_LOGT_STOP(DNS.timeout); - ev_timer_stop (event_base, &IO->DNS.timeout); - - IO->DNS.Query->DNSStatus = status; - if (status == ARES_SUCCESS) - IO->DNS.Query->DNS_CB(arg, abuf, alen); - else { - syslog(LOG_DEBUG, "c-ares: Failed by: %s error %s", __FUNCTION__, ares_strerror(status)); - StrBufPrintf(IO->ErrMsg, - "%s-lookup %s - %s", - IO->DNS.Query->QueryTYPE, - (IO->DNS.Query->QStr != NULL)? IO->DNS.Query->QStr : "", - ares_strerror(status)); - IO->DNS.Query->DNSStatus = status; - } - - ev_idle_init(&IO->unwind_stack, - IO_postdns_callback); - IO->unwind_stack.data = IO; - EV_DNS_LOGT_INIT(unwind_stack); - EV_DNS_LOGT_START(unwind_stack); - ev_idle_start(event_base, &IO->unwind_stack); -} - -void QueryCbDone(AsyncIO *IO) -{ - SetEVState(IO, eCaresDoneIO); - syslog(LOG_DEBUG, "c-ares: %s", __FUNCTION__); - - EV_DNS_LOGT_STOP(DNS.timeout); - ev_timer_stop (event_base, &IO->DNS.timeout); - - EV_DNS_LOGT_STOP(unwind_stack); - ev_idle_stop(event_base, &IO->unwind_stack); -} - -void DestructCAres(AsyncIO *IO) -{ - SetEVState(IO, eCaresX); - syslog(LOG_DEBUG, "c-ares: %s", __FUNCTION__); - syslog(LOG_DEBUG, "c-ares: stopping %s %d %p", "DNS.recv_event", IO->DNS.recv_event.fd, &IO->DNS.recv_event); - ev_io_stop(event_base, &IO->DNS.recv_event); - syslog(LOG_DEBUG, "c-ares: stopping %s %d %p", "DNS.send_event", IO->DNS.send_event.fd, &IO->DNS.send_event); - ev_io_stop(event_base, &IO->DNS.send_event); - syslog(LOG_DEBUG, "c-ares: stopping %s %p", "DNS.timeout", &IO->DNS.send_event); - ev_timer_stop (event_base, &IO->DNS.timeout); - syslog(LOG_DEBUG, "c-ares: stopping %s %p", "DNS.unwind_stack", &IO->unwind_stack); - ev_idle_stop(event_base, &IO->unwind_stack); - ares_destroy_options(&IO->DNS.Options); -} - - -void InitC_ares_dns(AsyncIO *IO) -{ - int optmask = 0; - - syslog(LOG_DEBUG, "c-ares: %s %p", __FUNCTION__, IO->DNS.Channel); - - if (IO->DNS.Channel == NULL) { - optmask |= ARES_OPT_SOCK_STATE_CB; - IO->DNS.Options.sock_state_cb = SockStateCb; - IO->DNS.Options.sock_state_cb_data = IO; - ares_init_options(&IO->DNS.Channel, &IO->DNS.Options, optmask); - } - IO->DNS.Query->DNSStatus = 0; -} - -static void -DNStimeouttrigger_callback(struct ev_loop *loop, ev_timer *watcher, int revents) -{ - AsyncIO *IO = watcher->data; - struct timeval tv, MaxTV; - struct timeval *NextTV; - - memset(&MaxTV, 0, sizeof(MaxTV)); - memset(&tv, 0, sizeof(tv)); - MaxTV.tv_sec = 30; - NextTV = ares_timeout(IO->DNS.Channel, &MaxTV, &tv); - - if ((NextTV->tv_sec != MaxTV.tv_sec) || - (NextTV->tv_usec != MaxTV.tv_usec)) - { - fd_set readers, writers; - syslog(LOG_DEBUG, "c-ares: %s Timeout!", __FUNCTION__); - - FD_ZERO(&readers); - FD_ZERO(&writers); - ares_fds(IO->DNS.Channel, &readers, &writers); - ares_process(IO->DNS.Channel, &readers, &writers); - } -} - -void QueueGetHostByNameDone(void *Ctx, - int status, - int timeouts, - struct hostent *hostent) -{ - AsyncIO *IO = (AsyncIO *) Ctx; - - syslog(LOG_DEBUG, "c-ares: %s", __FUNCTION__); - - - IO->DNS.Query->DNSStatus = status; - IO->DNS.Query->VParsedDNSReply = hostent; - IO->DNS.Query->DNSReplyFree = (FreeDNSReply) ares_free_hostent; - - EV_DNS_LOGT_STOP(DNS.timeout); - ev_timer_stop (event_base, &IO->DNS.timeout); - - ev_idle_init(&IO->unwind_stack, - IO_postdns_callback); - IO->unwind_stack.data = IO; - EV_DNS_LOGT_INIT(unwind_stack); - EV_DNS_LOGT_START(unwind_stack); - ev_idle_start(event_base, &IO->unwind_stack); - -} - -void QueueGetHostByName(AsyncIO *IO, - const char *Hostname, - DNSQueryParts *QueryParts, - IO_CallBack PostDNS) -{ - - syslog(LOG_DEBUG, "c-ares: %s", __FUNCTION__); - IO->DNS.SourcePort = 0; - - IO->DNS.Query = QueryParts; - IO->DNS.Query->PostDNS = PostDNS; - - InitC_ares_dns(IO); - - ev_timer_init(&IO->DNS.timeout, DNStimeouttrigger_callback, 10, 1); - EV_DNS_LOGT_INIT(DNS.timeout); - IO->DNS.timeout.data = IO; - ares_gethostbyname(IO->DNS.Channel, - Hostname, - AF_INET6, /* it falls back to ipv4 in doubt... */ - QueueGetHostByNameDone, - IO); - EV_DNS_LOGT_START(DNS.timeout); - ev_timer_start(event_base, &IO->DNS.timeout); - -} - -const char* QT[] = { - "A", - "AAAA", - "MX", - "NS", - "TXT", - "SRV", - "CNAME", - "PTR" -}; - -int QueueQuery(ns_type Type, - const char *name, - AsyncIO *IO, - DNSQueryParts *QueryParts, - IO_CallBack PostDNS) -{ - int length, family; - char address_b[sizeof(struct in6_addr)]; - - IO->DNS.SourcePort = 0; - - IO->DNS.Query = QueryParts; - IO->DNS.Query->PostDNS = PostDNS; - IO->DNS.Start = IO->Now; - IO->DNS.Query->QStr = name; - - InitC_ares_dns(IO); - - ev_timer_init(&IO->DNS.timeout, DNStimeouttrigger_callback, 10, 1); - IO->DNS.timeout.data = IO; - EV_DNS_LOGT_INIT(DNS.timeout); - - switch(Type) { - case ns_t_a: - IO->DNS.Query->DNS_CB = ParseAnswerA; - IO->DNS.Query->QueryTYPE = QT[0]; - break; - - case ns_t_aaaa: - IO->DNS.Query->DNS_CB = ParseAnswerAAAA; - IO->DNS.Query->QueryTYPE = QT[1]; - break; - - case ns_t_mx: - IO->DNS.Query->DNS_CB = ParseAnswerMX; - IO->DNS.Query->QueryTYPE = QT[2]; - break; - - case ns_t_ns: - IO->DNS.Query->DNS_CB = ParseAnswerNS; - IO->DNS.Query->QueryTYPE = QT[3]; - break; - - case ns_t_txt: - IO->DNS.Query->DNS_CB = ParseAnswerTXT; - IO->DNS.Query->QueryTYPE = QT[4]; - break; - - case ns_t_srv: - IO->DNS.Query->DNS_CB = ParseAnswerSRV; - IO->DNS.Query->QueryTYPE = QT[5]; - break; - - case ns_t_cname: - IO->DNS.Query->DNS_CB = ParseAnswerCNAME; - IO->DNS.Query->QueryTYPE = QT[6]; - break; - - case ns_t_ptr: - IO->DNS.Query->QueryTYPE = QT[7]; - if (inet_pton(AF_INET, name, &address_b) == 1) { - length = sizeof(struct in_addr); - family = AF_INET; - } else if (inet_pton(AF_INET6, name, &address_b) == 1) { - length = sizeof(struct in6_addr); - family = AF_INET6; - } else { - return -1; - } - - ares_gethostbyaddr(IO->DNS.Channel, - address_b, - length, - family, - HostByAddrCb, - IO); - EV_DNS_LOGT_START(DNS.timeout); - ev_timer_start(event_base, &IO->DNS.timeout); - - syslog(LOG_DEBUG, "c-ares: %s X1", __FUNCTION__); - return 1; - - default: - - syslog(LOG_DEBUG, "c-ares: %sX2", __FUNCTION__); - return 0; - } - syslog(LOG_DEBUG, "c-ares: %s", __FUNCTION__); - - ares_query(IO->DNS.Channel, name, ns_c_in, Type, QueryCb, IO); - EV_DNS_LOGT_START(DNS.timeout); - ev_timer_start(event_base, &IO->DNS.timeout); - return 1; -} - - - - - -/***************************************************************************** - * libev / c-ares integration * - *****************************************************************************/ -static void DNS_send_callback(struct ev_loop *loop, ev_io *watcher, int revents) -{ - AsyncIO *IO = watcher->data; - - IO->Now = ev_now(event_base); - - syslog(LOG_DEBUG, "c-ares: %s", __FUNCTION__); - - ares_process_fd(IO->DNS.Channel, - ARES_SOCKET_BAD, - IO->DNS.send_event.fd); -} -static void DNS_recv_callback(struct ev_loop *loop, ev_io *watcher, int revents) -{ - AsyncIO *IO = watcher->data; - - IO->Now = ev_now(event_base); - - syslog(LOG_DEBUG, "c-ares: %s", __FUNCTION__); - - ares_process_fd(IO->DNS.Channel, - IO->DNS.recv_event.fd, - ARES_SOCKET_BAD); -} - -void SockStateCb(void *data, int sock, int read, int write) -{ - AsyncIO *IO = data; -/* already inside of the event queue. */ - if (DebugCAres) - { - struct sockaddr_in sin; - socklen_t slen; - memset(&sin, 0, sizeof(sin)); - slen = sizeof(sin); - if ((IO->DNS.SourcePort == 0) && - (getsockname(sock, &sin, &slen) == 0)) - { - IO->DNS.SourcePort = ntohs(sin.sin_port); - } - syslog(LOG_DEBUG, "c-ares: %s %d|%d Sock %d port %hu", __FUNCTION__, read, write, sock, IO->DNS.SourcePort); - } - - IO->Now = ev_now(event_base); - - if (read) { - if ((IO->DNS.recv_event.fd != sock) && - (IO->DNS.recv_event.fd != 0)) { - EV_DNS_LOG_STOP(DNS.recv_event); - ev_io_stop(event_base, &IO->DNS.recv_event); - } - IO->DNS.recv_event.fd = sock; - ev_io_init(&IO->DNS.recv_event, - DNS_recv_callback, - IO->DNS.recv_event.fd, - EV_READ); - EV_DNS_LOG_INIT(DNS.recv_event); - IO->DNS.recv_event.data = IO; - EV_DNS_LOG_START(DNS.recv_event); - ev_io_start(event_base, &IO->DNS.recv_event); - } - if (write) { - if ((IO->DNS.send_event.fd != sock) && - (IO->DNS.send_event.fd != 0)) { - EV_DNS_LOG_STOP(DNS.send_event); - ev_io_stop(event_base, &IO->DNS.send_event); - } - IO->DNS.send_event.fd = sock; - ev_io_init(&IO->DNS.send_event, - DNS_send_callback, - IO->DNS.send_event.fd, - EV_WRITE); - IO->DNS.send_event.data = IO; - EV_DNS_LOG_INIT(DNS.send_event); - EV_DNS_LOG_START(DNS.send_event); - ev_io_start(event_base, &IO->DNS.send_event); - } - if ((read == 0) && (write == 0)) { - EV_DNS_LOG_STOP(DNS.recv_event); - EV_DNS_LOG_STOP(DNS.send_event); - ev_io_stop(event_base, &IO->DNS.recv_event); - ev_io_stop(event_base, &IO->DNS.send_event); - } -} -void EnableDebugCAres(const int n) -{ - DebugCAres = n; -} - -CTDL_MODULE_INIT(c_ares_client) -{ - if (!threading) - { - CtdlRegisterDebugFlagHook(HKEY("cares"), EnableDebugCAres, &DebugCAres); - int r = ares_library_init(ARES_LIB_INIT_ALL); - if (0 != r) { - - } - } - return "c-ares"; -} diff --git a/citadel/modules/calendar/serv_calendar.c b/citadel/modules/calendar/serv_calendar.c index 8fc0dbad1..f727a5555 100644 --- a/citadel/modules/calendar/serv_calendar.c +++ b/citadel/modules/calendar/serv_calendar.c @@ -1749,7 +1749,7 @@ void ical_putics(void) } cprintf("%d Transmit data now\n", SEND_LISTING); - calstream = CtdlReadMessageBody(HKEY("000"), CtdlGetConfigLong("c_maxmsglen"), NULL, 0, 0); + calstream = CtdlReadMessageBody(HKEY("000"), CtdlGetConfigLong("c_maxmsglen"), NULL, 0); if (calstream == NULL) { return; } diff --git a/citadel/modules/ctdlproto/serv_file.c b/citadel/modules/ctdlproto/serv_file.c index 0b5ebc0c1..92dd92d49 100644 --- a/citadel/modules/ctdlproto/serv_file.c +++ b/citadel/modules/ctdlproto/serv_file.c @@ -12,10 +12,14 @@ * GNU General Public License for more details. */ +#include +#include #include +#include #include #include - +#include +#include #include "ctdl_module.h" #include "citserver.h" #include "support.h" diff --git a/citadel/modules/ctdlproto/serv_rooms.c b/citadel/modules/ctdlproto/serv_rooms.c index 10ddfc1f3..d789372a3 100644 --- a/citadel/modules/ctdlproto/serv_rooms.c +++ b/citadel/modules/ctdlproto/serv_rooms.c @@ -12,7 +12,11 @@ * GNU General Public License for more details. */ +#include +#include #include +#include +#include #include /* for cmd_rdir to read contents of the directory */ #include diff --git a/citadel/modules/dspam/.gitignore b/citadel/modules/dspam/.gitignore deleted file mode 100644 index 5761abcfd..000000000 --- a/citadel/modules/dspam/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.o diff --git a/citadel/modules/dspam/serv_dspam.c b/citadel/modules/dspam/serv_dspam.c deleted file mode 100644 index 7454634f7..000000000 --- a/citadel/modules/dspam/serv_dspam.c +++ /dev/null @@ -1,268 +0,0 @@ -/* - * This module glues libDSpam to the Citadel server in order to implement - * DSPAM Spamchecking - * - * Copyright (c) 2012 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. - * - * - * - * 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. - * - * - * - * - */ - -#include "sysdep.h" -#include -#include -#include -#include -#include -#include -#include -#include - -#if TIME_WITH_SYS_TIME -# include -# include -#else -# if HAVE_SYS_TIME_H -# include -# else -# include -# endif -#endif - -#include -#include -#include -#include -#include "citadel.h" -#include "server.h" -#include "citserver.h" -#include "support.h" -#include "config.h" -#include "database.h" -#include "msgbase.h" -#include "internet_addressing.h" - - -#include "ctdl_module.h" - - -#ifdef HAVE_LIBDSPAM -#define CONFIG_DEFAULT file_dpsam_conf -#define LOGDIR file_dspam_log - - -//#define HAVE_CONFIG_H -#include -//#define HAVE_CONFIG_H - -typedef struct stringlist stringlist; - -struct stringlist { - char *Str; - long len; - stringlist *Next; -}; - - -/* - * Citadel protocol to manage sieve scripts. - * This is basically a simplified (read: doesn't resemble IMAP) version - * of the 'managesieve' protocol. - */ -void cmd_tspam(char *argbuf) { - char buf[SIZ]; - long len; - long count; - stringlist *Messages; - stringlist *NextMsg; - - Messages = NULL; - NextMsg = NULL; - count = 0; - if (CtdlAccessCheck(ac_room_aide)) return; - if (atoi(argbuf) == 0) { - cprintf("%d Ok.\n", CIT_OK); - return; - } - cprintf("%d Send info...\n", SEND_LISTING); - - do { - len = client_getln(buf, sizeof buf); - if (strcmp(buf, "000")) { - if (Messages == NULL) { - Messages = malloc (sizeof (stringlist)); - NextMsg = Messages; - } - else { - Messages->Next = malloc (sizeof (stringlist)); - NextMsg = NextMsg->Next; - } - NextMsg->Next = NULL; - NextMsg->Str = malloc (len+1); - NextMsg->len = len; - memcpy (NextMsg->Str, buf, len + 1);/// maybe split spam /ham per line? - count++; - } - } while (strcmp(buf, "000")); -/// is there a way to filter foreachmessage by a list? - /* tag mails as spam or Ham */ - /* probably do: dspam_init(ctdl_dspam_dir); dspam_process dspam_addattribute; dspam_destroy*/ - // extract DSS_ERROR or DSS_CORPUS from the commandline. error->ham; corpus -> spam? - /// todo: send answer listing... -} - - - -void ctdl_dspam_init(void) { - -/// libdspam_init("bdb");/* redirect_buffer = malloc(SIZ); - CC->redirect_len = 0; - CC->redirect_alloc = SIZ; - CtdlOutputPreLoadedMsg(msg, MT_RFC822, HEADERS_ALL, 0, 1, 0); - msgtext = CC->redirect_buffer; -// don't need? msglen = CC->redirect_len; - CC->redirect_buffer = NULL; - CC->redirect_len = 0; - CC->redirect_alloc = 0; - - /* Call DSPAM's processor with the message text */ - if (dspam_process (CTX, msgtext) != 0) - { - free(msgtext); - syslog(LOG_CRIT, "ERROR: dspam_process failed"); - return; - } - if (CTX->signature == NULL) - { - syslog(LOG_CRIT,"No signature provided\n"); - } - else - { -/* Copy to a safe place */ - // TODO: len -> cm_fields? - msg->cm_fields[eErrorMsg] = malloc (CTX->signature->length * 2); - size_t len = CtdlEncodeBase64(msg->cm_fields[eErrorMsg], CTX->signature->data, CTX->signature->length, 0); - - if (msg->cm_fields[eErrorMsg][len - 1] == '\n') { - msg->cm_fields[eErrorMsg][len - 1] = '\0'; - } - } - free(msgtext); - - SIG.length = CTX->signature->length; - /* Print processing results */ - syslog(LOG_DEBUG, "Probability: %2.4f Confidence: %2.4f, Result: %s\n", - CTX->probability, - CTX->confidence, - (CTX->result == DSR_ISSPAM) ? "Spam" : "Innocent"); - - //// todo: put signature into the citadel message - //// todo: save message; destroy message. -} - -int serv_dspam_room(struct ctdlroom *room) -{ - DSPAM_CTX *CTX; /* DSPAM Context */ - - /* scan for spam; do */ - /* probably do: dspam_init; dspam_process dspam_addattribute; dspam_destroy*/ -//DSS_NONE -//#define DSR_ISSPAM 0x01 -//#define DSR_ISINNOCENT 0x02 -// dspam_init (cc->username, NULL, ctdl_dspam_home, DSM_PROCESS, - // DSF_SIGNATURE | DSF_NOISE); - /// todo: if roomname = spam / ham -> learn! - if ((room->QRflags & QR_PRIVATE) &&/* Are we sending to a private mailbox? */ - (strstr(room->QRname, ".Mail")!=NULL)) - - { - char User[64]; - // maybe we should better get our realname here? - snprintf(User, 64, "%ld", room->QRroomaide); - extract_token(User, room->QRname, 0, '.', sizeof(User)); - CTX = dspam_init(User, - NULL, - ctdl_dspam_dir, - DSM_PROCESS, - DSF_SIGNATURE | DSF_NOISE); - } - else return 0;//// - /// else -> todo: global user for public rooms etc. - if (CTX == NULL) - { - syslog(LOG_CRIT, "ERROR: dspam_init failed!\n"); - return ERROR + INTERNAL_ERROR; - } - /* Use graham and robinson algorithms, graham's p-values */ - CTX->algorithms = DSA_GRAHAM | DSA_BURTON | DSP_GRAHAM; - - /* Use CHAIN tokenizer */ - CTX->tokenizer = DSZ_CHAIN; - - CtdlForEachMessage(MSGS_GT, 1, NULL, NULL, NULL, - dspam_do_msg, - (void *) &CTX); - - return 0; -} - -void serv_dspam_shutdown (void) -{ - libdspam_shutdown (); -} -#endif /* HAVE_LIBDSPAM */ - -CTDL_MODULE_INIT(dspam) -{ - return "disabled."; - if (!threading) - { -#ifdef HAVE_LIBDSPAM - - ctdl_dspam_init(); - CtdlRegisterCleanupHook(serv_dspam_shutdown); - CtdlRegisterProtoHook(cmd_tspam, "SPAM", "Tag Message as Spam/Ham to learn DSPAM"); - - CtdlRegisterRoomHook(serv_dspam_room); - - ///CtdlRegisterSessionHook(perform_dspam_processing, EVT_HOUSE); - -#else /* HAVE_LIBDSPAM */ - - syslog(LOG_INFO, "This server is missing libdspam Spam filtering will be disabled.\n"); - -#endif /* HAVE_LIBDSPAM */ - } - - /* return our module name for the log */ - return "dspam"; -} - diff --git a/citadel/modules/eventclient/serv_curl.h b/citadel/modules/eventclient/serv_curl.h deleted file mode 100644 index e69de29bb..000000000 diff --git a/citadel/modules/eventclient/serv_eventclient.c b/citadel/modules/eventclient/serv_eventclient.c deleted file mode 100644 index 520ae7fc8..000000000 --- a/citadel/modules/eventclient/serv_eventclient.c +++ /dev/null @@ -1,917 +0,0 @@ -/* - * Copyright (c) 1998-2015 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. - * - * 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. - */ - -#include "sysdep.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if TIME_WITH_SYS_TIME -# include -# include -#else -# if HAVE_SYS_TIME_H -# include -# else -# include -# endif -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "citadel.h" -#include "server.h" -#include "citserver.h" -#include "support.h" -#include "ctdl_module.h" -#include "config.h" -#include "event_client.h" -#include "serv_curl.h" - -ev_loop *event_base; -int DebugEventLoop = 0; -int DebugEventLoopBacktrace = 0; -int DebugCurl = 0; -pthread_key_t evConKey; - -long EvIDSource = 1; -/***************************************************************************** - * libevent / curl integration * - *****************************************************************************/ - -#define MOPT(s, v) \ - do { \ - sta = curl_multi_setopt(mhnd, (CURLMOPT_##s), (v)); \ - if (sta) { \ - syslog(LOG_ERR, "error setting option " \ - #s " on curl multi handle: %s\n", \ - curl_easy_strerror(sta)); \ - exit (1); \ - } \ - } while (0) - - -typedef struct _evcurl_global_data { - int magic; - CURLM *mhnd; - ev_timer timeev; - int nrun; -} evcurl_global_data; - -ev_async WakeupCurl; -evcurl_global_data global; - -eNextState QueueAnDBOperation(AsyncIO *IO); - -static void -gotstatus(int nnrun) -{ - CURLMsg *msg; - int nmsg; - - global.nrun = nnrun; - - syslog(LOG_DEBUG, - "gotstatus(): about to call curl_multi_info_read\n"); - while ((msg = curl_multi_info_read(global.mhnd, &nmsg))) { - syslog(LOG_DEBUG, - "got curl multi_info message msg=%d\n", - msg->msg); - - if (CURLMSG_DONE == msg->msg) { - CURL *chnd; - void *chandle = NULL; - CURLcode sta; - CURLMcode msta; - AsyncIO*IO; - - chandle = NULL;; - chnd = msg->easy_handle; - sta = curl_easy_getinfo(chnd, - CURLINFO_PRIVATE, - &chandle); - if (sta) { - syslog(LOG_ERR, - "error asking curl for private" - " cookie of curl handle: %s\n", - curl_easy_strerror(sta)); - continue; - } - IO = (AsyncIO *)chandle; - if (IO->ID == 0) { - syslog(LOG_ERR, - "Error, invalid IO context %p\n", - IO); - continue; - } - SetEVState(IO, eCurlGotStatus); - - syslog(LOG_DEBUG, "request complete\n"); - - IO->CitContext->lastcmd = IO->Now = ev_now(event_base); - - ev_io_stop(event_base, &IO->recv_event); - ev_io_stop(event_base, &IO->send_event); - - sta = msg->data.result; - if (sta) { - syslog(LOG_ERR, - "error description: %s\n", - IO->HttpReq.errdesc); - IO->HttpReq.CurlError = curl_easy_strerror(sta); - syslog(LOG_ERR, - "error performing request: %s\n", - IO->HttpReq.CurlError); - if (sta == CURLE_OPERATION_TIMEDOUT) - { - IO->SendBuf.fd = 0; - IO->RecvBuf.fd = 0; - } - } - sta = curl_easy_getinfo(chnd, - CURLINFO_RESPONSE_CODE, - &IO->HttpReq.httpcode); - if (sta) - syslog(LOG_ERR, - "error asking curl for " - "response code from request: %s\n", - curl_easy_strerror(sta)); - syslog(LOG_DEBUG, - "http response code was %ld\n", - (long)IO->HttpReq.httpcode); - - - curl_slist_free_all(IO->HttpReq.headers); - IO->HttpReq.headers = NULL; - msta = curl_multi_remove_handle(global.mhnd, chnd); - if (msta) - syslog(LOG_ERR, - "warning problem detaching " - "completed handle from curl multi: " - "%s\n", - curl_multi_strerror(msta)); - - ev_cleanup_stop(event_base, &IO->abort_by_shutdown); - - IO->HttpReq.attached = 0; - switch(IO->SendDone(IO)) - { - case eDBQuery: - FreeURL(&IO->ConnectMe); - QueueAnDBOperation(IO); - break; - case eSendDNSQuery: - case eReadDNSReply: - case eConnect: - case eSendReply: - case eSendMore: - case eSendFile: - case eReadMessage: - case eReadMore: - case eReadPayload: - case eReadFile: - break; - case eTerminateConnection: - case eAbort: - curl_easy_cleanup(IO->HttpReq.chnd); - IO->HttpReq.chnd = NULL; - FreeStrBuf(&IO->HttpReq.ReplyData); - FreeURL(&IO->ConnectMe); - RemoveContext(IO->CitContext); - IO->Terminate(IO); - } - } - } -} - -static void -stepmulti(void *data, curl_socket_t fd, int which) -{ - int running_handles = 0; - CURLMcode msta; - - msta = curl_multi_socket_action(global.mhnd, - fd, - which, - &running_handles); - - syslog(LOG_DEBUG, "stepmulti(): calling gotstatus()\n"); - if (msta) - syslog(LOG_ERR, - "error in curl processing events" - "on multi handle, fd %d: %s\n", - (int)fd, - curl_multi_strerror(msta)); - - if (global.nrun != running_handles) - gotstatus(running_handles); -} - -static void -gottime(struct ev_loop *loop, ev_timer *timeev, int events) -{ - syslog(LOG_DEBUG, "EVCURL: waking up curl for timeout\n"); - stepmulti(NULL, CURL_SOCKET_TIMEOUT, 0); -} - -static void -got_in(struct ev_loop *loop, ev_io *ioev, int events) -{ - syslog(LOG_DEBUG, - "EVCURL: waking up curl for io on fd %d\n", - (int)ioev->fd); - - stepmulti(ioev->data, ioev->fd, CURL_CSELECT_IN); -} - -static void -got_out(struct ev_loop *loop, ev_io *ioev, int events) -{ - syslog(LOG_DEBUG, - "waking up curl for io on fd %d\n", - (int)ioev->fd); - - stepmulti(ioev->data, ioev->fd, CURL_CSELECT_OUT); -} - -static size_t -gotdata(void *data, size_t size, size_t nmemb, void *cglobal) -{ - AsyncIO *IO = (AsyncIO*) cglobal; - - SetEVState(IO, eCurlGotData); - if (IO->HttpReq.ReplyData == NULL) - { - IO->HttpReq.ReplyData = NewStrBufPlain(NULL, SIZ); - } - IO->CitContext->lastcmd = IO->Now = ev_now(event_base); - return CurlFillStrBuf_callback(data, - size, - nmemb, - IO->HttpReq.ReplyData); -} - -static int -gotwatchtime(CURLM *multi, long tblock_ms, void *cglobal) { - syslog(LOG_DEBUG, "EVCURL: gotwatchtime called %ld ms\n", tblock_ms); - evcurl_global_data *global = cglobal; - ev_timer_stop(EV_DEFAULT, &global->timeev); - if (tblock_ms < 0 || 14000 < tblock_ms) - tblock_ms = 14000; - ev_timer_set(&global->timeev, 0.5e-3 + 1.0e-3 * tblock_ms, 14.0); - ev_timer_start(EV_DEFAULT_UC, &global->timeev); - curl_multi_perform(global, &global->nrun); - return 0; -} - -static int -gotwatchsock(CURL *easy, - curl_socket_t fd, - int action, - void *cglobal, - void *vIO) -{ - evcurl_global_data *global = cglobal; - CURLM *mhnd = global->mhnd; - void *f; - AsyncIO *IO = (AsyncIO*) vIO; - CURLcode sta; - const char *Action; - - if (IO == NULL) { - sta = curl_easy_getinfo(easy, CURLINFO_PRIVATE, &f); - if (sta) { - syslog(LOG_ERR, - "EVCURL: error asking curl for private " - "cookie of curl handle: %s\n", - curl_easy_strerror(sta)); - return -1; - } - IO = (AsyncIO *) f; - SetEVState(IO, eCurlNewIO); - syslog(LOG_DEBUG, - "EVCURL: got socket for URL: %s\n", - IO->ConnectMe->PlainUrl); - - if (IO->SendBuf.fd != 0) - { - ev_io_stop(event_base, &IO->recv_event); - ev_io_stop(event_base, &IO->send_event); - } - IO->SendBuf.fd = fd; - ev_io_init(&IO->recv_event, &got_in, fd, EV_READ); - ev_io_init(&IO->send_event, &got_out, fd, EV_WRITE); - curl_multi_assign(mhnd, fd, IO); - } - - SetEVState(IO, eCurlGotIO); - IO->CitContext->lastcmd = IO->Now = ev_now(event_base); - - Action = ""; - switch (action) - { - case CURL_POLL_NONE: - Action = "CURL_POLL_NONE"; - break; - case CURL_POLL_REMOVE: - Action = "CURL_POLL_REMOVE"; - break; - case CURL_POLL_IN: - Action = "CURL_POLL_IN"; - break; - case CURL_POLL_OUT: - Action = "CURL_POLL_OUT"; - break; - case CURL_POLL_INOUT: - Action = "CURL_POLL_INOUT"; - break; - } - - - syslog(LOG_DEBUG, - "EVCURL: gotwatchsock called fd=%d action=%s[%d]\n", - (int)fd, Action, action); - - switch (action) - { - case CURL_POLL_NONE: - syslog(LOG_DEBUG, - "called first time " - "to register this sockwatcker\n"); - break; - case CURL_POLL_REMOVE: - syslog(LOG_DEBUG, - "called last time to unregister " - "this sockwatcher\n"); - ev_io_stop(event_base, &IO->recv_event); - ev_io_stop(event_base, &IO->send_event); - break; - case CURL_POLL_IN: - ev_io_start(event_base, &IO->recv_event); - ev_io_stop(event_base, &IO->send_event); - break; - case CURL_POLL_OUT: - ev_io_start(event_base, &IO->send_event); - ev_io_stop(event_base, &IO->recv_event); - break; - case CURL_POLL_INOUT: - ev_io_start(event_base, &IO->send_event); - ev_io_start(event_base, &IO->recv_event); - break; - } - return 0; -} - -void curl_init_connectionpool(void) -{ - CURLM *mhnd ; - - ev_timer_init(&global.timeev, &gottime, 14.0, 14.0); - global.timeev.data = (void *)&global; - global.nrun = -1; - CURLcode sta = curl_global_init(CURL_GLOBAL_ALL); - - if (sta) - { - syslog(LOG_ERR, - "error initializing curl library: %s\n", - curl_easy_strerror(sta)); - - exit(1); - } - mhnd = global.mhnd = curl_multi_init(); - if (!mhnd) - { - syslog(LOG_ERR, - "error initializing curl multi handle\n"); - exit(3); - } - - MOPT(SOCKETFUNCTION, &gotwatchsock); - MOPT(SOCKETDATA, (void *)&global); - MOPT(TIMERFUNCTION, &gotwatchtime); - MOPT(TIMERDATA, (void *)&global); - - return; -} - -int evcurl_init(AsyncIO *IO) -{ - CURLcode sta; - CURL *chnd; - - syslog(LOG_DEBUG, "EVCURL: evcurl_init called ms\n"); - IO->HttpReq.attached = 0; - chnd = IO->HttpReq.chnd = curl_easy_init(); - if (!chnd) - { - syslog(LOG_ERR, "EVCURL: error initializing curl handle\n"); - return 0; - } - -#if DEBUG - OPT(VERBOSE, (long)1); -#endif - OPT(NOPROGRESS, 1L); - - OPT(NOSIGNAL, 1L); - OPT(FAILONERROR, (long)1); - OPT(ENCODING, ""); - OPT(FOLLOWLOCATION, (long)0); - OPT(MAXREDIRS, (long)0); - OPT(USERAGENT, CITADEL); - - OPT(TIMEOUT, (long)1800); - OPT(LOW_SPEED_LIMIT, (long)64); - OPT(LOW_SPEED_TIME, (long)600); - OPT(CONNECTTIMEOUT, (long)600); - OPT(PRIVATE, (void *)IO); - - OPT(FORBID_REUSE, 1); - OPT(WRITEFUNCTION, &gotdata); - OPT(WRITEDATA, (void *)IO); - OPT(ERRORBUFFER, IO->HttpReq.errdesc); - - if ((!IsEmptyStr(CtdlGetConfigStr("c_ip_addr"))) - && (strcmp(CtdlGetConfigStr("c_ip_addr"), "*")) - && (strcmp(CtdlGetConfigStr("c_ip_addr"), "::")) - && (strcmp(CtdlGetConfigStr("c_ip_addr"), "0.0.0.0")) - ) - { - OPT(INTERFACE, CtdlGetConfigStr("c_ip_addr")); - } - -#ifdef CURLOPT_HTTP_CONTENT_DECODING - OPT(HTTP_CONTENT_DECODING, 1); - OPT(ENCODING, ""); -#endif - - IO->HttpReq.headers = curl_slist_append(IO->HttpReq.headers, - "Connection: close"); - - return 1; -} - - -static void IOcurl_abort_shutdown_callback(struct ev_loop *loop, - ev_cleanup *watcher, - int revents) -{ - CURLMcode msta; - AsyncIO *IO = watcher->data; - - if (IO == NULL) - return; - - SetEVState(IO, eCurlShutdown); - IO->CitContext->lastcmd = IO->Now = ev_now(event_base); - syslog(LOG_DEBUG, "EVENT Curl: %s\n", __FUNCTION__); - - curl_slist_free_all(IO->HttpReq.headers); - IO->HttpReq.headers = NULL; - msta = curl_multi_remove_handle(global.mhnd, IO->HttpReq.chnd); - if (msta) - { - syslog(LOG_ERR, - "EVCURL: warning problem detaching completed handle " - "from curl multi: %s\n", - curl_multi_strerror(msta)); - } - - curl_easy_cleanup(IO->HttpReq.chnd); - IO->HttpReq.chnd = NULL; - ev_cleanup_stop(event_base, &IO->abort_by_shutdown); - ev_io_stop(event_base, &IO->recv_event); - ev_io_stop(event_base, &IO->send_event); - assert(IO->ShutdownAbort); - IO->ShutdownAbort(IO); -} - -eNextState -evcurl_handle_start(AsyncIO *IO) -{ - CURLMcode msta; - CURLcode sta; - CURL *chnd; - - SetEVState(IO, eCurlStart); - chnd = IO->HttpReq.chnd; - syslog(LOG_DEBUG, - "EVCURL: Loading URL: %s\n", IO->ConnectMe->PlainUrl); - OPT(URL, IO->ConnectMe->PlainUrl); - if (StrLength(IO->ConnectMe->CurlCreds)) - { - OPT(HTTPAUTH, (long)CURLAUTH_BASIC); - OPT(USERPWD, ChrPtr(IO->ConnectMe->CurlCreds)); - } - if (StrLength(IO->HttpReq.PostData) > 0) - { - OPT(POSTFIELDS, ChrPtr(IO->HttpReq.PostData)); - OPT(POSTFIELDSIZE, StrLength(IO->HttpReq.PostData)); - - } - else if ((IO->HttpReq.PlainPostDataLen != 0) && - (IO->HttpReq.PlainPostData != NULL)) - { - OPT(POSTFIELDS, IO->HttpReq.PlainPostData); - OPT(POSTFIELDSIZE, IO->HttpReq.PlainPostDataLen); - } - OPT(HTTPHEADER, IO->HttpReq.headers); - - IO->NextState = eConnect; - syslog(LOG_DEBUG, "EVCURL: attaching to curl multi handle\n"); - msta = curl_multi_add_handle(global.mhnd, IO->HttpReq.chnd); - if (msta) - { - syslog(LOG_ERR, - "EVCURL: error attaching to curl multi handle: %s\n", - curl_multi_strerror(msta)); - } - - IO->HttpReq.attached = 1; - ev_async_send (event_base, &WakeupCurl); - - ev_cleanup_init(&IO->abort_by_shutdown, - IOcurl_abort_shutdown_callback); - - ev_cleanup_start(event_base, &IO->abort_by_shutdown); - - return eReadMessage; -} - -static void WakeupCurlCallback(EV_P_ ev_async *w, int revents) -{ - syslog(LOG_DEBUG, "waking up curl multi handle\n"); - - curl_multi_perform(&global, CURL_POLL_NONE); -} - -static void evcurl_shutdown (void) -{ - curl_global_cleanup(); - curl_multi_cleanup(global.mhnd); - syslog(LOG_DEBUG, "exiting\n"); -} -/***************************************************************************** - * libevent integration * - *****************************************************************************/ -/* - * client event queue plus its methods. - * this currently is the main loop (which may change in some future?) - */ -int evbase_count = 0; -pthread_mutex_t EventQueueMutex; /* locks the access to the following vars: */ -pthread_mutex_t EventExitQueueMutex; /* locks the access to the event queue pointer on exit. */ -HashList *QueueEvents = NULL; -HashList *InboundEventQueue = NULL; -HashList *InboundEventQueues[2] = { NULL, NULL }; -extern void ShutDownCLient(AsyncIO *IO); - -ev_async AddJob; -ev_async ExitEventLoop; - -static void QueueEventAddCallback(EV_P_ ev_async *w, int revents) -{ - CitContext *Ctx; - long IOID = -1; - long count = 0; - ev_tstamp Now; - HashList *q; - void *v; - HashPos*It; - long len; - const char *Key; - - /* get the control command... */ - pthread_mutex_lock(&EventQueueMutex); - - if (InboundEventQueues[0] == InboundEventQueue) { - InboundEventQueue = InboundEventQueues[1]; - q = InboundEventQueues[0]; - } - else { - InboundEventQueue = InboundEventQueues[0]; - q = InboundEventQueues[1]; - } - pthread_mutex_unlock(&EventQueueMutex); - Now = ev_now (event_base); - It = GetNewHashPos(q, 0); - while (GetNextHashPos(q, It, &len, &Key, &v)) - { - IOAddHandler *h = v; - count ++; - if (h->IO->ID == 0) { - h->IO->ID = EvIDSource++; - } - IOID = h->IO->ID; - if (h->IO->StartIO == 0.0) - h->IO->StartIO = Now; - - SetEVState(h->IO, eIOAttach); - - Ctx = h->IO->CitContext; - become_session(Ctx); - - h->IO->CitContext->lastcmd = h->IO->Now = Now; - switch (h->EvAttch(h->IO)) - { - case eReadMore: - case eReadMessage: - case eReadFile: - case eSendReply: - case eSendMore: - case eReadPayload: - case eSendFile: - case eDBQuery: - case eSendDNSQuery: - case eReadDNSReply: - case eConnect: - break; - case eTerminateConnection: - case eAbort: - ShutDownCLient(h->IO); - break; - } - } - DeleteHashPos(&It); - DeleteHashContent(&q); - syslog(LOG_DEBUG, "%s CC[%ld] EVENT Q Add %ld done.", IOSTR, IOID, count); -} - - -static void EventExitCallback(EV_P_ ev_async *w, int revents) -{ - ev_break(event_base, EVBREAK_ALL); - - syslog(LOG_DEBUG, "EVENT Q exiting.\n"); -} - - - -void InitEventQueue(void) -{ - pthread_mutex_init(&EventQueueMutex, NULL); - pthread_mutex_init(&EventExitQueueMutex, NULL); - - QueueEvents = NewHash(1, Flathash); - InboundEventQueues[0] = NewHash(1, Flathash); - InboundEventQueues[1] = NewHash(1, Flathash); - InboundEventQueue = InboundEventQueues[0]; -} -extern void CtdlDestroyEVCleanupHooks(void); - -extern int EVQShutDown; -const char *IOLog = "IO"; -/* - * this thread operates the select() etc. via libev. - */ -void *client_event_thread(void *arg) -{ - struct CitContext libev_client_CC; - - CtdlFillSystemContext(&libev_client_CC, "LibEv Thread"); - - pthread_setspecific(evConKey, IOLog); - - syslog(LOG_DEBUG, "client_event_thread() initializing\n"); - - event_base = ev_default_loop (EVFLAG_AUTO); - ev_async_init(&AddJob, QueueEventAddCallback); - ev_async_start(event_base, &AddJob); - ev_async_init(&ExitEventLoop, EventExitCallback); - ev_async_start(event_base, &ExitEventLoop); - ev_async_init(&WakeupCurl, WakeupCurlCallback); - ev_async_start(event_base, &WakeupCurl); - - curl_init_connectionpool(); - - ev_run (event_base, 0); - - syslog(LOG_DEBUG, "client_event_thread() exiting\n"); - -///what todo here? CtdlClearSystemContext(); - pthread_mutex_lock(&EventExitQueueMutex); - ev_loop_destroy (EV_DEFAULT_UC); - event_base = NULL; - DeleteHash(&QueueEvents); - InboundEventQueue = NULL; - DeleteHash(&InboundEventQueues[0]); - DeleteHash(&InboundEventQueues[1]); -/* citthread_mutex_destroy(&EventQueueMutex); TODO */ - evcurl_shutdown(); - - CtdlDestroyEVCleanupHooks(); - - pthread_mutex_unlock(&EventExitQueueMutex); - EVQShutDown = 1; - return(NULL); -} - -/*----------------------------------------------------------------------------*/ -/* - * DB-Queue; does async bdb operations. - * has its own set of handlers. - */ -ev_loop *event_db; -int evdb_count = 0; -pthread_mutex_t DBEventQueueMutex; /* locks the access to the following vars: */ -pthread_mutex_t DBEventExitQueueMutex; /* locks the access to the db-event queue pointer on exit. */ -HashList *DBQueueEvents = NULL; -HashList *DBInboundEventQueue = NULL; -HashList *DBInboundEventQueues[2] = { NULL, NULL }; - -ev_async DBAddJob; -ev_async DBExitEventLoop; - -extern void ShutDownDBCLient(AsyncIO *IO); - -static void DBQueueEventAddCallback(EV_P_ ev_async *w, int revents) -{ - CitContext *Ctx; - long IOID = -1; - long count = 0;; - ev_tstamp Now; - HashList *q; - void *v; - HashPos *It; - long len; - const char *Key; - - /* get the control command... */ - pthread_mutex_lock(&DBEventQueueMutex); - - if (DBInboundEventQueues[0] == DBInboundEventQueue) { - DBInboundEventQueue = DBInboundEventQueues[1]; - q = DBInboundEventQueues[0]; - } - else { - DBInboundEventQueue = DBInboundEventQueues[0]; - q = DBInboundEventQueues[1]; - } - pthread_mutex_unlock(&DBEventQueueMutex); - - Now = ev_now (event_db); - It = GetNewHashPos(q, 0); - while (GetNextHashPos(q, It, &len, &Key, &v)) - { - IOAddHandler *h = v; - eNextState rc; - count ++; - if (h->IO->ID == 0) - h->IO->ID = EvIDSource++; - IOID = h->IO->ID; - if (h->IO->StartDB == 0.0) - h->IO->StartDB = Now; - h->IO->CitContext->lastcmd = h->IO->Now = Now; - - SetEVState(h->IO, eDBAttach); - Ctx = h->IO->CitContext; - become_session(Ctx); - ev_cleanup_start(event_db, &h->IO->db_abort_by_shutdown); - rc = h->EvAttch(h->IO); - switch (rc) - { - case eAbort: - ShutDownDBCLient(h->IO); - default: - break; - } - } - DeleteHashPos(&It); - DeleteHashContent(&q); - syslog(LOG_DEBUG, "%s CC[%ld] DBEVENT Q Add %ld done.", IOSTR, IOID, count); -} - - -static void DBEventExitCallback(EV_P_ ev_async *w, int revents) -{ - syslog(LOG_DEBUG, "DB EVENT Q exiting.\n"); - ev_break(event_db, EVBREAK_ALL); -} - - - -void DBInitEventQueue(void) -{ - pthread_mutex_init(&DBEventQueueMutex, NULL); - pthread_mutex_init(&DBEventExitQueueMutex, NULL); - - DBQueueEvents = NewHash(1, Flathash); - DBInboundEventQueues[0] = NewHash(1, Flathash); - DBInboundEventQueues[1] = NewHash(1, Flathash); - DBInboundEventQueue = DBInboundEventQueues[0]; -} - -const char *DBLog = "BD"; - -/* - * this thread operates writing to the message database via libev. - */ -void *db_event_thread(void *arg) -{ - ev_loop *tmp; - struct CitContext libev_msg_CC; - - pthread_setspecific(evConKey, DBLog); - - CtdlFillSystemContext(&libev_msg_CC, "LibEv DB IO Thread"); - - syslog(LOG_DEBUG, "dbevent_thread() initializing\n"); - - tmp = event_db = ev_loop_new (EVFLAG_AUTO); - - ev_async_init(&DBAddJob, DBQueueEventAddCallback); - ev_async_start(event_db, &DBAddJob); - ev_async_init(&DBExitEventLoop, DBEventExitCallback); - ev_async_start(event_db, &DBExitEventLoop); - - ev_run (event_db, 0); - - pthread_mutex_lock(&DBEventExitQueueMutex); - - event_db = NULL; - syslog(LOG_INFO, "dbevent_thread() exiting\n"); - - DeleteHash(&DBQueueEvents); - DBInboundEventQueue = NULL; - DeleteHash(&DBInboundEventQueues[0]); - DeleteHash(&DBInboundEventQueues[1]); - -/* citthread_mutex_destroy(&DBEventQueueMutex); TODO */ - - ev_loop_destroy (tmp); - pthread_mutex_unlock(&DBEventExitQueueMutex); - return(NULL); -} - -void ShutDownEventQueues(void) -{ - syslog(LOG_DEBUG, "EVENT Qs triggering exits.\n"); - - pthread_mutex_lock(&DBEventQueueMutex); - ev_async_send (event_db, &DBExitEventLoop); - pthread_mutex_unlock(&DBEventQueueMutex); - - pthread_mutex_lock(&EventQueueMutex); - ev_async_send (EV_DEFAULT_ &ExitEventLoop); - pthread_mutex_unlock(&EventQueueMutex); -} - -void DebugEventloopEnable(const int n) -{ - DebugEventLoop = n; -} -void DebugEventloopBacktraceEnable(const int n) -{ - DebugEventLoopBacktrace = n; -} - -void DebugCurlEnable(const int n) -{ - DebugCurl = n; -} - -const char *WLog = "WX"; -CTDL_MODULE_INIT(event_client) -{ - if (!threading) - { - if (pthread_key_create(&evConKey, NULL) != 0) { - syslog(LOG_CRIT, "Can't create TSD key: %s", strerror(errno)); - } - pthread_setspecific(evConKey, WLog); - - CtdlRegisterDebugFlagHook(HKEY("eventloop"), DebugEventloopEnable, &DebugEventLoop); - CtdlRegisterDebugFlagHook(HKEY("eventloopbacktrace"), DebugEventloopBacktraceEnable, &DebugEventLoopBacktrace); - CtdlRegisterDebugFlagHook(HKEY("curl"), DebugCurlEnable, &DebugCurl); - InitEventQueue(); - DBInitEventQueue(); - CtdlThreadCreate(client_event_thread); - CtdlThreadCreate(db_event_thread); - } - return "event"; -} diff --git a/citadel/modules/extnotify/.gitignore b/citadel/modules/extnotify/.gitignore deleted file mode 100644 index 5761abcfd..000000000 --- a/citadel/modules/extnotify/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.o diff --git a/citadel/modules/extnotify/extnotify.h b/citadel/modules/extnotify/extnotify.h deleted file mode 100644 index f684ec479..000000000 --- a/citadel/modules/extnotify/extnotify.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * File: extnotify.h - * Author: Mathew McBride / - * Copyright (c) 2008-2009 - * - * 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. - * - * - * - * 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. - * - * - * - * - */ - -#include "../eventclient/serv_curl.h" -#define PAGER_CONFIG_MESSAGE "__ Push email settings __" -#define FUNAMBOL_CONFIG_TEXT "funambol" -#define PAGER_CONFIG_SYSTEM "textmessage" -#define PAGER_CONFIG_HTTP "httpmessage" -typedef enum _eNotifyType { - eNone, - eFunambol, - eHttpMessages, - eTextMessage -}eNotifyType; - - -#define FUNAMBOL_WS "/funambol/services/admin" - -typedef struct _NotifyContext { - StrBuf **NotifyHostList; - int nNotifyHosts; - HashList *NotifyErrors; - AsyncIO IO; -} NotifyContext; - -int notify_http_server(char *remoteurl, - const char* template, - long tlen, - char *user, - char *msgid, - long MsgNum, - NotifyContext *Ctx); - -void ExtNotify_PutErrorMessage(NotifyContext *Ctx, StrBuf *ErrMsg); - -///void process_notify(long msgnum, void *usrdata); diff --git a/citadel/modules/extnotify/extnotify_main.c b/citadel/modules/extnotify/extnotify_main.c deleted file mode 100644 index 7bbad0503..000000000 --- a/citadel/modules/extnotify/extnotify_main.c +++ /dev/null @@ -1,518 +0,0 @@ -/* - * extnotify_main.c - * Mathew McBride - * - * This module implements an external pager hook for when notifcation - * of a new email is wanted. - * - * Based on bits of serv_funambol - * Contact: / - * - * Copyright (c) 2008-2015 - * - * This program is open source 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 3 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. - */ - - -#include "sysdep.h" -#include -#include -#include -#include -#include -#include -#include -#include - -#if TIME_WITH_SYS_TIME -# include -# include -#else -# if HAVE_SYS_TIME_H -# include -# else -# include -# endif -#endif - -#include -#include -#include -#include -#include -#include "citadel.h" -#include "server.h" -#include "citserver.h" -#include "support.h" -#include "config.h" -#include "control.h" -#include "user_ops.h" -#include "database.h" -#include "msgbase.h" -#include "internet_addressing.h" -#include "domain.h" -#include "clientsocket.h" -#include "event_client.h" -#include "extnotify.h" -#include "ctdl_module.h" - -struct CitContext extnotify_queue_CC; - -void ExtNotify_PutErrorMessage(NotifyContext *Ctx, StrBuf *ErrMsg) -{ - int nNext; - if (Ctx->NotifyErrors == NULL) - Ctx->NotifyErrors = NewHash(1, Flathash); - - nNext = GetCount(Ctx->NotifyErrors) + 1; - Put(Ctx->NotifyErrors, - (char*)&nNext, - sizeof(int), - ErrMsg, - HFreeStrBuf); -} - -StrBuf* GetNHBuf(int i, int allocit, StrBuf **NotifyHostList) -{ - if ((NotifyHostList[i] == NULL) && (allocit != 0)) - NotifyHostList[i] = NewStrBuf(); - return NotifyHostList[i]; -} - - -int GetNotifyHosts(NotifyContext *Ctx) -{ - char NotifyHostsBuf[SIZ]; - StrBuf *Host; - StrBuf *File; - StrBuf *NotifyBuf; - int notify; - const char *pchs, *pche; - const char *NextHost = NULL; - - /* See if we have any Notification Hosts configured */ - Ctx->nNotifyHosts = get_hosts(NotifyHostsBuf, "notify"); - if (Ctx->nNotifyHosts < 1) - return 0; - - Ctx->NotifyHostList = malloc(sizeof(StrBuf*) * - 2 * - (Ctx->nNotifyHosts + 1)); - memset(Ctx->NotifyHostList, 0, - sizeof(StrBuf*) * 2 * (Ctx->nNotifyHosts + 1)); - - NotifyBuf = NewStrBufPlain(NotifyHostsBuf, -1); - /* get all configured notifiers's */ - for (notify=0; notifynNotifyHosts; notify++) { - - Host = GetNHBuf(notify * 2, 1, Ctx->NotifyHostList); - StrBufExtract_NextToken(Host, NotifyBuf, &NextHost, '|'); - pchs = ChrPtr(Host); - pche = strchr(pchs, ':'); - if (pche == NULL) { - syslog(LOG_ERR, - "extnotify: filename of notification " - "template not found in %s.", - pchs); - continue; - } - File = GetNHBuf(notify * 2 + 1, 1, Ctx->NotifyHostList); - StrBufPlain(File, pchs, pche - pchs); - StrBufCutLeft(Host, pche - pchs + 1); - } - FreeStrBuf(&NotifyBuf); - return Ctx->nNotifyHosts; -} - - - -/*! \brief Get configuration message for pager/funambol system from the - * users "My Citadel Config" room - */ -eNotifyType extNotify_getConfigMessage(char *username, - char **PagerNumber, - char **FreeMe) -{ - struct ctdlroom qrbuf; // scratch for room - struct ctdluser user; // ctdl user instance - char configRoomName[ROOMNAMELEN]; - struct CtdlMessage *msg = NULL; - struct cdbdata *cdbfr; - long *msglist = NULL; - int num_msgs = 0; - int a; - char *configMsg; - long clen; - char *pch; - - // Get the user - CtdlGetUser(&user, username); - - CtdlMailboxName(configRoomName, - sizeof(configRoomName), - &user, - USERCONFIGROOM); - // Fill qrbuf - CtdlGetRoom(&qrbuf, configRoomName); - /* Do something really, really stoopid here. Raid the room on ourselves, - * loop through the messages manually and find it. I don't want - * to use a CtdlForEachMessage callback here, as we would be - * already in one */ - cdbfr = cdb_fetch(CDB_MSGLISTS, &qrbuf.QRnumber, sizeof(long)); - if (cdbfr != NULL) { - msglist = (long *) cdbfr->ptr; - cdbfr->ptr = NULL; - /* CtdlForEachMessage() now owns this memory */ - num_msgs = cdbfr->len / sizeof(long); - cdb_free(cdbfr); - } else { - syslog(LOG_DEBUG, - "extNotify_getConfigMessage: " - "No config messages found"); - return eNone; /* No messages at all? No further action. */ - } - for (a = 0; a < num_msgs; ++a) { - msg = CtdlFetchMessage(msglist[a], 1, 1); - if (msg != NULL) { - if (!CM_IsEmpty(msg, eMsgSubject) && - (strncasecmp(msg->cm_fields[eMsgSubject], - PAGER_CONFIG_MESSAGE, - strlen(PAGER_CONFIG_MESSAGE)) == 0)) - { - break; - } - CM_Free(msg); - msg = NULL; - } - } - - free(msglist); - if (msg == NULL) - return eNone; - - // Do a simple string search to see if 'funambol' is selected as the - // type. This string would be at the very top of the message contents. - - CM_GetAsField(msg, eMesageText, &configMsg, &clen); - CM_Free(msg); - - /* here we would find the pager number... */ - pch = strchr(configMsg, '\n'); - if (pch != NULL) - { - *pch = '\0'; - pch ++; - } - - /* Check to see if: - * 1. The user has configured paging / They have and disabled it - * AND 2. There is an external pager program - * 3. A Funambol server has been entered - * - */ - if (!strncasecmp(configMsg, "none", 4)) - { - free(configMsg); - return eNone; - } - - if (!strncasecmp(configMsg, HKEY(PAGER_CONFIG_HTTP))) - { - free(configMsg); - return eHttpMessages; - } - if (!strncasecmp(configMsg, HKEY(FUNAMBOL_CONFIG_TEXT))) - { - free(configMsg); - return eFunambol; - } - else if (!strncasecmp(configMsg, HKEY(PAGER_CONFIG_SYSTEM))) - { - // whats the pager number? - if (!pch || (*pch == '\0')) - { - free(configMsg); - - return eNone; - } - while (isspace(*pch)) - pch ++; - *PagerNumber = pch; - while (isdigit(*pch) || (*pch == '+')) - pch++; - *pch = '\0'; - *FreeMe = configMsg; - return eTextMessage; - } - - free(configMsg); - return eNone; -} - - -/* - * Process messages in the external notification queue - */ -void process_notify(long NotifyMsgnum, void *usrdata) -{ - NotifyContext *Ctx; - long msgnum = 0; - long todelete[1]; - char *pch; - struct CtdlMessage *msg; - eNotifyType Type; - char remoteurl[SIZ]; - char *FreeMe = NULL; - char *PagerNo; - - Ctx = (NotifyContext*) usrdata; - - msg = CtdlFetchMessage(NotifyMsgnum, 1, 1); - if (!CM_IsEmpty(msg, eExtnotify)) - { - Type = extNotify_getConfigMessage( - msg->cm_fields[eExtnotify], - &PagerNo, - &FreeMe); - - pch = strstr(msg->cm_fields[eMesageText], "msgid|"); - if (pch != NULL) - msgnum = atol(pch + sizeof("msgid")); - - switch (Type) - { - case eFunambol: - snprintf(remoteurl, SIZ, "http://%s@%s:%d/%s", - CtdlGetConfigStr("c_funambol_auth"), - CtdlGetConfigStr("c_funambol_host"), - CtdlGetConfigInt("c_funambol_port"), - FUNAMBOL_WS); - - notify_http_server(remoteurl, - file_funambol_msg, - strlen(file_funambol_msg),/*GNA*/ - msg->cm_fields[eExtnotify], - msg->cm_fields[emessageId], - msgnum, - NULL); - break; - case eHttpMessages: - { - int i = 0; - StrBuf *URL; - char URLBuf[SIZ]; - StrBuf *File; - StrBuf *FileBuf = NewStrBuf(); - - for (i = 0; i < Ctx->nNotifyHosts; i++) - { - - URL = GetNHBuf(i*2, 0, Ctx->NotifyHostList); - if (URL==NULL) break; - File = GetNHBuf(i*2 + 1, 0, - Ctx->NotifyHostList); - if (File==NULL) break; - - if (StrLength(File)>0) - StrBufPrintf(FileBuf, "%s/%s", - ctdl_shared_dir, - ChrPtr(File)); - else - FlushStrBuf(FileBuf); - memcpy(URLBuf, ChrPtr(URL), StrLength(URL) + 1); - - notify_http_server(URLBuf, - ChrPtr(FileBuf), - StrLength(FileBuf), - msg->cm_fields[eExtnotify], - msg->cm_fields[emessageId], - msgnum, - NULL); - } - FreeStrBuf(&FileBuf); - } - break; - case eTextMessage: - { - int commandSiz; - char *command; - - commandSiz = sizeof(CtdlGetConfigStr("c_pager_program")) + - strlen(PagerNo) + - msg->cm_lengths[eExtnotify] + 5; - - command = malloc(commandSiz); - - snprintf(command, - commandSiz, - "%s %s -u %s", - CtdlGetConfigStr("c_pager_program"), - PagerNo, - msg->cm_fields[eExtnotify]); - - system(command); - free(command); - } - break; - case eNone: - break; - } - } - if (FreeMe != NULL) - free(FreeMe); - CM_Free(msg); - todelete[0] = NotifyMsgnum; - CtdlDeleteMessages(FNBL_QUEUE_ROOM, todelete, 1, ""); -} - -/*! - * \brief Run through the pager room queue - * Checks to see what notification option the user has set - */ -void do_extnotify_queue(void) -{ - NotifyContext Ctx; - static int doing_queue = 0; - int i = 0; - - /* - * This is a simple concurrency check to make sure only one queue run - * is done at a time. We could do this with a mutex, but since we - * don't really require extremely fine granularity here, we'll do it - * with a static variable instead. - */ - if (IsEmptyStr(CtdlGetConfigStr("c_pager_program")) && - IsEmptyStr(CtdlGetConfigStr("c_funambol_host"))) - { - syslog(LOG_DEBUG, - "No external notifiers configured on system/user"); - return; - } - - if (doing_queue) - return; - - doing_queue = 1; - - become_session(&extnotify_queue_CC); - - pthread_setspecific(MyConKey, (void *)&extnotify_queue_CC); - - /* - * Go ahead and run the queue - */ - syslog(LOG_DEBUG, "serv_extnotify: processing notify queue"); - - memset(&Ctx, 0, sizeof(NotifyContext)); - if ((GetNotifyHosts(&Ctx) > 0) && - (CtdlGetRoom(&CC->room, FNBL_QUEUE_ROOM) != 0)) - { - syslog(LOG_ERR, "Cannot find room <%s>", FNBL_QUEUE_ROOM); - if (Ctx.nNotifyHosts > 0) - { - for (i = 0; i < Ctx.nNotifyHosts * 2; i++) - FreeStrBuf(&Ctx.NotifyHostList[i]); - free(Ctx.NotifyHostList); - } - return; - } - CtdlForEachMessage(MSGS_ALL, 0L, NULL, - SPOOLMIME, NULL, process_notify, &Ctx); - syslog(LOG_DEBUG, "serv_extnotify: queue run completed"); - doing_queue = 0; - if (Ctx.nNotifyHosts > 0) - { - for (i = 0; i < Ctx.nNotifyHosts * 2; i++) - FreeStrBuf(&Ctx.NotifyHostList[i]); - free(Ctx.NotifyHostList); - } -} - - - -/* Create the notify message queue. We use the exact same room - * as the Funambol module. - * - * Run at server startup, creates FNBL_QUEUE_ROOM if it doesn't exist - * and sets as system room. - */ -void create_extnotify_queue(void) { - struct ctdlroom qrbuf; - - CtdlCreateRoom(FNBL_QUEUE_ROOM, 3, "", 0, 1, 0, VIEW_QUEUE); - - CtdlFillSystemContext(&extnotify_queue_CC, "Extnotify"); - - /* - * Make sure it's set to be a "system room" so it doesn't show up - * in the nown rooms list for Aides. - */ - if (CtdlGetRoomLock(&qrbuf, FNBL_QUEUE_ROOM) == 0) { - qrbuf.QRflags2 |= QR2_SYSTEM; - CtdlPutRoomLock(&qrbuf); - } -} - -int extnotify_after_mbox_save(struct CtdlMessage *msg, - recptypes *recps) - -{ - /* If this is private, local mail, make a copy in the - * recipient's mailbox and bump the reference count. - */ - if (!IsEmptyStr(CtdlGetConfigStr("c_funambol_host")) || !IsEmptyStr(CtdlGetConfigStr("c_pager_program"))) - { - /* Generate a instruction message for the Funambol notification - * server, in the same style as the SMTP queue - */ - StrBuf *instr; - struct CtdlMessage *imsg; - - instr = NewStrBufPlain(NULL, 1024); - StrBufPrintf(instr, - "Content-type: "SPOOLMIME"\n" - "\n" - "msgid|%s\n" - "submitted|%ld\n" - "bounceto|%s\n", - msg->cm_fields[eVltMsgNum], - (long)time(NULL), //todo: time() is expensive! - recps->bounce_to - ); - - imsg = malloc(sizeof(struct CtdlMessage)); - memset(imsg, 0, sizeof(struct CtdlMessage)); - imsg->cm_magic = CTDLMESSAGE_MAGIC; - imsg->cm_anon_type = MES_NORMAL; - imsg->cm_format_type = FMT_RFC822; - CM_SetField(imsg, eMsgSubject, HKEY("QMSG")); - CM_SetField(imsg, eAuthor, HKEY("Citadel")); - CM_SetField(imsg, eJournal, HKEY("do not journal")); - CM_SetAsFieldSB(imsg, eMesageText, &instr); - CM_SetField(imsg, eExtnotify, recps->recp_local, strlen(recps->recp_local)); - CtdlSubmitMsg(imsg, NULL, FNBL_QUEUE_ROOM, 0); - CM_Free(imsg); - } - return 0; -} - -CTDL_MODULE_INIT(extnotify) -{ - if (!threading) - { - create_extnotify_queue(); - CtdlRegisterMessageHook(extnotify_after_mbox_save, EVT_AFTERUSRMBOXSAVE); - - CtdlRegisterSessionHook(do_extnotify_queue, EVT_TIMER, PRIO_SEND + 10); - } - /* return our module name for the log */ - return "extnotify"; -} diff --git a/citadel/modules/extnotify/funambol65.c b/citadel/modules/extnotify/funambol65.c deleted file mode 100644 index 1a1099719..000000000 --- a/citadel/modules/extnotify/funambol65.c +++ /dev/null @@ -1,315 +0,0 @@ -/* - * funambol65.c - * Author: Mathew McBride - * - * This module facilitates notifications to a Funambol server - * for push email - * - * Based on bits of the previous serv_funambol - * Contact: / - * - * Copyright (c) 2008-2015 - * - * 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. - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "citadel.h" -#include "citserver.h" -#include "citadel_dirs.h" -#include "clientsocket.h" -#include "sysdep.h" -#include "config.h" -#include "sysdep_decls.h" -#include "msgbase.h" -#include "ctdl_module.h" - -#include "event_client.h" -#include "extnotify.h" - -eNextState EvaluateResult(AsyncIO *IO); -eNextState ExtNotifyTerminate(AsyncIO *IO); -eNextState ExtNotifyTerminateDB(AsyncIO *IO); -eNextState ExtNotifyShutdownAbort(AsyncIO *IO); - -/* -* \brief Sends a message to the Funambol server notifying -* of new mail for a user -* Returns 0 if unsuccessful -*/ -int notify_http_server(char *remoteurl, - const char* template, long tlen, - char *user, - char *msgid, - long MsgNum, - NotifyContext *Ctx) -{ - CURLcode sta; - char msgnumstr[128]; - char *buf = NULL; - char *SOAPMessage = NULL; - char *contenttype = NULL; - StrBuf *ReplyBuf; - StrBuf *Buf; - CURL *chnd; - AsyncIO *IO; - - IO = (AsyncIO*) malloc(sizeof(AsyncIO)); - memset(IO, 0, sizeof(AsyncIO)); - - if (! InitcURLIOStruct(IO, - NULL, /* we don't have personal data anymore. */ - "Citadel ExtNotify", - EvaluateResult, - ExtNotifyTerminate, - ExtNotifyTerminateDB, - ExtNotifyShutdownAbort)) - { - syslog(LOG_ALERT, "Unable to initialize libcurl.\n"); - goto abort; - } - - snprintf(msgnumstr, 128, "%ld", MsgNum); - - if (tlen > 0) { - /* Load the template message. Get mallocs done too */ - int fd; - struct stat statbuf; - const char *mimetype; - const char *Err = NULL; - - fd = open(template, O_RDONLY); - if ((fd < 0) || - (fstat(fd, &statbuf) == -1)) - { - char buf[SIZ]; - - snprintf(buf, SIZ, - "Cannot load template file %s [%s] " - "won't send notification\r\n", - file_funambol_msg, - strerror(errno)); - syslog(LOG_ERR, "%s", buf); - // TODO: once an hour! - CtdlAideMessage( - buf, - "External notifier: " - "unable to find/stat message template!"); - goto abort; - } - - Buf = NewStrBufPlain(NULL, statbuf.st_size + 1); - if (StrBufReadBLOB(Buf, &fd, 1, statbuf.st_size, &Err) < 0) { - char buf[SIZ]; - - close(fd); - - snprintf(buf, SIZ, - "Cannot load template file %s [%s] " - "won't send notification\r\n", - file_funambol_msg, - Err); - syslog(LOG_ERR, "%s", buf); - // TODO: once an hour! - CtdlAideMessage( - buf, - "External notifier: " - "unable to load message template!"); - goto abort; - } - close(fd); - - mimetype = GuessMimeByFilename(template, tlen); - - SOAPMessage = SmashStrBuf(&Buf); - - // Do substitutions - help_subst(SOAPMessage, "^notifyuser", user); - help_subst(SOAPMessage, "^syncsource", CtdlGetConfigStr("c_funambol_source")); - help_subst(SOAPMessage, "^msgid", msgid); - help_subst(SOAPMessage, "^msgnum", msgnumstr); - - /* pass our list of custom made headers */ - - contenttype=(char*) malloc(40+strlen(mimetype)); - sprintf(contenttype, - "Content-Type: %s; charset=utf-8", - mimetype); - - IO->HttpReq.headers = curl_slist_append( - IO->HttpReq.headers, - "SOAPAction: \"\""); - - IO->HttpReq.headers = curl_slist_append( - IO->HttpReq.headers, - contenttype); - free(contenttype); - contenttype = NULL; - IO->HttpReq.headers = curl_slist_append( - IO->HttpReq.headers, - "Accept: application/soap+xml, " - "application/mime, multipart/related, text/*"); - - IO->HttpReq.headers = curl_slist_append( - IO->HttpReq.headers, - "Pragma: no-cache"); - - /* Now specify the POST binary data */ - IO->HttpReq.PlainPostData = SOAPMessage; - IO->HttpReq.PlainPostDataLen = strlen(SOAPMessage); - } - else { - help_subst(remoteurl, "^notifyuser", user); - help_subst(remoteurl, "^syncsource", CtdlGetConfigStr("c_funambol_source")); - help_subst(remoteurl, "^msgid", msgid); - help_subst(remoteurl, "^msgnum", msgnumstr); - - IO->HttpReq.headers = curl_slist_append( - IO->HttpReq.headers, - "Accept: application/soap+xml, " - "application/mime, multipart/related, text/*"); - - IO->HttpReq.headers = curl_slist_append( - IO->HttpReq.headers, - "Pragma: no-cache"); - } - - Buf = NewStrBufPlain (remoteurl, -1); - ParseURL(&IO->ConnectMe, Buf, 80); - FreeStrBuf(&Buf); /* TODO: this is uncool... */ - CurlPrepareURL(IO->ConnectMe); - - chnd = IO->HttpReq.chnd; - OPT(SSL_VERIFYPEER, 0); - OPT(SSL_VERIFYHOST, 0); - - QueueCurlContext(IO); - - return 0; -abort: - - if (contenttype) free(contenttype); - if (SOAPMessage != NULL) free(SOAPMessage); - if (buf != NULL) free(buf); - FreeStrBuf (&ReplyBuf); - return 1; -} - - -eNextState EvaluateResult(AsyncIO *IO) -{ - - if (IO->HttpReq.httpcode != 200) { - StrBuf *ErrMsg; - - syslog(LOG_ALERT, "libcurl error %ld: %s\n", - IO->HttpReq.httpcode, - IO->HttpReq.errdesc); - - ErrMsg = NewStrBufPlain( - HKEY("Error sending your Notification\n")); - StrBufAppendPrintf(ErrMsg, "\nlibcurl error %ld: \n\t\t%s\n", - IO->HttpReq.httpcode, - IO->HttpReq.errdesc); - - StrBufAppendBufPlain(ErrMsg, - HKEY("\nWas Trying to send: \n"), - 0); - - StrBufAppendBufPlain(ErrMsg, IO->ConnectMe->PlainUrl, -1, 0); - if (IO->HttpReq.PlainPostDataLen > 0) { - StrBufAppendBufPlain( - ErrMsg, - HKEY("\nThe Post document was: \n"), - 0); - StrBufAppendBufPlain(ErrMsg, - IO->HttpReq.PlainPostData, - IO->HttpReq.PlainPostDataLen, 0); - StrBufAppendBufPlain(ErrMsg, HKEY("\n\n"), 0); - } - if (StrLength(IO->HttpReq.ReplyData) > 0) { - StrBufAppendBufPlain( - ErrMsg, - HKEY("\n\nThe Serverreply was: \n\n"), - 0); - StrBufAppendBuf(ErrMsg, IO->HttpReq.ReplyData, 0); - } - else - StrBufAppendBufPlain( - ErrMsg, - HKEY("\n\nThere was no Serverreply.\n\n"), - 0); - ///ExtNotify_PutErrorMessage(Ctx, ErrMsg); - CtdlAideMessage(ChrPtr(ErrMsg), - "External notifier: " - "unable to contact notification host!"); - FreeStrBuf(&ErrMsg); - } - - syslog(LOG_DEBUG, "Funambol notified\n"); -/* - while ((Ctx.NotifyHostList != NULL) && (Ctx.NotifyHostList[i] != NULL)) - FreeStrBuf(&Ctx.NotifyHostList[i]); - - if (Ctx.NotifyErrors != NULL) - { - long len; - const char *Key; - HashPos *It; - void *vErr; - StrBuf *ErrMsg; - - It = GetNewHashPos(Ctx.NotifyErrors, 0); - while (GetNextHashPos(Ctx.NotifyErrors, - It, &len, &Key, &vErr) && - (vErr != NULL)) { - ErrMsg = (StrBuf*) vErr; - quickie_message("Citadel", NULL, NULL, - AIDEROOM, ChrPtr(ErrMsg), FMT_FIXED, - "Failed to notify external service about inbound mail"); - } - - DeleteHashPos(&It); - DeleteHash(&Ctx.NotifyErrors); - } -*/ - -//// curl_slist_free_all (headers); -/// curl_easy_cleanup(curl); - ///if (contenttype) free(contenttype); - ///if (SOAPMessage != NULL) free(SOAPMessage); - ///if (buf != NULL) free(buf); - ///FreeStrBuf (&ReplyBuf); - return eTerminateConnection; -} - -eNextState ExtNotifyTerminateDB(AsyncIO *IO) -{ - free(IO); - return eAbort; -} -eNextState ExtNotifyTerminate(AsyncIO *IO) -{ - free(IO); - return eAbort; -} -eNextState ExtNotifyShutdownAbort(AsyncIO *IO) -{ - free(IO); - return eAbort; -} diff --git a/citadel/modules/network/serv_netmail.c b/citadel/modules/network/serv_netmail.c index 76018eba0..ddd3ba19d 100644 --- a/citadel/modules/network/serv_netmail.c +++ b/citadel/modules/network/serv_netmail.c @@ -535,20 +535,19 @@ void network_process_ignetpush(SpoolControl *sc, struct CtdlMessage *omsg, long /* write it to a spool file */ snprintf(filename, - sizeof(filename), - "%s/%s@%lx%x", - ctdl_netout_dir, - ChrPtr(Recipient), - time(NULL), - rand() - ); + sizeof(filename), + "%s/%s@%lx%x", + ctdl_netout_dir, + ChrPtr(Recipient), + time(NULL), + rand() + ); syslog(LOG_DEBUG, "netmail: appending to %s", filename); fp = fopen(filename, "ab"); if (fp != NULL) { - fwrite(sermsg.ser, - sermsg.len, 1, fp); + fwrite(sermsg.ser, sermsg.len, 1, fp); fclose(fp); } else { diff --git a/citadel/modules/network/serv_netspool.c b/citadel/modules/network/serv_netspool.c index 9c4adff9e..a17980ece 100644 --- a/citadel/modules/network/serv_netspool.c +++ b/citadel/modules/network/serv_netspool.c @@ -914,6 +914,9 @@ void network_consolidate_spoolout(HashList *working_ignetcfg, HashList *the_netm int d_type = 0; + + return; // FIXME still trying to figure this out + /* Step 1: consolidate files in the outbound queue into one file per neighbor node */ d = (struct dirent *)malloc(offsetof(struct dirent, d_name) + PATH_MAX + 1); if (d == NULL) return; @@ -982,7 +985,7 @@ void network_consolidate_spoolout(HashList *working_ignetcfg, HashList *the_netm syslog(LOG_DEBUG, "netspool: consolidate %s to %s", filename, ChrPtr(NextHop)); if (CtdlNetworkTalkingTo(SKEY(NextHop), NTT_CHECK)) { nFailed++; - syslog(LOG_DEBUG, "netspool: urrently online with %s - skipping for now", ChrPtr(NextHop)); + syslog(LOG_DEBUG, "netspool: currently online with %s - skipping for now", ChrPtr(NextHop)); } else { size_t dsize; @@ -1135,7 +1138,6 @@ void free_spoolcontrol_struct_members(SpoolControl *sc) } - /* * It's ok if these directories already exist. Just fail silently. */ diff --git a/citadel/modules/networkclient/serv_networkclient.c b/citadel/modules/networkclient/serv_networkclient.c index 9daddd486..66bcae45b 100644 --- a/citadel/modules/networkclient/serv_networkclient.c +++ b/citadel/modules/networkclient/serv_networkclient.c @@ -1,6 +1,5 @@ /* - * This module handles shared rooms, inter-Citadel mail, and outbound - * mailing list processing. + * This module polls other Citadel servers for inter-site networking. * * Copyright (c) 2000-2017 by the citadel.org team * @@ -73,837 +72,136 @@ struct CitContext networker_client_CC; -#define NODE ChrPtr(((AsyncNetworker*)IO->Data)->node) -#define N ((AsyncNetworker*)IO->Data)->n -typedef enum _eNWCState { - eGreating, - eAuth, - eNDOP, - eREAD, - eReadBLOB, - eCLOS, - eNUOP, - eWRIT, - eWriteBLOB, - eUCLS, - eQUIT -}eNWCState; - -typedef enum _eNWCVState { - eNWCVSLookup, - eNWCVSConnecting, - eNWCVSConnFail, - eNWCVSGreating, - eNWCVSAuth, - eNWCVSAuthFailNTT, - eNWCVSAuthFail, - eNWCVSNDOP, - eNWCVSNDOPDone, - eNWCVSNUOP, - eNWCVSNUOPDone, - eNWCVSFail -}eNWCVState; - -ConstStr NWCStateStr[] = { - {HKEY("Looking up Host")}, - {HKEY("Connecting host")}, - {HKEY("Failed to connect")}, - {HKEY("Rread Greeting")}, - {HKEY("Authenticating")}, - {HKEY("Auth failed by NTT")}, - {HKEY("Auth failed")}, - {HKEY("Downloading")}, - {HKEY("Downloading Success")}, - {HKEY("Uploading Spoolfile")}, - {HKEY("Uploading done")}, - {HKEY("failed")} -}; - -void SetNWCState(AsyncIO *IO, eNWCVState State) -{ - CitContext* CCC = IO->CitContext; - memcpy(CCC->cs_clientname, NWCStateStr[State].Key, NWCStateStr[State].len + 1); -} - -typedef struct _async_networker { - AsyncIO IO; - DNSQueryParts HostLookup; - eNWCState State; - long n; - StrBuf *SpoolFileName; - StrBuf *tempFileName; - StrBuf *node; - StrBuf *host; - StrBuf *port; - StrBuf *secret; - StrBuf *Url; -} AsyncNetworker; - -typedef eNextState(*NWClientHandler)(AsyncNetworker* NW); -eNextState nwc_get_one_host_ip(AsyncIO *IO); - -eNextState nwc_connect_ip(AsyncIO *IO); - -eNextState NWC_SendQUIT(AsyncNetworker *NW); -eNextState NWC_DispatchWriteDone(AsyncIO *IO); - -void DeleteNetworker(void *vptr) -{ - AsyncNetworker *NW = (AsyncNetworker *)vptr; - FreeStrBuf(&NW->SpoolFileName); - FreeStrBuf(&NW->tempFileName); - FreeStrBuf(&NW->node); - FreeStrBuf(&NW->host); - FreeStrBuf(&NW->port); - FreeStrBuf(&NW->secret); - FreeStrBuf(&NW->Url); - FreeStrBuf(&NW->IO.ErrMsg); - FreeAsyncIOContents(&NW->IO); - if (NW->HostLookup.VParsedDNSReply != NULL) { - NW->HostLookup.DNSReplyFree(NW->HostLookup.VParsedDNSReply); - NW->HostLookup.VParsedDNSReply = NULL; +/* + * Poll one Citadel node (the Citadel node name, host/ip, port number, and shared secret are supplied by the caller) + */ +void network_poll_node(StrBuf *node, StrBuf *host, StrBuf *port, StrBuf *secret) +{ + char buf[SIZ]; + CC->SBuf.Buf = NewStrBuf(); + CC->sMigrateBuf = NewStrBuf(); + CC->SBuf.ReadWritePointer = NULL; + int bytes_read = 0; + int bytes_total = 0; + int this_block = 0; + StrBuf *SpoolFileName = NULL; + + syslog(LOG_DEBUG, "netpoll: polling %s at %s:%s", ChrPtr(node), ChrPtr(host), ChrPtr(port)); + + int sock = sock_connect((char *)ChrPtr(host), (char *)ChrPtr(port)); + if (sock < 0) { + syslog(LOG_ERR, "%s: %s", ChrPtr(host), strerror(errno)); + return; } - free(NW); -} -eNextState NWC_SendFailureMessage(AsyncIO *IO) -{ - AsyncNetworker *NW = IO->Data; - - syslog(LOG_DEBUG, "netpoll: %s", __FUNCTION__); - - CtdlAideMessage(ChrPtr(NW->IO.ErrMsg), "Networker error"); - return eAbort; -} - -eNextState FinalizeNetworker(AsyncIO *IO) -{ - AsyncNetworker *NW = (AsyncNetworker *)IO->Data; - - CtdlNetworkTalkingTo(SKEY(NW->node), NTT_REMOVE); - - DeleteNetworker(IO->Data); - return eAbort; -} - -eNextState NWC_ReadGreeting(AsyncNetworker *NW) -{ - char connected_to[SIZ]; - AsyncIO *IO = &NW->IO; - SetNWCState(IO, eNWCVSGreating); /* Read the server greeting */ - /* Check that the remote is who we think it is and warn the Aide if not */ - extract_token (connected_to, ChrPtr(NW->IO.IOBuf), 1, ' ', sizeof connected_to); - if (strcmp(connected_to, ChrPtr(NW->node)) != 0) - { - if (NW->IO.ErrMsg == NULL) - NW->IO.ErrMsg = NewStrBuf(); - StrBufPrintf(NW->IO.ErrMsg, - "Connected to node \"%s\" but I was expecting to connect to node \"%s\".", - connected_to, ChrPtr(NW->node)); - syslog(LOG_ERR, "netpoll: %s", ChrPtr(NW->IO.ErrMsg)); - - return EventQueueDBOperation(IO, NWC_SendFailureMessage, 1); - } - return eSendReply; -} - -eNextState NWC_SendAuth(AsyncNetworker *NW) -{ - AsyncIO *IO = &NW->IO; - SetNWCState(IO, eNWCVSAuth); - /* We're talking to the correct node. Now identify ourselves. */ - StrBufPrintf(NW->IO.SendBuf.Buf, "NETP %s|%s\n", - CtdlGetConfigStr("c_nodename"), - ChrPtr(NW->secret)); - return eSendReply; -} + if (sock_getln(&sock, buf, sizeof buf) < 0) { + goto bail; + } -eNextState NWC_ReadAuthReply(AsyncNetworker *NW) -{ - AsyncIO *IO = &NW->IO; - if (ChrPtr(NW->IO.IOBuf)[0] == '2') - { - return eSendReply; + /* Check that the remote is who we think it is and warn the site admin if not */ + if (strncmp(&buf[4], ChrPtr(node), StrLength(node))) { + CtdlAideMessage(buf, "Connected to wrong node!"); + syslog(LOG_ERR, "netpoll: was expecting node <%s> but got %s", ChrPtr(node), buf); + goto bail; } - else - { - int Error = atol(ChrPtr(NW->IO.IOBuf)); - if (NW->IO.ErrMsg == NULL) - NW->IO.ErrMsg = NewStrBuf(); - StrBufPrintf(NW->IO.ErrMsg, - "Connected to node \"%s\" but my secret wasn't accurate.\nReason was:%s\n", - ChrPtr(NW->node), ChrPtr(NW->IO.IOBuf) + 4); - if (Error == 552) { - SetNWCState(IO, eNWCVSAuthFailNTT); - syslog(LOG_INFO, "netpoll: already talking to %s; skipping this time.", ChrPtr(NW->node)); - - } - else { - SetNWCState(IO, eNWCVSAuthFailNTT); - syslog(LOG_ERR, "netpoll: %s", ChrPtr(NW->IO.ErrMsg)); - return EventQueueDBOperation(IO, NWC_SendFailureMessage, 1); - } - return eAbort; - } -} -eNextState NWC_SendNDOP(AsyncNetworker *NW) -{ - AsyncIO *IO = &NW->IO; - SetNWCState(IO, eNWCVSNDOP); - NW->tempFileName = NewStrBuf(); - NW->SpoolFileName = NewStrBuf(); - StrBufPrintf(NW->SpoolFileName, - "%s/%s.%lx%x", - ctdl_netin_dir, - ChrPtr(NW->node), - time(NULL),// TODO: get time from libev - rand()); - StrBufStripSlashes(NW->SpoolFileName, 1); - StrBufPrintf(NW->tempFileName, - "%s/%s.%lx%x", - ctdl_nettmp_dir, - ChrPtr(NW->node), - time(NULL),// TODO: get time from libev - rand()); - StrBufStripSlashes(NW->tempFileName, 1); /* We're talking to the correct node. Now identify ourselves. */ - StrBufPlain(NW->IO.SendBuf.Buf, HKEY("NDOP\n")); - return eSendReply; -} - -eNextState NWC_ReadNDOPReply(AsyncNetworker *NW) -{ - AsyncIO *IO = &NW->IO; - int TotalSendSize; - if (ChrPtr(NW->IO.IOBuf)[0] == '2') - { - int LogLevel = LOG_DEBUG; - - NW->IO.IOB.TotalSentAlready = 0; - - TotalSendSize = atol (ChrPtr(NW->IO.IOBuf) + 4); - - if (TotalSendSize > 0) - LogLevel = LOG_INFO; - - syslog(LogLevel, "netpoll: expecting to transfer %d bytes to %s", TotalSendSize, ChrPtr(NW->tempFileName)); - - if (TotalSendSize <= 0) { - NW->State = eNUOP - 1; - } - else { - int fd; - fd = open(ChrPtr(NW->tempFileName), - O_EXCL|O_CREAT|O_NONBLOCK|O_WRONLY, - S_IRUSR|S_IWUSR); - if (fd < 0) - { - SetNWCState(IO, eNWCVSFail); - syslog(LOG_ERR, "%s: %s", ChrPtr(NW->tempFileName), strerror(errno)); - - NW->State = eQUIT - 1; - return eAbort; + snprintf(buf, sizeof buf, "NETP %s|%s", CtdlGetConfigStr("c_nodename"), ChrPtr(secret)); + sock_puts(&sock, buf); + if (sock_getln(&sock, buf, sizeof buf) < 0) { + goto bail; + } + if (buf[0] != '2') { + CtdlAideMessage(buf, "Could not authenticate to network peer"); + syslog(LOG_ERR, "netpoll: could not authenticate to <%s> : %s", ChrPtr(node), buf); + goto bail; + } + + /* Tell it we want to download anything headed our way. */ + sock_puts(&sock, "NDOP"); + if (sock_getln(&sock, buf, sizeof buf) < 0) { + goto bail; + } + if (buf[0] != '2') { + CtdlAideMessage(buf, "NDOP error"); + syslog(LOG_ERR, "netpoll: NDOP error talking to <%s> : %s", ChrPtr(node), buf); + goto bail; + } + + bytes_total = atoi(&buf[4]); + bytes_read = 0; + + SpoolFileName = NewStrBuf(); + StrBufPrintf(SpoolFileName, // Incoming packets get dropped into the "spoolin/" directory + "%s/%s.%lx%x", + ctdl_netin_dir, + ChrPtr(node), + time(NULL), + rand() + ); + StrBufStripSlashes(SpoolFileName, 1); + + FILE *netinfp = fopen(ChrPtr(SpoolFileName), "w"); + FreeStrBuf(&SpoolFileName); + if (!netinfp) { + goto bail; + } + + while (bytes_read < bytes_total) { + snprintf(buf, sizeof buf, "READ %d|%d", bytes_read, bytes_total-bytes_read); + sock_puts(&sock, buf); + if (sock_getln(&sock, buf, sizeof buf) < 0) { + fclose(netinfp); + goto bail; + } + if (buf[0] == '6') { + this_block = atoi(&buf[4]); + + // Use buffered reads to download the data from remote server + StrBuf *ThisBlockBuf = NewStrBuf(); + int blen = socket_read_blob(&sock, ThisBlockBuf, this_block, 20); + if (blen > 0) { + fwrite(ChrPtr(ThisBlockBuf), blen, 1, netinfp); + bytes_read += blen; + } + FreeStrBuf(&ThisBlockBuf); + if (blen < this_block) { + syslog(LOG_DEBUG, "netpoll: got short block, ftn"); + fclose(netinfp); + goto bail; } - FDIOBufferInit(&NW->IO.IOB, &NW->IO.RecvBuf, fd, TotalSendSize); - } - return eSendReply; - } - else - { - SetNWCState(IO, eNWCVSFail); - return eAbort; - } -} - -eNextState NWC_SendREAD(AsyncNetworker *NW) -{ - AsyncIO *IO = &NW->IO; - eNextState rc; - - if (NW->IO.IOB.TotalSentAlready < NW->IO.IOB.TotalSendSize) - { - /* - * If shutting down we can exit here and unlink the temp file. - * this shouldn't loose us any messages. - */ - if (server_shutting_down) - { - FDIOBufferDelete(&NW->IO.IOB); - unlink(ChrPtr(NW->tempFileName)); - FDIOBufferDelete(&IO->IOB); - SetNWCState(IO, eNWCVSFail); - return eAbort; - } - StrBufPrintf(NW->IO.SendBuf.Buf, "READ "LOFF_T_FMT"|%ld\n", - NW->IO.IOB.TotalSentAlready, - NW->IO.IOB.TotalSendSize); - return eSendReply; - } - else - { - NW->State = eCLOS; - rc = NWC_DispatchWriteDone(&NW->IO); - - return rc; - } -} - -eNextState NWC_ReadREADState(AsyncNetworker *NW) -{ - AsyncIO *IO = &NW->IO; - if (ChrPtr(NW->IO.IOBuf)[0] == '6') - { - NW->IO.IOB.ChunkSendRemain = - NW->IO.IOB.ChunkSize = atol(ChrPtr(NW->IO.IOBuf)+4); - return eReadFile; - } - FDIOBufferDelete(&IO->IOB); - return eAbort; -} -eNextState NWC_ReadREADBlobDone(AsyncNetworker *NW); -eNextState NWC_ReadREADBlob(AsyncNetworker *NW) -{ - eNextState rc; - if (NW->IO.IOB.TotalSendSize == NW->IO.IOB.TotalSentAlready) - { - NW->State ++; - - FDIOBufferDelete(&NW->IO.IOB); - - if (link(ChrPtr(NW->tempFileName), ChrPtr(NW->SpoolFileName)) != 0) { - syslog(LOG_ERR, "netpoll: could not link %s to %s: %s", ChrPtr(NW->tempFileName), ChrPtr(NW->SpoolFileName), strerror(errno)); - } - else { - syslog(LOG_INFO, "netpoll: moved %s to %s", ChrPtr(NW->tempFileName), ChrPtr(NW->SpoolFileName)); - } - - unlink(ChrPtr(NW->tempFileName)); - rc = NWC_DispatchWriteDone(&NW->IO); - NW->State --; - return rc; - } - else { - NW->State --; - NW->IO.IOB.ChunkSendRemain = NW->IO.IOB.ChunkSize; - return eSendReply; //NWC_DispatchWriteDone(&NW->IO); - } -} - -eNextState NWC_ReadREADBlobDone(AsyncNetworker *NW) -{ - eNextState rc; -/* we don't have any data to debug print here. */ - if (NW->IO.IOB.TotalSentAlready >= NW->IO.IOB.TotalSendSize) - { - NW->State ++; - - FDIOBufferDelete(&NW->IO.IOB); - if (link(ChrPtr(NW->tempFileName), ChrPtr(NW->SpoolFileName)) != 0) { - syslog(LOG_ERR, "netpoll: could not link %s to %s: %s", ChrPtr(NW->tempFileName), ChrPtr(NW->SpoolFileName), strerror(errno)); - } - else { - syslog(LOG_INFO, "netpoll: moved %s to %s", ChrPtr(NW->tempFileName), ChrPtr(NW->SpoolFileName)); - } - - unlink(ChrPtr(NW->tempFileName)); - rc = NWC_DispatchWriteDone(&NW->IO); - NW->State --; - return rc; - } - else { - NW->State --; - NW->IO.IOB.ChunkSendRemain = NW->IO.IOB.ChunkSize; - return NWC_DispatchWriteDone(&NW->IO); - } -} -eNextState NWC_SendCLOS(AsyncNetworker *NW) -{ - AsyncIO *IO = &NW->IO; - SetNWCState(IO, eNWCVSNDOPDone); - StrBufPlain(NW->IO.SendBuf.Buf, HKEY("CLOS\n")); - return eSendReply; -} - -eNextState NWC_ReadCLOSReply(AsyncNetworker *NW) -{ - AsyncIO *IO = &NW->IO; - FDIOBufferDelete(&IO->IOB); - if (ChrPtr(NW->IO.IOBuf)[0] != '2') - return eTerminateConnection; - return eSendReply; -} - - -eNextState NWC_SendNUOP(AsyncNetworker *NW) -{ - AsyncIO *IO = &NW->IO; - eNextState rc; - long TotalSendSize; - struct stat statbuf; - int fd; - - SetNWCState(IO, eNWCVSNUOP); - StrBufPrintf(NW->SpoolFileName, - "%s/%s", - ctdl_netout_dir, - ChrPtr(NW->node)); - StrBufStripSlashes(NW->SpoolFileName, 1); - - fd = open(ChrPtr(NW->SpoolFileName), O_EXCL|O_NONBLOCK|O_RDONLY); - if (fd < 0) { - if (errno != ENOENT) { - syslog(LOG_ERR, "%s: %s", ChrPtr(NW->SpoolFileName), strerror(errno)); - } - NW->State = eQUIT; - rc = NWC_SendQUIT(NW); - return rc; - } - - if (fstat(fd, &statbuf) == -1) { - syslog(LOG_ERR, "%s: %s", ChrPtr(NW->SpoolFileName), strerror(errno)); - if (fd > 0) close(fd); - return eAbort; - } - TotalSendSize = statbuf.st_size; - if (TotalSendSize == 0) { - syslog(LOG_DEBUG, "netpoll: nothing to send."); - NW->State = eQUIT; - rc = NWC_SendQUIT(NW); - if (fd > 0) close(fd); - return rc; - } - else - { - syslog(LOG_INFO, "netpoll: sending %s to %s", ChrPtr(NW->SpoolFileName), ChrPtr(NW->node)); - } - - FDIOBufferInit(&NW->IO.IOB, &NW->IO.SendBuf, fd, TotalSendSize); - - StrBufPlain(NW->IO.SendBuf.Buf, HKEY("NUOP\n")); - return eSendReply; - -} -eNextState NWC_ReadNUOPReply(AsyncNetworker *NW) -{ - AsyncIO *IO = &NW->IO; - if (ChrPtr(NW->IO.IOBuf)[0] != '2') { - FDIOBufferDelete(&IO->IOB); - return eAbort; - } - return eSendReply; -} - -eNextState NWC_SendWRIT(AsyncNetworker *NW) -{ - StrBufPrintf(NW->IO.SendBuf.Buf, "WRIT "LOFF_T_FMT"\n", - NW->IO.IOB.TotalSendSize - NW->IO.IOB.TotalSentAlready); - return eSendReply; -} -eNextState NWC_ReadWRITReply(AsyncNetworker *NW) -{ - AsyncIO *IO = &NW->IO; - if (ChrPtr(NW->IO.IOBuf)[0] != '7') - { - FDIOBufferDelete(&IO->IOB); - return eAbort; - } - - NW->IO.IOB.ChunkSendRemain = - NW->IO.IOB.ChunkSize = atol(ChrPtr(NW->IO.IOBuf)+4); - return eSendFile; -} - -eNextState NWC_SendBlobDone(AsyncNetworker *NW) -{ - AsyncIO *IO = &NW->IO; - eNextState rc; - if (NW->IO.IOB.TotalSentAlready >= IO->IOB.TotalSendSize) - { - NW->State ++; - - FDIOBufferDelete(&IO->IOB); - rc = NWC_DispatchWriteDone(IO); - NW->State --; - return rc; - } - else { - NW->State --; - IO->IOB.ChunkSendRemain = IO->IOB.ChunkSize; - rc = NWC_DispatchWriteDone(IO); - NW->State --; - return rc; - } -} - -eNextState NWC_SendUCLS(AsyncNetworker *NW) -{ - StrBufPlain(NW->IO.SendBuf.Buf, HKEY("UCLS 1\n")); - return eSendReply; - -} -eNextState NWC_ReadUCLS(AsyncNetworker *NW) -{ - AsyncIO *IO = &NW->IO; - - syslog(LOG_INFO, "netpoll: sent %s (%ld octets) to <%s>", ChrPtr(NW->SpoolFileName), NW->IO.IOB.ChunkSize, ChrPtr(NW->node)); - - if (ChrPtr(NW->IO.IOBuf)[0] == '2') { - syslog(LOG_DEBUG, "Removing <%s>\n", ChrPtr(NW->SpoolFileName)); - unlink(ChrPtr(NW->SpoolFileName)); - } - FDIOBufferDelete(&IO->IOB); - SetNWCState(IO, eNWCVSNUOPDone); - return eSendReply; -} - -eNextState NWC_SendQUIT(AsyncNetworker *NW) -{ - StrBufPlain(NW->IO.SendBuf.Buf, HKEY("QUIT\n")); - - return eSendReply; -} - -eNextState NWC_ReadQUIT(AsyncNetworker *NW) -{ - return eAbort; -} - - -NWClientHandler NWC_ReadHandlers[] = { - NWC_ReadGreeting, - NWC_ReadAuthReply, - NWC_ReadNDOPReply, - NWC_ReadREADState, - NWC_ReadREADBlob, - NWC_ReadCLOSReply, - NWC_ReadNUOPReply, - NWC_ReadWRITReply, - NWC_SendBlobDone, - NWC_ReadUCLS, - NWC_ReadQUIT}; - -long NWC_ConnTimeout = 100; - -const long NWC_SendTimeouts[] = { - 100, - 100, - 100, - 100, - 100, - 100, - 100, - 100 -}; -const ConstStr NWC[] = { - {HKEY("Connection broken during ")}, - {HKEY("Connection broken during ")}, - {HKEY("Connection broken during ")}, - {HKEY("Connection broken during ")}, - {HKEY("Connection broken during ")}, - {HKEY("Connection broken during ")}, - {HKEY("Connection broken during ")}, - {HKEY("Connection broken during ")} -}; - -NWClientHandler NWC_SendHandlers[] = { - NULL, - NWC_SendAuth, - NWC_SendNDOP, - NWC_SendREAD, - NWC_ReadREADBlobDone, - NWC_SendCLOS, - NWC_SendNUOP, - NWC_SendWRIT, - NWC_SendBlobDone, - NWC_SendUCLS, - NWC_SendQUIT -}; - -const long NWC_ReadTimeouts[] = { - 100, - 100, - 100, - 100, - 100, - 100, - 100, - 100, - 100, - 100 -}; - - -eNextState nwc_get_one_host_ip_done(AsyncIO *IO) -{ - AsyncNetworker *NW = IO->Data; - struct hostent *hostent; - - QueryCbDone(IO); - - hostent = NW->HostLookup.VParsedDNSReply; - if ((NW->HostLookup.DNSStatus == ARES_SUCCESS) && - (hostent != NULL) ) { - memset(&NW->IO.ConnectMe->Addr, 0, sizeof(struct in6_addr)); - if (NW->IO.ConnectMe->IPv6) { - memcpy(&NW->IO.ConnectMe->Addr.sin6_addr.s6_addr, - &hostent->h_addr_list[0], - sizeof(struct in6_addr)); - - NW->IO.ConnectMe->Addr.sin6_family = hostent->h_addrtype; - NW->IO.ConnectMe->Addr.sin6_port = htons(atol(ChrPtr(NW->port)));//// TODO use the one from the URL. - } - else { - struct sockaddr_in *addr = (struct sockaddr_in*) &NW->IO.ConnectMe->Addr; - /* Bypass the ns lookup result like this: IO->Addr.sin_addr.s_addr = inet_addr("127.0.0.1"); */ -// addr->sin_addr.s_addr = htonl((uint32_t)&hostent->h_addr_list[0]); - memcpy(&addr->sin_addr.s_addr, - hostent->h_addr_list[0], - sizeof(uint32_t)); - - addr->sin_family = hostent->h_addrtype; - addr->sin_port = htons(504);/// default citadel port - } - return nwc_connect_ip(IO); } - else - return eAbort; -} - - -eNextState nwc_get_one_host_ip(AsyncIO *IO) -{ - AsyncNetworker *NW = IO->Data; - /* - * here we start with the lookup of one host. - */ - syslog(LOG_DEBUG, "netpoll: %s", __FUNCTION__); + syslog(LOG_DEBUG, "netpoll: downloaded %d of %d bytes from %s", bytes_read, bytes_total, ChrPtr(node)); - syslog(LOG_DEBUG, - "netpoll: [%ld]: looking up %s-Record %s : %d ...", - NW->n, - (NW->IO.ConnectMe->IPv6)? "aaaa": "a", - NW->IO.ConnectMe->Host, - NW->IO.ConnectMe->Port); - - QueueQuery((NW->IO.ConnectMe->IPv6)? ns_t_aaaa : ns_t_a, - NW->IO.ConnectMe->Host, - &NW->IO, - &NW->HostLookup, - nwc_get_one_host_ip_done); - IO->NextState = eReadDNSReply; - return IO->NextState; -} -/** - * @brief lineread Handler; understands when to read more POP3 lines, and when this is a one-lined reply. - */ -eReadState NWC_ReadServerStatus(AsyncIO *IO) -{ -// AsyncNetworker *NW = IO->Data; - eReadState Finished = eBufferNotEmpty; - - switch (IO->NextState) { - case eSendDNSQuery: - case eReadDNSReply: - case eDBQuery: - case eConnect: - case eTerminateConnection: - case eAbort: - Finished = eReadFail; - break; - case eSendReply: - case eSendMore: - case eReadMore: - case eReadMessage: - Finished = StrBufChunkSipLine(IO->IOBuf, &IO->RecvBuf); - break; - case eReadFile: - case eSendFile: - case eReadPayload: - break; + if (fclose(netinfp) == 0) { + sock_puts(&sock, "CLOS"); // CLOSing the download causes it to be deleted on the other node + if (sock_getln(&sock, buf, sizeof buf) < 0) { + goto bail; + } } - return Finished; -} - - -eNextState NWC_FailNetworkConnection(AsyncIO *IO) -{ - SetNWCState(IO, eNWCVSConnFail); - return EventQueueDBOperation(IO, NWC_SendFailureMessage, 1); -} - -void NWC_SetTimeout(eNextState NextTCPState, AsyncNetworker *NW) -{ - double Timeout = 0.0; - - switch (NextTCPState) { - case eSendMore: - case eSendReply: - case eReadMessage: - Timeout = NWC_ReadTimeouts[NW->State]; - break; - case eReadFile: - case eSendFile: - case eReadPayload: - Timeout = 100000; - break; - case eSendDNSQuery: - case eReadDNSReply: - case eDBQuery: - case eReadMore: - case eConnect: - case eTerminateConnection: - case eAbort: - return; - } - if (Timeout > 0) { - syslog(LOG_DEBUG, "netpoll: %s - %d %f", __FUNCTION__, NextTCPState, Timeout); - SetNextTimeout(&NW->IO, Timeout*100); - } -} - - -eNextState NWC_DispatchReadDone(AsyncIO *IO) -{ - syslog(LOG_DEBUG, "netpoll: %s", __FUNCTION__); - AsyncNetworker *NW = IO->Data; - eNextState rc; - - rc = NWC_ReadHandlers[NW->State](NW); - - if ((rc != eReadMore) && - (rc != eAbort) && - (rc != eDBQuery)) { - NW->State++; + // Now get ready to send our network data to the other node. + SpoolFileName = NewStrBuf(); + StrBufPrintf(SpoolFileName, // Outgoing packets come from the "spoolout/" directory + "%s/%s", + ctdl_netout_dir, + ChrPtr(node) + ); + FILE *netoutfp = fopen(ChrPtr(SpoolFileName), "w"); + FreeStrBuf(&SpoolFileName); + if (!netoutfp) { + goto bail; } + fclose(netoutfp); + //unlink(netoutfp); - NWC_SetTimeout(rc, NW); - - return rc; -} -eNextState NWC_DispatchWriteDone(AsyncIO *IO) -{ - syslog(LOG_DEBUG, "netpoll: %s", __FUNCTION__); - AsyncNetworker *NW = IO->Data; - eNextState rc; - - rc = NWC_SendHandlers[NW->State](NW); - NWC_SetTimeout(rc, NW); - return rc; -} - -/*****************************************************************************/ -/* Networker CLIENT ERROR CATCHERS */ -/*****************************************************************************/ -eNextState NWC_Terminate(AsyncIO *IO) -{ - syslog(LOG_DEBUG, "netpoll: %s", __FUNCTION__); - FinalizeNetworker(IO); - return eAbort; -} - -eNextState NWC_TerminateDB(AsyncIO *IO) -{ - syslog(LOG_DEBUG, "netpoll: %s", __FUNCTION__); - FinalizeNetworker(IO); - return eAbort; -} - -eNextState NWC_Timeout(AsyncIO *IO) -{ - AsyncNetworker *NW = IO->Data; - syslog(LOG_DEBUG, "netpoll: %s", __FUNCTION__); - - if (NW->IO.ErrMsg == NULL) - NW->IO.ErrMsg = NewStrBuf(); - StrBufPrintf(NW->IO.ErrMsg, "Timeout while talking to %s \r\n", ChrPtr(NW->host)); - return NWC_FailNetworkConnection(IO); -} -eNextState NWC_ConnFail(AsyncIO *IO) -{ - AsyncNetworker *NW = IO->Data; - - syslog(LOG_DEBUG, "netpoll: %s", __FUNCTION__); - if (NW->IO.ErrMsg == NULL) - NW->IO.ErrMsg = NewStrBuf(); - StrBufPrintf(NW->IO.ErrMsg, "failed to connect %s \r\n", ChrPtr(NW->host)); - - return NWC_FailNetworkConnection(IO); -} -eNextState NWC_DNSFail(AsyncIO *IO) -{ - AsyncNetworker *NW = IO->Data; - - syslog(LOG_DEBUG, "netpoll: %s", __FUNCTION__); - if (NW->IO.ErrMsg == NULL) - NW->IO.ErrMsg = NewStrBuf(); - StrBufPrintf(NW->IO.ErrMsg, "failed to look up %s \r\n", ChrPtr(NW->host)); - - return NWC_FailNetworkConnection(IO); -} -eNextState NWC_Shutdown(AsyncIO *IO) -{ - syslog(LOG_DEBUG, "netpoll: %s", __FUNCTION__); - - FinalizeNetworker(IO); - return eAbort; -} - - -eNextState nwc_connect_ip(AsyncIO *IO) -{ - AsyncNetworker *NW = IO->Data; - - SetNWCState(&NW->IO, eNWCVSConnecting); - syslog(LOG_DEBUG, "netpoll: %s", __FUNCTION__); - syslog(LOG_INFO, "netpoll: onnecting to <%s> at %s:%s", ChrPtr(NW->node), ChrPtr(NW->host), ChrPtr(NW->port)); - - return EvConnectSock(IO, - NWC_ConnTimeout, - NWC_ReadTimeouts[0], - 1); -} - -static int NetworkerCount = 0; -void RunNetworker(AsyncNetworker *NW) -{ - NW->n = NetworkerCount++; - CtdlNetworkTalkingTo(SKEY(NW->node), NTT_ADD); - syslog(LOG_DEBUG, "netpoll: NW[%s][%ld]: polling", ChrPtr(NW->node), NW->n); - ParseURL(&NW->IO.ConnectMe, NW->Url, 504); - - InitIOStruct(&NW->IO, - NW, - eReadMessage, - NWC_ReadServerStatus, - NWC_DNSFail, - NWC_DispatchWriteDone, - NWC_DispatchReadDone, - NWC_Terminate, - NWC_TerminateDB, - NWC_ConnFail, - NWC_Timeout, - NWC_Shutdown); - - safestrncpy(((CitContext *)NW->IO.CitContext)->cs_host, - ChrPtr(NW->host), - sizeof(((CitContext *)NW->IO.CitContext)->cs_host)); - - if (NW->IO.ConnectMe->IsIP) { - SetNWCState(&NW->IO, eNWCVSLookup); - QueueEventContext(&NW->IO, - nwc_connect_ip); - } - else { /* uneducated admin has chosen to add DNS to the equation... */ - SetNWCState(&NW->IO, eNWCVSConnecting); - QueueEventContext(&NW->IO, - nwc_get_one_host_ip); - } +bail: close(sock); + FreeStrBuf(&CC->SBuf.Buf); + FreeStrBuf(&CC->sMigrateBuf); } @@ -918,7 +216,6 @@ void network_poll_other_citadel_nodes(int full_poll, HashList *ignetcfg) long len; HashPos *Pos; void *vCfg; - AsyncNetworker *NW; StrBuf *SpoolFileName; int poll = 0; @@ -936,28 +233,26 @@ void network_poll_other_citadel_nodes(int full_poll, HashList *ignetcfg) while (GetNextHashPos(ignetcfg, Pos, &len, &key, &vCfg)) { /* Use the string tokenizer to grab one line at a time */ - if(server_shutting_down) - return;/* TODO free stuff*/ + if (server_shutting_down) { + return; + } CtdlNodeConf *pNode = (CtdlNodeConf*) vCfg; poll = 0; - NW = (AsyncNetworker*)malloc(sizeof(AsyncNetworker)); - memset(NW, 0, sizeof(AsyncNetworker)); - NW->node = NewStrBufDup(pNode->NodeName); - NW->host = NewStrBufDup(pNode->Host); - NW->port = NewStrBufDup(pNode->Port); - NW->secret = NewStrBufDup(pNode->Secret); + StrBuf *node = NewStrBufDup(pNode->NodeName); + StrBuf *host = NewStrBufDup(pNode->Host); + StrBuf *port = NewStrBufDup(pNode->Port); + StrBuf *secret = NewStrBufDup(pNode->Secret); - if ( (StrLength(NW->node) != 0) && - (StrLength(NW->secret) != 0) && - (StrLength(NW->host) != 0) && - (StrLength(NW->port) != 0)) - { + if ( (StrLength(node) != 0) && + (StrLength(secret) != 0) && + (StrLength(host) != 0) + ) { poll = full_poll; if (poll == 0) { StrBufAppendBufPlain(SpoolFileName, HKEY("/"), 0); - StrBufAppendBuf(SpoolFileName, NW->node, 0); + StrBufAppendBuf(SpoolFileName, node, 0); StrBufStripSlashes(SpoolFileName, 1); if (access(ChrPtr(SpoolFileName), R_OK) == 0) { @@ -965,17 +260,15 @@ void network_poll_other_citadel_nodes(int full_poll, HashList *ignetcfg) } } } - if (poll && (StrLength(NW->host) > 0) && strcmp("0.0.0.0", ChrPtr(NW->host))) - { - NW->Url = NewStrBuf(); - StrBufPrintf(NW->Url, "citadel://%s@%s:%s", ChrPtr(NW->secret), ChrPtr(NW->host), ChrPtr(NW->port)); - if (!CtdlNetworkTalkingTo(SKEY(NW->node), NTT_CHECK)) - { - RunNetworker(NW); - continue; + if (poll && (StrLength(host) > 0) && strcmp("0.0.0.0", ChrPtr(host))) { + if (!CtdlNetworkTalkingTo(SKEY(node), NTT_CHECK)) { + network_poll_node(node, host, port, secret); } } - DeleteNetworker(NW); + FreeStrBuf(&node); + FreeStrBuf(&host); + FreeStrBuf(&secret); + FreeStrBuf(&port); } FreeStrBuf(&SpoolFileName); DeleteHashPos(&Pos); diff --git a/citadel/modules/rwho/serv_rwho.c b/citadel/modules/rwho/serv_rwho.c index 5329bc70a..8967aca36 100644 --- a/citadel/modules/rwho/serv_rwho.c +++ b/citadel/modules/rwho/serv_rwho.c @@ -214,6 +214,7 @@ void cmd_rwho(char *argbuf) { cprintf("000\n"); } +#if 0 /* * check for async io jobs that are stuck (didn't ping back for 10 mins) */ @@ -276,8 +277,8 @@ void dead_io_check(void) { /* release out copy of the context list */ free(nptr); - } +#endif /* * Masquerade roomname @@ -381,7 +382,7 @@ CTDL_MODULE_INIT(rwho) CtdlRegisterProtoHook(cmd_rchg, "RCHG", "Masquerade roomname"); CtdlRegisterProtoHook(cmd_uchg, "UCHG", "Masquerade username"); CtdlRegisterProtoHook(cmd_stel, "STEL", "Enter/exit stealth mode"); - CtdlRegisterSessionHook(dead_io_check, EVT_TIMER, PRIO_QUEUE + 50); + //CtdlRegisterSessionHook(dead_io_check, EVT_TIMER, PRIO_QUEUE + 50); } diff --git a/citadel/modules/sieve/serv_sieve.c b/citadel/modules/sieve/serv_sieve.c index 40779c598..c948bc619 100644 --- a/citadel/modules/sieve/serv_sieve.c +++ b/citadel/modules/sieve/serv_sieve.c @@ -2,7 +2,7 @@ * This module glues libSieve to the Citadel server in order to implement * the Sieve mailbox filtering language (RFC 3028). * - * Copyright (c) 1987-2015 by the citadel.org team + * Copyright (c) 1987-2017 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. @@ -1174,7 +1174,7 @@ void cmd_msiv(char *argbuf) { extract_token(script_name, argbuf, 1, '|', sizeof script_name); if (!IsEmptyStr(script_name)) { cprintf("%d Transmit script now\n", SEND_LISTING); - script_content = CtdlReadMessageBody(HKEY("000"), CtdlGetConfigLong("c_maxmsglen"), NULL, 0, 0); + script_content = CtdlReadMessageBody(HKEY("000"), CtdlGetConfigLong("c_maxmsglen"), NULL, 0); msiv_putscript(&u, script_name, script_content); changes_made = 1; } diff --git a/citadel/modules/smtp/serv_smtp.c b/citadel/modules/smtp/serv_smtp.c index 756116637..d3634b046 100644 --- a/citadel/modules/smtp/serv_smtp.c +++ b/citadel/modules/smtp/serv_smtp.c @@ -847,7 +847,7 @@ void smtp_data(long offset, long flags) nowstamp); } } - body = CtdlReadMessageBodyBuf(HKEY("."), CtdlGetConfigLong("c_maxmsglen"), defbody, 1, NULL); + body = CtdlReadMessageBodyBuf(HKEY("."), CtdlGetConfigLong("c_maxmsglen"), defbody, 1); FreeStrBuf(&defbody); if (body == NULL) { cprintf("550 Unable to save message: internal error.\r\n"); diff --git a/citadel/msgbase.c b/citadel/msgbase.c index bef8137bd..bd58be4bd 100644 --- a/citadel/msgbase.c +++ b/citadel/msgbase.c @@ -13,12 +13,13 @@ */ +#include +#include #include #include +#include #include - #include "md5.h" - #include "ctdl_module.h" #include "citserver.h" #include "control.h" @@ -27,7 +28,6 @@ #include "genstamp.h" #include "room_ops.h" #include "user_ops.h" - #include "internet_addressing.h" #include "euidindex.h" #include "msgbase.h" @@ -3090,8 +3090,7 @@ StrBuf *CtdlReadMessageBodyBuf(char *terminator, /* token signalling EOT */ size_t maxlen, /* maximum message length */ StrBuf *exist, /* if non-null, append to it; exist is ALWAYS freed */ - int crlf, /* CRLF newlines instead of LF */ - int *sock /* socket handle or 0 for this session's client socket */ + int crlf /* CRLF newlines instead of LF */ ) { StrBuf *Message; @@ -3115,18 +3114,12 @@ StrBuf *CtdlReadMessageBodyBuf(char *terminator, /* token signalling EOT */ /* read in the lines of message text one by one */ do { - if (sock != NULL) { - if ((CtdlSockGetLine(sock, LineBuf, 5) < 0) || - (*sock == -1)) - finished = 1; - } - else { - if (CtdlClientGetLine(LineBuf) < 0) finished = 1; + if (CtdlClientGetLine(LineBuf) < 0) { + finished = 1; } - if ((StrLength(LineBuf) == tlen) && - (!strcmp(ChrPtr(LineBuf), terminator))) + if ((StrLength(LineBuf) == tlen) && (!strcmp(ChrPtr(LineBuf), terminator))) { finished = 1; - + } if ( (!flushing) && (!finished) ) { if (crlf) { StrBufAppendBufPlain(LineBuf, HKEY("\r\n"), 0); @@ -3154,174 +3147,6 @@ StrBuf *CtdlReadMessageBodyBuf(char *terminator, /* token signalling EOT */ return Message; } -void DeleteAsyncMsg(ReadAsyncMsg **Msg) -{ - if (*Msg == NULL) - return; - FreeStrBuf(&(*Msg)->MsgBuf); - - free(*Msg); - *Msg = NULL; -} - -ReadAsyncMsg *NewAsyncMsg(const char *terminator, /* token signalling EOT */ - long tlen, - size_t maxlen, /* maximum message length */ - size_t expectlen, /* if we expect a message, how long should it be? */ - StrBuf *exist, /* if non-null, append to it; - exist is ALWAYS freed */ - long eLen, /* length of exist */ - int crlf /* CRLF newlines instead of LF */ - ) -{ - ReadAsyncMsg *NewMsg; - - NewMsg = (ReadAsyncMsg *)malloc(sizeof(ReadAsyncMsg)); - memset(NewMsg, 0, sizeof(ReadAsyncMsg)); - - if (exist == NULL) { - long len; - - if (expectlen == 0) { - len = 4 * SIZ; - } - else { - len = expectlen + 10; - } - NewMsg->MsgBuf = NewStrBufPlain(NULL, len); - } - else { - NewMsg->MsgBuf = NewStrBufDup(exist); - } - /* Do we need to change leading ".." to "." for SMTP escaping? */ - if ((tlen == 1) && (*terminator == '.')) { - NewMsg->dodot = 1; - } - - NewMsg->terminator = terminator; - NewMsg->tlen = tlen; - - NewMsg->maxlen = maxlen; - - NewMsg->crlf = crlf; - - return NewMsg; -} - -/* - * Back end function used by CtdlMakeMessage() and similar functions - */ -eReadState CtdlReadMessageBodyAsync(AsyncIO *IO) -{ - ReadAsyncMsg *ReadMsg; - int MsgFinished = 0; - eReadState Finished = eMustReadMore; - -#ifdef BIGBAD_IODBG - char fn [SIZ]; - FILE *fd; - const char *pch = ChrPtr(IO->SendBuf.Buf); - const char *pchh = IO->SendBuf.ReadWritePointer; - long nbytes; - - if (pchh == NULL) - pchh = pch; - - nbytes = StrLength(IO->SendBuf.Buf) - (pchh - pch); - snprintf(fn, SIZ, "/tmp/foolog_ev_%s.%d", - ((CitContext*)(IO->CitContext))->ServiceName, - IO->SendBuf.fd); - - fd = fopen(fn, "a+"); - if (fd == NULL) { - syslog(LOG_ERR, "%s: %s", fn, strerror(errno)); - cit_backtrace(); - exit(1); - } -#endif - - ReadMsg = IO->ReadMsg; - - /* read in the lines of message text one by one */ - do { - Finished = StrBufChunkSipLine(IO->IOBuf, &IO->RecvBuf); - - switch (Finished) { - case eMustReadMore: /// read new from socket... -#ifdef BIGBAD_IODBG - if (IO->RecvBuf.ReadWritePointer != NULL) { - nbytes = StrLength(IO->RecvBuf.Buf) - (IO->RecvBuf.ReadWritePointer - ChrPtr(IO->RecvBuf.Buf)); - fprintf(fd, "Read; Line unfinished: %ld Bytes still in buffer [", nbytes); - - fwrite(IO->RecvBuf.ReadWritePointer, nbytes, 1, fd); - - fprintf(fd, "]\n"); - } else { - fprintf(fd, "BufferEmpty! \n"); - } - fclose(fd); -#endif - return Finished; - break; - case eBufferNotEmpty: /* shouldn't happen... */ - case eReadSuccess: /// done for now... - break; - case eReadFail: /// WHUT? - ///todo: shut down! - break; - } - - - if ((StrLength(IO->IOBuf) == ReadMsg->tlen) && - (!strcmp(ChrPtr(IO->IOBuf), ReadMsg->terminator))) { - MsgFinished = 1; -#ifdef BIGBAD_IODBG - fprintf(fd, "found Terminator; Message Size: %d\n", StrLength(ReadMsg->MsgBuf)); -#endif - } - else if (!ReadMsg->flushing) { - -#ifdef BIGBAD_IODBG - fprintf(fd, "Read Line: [%d][%s]\n", StrLength(IO->IOBuf), ChrPtr(IO->IOBuf)); -#endif - - /* Unescape SMTP-style input of two dots at the beginning of the line */ - if ((ReadMsg->dodot) && - (StrLength(IO->IOBuf) == 2) && /* TODO: do we just unescape lines with two dots or any line? */ - (!strcmp(ChrPtr(IO->IOBuf), ".."))) - { -#ifdef BIGBAD_IODBG - fprintf(fd, "UnEscaped!\n"); -#endif - StrBufCutLeft(IO->IOBuf, 1); - } - - if (ReadMsg->crlf) { - StrBufAppendBufPlain(IO->IOBuf, HKEY("\r\n"), 0); - } - else { - StrBufAppendBufPlain(IO->IOBuf, HKEY("\n"), 0); - } - - StrBufAppendBuf(ReadMsg->MsgBuf, IO->IOBuf, 0); - } - - /* if we've hit the max msg length, flush the rest */ - if (StrLength(ReadMsg->MsgBuf) >= ReadMsg->maxlen) ReadMsg->flushing = 1; - - } while (!MsgFinished); - -#ifdef BIGBAD_IODBG - fprintf(fd, "Done with reading; %s.\n, ", - (MsgFinished)?"Message Finished": "FAILED"); - fclose(fd); -#endif - if (MsgFinished) - return eReadSuccess; - else - return eReadFail; -} - /* * Back end function used by CtdlMakeMessage() and similar functions @@ -3331,8 +3156,7 @@ char *CtdlReadMessageBody(char *terminator, /* token signalling EOT */ size_t maxlen, /* maximum message length */ StrBuf *exist, /* if non-null, append to it; exist is ALWAYS freed */ - int crlf, /* CRLF newlines instead of LF */ - int *sock /* socket handle or 0 for this session's client socket */ + int crlf /* CRLF newlines instead of LF */ ) { StrBuf *Message; @@ -3341,8 +3165,8 @@ char *CtdlReadMessageBody(char *terminator, /* token signalling EOT */ tlen, maxlen, exist, - crlf, - sock); + crlf + ); if (Message == NULL) return NULL; else @@ -3522,7 +3346,7 @@ struct CtdlMessage *CtdlMakeMessageLen( } else { StrBuf *MsgBody; - MsgBody = CtdlReadMessageBodyBuf(HKEY("000"), CtdlGetConfigLong("c_maxmsglen"), NULL, 0, 0); + MsgBody = CtdlReadMessageBodyBuf(HKEY("000"), CtdlGetConfigLong("c_maxmsglen"), NULL, 0); if (MsgBody != NULL) { CM_SetAsFieldSB(msg, eMesageText, &MsgBody); } diff --git a/citadel/msgbase.h b/citadel/msgbase.h index bdd175991..ec22c2020 100644 --- a/citadel/msgbase.h +++ b/citadel/msgbase.h @@ -2,7 +2,6 @@ #ifndef MSGBASE_H #define MSGBASE_H -#include "event_client.h" enum { MSGS_ALL, MSGS_OLD, @@ -76,30 +75,12 @@ struct addresses_to_be_filed { extern struct addresses_to_be_filed *atbf; int GetFieldFromMnemonic(eMsgField *f, const char* c); - - void memfmout (char *mptr, const char *nl); void output_mime_parts(char *); long send_message (struct CtdlMessage *); void loadtroom (void); long CtdlSubmitMsg(struct CtdlMessage *, recptypes *, const char *, int); - long quickie_message(const char *from, const char *fromaddr, const char *to, char *room, const char *text, int format_type, const char *subject); - -void flood_protect_quickie_message(const char *from, - const char *fromaddr, - const char *to, - char *room, - const char *text, - int format_type, - const char *subject, - int nCriterions, - const char **CritStr, - const long *CritStrLen, - long ccid, - long ioid, - time_t NOW); - void GetMetaData(struct MetaData *, long); void PutMetaData(struct MetaData *); void AdjRefCount(long, int); @@ -152,18 +133,18 @@ void CtdlSerializeMessage(struct ser_ret *, struct CtdlMessage *); struct CtdlMessage *CtdlDeserializeMessage(long msgnum, int with_body, const char *Buffer, long Length); void ReplicationChecks(struct CtdlMessage *); int CtdlSaveMsgPointersInRoom(char *roomname, long newmsgidlist[], int num_newmsgs, - int do_repl_check, struct CtdlMessage *supplied_msg, int suppress_refcount_adj); + int do_repl_check, struct CtdlMessage *supplied_msg, int suppress_refcount_adj +); int CtdlSaveMsgPointerInRoom(char *roomname, long msgid, int do_repl_check, struct CtdlMessage *msg); long CtdlSaveThisMessage(struct CtdlMessage *msg, long msgid, int Reply); -char *CtdlReadMessageBody(char *terminator, long tlen, size_t maxlen, StrBuf *exist, int crlf, int *sock); -StrBuf *CtdlReadMessageBodyBuf(char *terminator, /* token signalling EOT */ - long tlen, - size_t maxlen, /* maximum message length */ - StrBuf *exist, /* if non-null, append to it; - exist is ALWAYS freed */ - int crlf, /* CRLF newlines instead of LF */ - int *sock /* socket handle or 0 for this session's client socket */ - ); +char *CtdlReadMessageBody(char *terminator, long tlen, size_t maxlen, StrBuf *exist, int crlf); +StrBuf *CtdlReadMessageBodyBuf( + char *terminator, /* token signalling EOT */ + long tlen, + size_t maxlen, /* maximum message length */ + StrBuf *exist, /* if non-null, append to it; exist is ALWAYS freed */ + int crlf /* CRLF newlines instead of LF */ +); int CtdlOutputMsg(long msg_num, /* message number (local) to fetch */ int mode, /* how would you like that message? */ @@ -197,9 +178,12 @@ enum { ctdlsetseen_seen, ctdlsetseen_answered }; + void CtdlSetSeen(long *target_msgnums, int num_target_msgnums, - int target_setting, int which_set, - struct ctdluser *which_user, struct ctdlroom *which_room); + int target_setting, int which_set, + struct ctdluser *which_user, struct ctdlroom *which_room +); + void CtdlGetSeen(char *buf, int which_set); @@ -239,29 +223,8 @@ struct CtdlMessage *CtdlMakeMessageLen( char *preformatted_text, /* ...or NULL to read text from client */ long textlen, char *references, /* Thread references */ - long reflen); - -/* - * loading messages async via an FD: - * add IO->ReadMsg = NewAsyncMsg(...) - * and then call CtdlReadMessageBodyAsync() from your linreader handler. - */ - -ReadAsyncMsg *NewAsyncMsg(const char *terminator, /* token signalling EOT */ - long tlen, - size_t expectlen, /* if we expect a message, how long should it be? */ - size_t maxlen, /* maximum message length */ - StrBuf *exist, /* if non-null, append to it; - exist is ALWAYS freed */ - long eLen, /* length of exist */ - int crlf /* CRLF newlines instead of LF */ - ); - -eReadState CtdlReadMessageBodyAsync(AsyncIO *IO); -void DeleteAsyncMsg(ReadAsyncMsg **Msg); - - - + long reflen +); #endif /* MSGBASE_H */ diff --git a/citadel/serv_extensions.c b/citadel/serv_extensions.c index 897f43c1b..86037aa5d 100644 --- a/citadel/serv_extensions.c +++ b/citadel/serv_extensions.c @@ -13,12 +13,13 @@ * GNU General Public License for more details. */ +#include +#include #include +#include #include - #include "sysdep_decls.h" #include "modules/crypto/serv_crypto.h" /* Needed until a universal crypto startup hook is implimented for CtdlStartTLS */ - #include "serv_extensions.h" #include "ctdl_module.h" #include "config.h" diff --git a/citadel/server_main.c b/citadel/server_main.c index 53be18071..10915b3c4 100644 --- a/citadel/server_main.c +++ b/citadel/server_main.c @@ -11,8 +11,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +#include +#include #include #include +#include #include #include #include @@ -212,23 +215,6 @@ int main(int argc, char **argv) drop_root_perms = 1; } -#if 0 - def HAVE_BACKTRACE - bzero(¶ms, sizeof(params)); - params.filename = file_pid_paniclog; - panic_fd=open(file_pid_paniclog, O_APPEND|O_CREAT|O_DIRECT); - params.filep = fopen(file_pid_paniclog, "a+"); - params.debugLevel = ECRASH_DEBUG_VERBOSE; - params.dumpAllThreads = TRUE; - params.useBacktraceSymbols = 1; - params.signals[0]=SIGSEGV; - params.signals[1]=SIGILL; - params.signals[2]=SIGBUS; - params.signals[3]=SIGABRT; - eCrash_Init(¶ms); - eCrash_RegisterThread("MasterThread", 0); -#endif - /* Tell 'em who's in da house */ syslog(LOG_NOTICE, " "); syslog(LOG_NOTICE, " "); diff --git a/citadel/sysdep.c b/citadel/sysdep.c index d913866b7..3ec7d16cc 100644 --- a/citadel/sysdep.c +++ b/citadel/sysdep.c @@ -16,14 +16,15 @@ */ #include "sysdep.h" - +#include +#include +#include #include #include #include #include #include - - +#include #include #include #include @@ -31,17 +32,13 @@ #include #include #include - #define SHOW_ME_VAPPEND_PRINTF #include - #include "citserver.h" #include "config.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 "housekeeping.h" #include "context.h" /* @@ -400,8 +397,7 @@ int client_write(const char *buf, int nbytes) cit_backtrace(); exit(1); } - fprintf(fd, "Sending: BufSize: %d BufContent: [", - nbytes); + fprintf(fd, "Sending: BufSize: %d BufContent: [", nbytes); rv = fwrite(buf, nbytes, 1, fd); fprintf(fd, "]\n"); fclose(fd); @@ -1230,8 +1226,6 @@ void *worker_thread(void *blah) { ++num_workers; pthread_mutex_unlock(&ThreadCountMutex); - pthread_setspecific(evConKey, WorkerLogStr); - while (!server_shutting_down) { /* make doubly sure we're not holding any stale db handles @@ -1314,9 +1308,6 @@ do_select: force_purge = 0; server_shutting_down = 1; continue; } else { -#if 0 - syslog(LOG_DEBUG, "Interrupted select()\n"); -#endif if (server_shutting_down) { --num_workers; return(NULL); diff --git a/citadel/threads.c b/citadel/threads.c index 5cb70334c..5773c8e3f 100644 --- a/citadel/threads.c +++ b/citadel/threads.c @@ -179,15 +179,6 @@ void go_threading(void) } /* When we get to this point we are getting ready to shut down our Citadel server */ - if (!EventQShuttingDown) - { - EventQShuttingDown = 1; - ShutDownEventQueues(); - } - while (!EVQShutDown) - usleep(1000000); - - terminate_all_sessions(); /* close all client sockets */ CtdlShutdownServiceHooks(); /* close all listener sockets to prevent new connections */ PerformSessionHooks(EVT_SHUTDOWN); /* run any registered shutdown hooks */ diff --git a/citadel/user_ops.c b/citadel/user_ops.c index e35953deb..5c3379b13 100644 --- a/citadel/user_ops.c +++ b/citadel/user_ops.c @@ -12,10 +12,12 @@ * GNU General Public License for more details. */ +#include +#include #include "sysdep.h" #include +#include #include - #include "control.h" #include "support.h" #include "citserver.h" -- 2.30.2