/* * 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 #include #include #include #include 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; struct string *pri; gchar *buffer; int len; TRACE_ENTER( "msg=%p, destination=%s\n", msg, destination->name ); pri = string_printf( "<%d>", LOG_MAKEPRI( msg->facility, msg->priority ) ); if( destination->u.relay.omit_hostname ) len = string_concat( &buffer, pri, msg->timestamp, msg->separator, msg->message, msg->end_of_line, NULL ); else len = string_concat( &buffer, pri, msg->timestamp, msg->separator, msg->hostname, msg->separator, msg->message, msg->end_of_line, NULL ); string_release( pri ); 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; }