/*
 * Program: Synonym
 * File: scan.c
 * Author: Cristian Draghici
 * Date: 17 Nov 2003
 *
 * $Id: scan.c,v 1.2 2004/01/19 09:24:31 diciu Exp $
 *
 * Licensed under the Modulo Consulting Software License
 * (see file license.txt)
 * 
 */
#include <sys/types.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <syslog.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <stdio.h>

#define SCAN_FAILURE	1
#define SCAN_SUCCESS	0
#define print_debug syslog

/* request scan from clamd */
int request_scan(char *scan_data, long scan_size)
{
	int data_sock, command_sock, retval = 0;
	struct timeval tv;
	fd_set data_wfds, command_wfds;
	struct sockaddr_in data_serv_addr, command_serv_addr;
	char buffer[1024];
	int bytes_read;
	struct hostent *temp_hostent;
	unsigned long clamd_hostaddr;
	int scan_port;
	
	if ((command_sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
	{
		syslog(LOG_ERR, "Failed to create the command socket for communicating with clamd - err code: %d", errno);
		return SCAN_FAILURE;
	}
	
	
	if((temp_hostent = gethostbyname("127.0.0.1"))==NULL)
	{
		print_debug(LOG_ERR, "Unable to resolve the notification host address %s\n", optarg);
		return SCAN_FAILURE;
	}

	clamd_hostaddr = *((unsigned long*)temp_hostent->h_addr);
	
	command_serv_addr.sin_family =  AF_INET;
	command_serv_addr.sin_addr.s_addr = clamd_hostaddr;
	command_serv_addr.sin_port = htons(3773);

	if (connect(command_sock, (struct sockaddr *)&command_serv_addr, sizeof(command_serv_addr)) != 0)
	{
		syslog(LOG_ERR, "Failed to connect to the notification engine command channel");
		close(command_sock);
		return SCAN_FAILURE;
	}
	tv.tv_sec = 2;
	tv.tv_usec = 0;
	FD_ZERO(&command_wfds);
	FD_SET(command_sock, &command_wfds);
	
	if ((retval = select((command_sock)+1, NULL, &command_wfds, NULL,&tv)) > 0)
	{
		write(command_sock, "STREAM", strlen("STREAM"));
	}
	
	/* now read the answer */
	if ((retval = select((command_sock)+1, NULL, &command_wfds, NULL,&tv)) > 0)
	{
		bytes_read = read(command_sock, buffer, 1024);
	}
	buffer[bytes_read] = '\0';
	print_debug(LOG_DEBUG, "Read %d bytes, %s", bytes_read, buffer);
	
	/* get the port from the answer */
	if(sscanf(buffer, "PORT %d\n", &scan_port) != 1)
		print_debug(LOG_DEBUG, "Reading scan port failed.");
	
	print_debug(LOG_DEBUG, "Scan port is %d", scan_port);
	
	if ((data_sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
	{
		syslog(LOG_ERR, "Failed to create the data socket for communicating with clamd - err code: %d", errno);
		return SCAN_FAILURE;
	}
	
	data_serv_addr.sin_family =  AF_INET;
	data_serv_addr.sin_addr.s_addr = clamd_hostaddr;
	data_serv_addr.sin_port = htons(scan_port);
	sleep(1);
	/* open a new connection */
	if (connect(data_sock, (struct sockaddr *)&data_serv_addr, sizeof(data_serv_addr)) != 0)
	{
		syslog(LOG_ERR, "Failed to connect to the notification engine data channel");
		close(data_sock);
		close(command_sock);
		return SCAN_FAILURE;
	}
	tv.tv_sec = 2;
	tv.tv_usec = 0;
	FD_ZERO(&data_wfds);
	FD_SET(data_sock, &data_wfds);
	
	if ((retval = select((data_sock)+1, NULL, &data_wfds, NULL,&tv)) > 0)
	{
		write(data_sock, scan_data, scan_size);
	}
	close(data_sock);	
	print_debug(LOG_DEBUG, "Sent data for scan, reading answer on command socket");
	
	/* now read the answer */
	if ((retval = select((command_sock)+1, NULL, &command_wfds, NULL,&tv)) > 0)
	{
		bytes_read = read(command_sock, buffer, 1024);
	}
	buffer[bytes_read] = '\0';
	print_debug(LOG_DEBUG, "Read %d bytes, %s", bytes_read, buffer);
	close(command_sock);
	return SCAN_SUCCESS;
}


syntax highlighted by Code2HTML, v. 0.9.1