375 lines
13 KiB
C
375 lines
13 KiB
C
#include "ipxdefs.h"
|
|
|
|
SERVICE_STATUS_HANDLE ServiceStatusHandle;
|
|
SERVICE_STATUS ServiceStatus;
|
|
SOCKET PingSocket;
|
|
UINT PacketSize;
|
|
DWORD PingTraceId;
|
|
volatile LONG RequestCount;
|
|
|
|
const union {
|
|
CHAR ch[4];
|
|
LONG l;
|
|
} ping_signature = {"Ping"};
|
|
#define IPX_PING_SIGNATURE ping_signature.l
|
|
|
|
VOID CALLBACK
|
|
ProcessPingRequest (
|
|
IN DWORD dwError,
|
|
IN DWORD cbTransferred,
|
|
IN LPWSAOVERLAPPED lpOverlapped
|
|
);
|
|
|
|
|
|
DWORD
|
|
PostReceiveRequest (
|
|
PVOID context
|
|
);
|
|
|
|
DWORD
|
|
StartPingSvc (
|
|
VOID
|
|
) {
|
|
BOOL flag;
|
|
SOCKADDR_IPX addr;
|
|
DWORD status;
|
|
int sz;
|
|
WORD wVersionRequested;
|
|
WSADATA wsaData;
|
|
int res;
|
|
|
|
|
|
wVersionRequested = MAKEWORD( 2, 0 );
|
|
PingTraceId = TraceRegister (TEXT ("IPXPing"));
|
|
|
|
res = WSAStartup( wVersionRequested, &wsaData );
|
|
if ((res==NO_ERROR)
|
|
&& (LOBYTE(wsaData.wVersion)==2)
|
|
&& (HIBYTE(wsaData.wVersion)==0)) {
|
|
PingSocket = socket (AF_IPX, SOCK_DGRAM, NSPROTO_IPX);
|
|
if (PingSocket!=INVALID_SOCKET) {
|
|
// Tell WS IPX to use extended addresses
|
|
flag = TRUE;
|
|
if (setsockopt (PingSocket,
|
|
NSPROTO_IPX,
|
|
IPX_EXTENDED_ADDRESS,
|
|
(PCHAR)&flag,
|
|
sizeof (BOOL))==0) {
|
|
// Bind to default address
|
|
memset (&addr, 0, sizeof (addr));
|
|
addr.sa_family = AF_IPX;
|
|
addr.sa_socket = htons (IPX_PING_SOCKET);
|
|
if (bind (PingSocket,
|
|
(PSOCKADDR)&addr,
|
|
sizeof (addr))==0) {
|
|
if (getsockopt (PingSocket,
|
|
SOL_SOCKET,
|
|
SO_MAX_MSG_SIZE,
|
|
(PCHAR)&PacketSize,
|
|
&sz)==0) {
|
|
status = NO_ERROR;
|
|
if (! SetIoCompletionProc ((HANDLE)PingSocket,
|
|
ProcessPingRequest))
|
|
{
|
|
status = GetLastError();
|
|
}
|
|
if (status==NO_ERROR) {
|
|
RequestCount = 0;
|
|
return NO_ERROR;
|
|
}
|
|
else {
|
|
TracePrintfEx (PingTraceId,
|
|
DBG_PING_ERRORS|TRACE_USE_MASK,
|
|
TEXT ("Failed to set IO completion proc, err:%ld.\n"),
|
|
status);
|
|
}
|
|
}
|
|
else {
|
|
status = WSAGetLastError ();
|
|
TracePrintfEx (PingTraceId,
|
|
DBG_PING_ERRORS|TRACE_USE_MASK,
|
|
TEXT ("Failed to get SO_MAX_MSG_SIZE, err:%ld.\n"),
|
|
status);
|
|
}
|
|
}
|
|
else {
|
|
status = WSAGetLastError ();
|
|
TracePrintfEx (PingTraceId,
|
|
DBG_PING_ERRORS|TRACE_USE_MASK,
|
|
TEXT ("Failed to bind to IPXPING socket (%.4x), err:%ld.\n"),
|
|
IPX_PING_SOCKET, status);
|
|
}
|
|
}
|
|
else {
|
|
status = WSAGetLastError ();
|
|
TracePrintfEx (PingTraceId,
|
|
DBG_PING_ERRORS|TRACE_USE_MASK,
|
|
TEXT ("Failed to set IPX_EXTENDED_ADDRESS option, err:%ld.\n"),
|
|
status);
|
|
}
|
|
}
|
|
else {
|
|
status = WSAGetLastError ();
|
|
TracePrintfEx (PingTraceId,
|
|
DBG_PING_ERRORS|TRACE_USE_MASK,
|
|
TEXT ("Failed to create socket, err:%ld.\n"),
|
|
status);
|
|
}
|
|
|
|
}
|
|
else {
|
|
TracePrintfEx (PingTraceId,
|
|
DBG_PING_ERRORS|TRACE_USE_MASK,
|
|
TEXT ("IPX Ping service implementation is"
|
|
" incompatible with version of sockets installed"
|
|
" on this system.\n"));
|
|
status = WSAVERNOTSUPPORTED;
|
|
}
|
|
|
|
PingSocket = INVALID_SOCKET;
|
|
WSACleanup ();
|
|
TracePrintfEx (PingTraceId,
|
|
DBG_PING_ERRORS|TRACE_USE_MASK,
|
|
TEXT ("IPX Ping service was not started!\n"));
|
|
TraceDeregister (PingTraceId);
|
|
return status;
|
|
}
|
|
|
|
VOID
|
|
ServiceHandler (
|
|
DWORD fdwControl
|
|
) {
|
|
switch (fdwControl) {
|
|
case SERVICE_CONTROL_STOP:
|
|
case SERVICE_CONTROL_SHUTDOWN:
|
|
ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
|
|
SetServiceStatus (ServiceStatusHandle, &ServiceStatus);
|
|
|
|
TracePrintfEx (PingTraceId,
|
|
DBG_PING_CONTROL|TRACE_USE_MASK,
|
|
TEXT ("Stop or shutdown command received.\n"));
|
|
|
|
StopPingSvc ();
|
|
break;
|
|
|
|
case SERVICE_CONTROL_PAUSE:
|
|
case SERVICE_CONTROL_CONTINUE:
|
|
case SERVICE_CONTROL_INTERROGATE:
|
|
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
|
|
ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP |
|
|
|
|
TracePrintfEx (PingTraceId,
|
|
DBG_PING_CONTROL|TRACE_USE_MASK,
|
|
TEXT ("Interrogate command received.\n"));
|
|
break;
|
|
|
|
default:
|
|
TracePrintfEx (PingTraceId,
|
|
DBG_PING_CONTROL|TRACE_USE_MASK,
|
|
TEXT ("Unknown or unsupported command received (%d).\n"),
|
|
fdwControl);
|
|
break;
|
|
|
|
}
|
|
SetServiceStatus (ServiceStatusHandle, &ServiceStatus);
|
|
}
|
|
|
|
VOID
|
|
ServiceMain (
|
|
DWORD argc,
|
|
LPTSTR argv[]
|
|
) {
|
|
HANDLE hEvent;
|
|
|
|
ServiceStatusHandle = RegisterServiceCtrlHandler (
|
|
TEXT("ipxping"), ServiceHandler);
|
|
if (ServiceStatusHandle)
|
|
{
|
|
ServiceStatus.dwServiceType = SERVICE_WIN32_SHARE_PROCESS;
|
|
ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
|
|
SetServiceStatus (ServiceStatusHandle, &ServiceStatus);
|
|
|
|
ServiceStatus.dwWin32ExitCode = StartPingSvc ();
|
|
if (ServiceStatus.dwWin32ExitCode==NO_ERROR) {
|
|
hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
|
|
if (hEvent!=NULL) {
|
|
|
|
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
|
|
ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP
|
|
| SERVICE_ACCEPT_SHUTDOWN;
|
|
SetServiceStatus (ServiceStatusHandle, &ServiceStatus);
|
|
|
|
while (PingSocket!=INVALID_SOCKET) {
|
|
if (PostReceiveRequest (hEvent)==NO_ERROR)
|
|
WaitForSingleObject (hEvent, INFINITE);
|
|
else
|
|
Sleep (3000);
|
|
}
|
|
while (RequestCount>0)
|
|
SleepEx (1000, TRUE);
|
|
}
|
|
else {
|
|
ServiceStatus.dwWin32ExitCode = GetLastError ();
|
|
TracePrintfEx (PingTraceId,
|
|
DBG_PING_ERRORS|TRACE_USE_MASK,
|
|
TEXT ("Failed to create receive event, err: %ld.\n"),
|
|
ServiceStatus.dwWin32ExitCode);
|
|
}
|
|
}
|
|
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
|
|
ServiceStatus.dwControlsAccepted = 0;
|
|
SetServiceStatus (ServiceStatusHandle, &ServiceStatus);
|
|
}
|
|
}
|
|
|
|
DWORD
|
|
PostReceiveRequest (
|
|
HANDLE hEvent
|
|
) {
|
|
PPING_DATA_BLOCK block;
|
|
int res;
|
|
DWORD status;
|
|
block = (PPING_DATA_BLOCK)GlobalAlloc (GPTR,
|
|
FIELD_OFFSET (PING_DATA_BLOCK, pinghdr)
|
|
+PacketSize);
|
|
if (block!=NULL) {
|
|
WSABUF bufArray[1];
|
|
DWORD cbBytes, sz;
|
|
DWORD flags;
|
|
|
|
block->ovlp.hEvent = hEvent;
|
|
bufArray[0].buf = (PCHAR)(&block->pinghdr);
|
|
bufArray[0].len = PacketSize;
|
|
flags = 0;
|
|
sz = sizeof (block->raddr);
|
|
|
|
res = WSARecvFrom (PingSocket,
|
|
bufArray,
|
|
sizeof (bufArray)/sizeof (bufArray[0]),
|
|
&cbBytes,
|
|
&flags,
|
|
(PSOCKADDR)&block->raddr,
|
|
&sz,
|
|
&block->ovlp,
|
|
NULL
|
|
);
|
|
if ((res==0) || (WSAGetLastError ()==WSA_IO_PENDING)) {
|
|
InterlockedIncrement ((PLONG)&RequestCount);
|
|
TracePrintfEx (PingTraceId,
|
|
DBG_PING_REQUESTS|TRACE_USE_MASK,
|
|
TEXT ("Posted ping request (%08lx).\n"),
|
|
block);
|
|
return NO_ERROR;
|
|
}
|
|
else {
|
|
status = WSAGetLastError ();
|
|
TracePrintfEx (PingTraceId,
|
|
DBG_PING_ERRORS|TRACE_USE_MASK,
|
|
TEXT ("Failed to post ping request, err: %ld.\n"),
|
|
status);
|
|
}
|
|
|
|
GlobalFree (block);
|
|
}
|
|
else {
|
|
status = GetLastError ();
|
|
TracePrintfEx (PingTraceId,
|
|
DBG_PING_ERRORS|TRACE_USE_MASK,
|
|
TEXT ("Failed to allocate receive buffer, err: %ld.\n"),
|
|
status);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
VOID CALLBACK
|
|
ProcessPingRequest (
|
|
IN DWORD error,
|
|
IN DWORD cbBytes,
|
|
IN LPWSAOVERLAPPED ovlp
|
|
) {
|
|
PPING_DATA_BLOCK block = CONTAINING_RECORD (ovlp, PING_DATA_BLOCK, ovlp);
|
|
USHORT pktlen;
|
|
int res;
|
|
|
|
TracePrintfEx (PingTraceId,
|
|
DBG_PING_REQUESTS|TRACE_USE_MASK,
|
|
TEXT ("Processing ping request (%08lx), size: %ld, err: %ld.\n"),
|
|
block, cbBytes, error);
|
|
|
|
|
|
if (error!=ERROR_OPERATION_ABORTED) {
|
|
|
|
if ((error==NO_ERROR)
|
|
&& (cbBytes>=sizeof (block->pinghdr))
|
|
&& (block->raddr.pkttype==0)
|
|
&& ((*((UNALIGNED LONG *)&block->pinghdr.signature))==IPX_PING_SIGNATURE)
|
|
&& (block->pinghdr.type==PING_PACKET_TYPE_REQUEST)
|
|
) {
|
|
|
|
block->pinghdr.type = PING_PACKET_TYPE_RESPONSE;
|
|
block->pinghdr.result =
|
|
(cbBytes>sizeof (block->pinghdr)) ? 1 : 0;
|
|
block->pinghdr.version = 1;
|
|
|
|
res = sendto (PingSocket,
|
|
(PCHAR)&block->pinghdr,
|
|
cbBytes,
|
|
0,
|
|
(PSOCKADDR)&block->saddr,
|
|
sizeof (block->saddr)
|
|
);
|
|
if (res!=SOCKET_ERROR) {
|
|
TracePrintfEx (PingTraceId,
|
|
DBG_PING_RESPONSES|TRACE_USE_MASK,
|
|
TEXT ("Sent response (%08lx) to"
|
|
" %.2x%.2x%.2x%.2x,%.2x%.2x%.2x%.2x%.2x%.2x,%.4x"
|
|
" with %d bytes of data.\n"),
|
|
block,
|
|
block->saddr.std.sa_netnum[0], block->saddr.std.sa_netnum[1],
|
|
block->saddr.std.sa_netnum[2], block->saddr.std.sa_netnum[3],
|
|
block->saddr.std.sa_nodenum[0], block->saddr.std.sa_netnum[1],
|
|
block->saddr.std.sa_netnum[2], block->saddr.std.sa_netnum[3],
|
|
block->saddr.std.sa_netnum[4], block->saddr.std.sa_netnum[5],
|
|
block->saddr.std.sa_socket,
|
|
cbBytes-sizeof (block->pinghdr));
|
|
}
|
|
else
|
|
TracePrintfEx (PingTraceId,
|
|
DBG_PING_ERRORS|TRACE_USE_MASK,
|
|
TEXT ("Failed to send response, err: %ld.\n"),
|
|
WSAGetLastError ());
|
|
}
|
|
else {
|
|
TracePrintfEx (PingTraceId,
|
|
DBG_PING_RESPONSES|TRACE_USE_MASK,
|
|
TEXT ("Invalid request packet received from"
|
|
" %.2x%.2x%.2x%.2x,%.2x%.2x%.2x%.2x%.2x%.2x,%.4x"
|
|
" (pktsize: %d, pkttype: %.2x, sig:%4.4s, type: %d, ver: %d).\n"),
|
|
block->raddr.std.sa_netnum[0], block->raddr.std.sa_netnum[1],
|
|
block->raddr.std.sa_netnum[2], block->raddr.std.sa_netnum[3],
|
|
block->raddr.std.sa_nodenum[0], block->raddr.std.sa_netnum[1],
|
|
block->raddr.std.sa_netnum[2], block->raddr.std.sa_netnum[3],
|
|
block->raddr.std.sa_netnum[4], block->raddr.std.sa_netnum[5],
|
|
block->raddr.std.sa_socket,
|
|
cbBytes, block->raddr.pkttype,
|
|
block->pinghdr.signature, block->pinghdr.type, block->pinghdr.version);
|
|
}
|
|
}
|
|
|
|
GlobalFree (block);
|
|
InterlockedDecrement ((PLONG)&RequestCount);
|
|
}
|
|
|
|
VOID
|
|
StopPingSvc (
|
|
VOID
|
|
) {
|
|
if (PingSocket!=INVALID_SOCKET) {
|
|
SOCKET s = PingSocket;
|
|
PingSocket = INVALID_SOCKET;
|
|
closesocket (s);
|
|
WSACleanup ();
|
|
TraceDeregister (PingTraceId);
|
|
}
|
|
}
|