#include "drwebdc-demo.h"

/*--------------------------------------------------------------------------
 Dr. Web daemon client demo (tools & data)
                                       ID Antivirus Lab http://www.drweb.ru 
                                             http://www.drweb.ru/unix/forum
                                                   http://www.drweb.ru/unix
--------------------------------------------------------------------------*/
char szSocketFile[ MAXPATHLEN + 2 ] = { 0 };
char szDaemonIP[ MAXPATHLEN + 2 ] = DRWEBD_DEFAULT_IP;
char szSocketFileName[ MAXPATHLEN + 2 ] = { 0 };

int  Timeout = DRWEBD_DEFAULT_TIMEOUT;
int  scanOptions = DRWEBD_DEFAULT_OPTIONS;

int  Socket = -1;
int  Port = DRWEBD_DEFAULT_PORT;
int  bQuiet = 0;

//--------------------------------------------------------------------------
void
printn( int n )
{
   if( !bQuiet )
   {
       printf( "%u", n );
   }
}

//--------------------------------------------------------------------------
void
prints( const char * s )
{
   if( !bQuiet )
   {
       printf( "%s", s );
   }
}

//--------------------------------------------------------------------------
void
closeSocket( void )
{
   if( Socket >= 0 )
   {
       shutdown( Socket, 2 );
       close( Socket );
       Socket = -1;
   }
}

//--------------------------------------------------------------------------
void
cleanup( void )
{
   closeSocket();
   if( *szSocketFileName ) unlink( szSocketFileName );
   prints( "\n" );
   fflush( stdout );
}

//--------------------------------------------------------------------------
static int
createUnixSocket( void )
{

struct sockaddr_un addr_un;

    if( ( Socket = socket(AF_UNIX,SOCK_STREAM, 0 ) ) < 0 )
    {
          prints( "\nsocket() error: " );
          prints( strerror(errno) );
          return 0;
    }

    bzero( (char *)&addr_un, sizeof(addr_un) );
    addr_un.sun_family = AF_UNIX;
    strncpy( addr_un.sun_path, szSocketFile, sizeof(addr_un.sun_path) );

    if( connect( Socket, (struct sockaddr *)(&addr_un), SUN_LEN(&addr_un) ) < 0 )
    {
          close( Socket );
          if( ( Socket = open( szSocketFile, O_RDWR ) ) == -1 )
          {
            prints( "\nopen socket error: " );
            prints( strerror(errno) );
            return 0;
          }
    }
    return 1;
}

//--------------------------------------------------------------------------
static int
createTcpSocket( void )
{

struct hostent * he = NULL;
struct  sockaddr_in addr_tcp;

    memset( &addr_tcp, 0, sizeof( addr_tcp ) );
    
    addr_tcp.sin_family = PF_INET;
    addr_tcp.sin_addr.s_addr = 0x0100007F;

    Socket = socket( PF_INET, SOCK_STREAM, 0 );
    if( Socket < 0 )
    {
          prints( "\nsocket() error: " );
          prints( strerror(errno) );
          return 0;
    }

    addr_tcp.sin_port = htons( Port );

    he = gethostbyname( szDaemonIP );
    if( !he || he -> h_addrtype != AF_INET )
    {
          prints( "\ninvalid IP address! " );
          prints( strerror(errno) );
          close( Socket );
	  Socket = -1;
          return 0;
    }
    memcpy( &addr_tcp.sin_addr.s_addr,
            he -> h_addr_list[0],
                       sizeof(addr_tcp.sin_addr.s_addr) );
	      

    if( connect( Socket, (struct sockaddr *)&addr_tcp, sizeof(addr_tcp) ) < 0 )
    {
          prints( "\nconnect() error: " );
          prints( strerror(errno) );
          return 0;
    }
    return 1;
}

//--------------------------------------------------------------------------
int
createSocket( void )
{
   if( Port == -1 )
   {
       if( !createUnixSocket() )
       {
           return DRWEBD_SOCKET_ERR;
       }
   }
   else
   {
       if( !createTcpSocket() )
       {
           return DRWEBD_SOCKET_ERR;
       }
   }
   
   return Socket;
}

//--------------------------------------------------------------------------
int
writeBuf( const void * buf, int n )
{

int written = 0, towrite = 0, already = 0;
const char * outBuffer = (const char *)buf;

    while( already != n )
    {
        towrite = 4096 * 4;
	if( already + towrite > n )
	{
	    towrite = n - already;
	} 
        written = write( Socket, outBuffer + already, towrite );

	switch( written )
	{
           case 0:
	        if( errno == EAGAIN || errno == EINTR )
		{
		    break; 
		}	
// sorry :)
           case -1:
		prints( "\nwriteBuf() error: " );
    		prints( strerror(errno) );
    		return 0;

           default:	   
	        already += written;
		break;
	}
    }
    return already;
}

//--------------------------------------------------------------------------
int
writeInt( int n )
{
    n = htonl( n );
    return writeBuf( &n, sizeof(n) );
}

//--------------------------------------------------------------------------
int
readOutput( int size, void * buf )
{

int already = 0, readed = 0, toread;
char * inBuffer = (char *)buf;
time_t t_end = time( NULL ) + (time_t)Timeout;

   while( already != size )
   {
      if( time( NULL ) > t_end )
      {
         prints( "\nError reading daemon output (timeout)" );
         return DRWEBD_TIMEOUT;
      }
      toread = 4096;
      if( already + toread > size )
      {
         toread = size - already;
      }
      readed = read( Socket, inBuffer + already, toread );

      switch( readed )
      {
         case 0:
              prints( "\nError reading daemon output (" );
              prints( strerror(errno) );
              prints( ")" );
              return DRWEBD_SREAD_ERR;

         case -1:
              if( errno == EAGAIN || errno == EINTR )
              {
	          break;
              }
              prints( "\nError reading daemon output (" );
              prints( strerror(errno) );
              prints( ")" );
              return DRWEBD_SREAD_ERR;

         default:
              already += readed;
	      break;
       }
    }
    return 0;
}

//--------------------------------------------------------------------------
