diff options
Diffstat (limited to 'daemon/dest_relay.c')
-rwxr-xr-x | daemon/dest_relay.c | 195 |
1 files changed, 195 insertions, 0 deletions
diff --git a/daemon/dest_relay.c b/daemon/dest_relay.c new file mode 100755 index 0000000..4bea0c6 --- /dev/null +++ b/daemon/dest_relay.c @@ -0,0 +1,195 @@ +/* + * dest_relay.c - syslogd implementation for windows, relay destination + * + * 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> + +struct dest_extra +{ + SOCKADDR_IN addr; + SOCKET sock; +}; + +/****************************************************************************** + * resolve_address + * + * Parse 'collector' parameter and init 'addr' in the dest_extra. + * Collector should contain host name or address optionally followed by colon + * and port number. + */ +static gboolean resolve_addr( struct destination* destination ) +{ + struct dest_extra *extra = destination->extra; + gboolean ret = FALSE; + char *p; + gchar *host; + struct hostent *phe; + + TRACE_ENTER( "destination=%s, collector=%s\n", + destination->name, destination->u.relay.collector ); + + memset( &extra->addr, 0, sizeof(SOCKADDR_IN) ); + extra->addr.sin_family = AF_INET; + + p = strchr( destination->u.relay.collector, ':' ); + if( p ) + host = g_strndup( destination->u.relay.collector, + p - destination->u.relay.collector ); + else + host = g_strdup( destination->u.relay.collector ); + + phe = gethostbyname( host ); + if( !phe ) + { + ERR( "Cannot resolve hostname %s for destination %s\n", + destination->u.relay.collector, destination->name ); + goto done; + } + + memcpy( &extra->addr.sin_addr.s_addr, phe->h_addr, phe->h_length ); + + if( p ) + extra->addr.sin_port = htons( (unsigned short) strtoul( p + 1, NULL, 0 ) ); + else + extra->addr.sin_port = htons( SYSLOG_PORT ); + + TRACE( "collector=%d.%d.%d.%d:%d\n", + extra->addr.sin_addr.S_un.S_un_b.s_b1, extra->addr.sin_addr.S_un.S_un_b.s_b2, + extra->addr.sin_addr.S_un.S_un_b.s_b3, extra->addr.sin_addr.S_un.S_un_b.s_b4, + ntohs( extra->addr.sin_port ) ); + + ret = TRUE; + +done: + g_free( host ); + + TRACE_LEAVE( "done; ret=%d\n", ret ); + return ret; +} + +/****************************************************************************** + * put_message_to_relay_dest + */ +static void put_message_to_relay_dest( struct destination* destination, struct message* msg ) +{ + struct dest_extra *extra = destination->extra; + char pri[16]; + gchar *buffer; + int len; + + TRACE_ENTER( "msg=%p, destination=%s\n", msg, destination->name ); + + sprintf( pri, "<%d>", LOG_MAKEPRI( msg->facility, msg->priority ) ); + if( destination->u.relay.omit_hostname ) + buffer = g_strconcat( pri, msg->timestamp, " ", msg->message, "\n", NULL ); + else + buffer = g_strconcat( pri, msg->timestamp, " ", + msg->hostname, " ", msg->message, "\n", NULL ); + + len = strlen( buffer ); + if( len > 1024 ) + { + buffer[ 1023 ] = '\n'; + buffer[ 1024 ] = '\0'; + len = 1024; + } + if( sendto( extra->sock, buffer, len, 0, + (SOCKADDR*) &extra->addr, sizeof(SOCKADDR_IN) ) == SOCKET_ERROR ) + ERR( "sendto error %lu\n", WSAGetLastError() ); + + g_free( buffer ); + + TRACE_LEAVE( "done\n" ); +} + +/****************************************************************************** + * finalize_relay_dest + * + * close socket + */ +static void finalize_relay_dest( struct destination* destination ) +{ + struct dest_extra *extra = destination->extra; + + TRACE_ENTER( "destination=%s\n", destination->name ); + if( extra->sock != INVALID_SOCKET ) + { + closesocket( extra->sock ); + } + TRACE_LEAVE( "done\n" ); +} + +/****************************************************************************** + * init_destination_relay + * + * initialize relay destination: resolve address of collector and create socket + */ +gboolean init_destination_relay( struct destination* destination ) +{ + struct dest_extra *extra; + int n; + + TRACE_ENTER( "destination=%s\n", destination->name ); + + extra = g_malloc( sizeof(struct dest_extra) ); + destination->extra = extra; + destination->put = put_message_to_relay_dest; + destination->fini = finalize_relay_dest; + extra->sock = INVALID_SOCKET; + + if( !resolve_addr( destination ) ) + goto error; + + for( n = 0;; n++ ) + { + SOCKADDR_IN sa_local; + + extra->sock = socket( AF_INET, SOCK_DGRAM, 0 ); + if( INVALID_SOCKET == extra->sock ) + { + ERR( "Cannot create socket\n" ); + goto error; + } + + memset( &sa_local, 0, sizeof(SOCKADDR_IN) ); + sa_local.sin_family = AF_INET; + if( bind( extra->sock, (SOCKADDR*) &sa_local, sizeof(SOCKADDR_IN) ) == 0 ) + break; + closesocket( extra->sock ); + extra->sock = INVALID_SOCKET; + if( n == 100 ) + { + ERR( "Cannot bind socket\n" ); + goto error; + } + Sleep(0); + } + TRACE_LEAVE( "ok\n" ); + return TRUE; + +error: + if( extra->sock != INVALID_SOCKET ) + closesocket( extra->sock ); + g_free( destination->extra ); + TRACE_LEAVE( "error\n" ); + return FALSE; +} |