diff options
author | yaworsky <yaworsky> | 2005-09-16 08:33:41 +0000 |
---|---|---|
committer | yaworsky <yaworsky> | 2005-09-16 08:33:41 +0000 |
commit | a2c534419863b2c09fd122d8d1ef6769398f7cf0 (patch) | |
tree | c58907db78a04c9d4fae9999651e1a7293cf38f1 /daemon/listener.c | |
parent | 7875bee3ddfd14f2128540609519306742a78dec (diff) | |
download | syslog-win32-a2c534419863b2c09fd122d8d1ef6769398f7cf0.tar.gz syslog-win32-a2c534419863b2c09fd122d8d1ef6769398f7cf0.tar.xz syslog-win32-a2c534419863b2c09fd122d8d1ef6769398f7cf0.zip |
Added to repository.
Diffstat (limited to 'daemon/listener.c')
-rw-r--r-- | daemon/listener.c | 335 |
1 files changed, 335 insertions, 0 deletions
diff --git a/daemon/listener.c b/daemon/listener.c new file mode 100644 index 0000000..32c6297 --- /dev/null +++ b/daemon/listener.c @@ -0,0 +1,335 @@ +/* + * listener.c - syslogd implementation for windows, listener for UDP + * and "internal" sources + * + * Created by Alexander Yaworsky + * + * THIS SOFTWARE IS NOT COPYRIGHTED + * + * This source code is offered for use in the public domain. You may + * use, modify or distribute it freely. + * + * This code is distributed in the hope that it will be useful but + * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY + * DISCLAIMED. This includes but is not limited to warranties of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + */ + +#include <stdio.h> +#include <winsock2.h> + +#include <glib.h> + +#include <syslog.h> +#include <syslogd.h> + +static SOCKET *socket_array = NULL; +static int socket_count = 0; + +static struct source **source_references = NULL; + +static HANDLE *event_array = NULL; +static int event_count = 0; + +/* message data */ +static unsigned max_datagram_size = 1024; +static gchar *datagram_buffer = NULL; +static struct raw_message message; + +static CRITICAL_SECTION cs_internal_message; +static HANDLE internal_message_accepted = NULL; +static gchar internal_message_buffer[ 1024 ]; + +/****************************************************************************** + * init_listener + * + * create sockets and synchronization objects including ones for "internal" + * source + */ +gboolean init_listener() +{ + gboolean ret = FALSE; + unsigned n; + GList *item; + int i; + struct source *internal_src; + + TRACE_ENTER( "\n" ); + + /* create critical section and event for the access serialization to internal message buffer + */ + InitializeCriticalSection( &cs_internal_message ); + internal_message_accepted = CreateEvent( NULL, FALSE, FALSE, NULL ); + if( !internal_message_accepted ) + { + ERR( "Cannot create event; error %lu\n", GetLastError() ); + goto done; + } + + /* allocate memory for sockets and events; + * the number of sockets is not greater than number of sources + */ + n = g_list_length( sources ); + socket_array = g_malloc( n * sizeof(SOCKET) ); + + /* number of source references is greater by one because of inclusion the event + * for "internal" source + * FIXME: how about multiple internal sources? + */ + source_references = g_malloc( (n + 1) * sizeof(struct source*) ); + + /* number of events is greater by two because of inclusion the event + * for "internal" source and the service_stop_event + */ + event_array = g_malloc( (n + 2) * sizeof(HANDLE) ); + + /* create sockets */ + for( item = sources; item; item = item->next ) + { + struct source *src = item->data; + SOCKET sock; + unsigned dgram_size; + int size; + + if( src->type == ST_INTERNAL ) + { + internal_src = src; + continue; + } + + if( src->type != ST_UDP ) + continue; + + sock = socket( AF_INET, SOCK_DGRAM, 0 ); + if( INVALID_SOCKET == sock ) + { + ERR( "socket() error %lu\n", WSAGetLastError() ); + goto done; + } + + if( bind( sock, (struct sockaddr*) &src->udp, sizeof(src->udp) ) ) + { + ERR( "bind() error %lu\n", WSAGetLastError() ); + closesocket( sock ); + goto done; + } + + size = sizeof(dgram_size); + if( getsockopt( sock, SOL_SOCKET, SO_MAX_MSG_SIZE, (char*) &dgram_size, &size ) ) + { + ERR( "getsockopt( SO_MAX_MSG_SIZE ) error %lu\n", WSAGetLastError() ); + closesocket( sock ); + goto done; + } + TRACE( "datagram size for %d.%d.%d.%d:%d is %u\n", + src->udp.sin_addr.S_un.S_un_b.s_b1, src->udp.sin_addr.S_un.S_un_b.s_b2, + src->udp.sin_addr.S_un.S_un_b.s_b3, src->udp.sin_addr.S_un.S_un_b.s_b4, + ntohs( src->udp.sin_port ), dgram_size ); + if( dgram_size > max_datagram_size ) + max_datagram_size = dgram_size; + + source_references[ socket_count ] = src; + socket_array[ socket_count++ ] = sock; + } + source_references[ socket_count ] = internal_src; + + /* create events; + * service_stop_event is added to the array + */ + while( event_count <= socket_count ) + { + HANDLE evt = CreateEvent( NULL, FALSE, FALSE, NULL ); + if( !evt ) + { + ERR( "Cannot create event; error %lu\n", GetLastError() ); + goto done; + } + event_array[ event_count++ ] = evt; + } + event_array[ event_count++ ] = service_stop_event; + + /* bind events to sockets */ + for( i = 0; i < socket_count; i++ ) + { + if( WSAEventSelect( socket_array[ i ], event_array[ i ], FD_READ ) ) + { + ERR( "WSAEventSelect() error %lu\n", WSAGetLastError() ); + goto done; + } + } + + /* allocate datagram buffer */ + datagram_buffer = g_malloc( max_datagram_size ); + + ret = TRUE; + +done: + if( !ret ) + fini_listener(); + + TRACE_LEAVE( "done; socket_count=%d, event_count=%d, max_datagram_size=%d, ret=%d\n", + socket_count, event_count, max_datagram_size, (int) ret ); + return ret; +} + +/****************************************************************************** + * fini_listener + */ +void fini_listener() +{ + int i; + + TRACE_ENTER( "\n" ); + + for( i = 0; i < socket_count; i++ ) + closesocket( socket_array[ i ] ); + g_free( socket_array ); + socket_array = NULL; + socket_count = 0; + + g_free( source_references ); + source_references = NULL; + + /* note that the last event is the service_stop_event + * and should not be destroyed + */ + for( i = 0; i < event_count - 1; i++ ) + CloseHandle( event_array[ i ] ); + g_free( event_array ); + event_array = NULL; + event_count = 0; + + g_free( datagram_buffer ); + datagram_buffer = NULL; + + if( internal_message_accepted ) + { + CloseHandle( internal_message_accepted ); + internal_message_accepted = NULL; + } + DeleteCriticalSection( &cs_internal_message ); + TRACE_LEAVE( "done\n" ); +} + +/****************************************************************************** + * listener + * + * wait for a message; generate mark message; + * allocates a new raw_message structure and assigns its pointer to *msg + */ +enum listener_status listener( struct raw_message** msg ) +{ + enum listener_status ret = LSNR_ERROR; + DWORD t, w; + int r; + int addrlen; + + TRACE_ENTER( "\n" ); + + for(;;) + { + if( !mark_interval ) + t = INFINITE; + else + t = mark_interval * 1000; + w = WaitForMultipleObjects( event_count, event_array, FALSE, t ); + if( WAIT_TIMEOUT == w ) + { + /* issue mark message */ + log_internal( LOG_NOTICE, "%s", mark_message ); + continue; + } + if( WAIT_FAILED == w ) + { + ERR( "Wait error %lu\n", GetLastError() ); + goto done; + } + if( w >= event_count ) + { + ERR( "Unknown wait error\n" ); + goto done; + } + if( w == event_count - 1 ) + { + /* shut down */ + ret = LSNR_SHUTDOWN; + goto done; + } + if( w == event_count - 2 ) + { + /* got "internal" message */ + message.source = source_references[ socket_count ]; + if( !message.source ) + { + /* internal source is not defined, cannot handle message */ + SetEvent( internal_message_accepted ); + continue; + } + message.msg = g_strdup( internal_message_buffer ); + SetEvent( internal_message_accepted ); + memset( &message.sender_addr, 0, sizeof(message.sender_addr) ); + goto alloc_msg; + } + /* got UDP message, read it */ + addrlen = sizeof(message.sender_addr); + r = recvfrom( socket_array[ w ], datagram_buffer, max_datagram_size, + 0, (struct sockaddr*) &message.sender_addr, &addrlen ); + if( r < 0 ) + { + ERR( "recvfrom() error %lu\n", WSAGetLastError() ); + goto done; + } + if( !r ) + continue; + + message.msg = g_strndup( datagram_buffer, r ); + message.source = source_references[ w ]; + + alloc_msg: + *msg = g_malloc( sizeof(struct raw_message) ); + memcpy( *msg, &message, sizeof(struct raw_message) ); + + ret = LSNR_GOT_MESSAGE; + goto done; + } + +done: + TRACE_LEAVE( "done; ret=%d\n", (int) ret ); + return ret; +} + +/****************************************************************************** + * log_internal + * + * generate internal log message + */ +void log_internal( int pri, char* fmt, ... ) +{ + va_list args; + SYSTEMTIME stm; + int len; + char *p; + + TRACE_ENTER( "\n" ); + EnterCriticalSection( &cs_internal_message ); + + GetLocalTime( &stm ); + len = sprintf( internal_message_buffer, "<%d>%s %2d %02d:%02d:%02d %s syslog: ", + LOG_SYSLOG | pri, + str_month[ stm.wMonth - 1 ], stm.wDay, stm.wHour, stm.wMinute, stm.wSecond, + local_hostname ); + va_start( args, fmt ); + vsnprintf( internal_message_buffer + len, sizeof(internal_message_buffer) - len, fmt, args ); + va_end( args ); + p = strchr( internal_message_buffer, '\n' ); + if( p ) + *p = 0; + p = strchr( internal_message_buffer, '\r' ); + if( p ) + *p = 0; + + SetEvent( event_array[ event_count - 2 ] ); + LeaveCriticalSection( &cs_internal_message ); + TRACE_LEAVE( "done\n" ); +} |