#endif
#include "citadel.h"
#include "server.h"
-#include "dynloader.h"
+#include "serv_extensions.h"
#include "sysdep_decls.h"
#include "citserver.h"
#include "support.h"
char buf[SIZ];
va_start(arg_ptr, format);
- vsprintf(buf, format, arg_ptr);
+ vsnprintf(buf, sizeof(buf), format, arg_ptr);
va_end(arg_ptr);
if (loglevel <= verbosity) {
struct timeval tv;
struct tm *tim;
+ time_t unixtime;
gettimeofday(&tv, NULL);
- tim = localtime(&(tv.tv_sec));
+ /* Promote to time_t; types differ on some OSes (like darwin) */
+ unixtime = tv.tv_sec;
+ tim = localtime(&unixtime);
/*
* Log provides millisecond accuracy. If you need
* microsecond accuracy and your OS supports it, change
* %03ld to %06ld and remove " / 1000" after tv.tv_usec.
*/
- if (CC) {
+ if (CC && CC->cs_pid) {
fprintf(stderr,
"%04d/%02d/%02d %2d:%02d:%02d.%03ld [%3d] %s",
tim->tm_year + 1900, tim->tm_mon + 1,
* Return a pointer to the CitContext structure bound to the thread which
* called this function. If there's no such binding (for example, if it's
* called by the housekeeper thread) then a generic 'master' CC is returned.
+ *
+ * It's inlined because it's used *VERY* frequently.
*/
-struct CitContext *MyContext(void) {
- struct CitContext *retCC;
- retCC = (struct CitContext *) pthread_getspecific(MyConKey);
- if (retCC == NULL) retCC = &masterCC;
- return(retCC);
+INLINE struct CitContext *MyContext(void) {
+ return ((pthread_getspecific(MyConKey) == NULL)
+ ? &masterCC
+ : (struct CitContext *) pthread_getspecific(MyConKey)
+ );
}
}
+/*
+ * buffer_output() ... tell client_write to buffer all output until
+ * instructed to dump it all out later
+ */
+void buffer_output(void) {
+ if (CC->buffering == 0) {
+ CC->buffering = 1;
+ CC->buffer_len = 0;
+ CC->output_buffer = mallok(SIZ);
+ }
+}
+
+/*
+ * unbuffer_output() ... dump out all that output we've been buffering.
+ */
+void unbuffer_output(void) {
+ if (CC->buffering == 1) {
+ CC->buffering = 0;
+ client_write(CC->output_buffer, CC->buffer_len);
+ phree(CC->output_buffer);
+ CC->output_buffer = NULL;
+ CC->buffer_len = 0;
+ }
+}
+
+
+
/*
* client_write() ... Send binary data to the client.
*/
int bytes_written = 0;
int retval;
int sock;
+ int old_buffer_len = 0;
if (CC->redirect_fp != NULL) {
fwrite(buf, nbytes, 1, CC->redirect_fp);
sock = CC->client_socket;
}
+ /* If we're buffering for later, do that now. */
+ if (CC->buffering) {
+ old_buffer_len = CC->buffer_len;
+ CC->buffer_len += nbytes;
+ CC->output_buffer = reallok(CC->output_buffer, CC->buffer_len);
+ memcpy(&CC->output_buffer[old_buffer_len], buf, nbytes);
+ return;
+ }
+
+ /* Ok, at this point we're not buffering. Go ahead and write. */
+
#ifdef HAVE_OPENSSL
if (CC->redirect_ssl) {
client_write_ssl(buf, nbytes);
* (This is implemented in terms of client_read_to() and could be
* justifiably moved out of sysdep.c)
*/
-inline int client_read(char *buf, int bytes)
+INLINE int client_read(char *buf, int bytes)
{
return(client_read_to(buf, bytes, config.c_sleeping));
}
*/
void create_worker(void) {
int ret;
- struct worker_node *n = mallok(sizeof *n);
+ struct worker_node *n;
pthread_attr_t attr;
+ n = mallok(sizeof(struct worker_node));
if (n == NULL) {
lprintf(1, "can't allocate worker_node, exiting\n");
time_to_die = -1;
return;
}
- /* we seem to need something bigger than
- FreeBSD's default of 64K of stack. */
+ /* we seem to need something bigger than FreeBSD's default 64k stack */
if ((ret = pthread_attr_setstacksize(&attr, 128 * 1024))) {
lprintf(1, "pthread_attr_setstacksize: %s\n", strerror(ret));
int retval;
struct CitContext *con= NULL; /* Temporary context pointer */
struct ServiceFunctionHook *serviceptr;
- struct sockaddr_in fsin; /* Data for master socket */
- int alen; /* Data for master socket */
int ssock; /* Descriptor for client socket */
struct timeval tv;
/*
* A naive implementation would have all idle threads
- * calling select() and then they'd all wake up at once. We
- * solve this problem by putting the select() in a critical
- * section, so only one thread has the opportunity to wake
- * up. If we wake up on a master socket, create a new
- * session context; otherwise, just bind the thread to the
- * context we want and go on our merry way.
+ * calling select() and then they'd all wake up at once
+ * (known in computer science as the "thundering herd"
+ * problem). We solve this problem by putting the select()
+ * in a critical section, so only one thread has the
+ * opportunity to wake up. If we wake up on a master
+ * socket, create a new session context; otherwise, just
+ * bind the thread to the context we want and go on our
+ * merry way.
*/
/* make doubly sure we're not holding any stale db handles
serviceptr = serviceptr->next ) {
if (FD_ISSET(serviceptr->msock, &readfds)) {
- alen = sizeof fsin;
- ssock = accept(serviceptr->msock,
- (struct sockaddr *)&fsin, &alen);
+ ssock = accept(serviceptr->msock, NULL, 0);
if (ssock < 0) {
lprintf(2, "citserver: accept(): %s\n",
strerror(errno));