#include "stdafx.h"
#include "resource.h"
#include "clamav.h"
#include "mainfrm.h"
#include "clamserver.h"
#include "servername.h"
#include <io.h>
#include <winsock.h>
#include <sys/stat.h>
ClamServer::ClamServer(void)
{
if(!InitInstance())
THROW(new CException());
progressBar = NULL;
stopping = FALSE;
}
ClamServer::ClamServer(CString& serverName, unsigned short p)
{
LPTSTR hostname = serverName.GetBuffer(64);
serverIP = inet_addr(hostname);
if(serverIP == -1L)
THROW(CException());
port = p;
const int sock = CreateConnection();
if(sock < 0)
THROW(CException());
progressBar = NULL;
stopping = FALSE;
}
ClamServer::~ClamServer()
{
if(progressBar) {
delete progressBar;
progressBar = NULL;
}
}
BOOL
ClamServer::InitInstance(void)
{
ServerName serverName;
if(serverName.DoModal() == IDCANCEL)
return FALSE;
const char *hostname = serverName.m_serverName;
serverIP = inet_addr(hostname);
if(serverIP == -1L) {
AfxMessageBox("Unknown host");
return FALSE;
}
port = (unsigned short)serverName.m_port;
const int sock = CreateConnection();
if(sock < 0)
return TRUE;
return CheckConnection(sock);
}
const BOOL
ClamServer::CheckConnection(int sock)
{
if(send(sock, "PING\n", 5, 0) < 5) {
closesocket(sock);
AfxMessageBox("Can't talk to clamdserver");
return FALSE;
}
char ret[5];
if(recv(sock, ret, sizeof(ret), 0) <= 4) {
closesocket(sock);
AfxMessageBox("Can't receive from clamdserver");
return FALSE;
}
closesocket(sock);
if(strncmp(ret, "PONG\n", 5) != 0) {
AfxMessageBox("Is that server running clamd?");
return FALSE;
}
return TRUE;
}
int
ClamServer::CreateConnection(void)
{
const int sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock < 0) {
AfxMessageBox("Can't create socket");
return FALSE;
}
struct sockaddr_in server;
memset(&server, '\0', sizeof(struct sockaddr_in));
server.sin_family = PF_INET;
server.sin_port = htons(port);
server.sin_addr.s_addr = serverIP;
if(connect(sock, (struct sockaddr *)&server, sizeof(struct sockaddr)) < 0) {
AfxMessageBox("Can't connect to clamdserver");
return FALSE;
}
return sock;
}
BOOL
ClamServer::Scan(const CString& filename, int level, CMainFrame *mainFrame, CWnd *parent, BOOL recursive, const CString& qDir)
{
if(level == 0)
stopping = FALSE;
else if(stopping) {
if(progressBar) {
delete progressBar;
progressBar = NULL;
}
return TRUE;
}
if(filename[filename.GetLength() - 1] == '.')
return TRUE;
struct stat statb;
if(stat(filename, &statb) < 0) {
WIN32_FIND_DATA findData;
HANDLE hFind = FindFirstFile(filename, &findData);
if(hFind == INVALID_HANDLE_VALUE) {
AfxMessageBox(CString("Can't stat ") + filename);
return TRUE;
}
return this->ScanWildCard(filename, level, mainFrame, parent, recursive, qDir);
}
if(progressBar && !stopping) {
if(progressBar->IsStopPressed())
stopping = TRUE;
progressBar->SetFilename(filename);
}
if(statb.st_mode&S_IFDIR) {
if((!recursive) && (level > 0))
return TRUE;
if(progressBar == NULL) {
progressBar = new CProgress(parent);
progressBar->Create(IDD_PROGRESS, parent);
}
return this->ScanFolder(filename, level, mainFrame, parent, recursive, qDir);
}
if(progressBar && (level == 0)) {
delete progressBar;
progressBar = NULL;
}
const int commandSocket = CreateConnection();
if(commandSocket < 0)
return TRUE;
if(send(commandSocket, "STREAM\n", 7, 0) < 7) {
closesocket(commandSocket);
AfxMessageBox("Send failed to clamd");
return TRUE;
}
char buf[64];
int nbytes = ClamdRecv(commandSocket, buf, sizeof(buf) - 1);
if(nbytes < 0) {
closesocket(commandSocket);
AfxMessageBox("recv failed from clamd getting PORT");
return TRUE;
}
buf[nbytes] = '\0';
unsigned short port;
if(sscanf(buf, "PORT %hu\n", &port) != 1) {
closesocket(commandSocket);
AfxMessageBox("Didn't get PORT information from clamd");
return TRUE;
}
const int dataSocket = socket(AF_INET, SOCK_STREAM, 0);
if(dataSocket < 0) {
closesocket(commandSocket);
AfxMessageBox("Can't create dataSocket");
return TRUE;
}
shutdown(dataSocket, 0);
struct sockaddr_in reply;
memset(&reply, '\0', sizeof(struct sockaddr_in));
reply.sin_family = PF_INET;
reply.sin_port = htons(port);
reply.sin_addr.s_addr = serverIP;
const int rc = connect(dataSocket, (struct sockaddr *)&reply, sizeof(struct sockaddr_in));
if(rc < 0) {
closesocket(commandSocket);
closesocket(dataSocket);
AfxMessageBox("Failed to connect to port given by clamd");
return TRUE;
}
CFile file;
if(!file.Open(filename, CFile::modeRead|CFile::typeBinary|CFile::shareDenyNone)) {
closesocket(commandSocket);
closesocket(dataSocket);
AfxMessageBox(CString("Can't open ") + filename + " to scan: ");
return TRUE;
}
if(progressBar)
progressBar->SetPercent(0);
char buffer[1500]; off_t bytesSent = (off_t)0;
BOOL error = FALSE;
while(((nbytes = file.Read(buffer, sizeof(buffer))) > 0) && !stopping) {
MSG Msg;
if(::PeekMessage(&Msg, NULL, WM_NULL, WM_USER - 1, PM_NOREMOVE)) {
::PeekMessage(&Msg, NULL, WM_NULL, WM_USER - 1, PM_REMOVE);
TranslateMessage(&Msg);
DispatchMessage(&Msg);
if((progressBar && progressBar->IsStopPressed()) ||
(Msg.message == WM_QUIT)) {
error = TRUE;
break;
}
}
char buf[81];
if(ClamdRecv(commandSocket, buf, sizeof(buf) - 1, 0) > 0) {
AfxMessageBox(buf);
error = TRUE;
break;
}
if(send(dataSocket, buffer, nbytes, 0) != nbytes) {
AfxMessageBox("Send error to clamd");
error = TRUE;
break;
}
if(progressBar) {
bytesSent += nbytes;
progressBar->SetPercent((int)(bytesSent * 100 / statb.st_size));
}
}
closesocket(dataSocket);
file.Close();
if(error) {
closesocket(commandSocket);
stopping = TRUE;
if(progressBar && (level == 0)) {
delete progressBar;
progressBar = NULL;
}
return TRUE;
}
nbytes = ClamdRecv(commandSocket, buffer, sizeof(buffer) - 1);
closesocket(commandSocket);
if(nbytes < 0) {
AfxMessageBox("recv error getting status");
return TRUE;
} else if(nbytes == 0)
return TRUE;
buffer[nbytes] = '\0';
if(strstr(buffer, "ERROR") != NULL) {
AfxMessageBox(filename + " " + buffer);
return TRUE;
}
if(strstr(buffer, "FOUND") == NULL)
return TRUE;
AfxMessageBox(filename + " " + buffer);
mainFrame->ChangeStatusText(filename + " " + buffer);
return FALSE;
}
BOOL
ClamServer::ScanFolder(const CString& string, int level, CMainFrame *mainFrame, CWnd *parent, BOOL recursive, const CString& qDir)
{
return ScanWildCard(string + "\\*.*", level, mainFrame, parent, recursive, qDir);
}
BOOL
ClamServer::ScanWildCard(const CString& string, int level, CMainFrame *mainFrame, CWnd *parent, BOOL recursive, const CString& qDir)
{
if(stopping)
return TRUE;
WIN32_FIND_DATA findData;
HANDLE hFind = FindFirstFile(string, &findData);
if(hFind == INVALID_HANDLE_VALUE)
return TRUE;
const int index = string.Find("\\*.*");
ASSERT(index >= 0);
const CString stub = string.Left(index);
BOOL rc = TRUE;
do
if(!this->Scan(stub + "\\" + findData.cFileName, level + 1, mainFrame, parent, recursive, qDir))
rc = FALSE;
while(FindNextFile(hFind, &findData) && !stopping);
if(progressBar && (level == 0)) {
delete progressBar;
progressBar = NULL;
}
return rc;
}
int
ClamServer::ClamdRecv(int sock, char *buf, size_t len, int timeout )
{
fd_set rfds;
struct timeval tv;
if(timeout == -1)
return recv(sock, buf, len, 0);
FD_ZERO(&rfds);
FD_SET(sock, &rfds);
tv.tv_sec = timeout; tv.tv_usec = 0;
switch(select(sock + 1, &rfds, NULL, NULL, &tv)) {
case -1:
AfxMessageBox("select failed");
return -1;
case 0:
if(timeout != 0)
AfxMessageBox("Timeout waiting for data from clamd");
return 0;
}
return recv(sock, buf, len, 0);
}