You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
215 lines
4.8 KiB
215 lines
4.8 KiB
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copyright (c) 2000, Microsoft Corp. All rights reserved.
|
|
//
|
|
// FILE
|
|
//
|
|
// udpsock.cpp
|
|
//
|
|
// SYNOPSIS
|
|
//
|
|
// Defines the class UDPSocket.
|
|
//
|
|
// MODIFICATION HISTORY
|
|
//
|
|
// 02/06/2000 Original version.
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include <proxypch.h>
|
|
#include <malloc.h>
|
|
#include <udpsock.h>
|
|
|
|
inline BOOL UDPSocket::createReceiveThread()
|
|
{
|
|
// check if the processing is still going on
|
|
if (!closing)
|
|
{
|
|
return IASRequestThread(this) ? TRUE : FALSE;
|
|
}
|
|
else
|
|
{
|
|
SetEvent(idle);
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
UDPSocket::UDPSocket() throw ()
|
|
: receiver(NULL),
|
|
sock(INVALID_SOCKET),
|
|
closing(FALSE),
|
|
idle(NULL)
|
|
{
|
|
CallbackRoutine = startRoutine;
|
|
}
|
|
|
|
UDPSocket::~UDPSocket() throw ()
|
|
{
|
|
if (idle) { CloseHandle(idle); }
|
|
if (sock != INVALID_SOCKET) { closesocket(sock); }
|
|
}
|
|
|
|
BOOL UDPSocket::open(
|
|
PacketReceiver* sink,
|
|
ULONG_PTR recvKey,
|
|
const SOCKADDR_IN* address
|
|
) throw ()
|
|
{
|
|
receiver = sink;
|
|
key = recvKey;
|
|
|
|
if (address)
|
|
{
|
|
localAddress = *address;
|
|
}
|
|
|
|
sock = WSASocket(
|
|
AF_INET,
|
|
SOCK_DGRAM,
|
|
0,
|
|
NULL,
|
|
0,
|
|
WSA_FLAG_OVERLAPPED
|
|
);
|
|
if (sock == INVALID_SOCKET) { return FALSE; }
|
|
|
|
int error = bind(
|
|
sock,
|
|
localAddress,
|
|
sizeof(localAddress)
|
|
);
|
|
if (error) { return FALSE; }
|
|
|
|
idle = CreateEventW(
|
|
NULL,
|
|
TRUE,
|
|
FALSE,
|
|
NULL
|
|
);
|
|
if (!idle) { return FALSE; }
|
|
|
|
BOOL threadCreated = createReceiveThread();
|
|
if (!threadCreated)
|
|
{
|
|
SetEvent(idle);
|
|
}
|
|
return threadCreated;
|
|
}
|
|
|
|
void UDPSocket::close() throw ()
|
|
{
|
|
if (sock != INVALID_SOCKET)
|
|
{
|
|
closing = TRUE;
|
|
|
|
closesocket(sock);
|
|
sock = INVALID_SOCKET;
|
|
|
|
WaitForSingleObject(idle, INFINITE);
|
|
}
|
|
|
|
if (idle)
|
|
{
|
|
CloseHandle(idle);
|
|
idle = NULL;
|
|
}
|
|
}
|
|
|
|
BOOL UDPSocket::send(
|
|
const SOCKADDR_IN& to,
|
|
const BYTE* buf,
|
|
ULONG buflen
|
|
) throw ()
|
|
{
|
|
WSABUF wsabuf = { buflen, (CHAR*)buf };
|
|
ULONG bytesSent;
|
|
return !WSASendTo(
|
|
sock,
|
|
&wsabuf,
|
|
1,
|
|
&bytesSent,
|
|
0,
|
|
(const SOCKADDR*)&to,
|
|
sizeof(to),
|
|
NULL,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
bool UDPSocket::receive() throw ()
|
|
{
|
|
// Return value from the function. Indicates whether or not the caller
|
|
// should call UDPSocket::receive() again
|
|
bool shouldCallAgain = false;
|
|
WSABUF wsabuf = { sizeof(buffer), (CHAR*)buffer };
|
|
ULONG bytesReceived;
|
|
ULONG flags = 0;
|
|
SOCKADDR_IN remoteAddress;
|
|
int remoteAddressLength;
|
|
remoteAddressLength = sizeof(remoteAddress);
|
|
|
|
int error = WSARecvFrom(
|
|
sock,
|
|
&wsabuf,
|
|
1,
|
|
&bytesReceived,
|
|
&flags,
|
|
(SOCKADDR*)&remoteAddress,
|
|
&remoteAddressLength,
|
|
NULL,
|
|
NULL
|
|
);
|
|
if (error)
|
|
{
|
|
error = WSAGetLastError();
|
|
switch (error)
|
|
{
|
|
case WSAECONNRESET:
|
|
{
|
|
shouldCallAgain = true;
|
|
break;
|
|
}
|
|
case WSAENOBUFS:
|
|
{
|
|
shouldCallAgain = true;
|
|
Sleep(5);
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
// Don't report errors while closing.
|
|
if (!closing)
|
|
{
|
|
receiver->onReceiveError(*this, key, error);
|
|
}
|
|
|
|
// There's no point getting another thread if the socket's no good, so
|
|
// we'll just exit.
|
|
SetEvent(idle);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Save the buffer locally.
|
|
PBYTE packet = (PBYTE)_alloca(bytesReceived);
|
|
memcpy(packet, buffer, bytesReceived);
|
|
|
|
// Get a replacement. Reuse the current thread if the allocation
|
|
// of the new one failed
|
|
shouldCallAgain = (createReceiveThread()? false : true);
|
|
|
|
// Invoke the callback.
|
|
receiver->onReceive(*this, key, remoteAddress, packet, bytesReceived);
|
|
}
|
|
|
|
return shouldCallAgain;
|
|
}
|
|
|
|
void UDPSocket::startRoutine(PIAS_CALLBACK This) throw ()
|
|
{
|
|
UDPSocket* receiveSocket = static_cast<UDPSocket*>(This);
|
|
while (receiveSocket->receive())
|
|
{
|
|
}
|
|
}
|