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
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 \
* GNU General Public License for more details.
*/
+#include <stdlib.h>
+#include <unistd.h>
#include <stdio.h>
+#include <sys/stat.h>
#include "sysdep.h"
#include <time.h>
#if HAVE_BACKTRACE
* 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"
* GNU General Public License for more details.
*/
+#include <stdlib.h>
+#include <unistd.h>
+#include <netdb.h>
#include <stdio.h>
#include <libcitadel.h>
#include "ctdl_module.h"
* 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);
}
}
-int CtdlSockGetLine(int *sock, StrBuf * Target, int nSec)
+int CtdlSockGetLine(int *sock, StrBuf *Target, int nSec)
{
CitContext *CCC = MyContext();
const char *Error;
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)
{
}
-
/*
* 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)
{
return i;
}
+
/*
* Multiline version of sock_gets() ... this is a convenience function for
* client side protocol implementations. It only returns the first line of
*/
#include "sysdep.h"
+#include <stdlib.h>
+#include <unistd.h>
#include <stdio.h>
+#include <netdb.h>
#include <sys/utsname.h>
#include <libcitadel.h>
#include <assert.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 <math.h>
-#include <ev.h>],
- [
- 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"
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) {
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);
}
}
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);
+ }
}
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++;
}
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);
}
}
{
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.
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.
*/
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);
}
free(con->cached_msglist);
}
- syslog(LOG_DEBUG, "Done with RemoveContext()");
+ syslog(LOG_DEBUG, "context: done with RemoveContext()");
}
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));
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));
/*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 {
}
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 */
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);
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;
* 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;
*/
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) {
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;
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;
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);
}
/*****************************************************************************/
#include "sysdep.h"
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/stat.h>
#include <stdio.h>
#include <dirent.h>
#include <zlib.h>
#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) */
+++ /dev/null
-/*
- * 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 <stdio.h>
-#include <string.h>
-#include <syslog.h>
-#include <assert.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#if HAVE_BACKTRACE
-#include <execinfo.h>
-#endif
-
-#include <libcitadel.h>
-
-#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);
-}
+++ /dev/null
-/*
- *
- * 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 <ev.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netdb.h>
-#include <arpa/nameser.h>
-#include <ares.h>
-#include <curl/curl.h>
-
-#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 <curl/curl.h>
-
-#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__ */
{
for (i=0; i<nContexts; i++)
{
- if ((nptr[i].state != CON_SYS) || (nptr[i].IO == NULL) || (nptr[i].lastcmd == 0))
+ if ((nptr[i].state != CON_SYS) || (nptr[i].lastcmd == 0))
continue;
ActiveBackgroundJobs ++;
syslog(LOG_INFO, "jousekeeping: job CC[%d] active; use TERM if you don't want to wait for it", nptr[i].cs_pid);
+++ /dev/null
-/*
- * 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.
- *
- * Inspired by NodeJS.org; thanks for the MX-Parser ;-)
- */
-
-#include "sysdep.h"
-#include <stdlib.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <termios.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <pwd.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <syslog.h>
-
-#if TIME_WITH_SYS_TIME
-# include <sys/time.h>
-# include <time.h>
-#else
-# if HAVE_SYS_TIME_H
-# include <sys/time.h>
-# else
-# include <time.h>
-# endif
-#endif
-#include <sys/wait.h>
-#include <ctype.h>
-#include <string.h>
-#include <limits.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-#include <libcitadel.h>
-#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";
-}
}
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;
}
* GNU General Public License for more details.
*/
+#include <stdlib.h>
+#include <unistd.h>
#include <stdio.h>
+#include <netdb.h>
#include <libcitadel.h>
#include <dirent.h>
-
+#include <sys/types.h>
+#include <sys/stat.h>
#include "ctdl_module.h"
#include "citserver.h"
#include "support.h"
* GNU General Public License for more details.
*/
+#include <stdlib.h>
+#include <unistd.h>
#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
#include <dirent.h> /* for cmd_rdir to read contents of the directory */
#include <libcitadel.h>
+++ /dev/null
-/*
- * 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 <stdlib.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <fcntl.h>
-#include <ctype.h>
-#include <pwd.h>
-#include <errno.h>
-#include <sys/types.h>
-
-#if TIME_WITH_SYS_TIME
-# include <sys/time.h>
-# include <time.h>
-#else
-# if HAVE_SYS_TIME_H
-# include <sys/time.h>
-# else
-# include <time.h>
-# endif
-#endif
-
-#include <sys/wait.h>
-#include <string.h>
-#include <limits.h>
-#include <libcitadel.h>
-#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 <dspam/libdspam.h>
-//#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");/* <which database backend do we prefer? */
-
-}
-
-void dspam_do_msg(long msgnum, void *userdata)
-{
- char *msgtext;
- DSPAM_CTX *CTX; /* DSPAM Context */
- struct CtdlMessage *msg;
- struct _ds_spam_signature SIG; /* signature */
-
- CTX = *(DSPAM_CTX**) userdata;
- msg = CtdlFetchMessage(msgnum, 0);
- if (msg == NULL) return;
-
-
- /* Message */
- CC->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";
-}
-
+++ /dev/null
-/*
- * 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 <stdlib.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <termios.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <pwd.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <syslog.h>
-
-#if TIME_WITH_SYS_TIME
-# include <sys/time.h>
-# include <time.h>
-#else
-# if HAVE_SYS_TIME_H
-# include <sys/time.h>
-# else
-# include <time.h>
-# endif
-#endif
-#include <sys/wait.h>
-#include <ctype.h>
-#include <string.h>
-#include <limits.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <assert.h>
-#include <arpa/inet.h>
-#include <libcitadel.h>
-#include <curl/curl.h>
-#include <curl/multi.h>
-#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";
-}
+++ /dev/null
-/*
- * File: extnotify.h
- * Author: Mathew McBride <matt@mcbridematt.dhs.org> / <matt@comalies>
- * 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);
+++ /dev/null
-/*
- * 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: <matt@mcbridematt.dhs.org> / <matt@comalies>
- *
- * 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 <stdlib.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <pwd.h>
-#include <errno.h>
-#include <sys/types.h>
-
-#if TIME_WITH_SYS_TIME
-# include <sys/time.h>
-# include <time.h>
-#else
-# if HAVE_SYS_TIME_H
-# include <sys/time.h>
-# else
-# include <time.h>
-# endif
-#endif
-
-#include <sys/wait.h>
-#include <string.h>
-#include <limits.h>
-#include <sys/socket.h>
-#include <libcitadel.h>
-#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; notify<Ctx->nNotifyHosts; 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 <K>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";
-}
+++ /dev/null
-/*
- * 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: <matt@mcbridematt.dhs.org> / <matt@comalies>
- *
- * 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 <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <sys/socket.h>
-#include <time.h>
-#include <libcitadel.h>
-#include <errno.h>
-#include <unistd.h>
-#include <curl/curl.h>
-
-#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;
-}
/* 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 {
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;
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;
}
-
/*
* It's ok if these directories already exist. Just fail silently.
*/
/*
- * 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
*
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);
}
long len;
HashPos *Pos;
void *vCfg;
- AsyncNetworker *NW;
StrBuf *SpoolFileName;
int poll = 0;
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) {
}
}
}
- 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);
cprintf("000\n");
}
+#if 0
/*
* check for async io jobs that are stuck (didn't ping back for 10 mins)
*/
/* release out copy of the context list */
free(nptr);
-
}
+#endif
/*
* Masquerade roomname
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);
}
* 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.
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;
}
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");
*/
+#include <stdlib.h>
+#include <unistd.h>
#include <stdio.h>
#include <regex.h>
+#include <sys/stat.h>
#include <libcitadel.h>
-
#include "md5.h"
-
#include "ctdl_module.h"
#include "citserver.h"
#include "control.h"
#include "genstamp.h"
#include "room_ops.h"
#include "user_ops.h"
-
#include "internet_addressing.h"
#include "euidindex.h"
#include "msgbase.h"
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;
/* 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);
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
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;
tlen,
maxlen,
exist,
- crlf,
- sock);
+ crlf
+ );
if (Message == NULL)
return NULL;
else
}
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);
}
#ifndef MSGBASE_H
#define MSGBASE_H
-#include "event_client.h"
enum {
MSGS_ALL,
MSGS_OLD,
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);
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? */
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);
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 */
* GNU General Public License for more details.
*/
+#include <stdlib.h>
+#include <unistd.h>
#include <stdio.h>
+#include <sys/stat.h>
#include <libcitadel.h>
-
#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"
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
+#include <stdlib.h>
+#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
+#include <sys/stat.h>
#include <grp.h>
#include <sys/file.h>
#include <libcitadel.h>
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, " ");
*/
#include "sysdep.h"
-
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/stat.h>
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <syslog.h>
#include <sys/syslog.h>
-
-
+#include <netdb.h>
#include <sys/un.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
-
#define SHOW_ME_VAPPEND_PRINTF
#include <libcitadel.h>
-
#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"
/*
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);
++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
server_shutting_down = 1;
continue;
} else {
-#if 0
- syslog(LOG_DEBUG, "Interrupted select()\n");
-#endif
if (server_shutting_down) {
--num_workers;
return(NULL);
}
/* 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 */
* GNU General Public License for more details.
*/
+#include <stdlib.h>
+#include <unistd.h>
#include "sysdep.h"
#include <stdio.h>
+#include <sys/stat.h>
#include <libcitadel.h>
-
#include "control.h"
#include "support.h"
#include "citserver.h"