/*
* 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;
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;
}