Permalink
Browse files

Implemented WSA* calls for Windows.

  • Loading branch information...
RoliSoft committed Oct 4, 2015
1 parent 83b7a21 commit 783052b49d39c3f2833e93c9bc183088eaec8797
Showing with 66 additions and 23 deletions.
  1. +54 −22 tcpscanner.cpp
  2. +12 −1 tcpscanner.h
@@ -1,5 +1,6 @@
#include "tcpscanner.h"
#include <boost/lexical_cast.hpp>
#include <iostream>
using namespace std;
using namespace boost;
@@ -111,12 +112,23 @@ void TcpScanner::initSocket(Service* service)
u_long mode = 1;
ioctlsocket(sock, FIONBIO, &mode);
// allocate file descriptor set
// set up the OS's choice of signaling for non-blocking sockets
#if Windows
WSAEVENT evt = WSACreateEvent();
WSAEventSelect(sock, evt, FD_WRITE);
WSAResetEvent(evt);
data->event = evt;
#elif Linux
data->fdset = new fd_set();
FD_ZERO(data->fdset);
FD_SET(sock, data->fdset);
#endif
// start non-blocking connection process
connect(sock, reinterpret_cast<struct sockaddr*>(info->ai_addr), info->ai_addrlen);
@@ -129,49 +141,57 @@ void TcpScanner::pollSocket(Service* service, bool last)
return;
}
TIMEVAL tv = { 0, 0 };
auto data = reinterpret_cast<TcpScanData*>(service->data);
// check if socket is writable, which basically means the connection was successful
#if Windows
// for some reason, Linux requires the first parameter to be counterintuitively socket+1, while Windows doesn't
// time spent searching for this error: ~1.5 hours
// check if the event was signalled
select(
data->socket
#if Linux
+ 1
#endif
, nullptr, data->fdset, nullptr, &tv
);
auto sigr = WSAWaitForMultipleEvents(1, &data->event, false, 0, false);
auto serr = WSAGetLastError();
// check if the writable flag is set
// the return value 258 is not documented in MSDN, however this
// is what seems to be returned in case of errors
auto isOpen = FD_ISSET(data->socket, data->fdset);
if (sigr == 258 && serr != WSAEWOULDBLOCK)
{
service->alive = false;
service->reason = AR_IcmpUnreachable;
}
else if (sigr == 0)
{
service->alive = true;
}
#if Linux
if (isOpen)
#elif Linux
// check if socket is writable
TIMEVAL tv = { 0, 0 };
select(data->socket + 1, nullptr, data->fdset, nullptr, &tv);
if (FD_ISSET(data->socket, data->fdset))
{
// yet again Linux decided to troll me. all select() requests will become "writable", and you have
// to check if there was an error or not, to actually determine if the connect() was successful
// since it seems writability bit will be set on connection refused errors,
// check if this is a legit instance of writable socket or an error
int serr;
socklen_t slen = sizeof(serr);
getsockopt(data->socket, SOL_SOCKET, SO_ERROR, &serr, &slen);
isOpen = serr == 0;
service->alive = serr == 0;
if (serr == ECONNREFUSED)
{
service->reason = AR_IcmpUnreachable;
}
}
#endif
service->alive = isOpen == 1;
#endif
// mark service accordingly
if (isOpen)
if (service->alive)
{
service->reason = AR_InProgress2;
readBanner(service, last);
@@ -185,8 +205,10 @@ void TcpScanner::pollSocket(Service* service, bool last)
}
else if (service->reason == AR_InProgress)
{
#if Linux
FD_ZERO(data->fdset);
FD_SET(data->socket, data->fdset);
#endif
return;
}
}
@@ -197,7 +219,12 @@ void TcpScanner::pollSocket(Service* service, bool last)
closesocket(data->socket);
#if Windows
WSACloseEvent(data->event);
#elif Linux
delete data->fdset;
#endif
delete data;
}
@@ -245,7 +272,12 @@ void TcpScanner::readBanner(Service* service, bool last)
shutdown(data->socket, SD_BOTH);
closesocket(data->socket);
#if Windows
WSACloseEvent(data->event);
#elif Linux
delete data->fdset;
#endif
delete data;
}
@@ -13,11 +13,22 @@ struct TcpScanData
*/
SOCKET socket;
#if Windows
/*!
* File descriptor set for writability.
* Event object to be signalled on connection.
*/
WSAEVENT event;
#elif Linux
/*!
* File descriptor set to determine writability.
*/
fd_set* fdset;
#endif
};
/*!

0 comments on commit 783052b

Please sign in to comment.