SSLproxy/logger.c

238 lines
5.6 KiB
C
Raw Normal View History

2012-04-13 12:47:30 +00:00
/*
* SSLsplit - transparent and scalable SSL/TLS interception
2013-04-24 18:36:38 +00:00
* Copyright (c) 2009-2013, Daniel Roethlisberger <daniel@roe.ch>
2012-04-13 12:47:30 +00:00
* All rights reserved.
* http://www.roe.ch/SSLsplit
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice unmodified, this list of conditions, and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "logger.h"
#include "thrqueue.h"
#include "logbuf.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
/*
* Logger for multithreaded environments. Disk writes are executed in a
* writer thread. Logging threads submit buffers to be logged by adding
* them to the thrqueue. Logging threads may block on the pthread mutex
* of the thrqueue, but not on disk writes.
*/
struct logger {
pthread_t thr;
logger_write_func_t write;
thrqueue_t *queue;
};
static void
logger_clear(logger_t *logger)
{
memset(logger, 0, sizeof(logger_t));
}
/*
* Create new logger with a specific write function callback.
* The callback will be executed in the logger's writer thread,
* not in the thread calling logger_submit().
*/
logger_t *
logger_new(logger_write_func_t writefunc)
{
logger_t *logger;
logger = malloc(sizeof(logger_t));
if (!logger)
return NULL;
logger_clear(logger);
logger->write = writefunc;
logger->queue = NULL;
2012-04-13 12:47:30 +00:00
return logger;
}
/*
* Free the logger data structures. Caller must call logger_stop()
* or logger_leave() and logger_join() prior to freeing.
*/
void
logger_free(logger_t *logger) {
if (logger->queue) {
thrqueue_free(logger->queue);
}
2012-04-13 12:47:30 +00:00
free(logger);
}
/*
* Submit a buffer to be logged by the logger thread.
* Buffer will be freed after logging completes.
* Returns -1 on error, 0 on success.
*/
int
logger_submit(logger_t *logger, logbuf_t *lb)
{
return thrqueue_enqueue(logger->queue, lb) ? 0 : -1;
2012-04-13 12:47:30 +00:00
}
/*
* Logger thread main function.
*/
static void *
logger_thread(void *arg)
{
logger_t *logger = arg;
logbuf_t *lb;
while ((lb = thrqueue_dequeue(logger->queue))) {
logbuf_write_free(lb, logger->write);
}
return NULL;
}
/*
* Start the logger's write thread.
*/
int
logger_start(logger_t *logger) {
int rv;
if (logger->queue) {
thrqueue_free(logger->queue);
}
logger->queue = thrqueue_new(1024);
2012-04-13 12:47:30 +00:00
rv = pthread_create(&logger->thr, NULL, logger_thread, logger);
if (rv)
return -1;
sched_yield();
2012-04-13 12:47:30 +00:00
return 0;
}
/*
* Tell the logger's write thread to write all pending write requests
* and then exit. Don't wait for the logger to exit.
*/
void
logger_leave(logger_t *logger) {
thrqueue_unblock_dequeue(logger->queue);
sched_yield();
2012-04-13 12:47:30 +00:00
}
/*
* Wait for the logger to exit.
*/
int
logger_join(logger_t *logger) {
int rv;
rv = pthread_join(logger->thr, NULL);
if (rv)
return -1;
return 0;
}
/*
* Tell the logger's write thread to write all pending write requests
* and then exit; wait for the logger to exit.
*/
int
logger_stop(logger_t *logger) {
logger_leave(logger);
return logger_join(logger);
}
/*
* Generic print to a logger. These functions should be called by the
* actual worker thread(s) doing network I/O.
*
* _printf(), _print() and _write() copy the input buffers.
* _ncprint() and _ncwrite() will free() the input buffers.
*
* The file descriptor argument is a virtual or real system file descriptor
* used for multiplexing write requests to several files over the same
* logger. This argument is passed to the write handler as-is and is not
* interpreted or used by the logger itself in any way.
*
* All of the functions return 0 on succes, -1 on failure.
*/
int
logger_printf(logger_t *logger, int fd, const char *fmt, ...)
{
va_list ap;
logbuf_t *lb;
lb = logbuf_new(NULL, 0, fd, NULL);
if (!lb)
return -1;
va_start(ap, fmt);
lb->sz = vasprintf((char**)&lb->buf, fmt, ap);
va_end(ap);
if (lb->sz == -1) {
logbuf_free(lb);
return -1;
}
return logger_submit(logger, lb);
}
int
logger_write(logger_t *logger, int fd, const void *buf, size_t sz)
{
logbuf_t *lb;
if (!(lb = logbuf_new_copy(buf, sz, fd, NULL)))
return -1;
return logger_submit(logger, lb);
}
int
logger_print(logger_t *logger, int fd, const char *s)
{
logbuf_t *lb;
if (!(lb = logbuf_new_copy(s, strlen(s), fd, NULL)))
return -1;
return logger_submit(logger, lb);
}
int
logger_write_freebuf(logger_t *logger, int fd, void *buf, size_t sz)
{
logbuf_t *lb;
if (!(lb = logbuf_new(buf, sz, fd, NULL)))
return -1;
return logger_submit(logger, lb);
}
int
logger_print_freebuf(logger_t *logger, int fd, char *s)
{
logbuf_t *lb;
if (!(lb = logbuf_new(s, strlen(s), fd, NULL)))
return -1;
return logger_submit(logger, lb);
}
/* vim: set noet ft=c: */