/////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 2000, Microsoft Corp. All rights reserved. // // FILE // // udpsock.cpp // // SYNOPSIS // // Defines the class UDPSocket. // // MODIFICATION HISTORY // // 02/06/2000 Original version. // /////////////////////////////////////////////////////////////////////////////// #include #include #include 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(This); while (receiveSocket->receive()) { } }