aboutsummaryrefslogtreecommitdiffstats
path: root/daemon/listener.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--daemon/listener.c335
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" );
+}