aboutsummaryrefslogblamecommitdiffstats
path: root/daemon/dest_relay.c
blob: 4bea0c6f48ba0ffb33f2b8db4a5b814ee333d85f (plain) (tree)


































































































































































































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