841 lines
20 KiB
C++
841 lines
20 KiB
C++
|
#include <rrcm.h>
|
|||
|
#include <queue.h>
|
|||
|
// Forward declarations
|
|||
|
DWORD WINAPI WS1MsgThread (LPVOID );
|
|||
|
LRESULT CALLBACK WS1WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
|||
|
BOOL StartWS1MsgThread();
|
|||
|
BOOL StopWS1MsgThread();
|
|||
|
void __stdcall SendRecvCompleteAPC(ULONG_PTR dw);
|
|||
|
|
|||
|
class CWS2EmulSock;
|
|||
|
|
|||
|
#define WM_WSA_READWRITE (WM_USER + 100)
|
|||
|
// structure used to store WSASendTo/WSARecvFrom parameters
|
|||
|
struct WSAIOREQUEST {
|
|||
|
WSAOVERLAPPED *pOverlapped;
|
|||
|
WSABUF wsabuf[2];
|
|||
|
DWORD dwBufCount;
|
|||
|
union {
|
|||
|
struct {
|
|||
|
struct sockaddr *pRecvFromAddr;
|
|||
|
LPINT pRecvFromLen;
|
|||
|
};
|
|||
|
struct sockaddr SendToAddr;
|
|||
|
};
|
|||
|
};
|
|||
|
|
|||
|
// global Winsock emulation state
|
|||
|
struct WS2Emul {
|
|||
|
#define MAX_EMUL_SOCKETS 10
|
|||
|
CWS2EmulSock *m_pEmulSocks[MAX_EMUL_SOCKETS];
|
|||
|
int numSockets;
|
|||
|
HWND hWnd;
|
|||
|
HANDLE hMsgThread;
|
|||
|
HANDLE hAckEvent;
|
|||
|
// external crit sect serializes the WS2EmulXX apis
|
|||
|
// to make them multi-thread safe
|
|||
|
CRITICAL_SECTION extcs;
|
|||
|
// internal crit sect serializes access between
|
|||
|
// MsgThread and WS2EmulXX apis
|
|||
|
// Never claim extcs while holding intcs.
|
|||
|
// (Is there a more elegant way to do this?)
|
|||
|
CRITICAL_SECTION intcs;
|
|||
|
|
|||
|
} g_WS2Emul;
|
|||
|
|
|||
|
/*
|
|||
|
CWS2EmulSock -
|
|||
|
WS2 socket emulation class
|
|||
|
Manages queues of overlapped i/o requests
|
|||
|
*/
|
|||
|
|
|||
|
class CWS2EmulSock
|
|||
|
{
|
|||
|
public:
|
|||
|
CWS2EmulSock(int myIndex) : m_myIndex(myIndex), m_RecvThreadId(0),m_SendThreadId(0),
|
|||
|
m_hRecvThread(NULL), m_hSendThread(NULL), m_sock(INVALID_SOCKET)
|
|||
|
{ ZeroMemory(&m_SendOverlapped, sizeof(m_SendOverlapped));}
|
|||
|
;
|
|||
|
BOOL NewSock(int af, int type, int protocol);
|
|||
|
int Close();
|
|||
|
int RecvFrom(
|
|||
|
LPWSABUF lpBuffers,DWORD dwBufferCount, LPDWORD lpNumberOfBytesRecvd, LPDWORD lpFlags,
|
|||
|
struct sockaddr FAR * lpFrom, LPINT lpFromlen,
|
|||
|
LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);
|
|||
|
int SendTo(
|
|||
|
LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesSent,DWORD dwFlags,
|
|||
|
const struct sockaddr FAR * lpTo, int iTolen,
|
|||
|
LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);
|
|||
|
|
|||
|
LRESULT HandleMessage(WPARAM wParam, LPARAM lParam); // WS1 window msg handler
|
|||
|
SOCKET GetSocket() { return m_sock;}
|
|||
|
WSAOVERLAPPED *GetSendOverlapped() {return &m_SendOverlapped;}
|
|||
|
private:
|
|||
|
SOCKET m_sock; // real socket handle
|
|||
|
int m_myIndex; // fake socket handle
|
|||
|
QueueOf<WSAIOREQUEST> m_RecvQ; // queue of overlapped recv requests
|
|||
|
QueueOf<WSAIOREQUEST> m_SendQ; // queue of overlapped send requests
|
|||
|
WSAOVERLAPPED m_SendOverlapped; // used only for synchronous send calls
|
|||
|
// the following fields are used to issue Send/Recv APCs
|
|||
|
DWORD m_RecvThreadId;
|
|||
|
DWORD m_SendThreadId;
|
|||
|
HANDLE m_hRecvThread; // thread issuing receive requests
|
|||
|
HANDLE m_hSendThread; // thread issuing send requests
|
|||
|
};
|
|||
|
|
|||
|
void WS2EmulInit()
|
|||
|
{
|
|||
|
InitializeCriticalSection(&g_WS2Emul.extcs);
|
|||
|
InitializeCriticalSection(&g_WS2Emul.intcs);
|
|||
|
}
|
|||
|
|
|||
|
void WS2EmulTerminate()
|
|||
|
{
|
|||
|
DeleteCriticalSection(&g_WS2Emul.extcs);
|
|||
|
DeleteCriticalSection(&g_WS2Emul.intcs);
|
|||
|
}
|
|||
|
|
|||
|
BOOL
|
|||
|
CWS2EmulSock::NewSock(int af,int type, int protocol)
|
|||
|
{
|
|||
|
m_sock = socket(af,type,protocol);
|
|||
|
if (m_sock != INVALID_SOCKET)
|
|||
|
{
|
|||
|
WSAAsyncSelect(m_sock, g_WS2Emul.hWnd, WM_WSA_READWRITE+m_myIndex, FD_READ|FD_WRITE);
|
|||
|
}
|
|||
|
return m_sock != INVALID_SOCKET;
|
|||
|
}
|
|||
|
|
|||
|
int
|
|||
|
CWS2EmulSock::RecvFrom(
|
|||
|
LPWSABUF lpBuffers,
|
|||
|
DWORD dwBufferCount,
|
|||
|
LPDWORD lpNumberOfBytesRecvd,
|
|||
|
LPDWORD lpFlags,
|
|||
|
struct sockaddr FAR * lpFrom,
|
|||
|
LPINT lpFromlen,
|
|||
|
LPWSAOVERLAPPED lpOverlapped,
|
|||
|
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
|
|||
|
{
|
|||
|
WSAIOREQUEST ioreq;
|
|||
|
int error = 0;
|
|||
|
|
|||
|
if (lpCompletionRoutine) {
|
|||
|
DWORD thid = GetCurrentThreadId();
|
|||
|
HANDLE hCurProcess;
|
|||
|
if (thid != m_RecvThreadId) {
|
|||
|
// need to create a thread handle for QueueUserAPC
|
|||
|
// typically this will only happen once
|
|||
|
if (!m_RecvQ.IsEmpty())
|
|||
|
{
|
|||
|
// dont allow simultaneous recv access by more than one thread
|
|||
|
error = WSAEINVAL;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (m_hRecvThread)
|
|||
|
CloseHandle(m_hRecvThread);
|
|||
|
m_hRecvThread = NULL;
|
|||
|
|
|||
|
hCurProcess = GetCurrentProcess();
|
|||
|
m_RecvThreadId = thid;
|
|||
|
if (!DuplicateHandle(
|
|||
|
|
|||
|
hCurProcess, // handle to process with handle to duplicate
|
|||
|
GetCurrentThread(), // handle to duplicate
|
|||
|
hCurProcess, // handle to process to duplicate to
|
|||
|
&m_hRecvThread, // pointer to duplicate handle
|
|||
|
0, // access for duplicate handle
|
|||
|
FALSE, // handle inheritance flag
|
|||
|
DUPLICATE_SAME_ACCESS // optional actions
|
|||
|
))
|
|||
|
{
|
|||
|
error = WSAEINVAL;
|
|||
|
m_RecvThreadId = 0;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
if (error || dwBufferCount != 1 || !lpOverlapped)
|
|||
|
{
|
|||
|
WSASetLastError(WSAENOBUFS);
|
|||
|
return SOCKET_ERROR;
|
|||
|
}
|
|||
|
|
|||
|
ioreq.pOverlapped = lpOverlapped;
|
|||
|
if (lpOverlapped) // cache away ptr to completion routine
|
|||
|
lpOverlapped->Pointer = lpCompletionRoutine;
|
|||
|
ioreq.pRecvFromAddr = lpFrom;
|
|||
|
ioreq.pRecvFromLen = lpFromlen;
|
|||
|
ioreq.wsabuf[0] = lpBuffers[0];
|
|||
|
ioreq.dwBufCount = dwBufferCount;
|
|||
|
|
|||
|
m_RecvQ.Put(ioreq);
|
|||
|
//LOG((LOGMSG_RECVFROM1,(UINT)lpOverlapped));
|
|||
|
// signal WS1 send/recv thread
|
|||
|
PostMessage(g_WS2Emul.hWnd, WM_WSA_READWRITE+m_myIndex, m_sock, FD_READ);
|
|||
|
|
|||
|
WSASetLastError(ERROR_IO_PENDING);
|
|||
|
return SOCKET_ERROR;
|
|||
|
}
|
|||
|
|
|||
|
int CWS2EmulSock::SendTo(
|
|||
|
LPWSABUF lpBuffers,
|
|||
|
DWORD dwBufferCount,
|
|||
|
LPDWORD lpNumberOfBytesSent,
|
|||
|
DWORD dwFlags,
|
|||
|
const struct sockaddr FAR * lpTo,
|
|||
|
int iTolen,
|
|||
|
LPWSAOVERLAPPED lpOverlapped,
|
|||
|
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
|
|||
|
{
|
|||
|
WSAIOREQUEST ioreq;
|
|||
|
int error = 0;
|
|||
|
|
|||
|
if (lpCompletionRoutine) {
|
|||
|
DWORD thid = GetCurrentThreadId();
|
|||
|
HANDLE hCurProcess;
|
|||
|
if (thid != m_SendThreadId) {
|
|||
|
// need to create a thread handle for QueueUserAPC
|
|||
|
if (!m_SendQ.IsEmpty())
|
|||
|
{
|
|||
|
// dont allow simultaneous send access by more than one thread
|
|||
|
error = WSAEINVAL;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (m_hSendThread)
|
|||
|
CloseHandle(m_hSendThread);
|
|||
|
m_hSendThread = NULL;
|
|||
|
|
|||
|
hCurProcess = GetCurrentProcess();
|
|||
|
m_SendThreadId = thid;
|
|||
|
if (!DuplicateHandle(
|
|||
|
|
|||
|
hCurProcess, // handle to process with handle to duplicate
|
|||
|
GetCurrentThread(), // handle to duplicate
|
|||
|
hCurProcess, // handle to process to duplicate to
|
|||
|
&m_hSendThread, // pointer to duplicate handle
|
|||
|
0, // access for duplicate handle
|
|||
|
FALSE, // handle inheritance flag
|
|||
|
DUPLICATE_SAME_ACCESS // optional actions
|
|||
|
))
|
|||
|
{
|
|||
|
error = WSAEINVAL;
|
|||
|
m_SendThreadId = 0;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
if (error || dwBufferCount != 1 || iTolen != sizeof(struct sockaddr) || !lpOverlapped)
|
|||
|
{
|
|||
|
WSASetLastError(WSAEINVAL);
|
|||
|
return SOCKET_ERROR;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
ioreq.pOverlapped = lpOverlapped;
|
|||
|
if (lpOverlapped) // cache away ptr to completion routine
|
|||
|
lpOverlapped->Pointer = lpCompletionRoutine;
|
|||
|
ioreq.SendToAddr = *lpTo;
|
|||
|
ioreq.wsabuf[0] = lpBuffers[0];
|
|||
|
ioreq.dwBufCount = dwBufferCount;
|
|||
|
|
|||
|
m_SendQ.Put(ioreq);
|
|||
|
// signal WS1 send/recv thread
|
|||
|
PostMessage(g_WS2Emul.hWnd, WM_WSA_READWRITE+m_myIndex, m_sock, FD_WRITE);
|
|||
|
|
|||
|
WSASetLastError(ERROR_IO_PENDING);
|
|||
|
return SOCKET_ERROR;
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
Close - close the socket and cancel pending i/o
|
|||
|
*/
|
|||
|
int
|
|||
|
CWS2EmulSock::Close()
|
|||
|
{
|
|||
|
WSAIOREQUEST ioreq;
|
|||
|
int status;
|
|||
|
|
|||
|
status = closesocket(m_sock);
|
|||
|
m_sock = NULL;
|
|||
|
while (m_SendQ.Get(&ioreq))
|
|||
|
{
|
|||
|
// complete the request
|
|||
|
ioreq.pOverlapped->Internal = WSA_OPERATION_ABORTED;
|
|||
|
// if there is a callback routine, its address is cached in pOverlapped->Offset
|
|||
|
if (ioreq.pOverlapped->Pointer)
|
|||
|
{
|
|||
|
QueueUserAPC(SendRecvCompleteAPC,m_hSendThread,(DWORD_PTR)ioreq.pOverlapped);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
SetEvent((HANDLE)ioreq.pOverlapped->hEvent);
|
|||
|
}
|
|||
|
}
|
|||
|
while (m_RecvQ.Get(&ioreq))
|
|||
|
{
|
|||
|
// complete the request
|
|||
|
ioreq.pOverlapped->Internal = WSA_OPERATION_ABORTED;
|
|||
|
if (ioreq.pOverlapped->Pointer)
|
|||
|
{
|
|||
|
QueueUserAPC(SendRecvCompleteAPC,m_hRecvThread,(DWORD_PTR)ioreq.pOverlapped);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
SetEvent((HANDLE)ioreq.pOverlapped->hEvent);
|
|||
|
}
|
|||
|
}
|
|||
|
if (m_hSendThread)
|
|||
|
{
|
|||
|
CloseHandle(m_hSendThread);
|
|||
|
m_hSendThread = NULL;
|
|||
|
}
|
|||
|
if (m_hRecvThread)
|
|||
|
{
|
|||
|
CloseHandle(m_hRecvThread);
|
|||
|
m_hRecvThread = NULL;
|
|||
|
}
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
LRESULT
|
|||
|
CWS2EmulSock::HandleMessage(WPARAM sock, LPARAM lParam)
|
|||
|
{
|
|||
|
WORD wEvent= (WSAGETSELECTEVENT(lParam));
|
|||
|
WORD wError= (WSAGETSELECTERROR(lParam));
|
|||
|
int iRet;
|
|||
|
int status;
|
|||
|
WSAIOREQUEST ioreq;
|
|||
|
HANDLE hThread;
|
|||
|
// make sure the message is intended for this socket
|
|||
|
if ((SOCKET) sock != m_sock)
|
|||
|
return 0;
|
|||
|
|
|||
|
// get the first RecvFrom or SendTo request, but leave it on the queue
|
|||
|
// in case the request blocks
|
|||
|
//if (wEvent == FD_READ)
|
|||
|
// LOG((LOGMSG_ONREAD1, (UINT)sock));
|
|||
|
|
|||
|
if (wEvent == FD_READ && m_RecvQ.Peek(&ioreq))
|
|||
|
{
|
|||
|
//LOG((LOGMSG_ONREAD2, (UINT)ioreq.pOverlapped));
|
|||
|
iRet = recvfrom(m_sock, ioreq.wsabuf[0].buf, ioreq.wsabuf[0].len, 0, ioreq.pRecvFromAddr, ioreq.pRecvFromLen);
|
|||
|
}
|
|||
|
else if (wEvent == FD_WRITE && m_SendQ.Peek(&ioreq))
|
|||
|
{
|
|||
|
iRet = sendto(m_sock, ioreq.wsabuf[0].buf, ioreq.wsabuf[0].len, 0, &ioreq.SendToAddr, sizeof(ioreq.SendToAddr));
|
|||
|
}
|
|||
|
else // some other event or no queued request
|
|||
|
return 1;
|
|||
|
|
|||
|
// complete send and recv
|
|||
|
|
|||
|
if(iRet >=0)
|
|||
|
{
|
|||
|
status = 0;
|
|||
|
ioreq.pOverlapped->InternalHigh = iRet; // numBytesReceived
|
|||
|
|
|||
|
} else {
|
|||
|
// error (or "would block") case falls out here
|
|||
|
ASSERT(iRet == SOCKET_ERROR);
|
|||
|
status = WSAGetLastError();
|
|||
|
ioreq.pOverlapped->InternalHigh = 0;
|
|||
|
}
|
|||
|
// check the error - it could be blocking
|
|||
|
if (status != WSAEWOULDBLOCK)
|
|||
|
{
|
|||
|
ioreq.pOverlapped->Internal = status;
|
|||
|
// pull request off the queue
|
|||
|
if (wEvent == FD_READ)
|
|||
|
{
|
|||
|
m_RecvQ.Get(NULL);
|
|||
|
hThread = m_hRecvThread;
|
|||
|
//LOG((LOGMSG_ONREADDONE1, (UINT)ioreq.pOverlapped));
|
|||
|
}
|
|||
|
else // wEvent == FD_WRITE
|
|||
|
{
|
|||
|
m_SendQ.Get(NULL);
|
|||
|
hThread = m_hSendThread;
|
|||
|
}
|
|||
|
|
|||
|
// complete the request
|
|||
|
if (ioreq.pOverlapped->Pointer)
|
|||
|
{
|
|||
|
// if there is a callback routine, its address is cached in pOverlapped->Offset
|
|||
|
QueueUserAPC(SendRecvCompleteAPC,hThread, (DWORD_PTR)ioreq.pOverlapped);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
SetEvent((HANDLE)ioreq.pOverlapped->hEvent);
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
return 1;
|
|||
|
}
|
|||
|
|
|||
|
void __stdcall
|
|||
|
SendRecvCompleteAPC(ULONG_PTR dw)
|
|||
|
{
|
|||
|
WSAOVERLAPPED *pOverlapped = (WSAOVERLAPPED *)dw;
|
|||
|
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
|
|||
|
= (LPWSAOVERLAPPED_COMPLETION_ROUTINE) pOverlapped->Pointer;
|
|||
|
|
|||
|
//LOG((LOGMSG_RECVFROM2,(UINT)pOverlapped));
|
|||
|
lpCompletionRoutine((DWORD)pOverlapped->Internal, (DWORD)pOverlapped->InternalHigh, pOverlapped, 0);
|
|||
|
}
|
|||
|
|
|||
|
inline
|
|||
|
CWS2EmulSock *
|
|||
|
EmulSockFromSocket(SOCKET s)
|
|||
|
{
|
|||
|
return ( ((UINT) s < MAX_EMUL_SOCKETS) ? g_WS2Emul.m_pEmulSocks[s] : NULL);
|
|||
|
}
|
|||
|
|
|||
|
inline SOCKET MapSocket(SOCKET s)
|
|||
|
{
|
|||
|
return (((UINT) s < MAX_EMUL_SOCKETS) && g_WS2Emul.m_pEmulSocks[s] ? g_WS2Emul.m_pEmulSocks[s]->GetSocket() : INVALID_SOCKET);
|
|||
|
}
|
|||
|
|
|||
|
SOCKET
|
|||
|
PASCAL
|
|||
|
WS2EmulSocket(
|
|||
|
int af,
|
|||
|
int type,
|
|||
|
int protocol,
|
|||
|
LPWSAPROTOCOL_INFO lpProtocolInfo,
|
|||
|
GROUP,
|
|||
|
DWORD)
|
|||
|
{
|
|||
|
SOCKET s = INVALID_SOCKET;
|
|||
|
int i;
|
|||
|
CWS2EmulSock *pESock;
|
|||
|
if (g_WS2Emul.numSockets == MAX_EMUL_SOCKETS)
|
|||
|
return s;
|
|||
|
|
|||
|
EnterCriticalSection(&g_WS2Emul.extcs);
|
|||
|
if (af == FROM_PROTOCOL_INFO)
|
|||
|
af = lpProtocolInfo->iAddressFamily;
|
|||
|
if (type == FROM_PROTOCOL_INFO)
|
|||
|
type = lpProtocolInfo->iSocketType;
|
|||
|
if (protocol == FROM_PROTOCOL_INFO)
|
|||
|
protocol = lpProtocolInfo->iProtocol;
|
|||
|
|
|||
|
for (i=0;i<MAX_EMUL_SOCKETS;i++)
|
|||
|
{
|
|||
|
if (g_WS2Emul.m_pEmulSocks[i] == NULL)
|
|||
|
{
|
|||
|
pESock = new CWS2EmulSock(i);
|
|||
|
if (pESock) {
|
|||
|
if (++g_WS2Emul.numSockets == 1)
|
|||
|
{
|
|||
|
StartWS1MsgThread();
|
|||
|
}
|
|||
|
if (pESock->NewSock(af,type,protocol))
|
|||
|
{
|
|||
|
g_WS2Emul.m_pEmulSocks[i] = pESock;
|
|||
|
s = (SOCKET)i;
|
|||
|
} else {
|
|||
|
delete pESock;
|
|||
|
if (--g_WS2Emul.numSockets == 0)
|
|||
|
{
|
|||
|
StopWS1MsgThread();
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
LeaveCriticalSection(&g_WS2Emul.extcs);
|
|||
|
return s;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
int
|
|||
|
PASCAL
|
|||
|
WS2EmulRecvFrom(
|
|||
|
SOCKET s,
|
|||
|
LPWSABUF lpBuffers,
|
|||
|
DWORD dwBufferCount,
|
|||
|
LPDWORD lpNumberOfBytesRecvd,
|
|||
|
LPDWORD lpFlags,
|
|||
|
struct sockaddr FAR * lpFrom,
|
|||
|
LPINT lpFromlen,
|
|||
|
LPWSAOVERLAPPED lpOverlapped,
|
|||
|
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
|
|||
|
)
|
|||
|
{
|
|||
|
CWS2EmulSock *pESock;
|
|||
|
int iret;
|
|||
|
EnterCriticalSection(&g_WS2Emul.extcs);
|
|||
|
|
|||
|
if (pESock = EmulSockFromSocket(s))
|
|||
|
{
|
|||
|
EnterCriticalSection(&g_WS2Emul.intcs);
|
|||
|
iret = pESock->RecvFrom(lpBuffers, dwBufferCount, lpNumberOfBytesRecvd,
|
|||
|
lpFlags,
|
|||
|
lpFrom, lpFromlen,
|
|||
|
lpOverlapped, lpCompletionRoutine);
|
|||
|
LeaveCriticalSection(&g_WS2Emul.intcs);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
WSASetLastError(WSAENOTSOCK);
|
|||
|
iret = SOCKET_ERROR;
|
|||
|
}
|
|||
|
LeaveCriticalSection(&g_WS2Emul.extcs);
|
|||
|
|
|||
|
return iret;
|
|||
|
}
|
|||
|
/*----------------------------------------------------------------------------
|
|||
|
* Function: WS2EmulSendCB
|
|||
|
* Description: private Winsock callback
|
|||
|
* This is only called if WS2EmulSendTo is called in synchronous mode
|
|||
|
* (i.e.) lpOverlapped == NULL. In that case, the sync call is converted to async
|
|||
|
* using a private Overlapped struct, and the WS2EmulSendTo api blocks until
|
|||
|
* this routine sets the hEvent field to TRUE;
|
|||
|
* Input:
|
|||
|
*
|
|||
|
* Return: None
|
|||
|
*--------------------------------------------------------------------------*/
|
|||
|
void CALLBACK WS2EmulSendCB (DWORD dwError,
|
|||
|
DWORD cbTransferred,
|
|||
|
LPWSAOVERLAPPED lpOverlapped,
|
|||
|
DWORD dwFlags)
|
|||
|
{
|
|||
|
lpOverlapped->Internal = dwError;
|
|||
|
lpOverlapped->InternalHigh = cbTransferred;
|
|||
|
lpOverlapped->hEvent = (WSAEVENT) TRUE;
|
|||
|
}
|
|||
|
|
|||
|
int
|
|||
|
PASCAL
|
|||
|
WS2EmulSendTo(
|
|||
|
SOCKET s,
|
|||
|
LPWSABUF lpBuffers,
|
|||
|
DWORD dwBufferCount,
|
|||
|
LPDWORD lpNumberOfBytesSent,
|
|||
|
DWORD dwFlags,
|
|||
|
const struct sockaddr FAR * lpTo,
|
|||
|
int iTolen,
|
|||
|
LPWSAOVERLAPPED lpOverlapped,
|
|||
|
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
|
|||
|
)
|
|||
|
{
|
|||
|
CWS2EmulSock *pESock;
|
|||
|
int iret;
|
|||
|
BOOL fSync = FALSE;
|
|||
|
|
|||
|
EnterCriticalSection(&g_WS2Emul.extcs);
|
|||
|
if (pESock = EmulSockFromSocket(s))
|
|||
|
{
|
|||
|
if (!lpOverlapped)
|
|||
|
{
|
|||
|
// synchronous call - we use our own overlapped struct to issue the
|
|||
|
// send request.
|
|||
|
lpOverlapped = pESock->GetSendOverlapped();
|
|||
|
lpOverlapped->hEvent = (WSAEVENT) FALSE; // will be set to TRUE in Callback
|
|||
|
lpCompletionRoutine = &WS2EmulSendCB;
|
|||
|
fSync = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
EnterCriticalSection(&g_WS2Emul.intcs);
|
|||
|
iret = pESock->SendTo(lpBuffers, dwBufferCount, lpNumberOfBytesSent,
|
|||
|
dwFlags,
|
|||
|
lpTo, iTolen,
|
|||
|
lpOverlapped, lpCompletionRoutine);
|
|||
|
LeaveCriticalSection(&g_WS2Emul.intcs);
|
|||
|
|
|||
|
if (fSync) {
|
|||
|
DWORD dwError;
|
|||
|
if (iret == SOCKET_ERROR)
|
|||
|
{
|
|||
|
dwError = WSAGetLastError();
|
|||
|
if (dwError != WSA_IO_PENDING) {
|
|||
|
// there was an error so there will not be a callback
|
|||
|
lpOverlapped->hEvent = (WSAEVENT) TRUE;
|
|||
|
lpOverlapped->Internal = dwError;
|
|||
|
}
|
|||
|
}
|
|||
|
// wait for the call to complete
|
|||
|
// WS2EmulSendCB sets the hEvent field to TRUE and sets the Internal field to
|
|||
|
// the completion status
|
|||
|
while (!lpOverlapped->hEvent)
|
|||
|
{
|
|||
|
dwError =SleepEx(5000,TRUE); // WARNING: sleeping inside a Critical Section
|
|||
|
ASSERT(dwError == WAIT_IO_COMPLETION);
|
|||
|
}
|
|||
|
WSASetLastError((int)lpOverlapped->Internal);
|
|||
|
if (lpNumberOfBytesSent)
|
|||
|
*lpNumberOfBytesSent = (DWORD)lpOverlapped->InternalHigh;
|
|||
|
iret = lpOverlapped->Internal ? SOCKET_ERROR : 0;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
WSASetLastError(WSAENOTSOCK);
|
|||
|
iret = SOCKET_ERROR;
|
|||
|
}
|
|||
|
LeaveCriticalSection(&g_WS2Emul.extcs);
|
|||
|
return iret;
|
|||
|
}
|
|||
|
|
|||
|
int
|
|||
|
PASCAL
|
|||
|
WS2EmulCloseSocket(SOCKET s)
|
|||
|
{
|
|||
|
CWS2EmulSock *pESock;
|
|||
|
int iret;
|
|||
|
EnterCriticalSection(&g_WS2Emul.extcs);
|
|||
|
|
|||
|
if (pESock = EmulSockFromSocket(s))
|
|||
|
{
|
|||
|
// shut out access to this socket
|
|||
|
// by the MsgThread
|
|||
|
EnterCriticalSection(&g_WS2Emul.intcs);
|
|||
|
g_WS2Emul.m_pEmulSocks[s] = NULL;
|
|||
|
pESock->Close();
|
|||
|
delete pESock;
|
|||
|
LeaveCriticalSection(&g_WS2Emul.intcs);
|
|||
|
if (--g_WS2Emul.numSockets == 0)
|
|||
|
{
|
|||
|
// cant stop the thread with while holding intcs
|
|||
|
StopWS1MsgThread();
|
|||
|
}
|
|||
|
|
|||
|
iret = 0;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
WSASetLastError(WSAENOTSOCK);
|
|||
|
iret = SOCKET_ERROR;
|
|||
|
}
|
|||
|
LeaveCriticalSection(&g_WS2Emul.extcs);
|
|||
|
return iret;
|
|||
|
}
|
|||
|
|
|||
|
int
|
|||
|
PASCAL
|
|||
|
WS2EmulSetSockOpt(
|
|||
|
SOCKET s, int level,int optname,const char FAR * optval,int optlen)
|
|||
|
{
|
|||
|
return setsockopt(MapSocket(s), level, optname, optval, optlen);
|
|||
|
}
|
|||
|
|
|||
|
int
|
|||
|
PASCAL
|
|||
|
WS2EmulBind( SOCKET s, const struct sockaddr FAR * name, int namelen)
|
|||
|
{
|
|||
|
return bind(MapSocket(s), name, namelen);
|
|||
|
}
|
|||
|
|
|||
|
int
|
|||
|
PASCAL
|
|||
|
WS2EmulGetSockName( SOCKET s,
|
|||
|
struct sockaddr * name,
|
|||
|
int * namelen )
|
|||
|
{
|
|||
|
return getsockname(MapSocket(s), name, namelen);
|
|||
|
}
|
|||
|
|
|||
|
int
|
|||
|
PASCAL
|
|||
|
WS2EmulHtonl(
|
|||
|
SOCKET s,
|
|||
|
u_long hostlong,
|
|||
|
u_long FAR * lpnetlong
|
|||
|
)
|
|||
|
{
|
|||
|
*lpnetlong = htonl(hostlong);
|
|||
|
return 0;
|
|||
|
}
|
|||
|
int
|
|||
|
PASCAL
|
|||
|
WS2EmulHtons(
|
|||
|
SOCKET s,
|
|||
|
u_short hostshort,
|
|||
|
u_short FAR * lpnetshort
|
|||
|
)
|
|||
|
{
|
|||
|
*lpnetshort = htons(hostshort);
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
int
|
|||
|
PASCAL
|
|||
|
WS2EmulNtohl(
|
|||
|
SOCKET s,
|
|||
|
u_long netlong,
|
|||
|
u_long FAR * lphostlong
|
|||
|
)
|
|||
|
{
|
|||
|
*lphostlong = ntohl(netlong);
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
int
|
|||
|
PASCAL
|
|||
|
WS2EmulNtohs(
|
|||
|
SOCKET s,
|
|||
|
u_short netshort,
|
|||
|
u_short FAR * lphostshort
|
|||
|
)
|
|||
|
{
|
|||
|
*lphostshort = ntohs(netshort);
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
int
|
|||
|
PASCAL
|
|||
|
WS2EmulGetHostName(char *name, int namelen)
|
|||
|
{
|
|||
|
return gethostname(name, namelen);
|
|||
|
}
|
|||
|
|
|||
|
struct hostent FAR *
|
|||
|
PASCAL
|
|||
|
WS2EmulGetHostByName(const char * name)
|
|||
|
{
|
|||
|
return gethostbyname(name);
|
|||
|
}
|
|||
|
|
|||
|
SOCKET
|
|||
|
PASCAL
|
|||
|
WS2EmulJoinLeaf(
|
|||
|
SOCKET s,
|
|||
|
const struct sockaddr FAR * name,
|
|||
|
int namelen,
|
|||
|
LPWSABUF lpCallerData,
|
|||
|
LPWSABUF lpCalleeData,
|
|||
|
LPQOS lpSQOS,
|
|||
|
LPQOS lpGQOS,
|
|||
|
DWORD dwFlags
|
|||
|
)
|
|||
|
{
|
|||
|
ASSERT(0);
|
|||
|
return (-1);
|
|||
|
}
|
|||
|
|
|||
|
int
|
|||
|
PASCAL
|
|||
|
WS2EmulIoctl(SOCKET s, DWORD dwIoControlCode, LPVOID lpvInBuffer,
|
|||
|
DWORD cbInBuffer, LPVOID lpvOutBuffer, DWORD cbOutBuffer,
|
|||
|
LPDWORD lpcbBytesReturned, LPWSAOVERLAPPED, LPWSAOVERLAPPED_COMPLETION_ROUTINE
|
|||
|
)
|
|||
|
|
|||
|
{
|
|||
|
ASSERT(0);
|
|||
|
return -1;
|
|||
|
}
|
|||
|
|
|||
|
BOOL StartWS1MsgThread()
|
|||
|
{
|
|||
|
DWORD threadId;
|
|||
|
DWORD dwStatus;
|
|||
|
ASSERT(g_WS2Emul.hMsgThread == 0);
|
|||
|
g_WS2Emul.hAckEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
|
|||
|
g_WS2Emul.hMsgThread = CreateThread(NULL,0, WS1MsgThread, 0, 0, &threadId);
|
|||
|
dwStatus = WaitForSingleObject(g_WS2Emul.hAckEvent,INFINITE);
|
|||
|
return dwStatus == WAIT_OBJECT_0;
|
|||
|
}
|
|||
|
|
|||
|
BOOL StopWS1MsgThread()
|
|||
|
{
|
|||
|
if (g_WS2Emul.hMsgThread && g_WS2Emul.hWnd)
|
|||
|
{
|
|||
|
PostMessage(g_WS2Emul.hWnd, WM_CLOSE, 0, 0);
|
|||
|
WaitForSingleObject(g_WS2Emul.hMsgThread,INFINITE);
|
|||
|
CloseHandle(g_WS2Emul.hMsgThread);
|
|||
|
CloseHandle(g_WS2Emul.hAckEvent);
|
|||
|
g_WS2Emul.hMsgThread = NULL;
|
|||
|
g_WS2Emul.hAckEvent = NULL;
|
|||
|
}
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
LRESULT CALLBACK WS1WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|||
|
{
|
|||
|
int i;
|
|||
|
CWS2EmulSock *pESock;
|
|||
|
EnterCriticalSection(&g_WS2Emul.intcs);
|
|||
|
|
|||
|
if (pESock = EmulSockFromSocket(msg - WM_WSA_READWRITE))
|
|||
|
{
|
|||
|
|
|||
|
LRESULT l = pESock->HandleMessage(wParam, lParam);
|
|||
|
LeaveCriticalSection(&g_WS2Emul.intcs);
|
|||
|
return l;
|
|||
|
}
|
|||
|
LeaveCriticalSection(&g_WS2Emul.intcs);
|
|||
|
if (msg == WM_DESTROY)
|
|||
|
PostQuitMessage(0);
|
|||
|
|
|||
|
return (DefWindowProc(hWnd, msg, wParam, lParam));
|
|||
|
}
|
|||
|
|
|||
|
DWORD WINAPI WS1MsgThread (LPVOID )
|
|||
|
{
|
|||
|
|
|||
|
HRESULT hr;
|
|||
|
BOOL fChange = FALSE;
|
|||
|
MSG msg;
|
|||
|
|
|||
|
// Register hidden window class:
|
|||
|
WNDCLASS wcHidden =
|
|||
|
{
|
|||
|
0L,
|
|||
|
WS1WindowProc,
|
|||
|
0,
|
|||
|
0,
|
|||
|
GetModuleHandle(NULL),
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
"WS1EmulWindowClass"
|
|||
|
};
|
|||
|
if (RegisterClass(&wcHidden)) {
|
|||
|
// Create hidden window
|
|||
|
// Create a hidden window for event processing:
|
|||
|
g_WS2Emul.hWnd = ::CreateWindow( "WS1EmulWindowClass",
|
|||
|
"",
|
|||
|
WS_POPUP, // not visible!
|
|||
|
0, 0, 0, 0,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
GetModuleHandle(NULL),
|
|||
|
NULL);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if(!g_WS2Emul.hWnd)
|
|||
|
{
|
|||
|
hr = GetLastError();
|
|||
|
goto CLEANUPEXIT;
|
|||
|
}
|
|||
|
//SetThreadPriority(m_hRecvThread, THREAD_PRIORITY_ABOVE_NORMAL);
|
|||
|
|
|||
|
// This function is guaranteed to create a queue on this thread
|
|||
|
PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
|
|||
|
|
|||
|
// notify thread creator that we're ready to recv messages
|
|||
|
SetEvent(g_WS2Emul.hAckEvent);
|
|||
|
|
|||
|
|
|||
|
// Wait for control messages or Winsock messages directed to
|
|||
|
// our hidden window
|
|||
|
while (GetMessage(&msg, NULL, 0, 0)) {
|
|||
|
TranslateMessage(&msg);
|
|||
|
DispatchMessage(&msg);
|
|||
|
}
|
|||
|
g_WS2Emul.hWnd = NULL;
|
|||
|
hr = S_OK;
|
|||
|
|
|||
|
CLEANUPEXIT:
|
|||
|
UnregisterClass("WS1EmulWindowClass",GetModuleHandle(NULL));
|
|||
|
SetEvent(g_WS2Emul.hAckEvent);
|
|||
|
return hr;
|
|||
|
}
|
|||
|
|