// Module:  Log4CPLUS
// File:    socket-unix.cxx
// Created: 4/2003
// Author:  Tad E. Smith
//
//
// Copyright (C) Tad E. Smith  All rights reserved.
//
// This software is published under the terms of the Apache Software
// License version 1.1, a copy of which has been included with this
// distribution in the LICENSE.APL file.
//
// $Log: socket-unix.cxx,v $
// Revision 1.10  2003/12/07 06:27:02  tcsmith
// 1)  Fixed Bug #831311 - "loggingserver.cxx clientsock.read()
// 2)  Fixed Bug #851074 - "build problem HPUX 11, gcc 3.3"
//
// Revision 1.9  2003/10/22 06:00:35  tcsmith
// Fixed the read() method so that it always fills the buffer.
//
// Revision 1.8  2003/09/10 07:03:19  tcsmith
// Added support for NetBSD.
//
// Revision 1.7  2003/09/05 08:10:10  tcsmith
// No longer uses MSG_NOSIGNAL when it is not defined.
//
// Revision 1.6  2003/08/27 14:58:03  tcsmith
// Made some minor changes to make the socket code more robust.
//
// Revision 1.5  2003/08/05 06:21:51  tcsmith
// Fixed FreeBSD compilation problem.
//
// Revision 1.4  2003/07/30 06:03:30  tcsmith
// Made changes to support Mac OS X builds.
//
// Revision 1.3  2003/07/19 15:30:22  tcsmith
// Changed the "errno.h" include statement for Solaris.
//
// Revision 1.2  2003/05/21 22:16:00  tcsmith
// Fixed compiler warning: "conversion from 'size_t' to 'int', possible loss
// of data".
//
// Revision 1.1  2003/05/04 07:25:16  tcsmith
// Initial version.
//

#include <log4cplus/helpers/socket.h>
#include <log4cplus/helpers/loglog.h>
#include <log4cplus/spi/loggingevent.h>

#if defined(__hpux__)
# ifndef _XOPEN_SOURCE_EXTENDED
# define _XOPEN_SOURCE_EXTENDED
# endif
# include <arpa/inet.h>
#endif
 

#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__hpux__)
#include <netinet/in.h>
#endif

#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <netdb.h>
#include <unistd.h>

#include <algorithm>

using namespace log4cplus;
using namespace log4cplus::helpers;


/////////////////////////////////////////////////////////////////////////////
// Global Methods
/////////////////////////////////////////////////////////////////////////////

SOCKET_TYPE
log4cplus::helpers::openSocket(unsigned short port, SocketState& state)
{
    SOCKET_TYPE sock = ::socket(AF_INET, SOCK_STREAM, 0);
    if(sock < 0) {
        return INVALID_SOCKET;
    }

    struct sockaddr_in server;
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = INADDR_ANY;
    server.sin_port = htons(port);

    int optval = 1;
    setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval) );

    if(bind(sock, (struct sockaddr*)&server, sizeof(server)) < 0) {
        return INVALID_SOCKET;
    }

    if(::listen(sock, 10)) {
        return INVALID_SOCKET;
    }

    state = ok;
    return sock;
}


SOCKET_TYPE
log4cplus::helpers::connectSocket(const log4cplus::tstring& hostn,
                                  unsigned short port, SocketState& state)
{
    struct sockaddr_in server;
    struct hostent *hp;
    SOCKET_TYPE sock;
    int retval;

    hp = ::gethostbyname(LOG4CPLUS_TSTRING_TO_STRING(hostn).c_str());
    if(hp == 0) {
        return INVALID_SOCKET;
    }

    sock = ::socket(AF_INET, SOCK_STREAM, 0);
    if(sock < 0) {
        return INVALID_SOCKET;
    }

    memcpy((char*)&server.sin_addr, hp->h_addr_list[0], hp->h_length);
    server.sin_port = htons(port);
    server.sin_family = AF_INET;

    while(   (retval = ::connect(sock, (struct sockaddr*)&server, sizeof(server))) == -1
          && (errno == EINTR))
        ;
    if(retval == INVALID_SOCKET) {
        ::close(sock);
        return INVALID_SOCKET;
    }

    state = ok;
    return sock;
}



SOCKET_TYPE
log4cplus::helpers::acceptSocket(SOCKET_TYPE sock, SocketState& state)
{
    struct sockaddr_in net_client;
    socklen_t len = sizeof(struct sockaddr);
    SOCKET_TYPE clientSock;
//    struct hostent *hostptr;

    while(   (clientSock = ::accept(sock, (struct sockaddr*)&net_client, &len)) == -1
          && (errno == EINTR))
        ;

//    hostptr = gethostbyaddr((char*)&(net_client.sin_addr.s_addr), 4, AF_INET);
    if(clientSock != INVALID_SOCKET) {
        state = ok;
    }

    return clientSock;
}



int
log4cplus::helpers::closeSocket(SOCKET_TYPE sock)
{
    return ::close(sock);
}



size_t
log4cplus::helpers::read(SOCKET_TYPE sock, SocketBuffer& buffer)
{
    size_t res, read = 0;
 
    do
    { 
        res = ::read(sock, buffer.getBuffer() + read, buffer.getMaxSize() - read);
        if( res <= 0 ) {
            return res;
        }
        read += res;
    } while( read < buffer.getMaxSize() );
 
    return read;
}



size_t
log4cplus::helpers::write(SOCKET_TYPE sock, const SocketBuffer& buffer)
{
#if defined(MSG_NOSIGNAL)
    int flags = MSG_NOSIGNAL;
#else
    int flags = 0;
#endif
     return ::send( sock, buffer.getBuffer(), buffer.getSize(), flags );
     // return ::write(sock, buffer.getBuffer(), buffer.getSize());
}





syntax highlighted by Code2HTML, v. 0.9.1