WINSOCK Socket operation on non-socket
Here is the Class Method (all methods and vars are declared public) NOTE: DiscoverWinsockLib does the WSAStartup stuff and I know that part works. It also does a LoadLibrary and finds the DLLs entry points for the functions below, renamed with lpfn_ prefix.
No matter what I do, I can't seem to resolve why I get the error condition of socket operation on non-socket in the Thread.
Any help is greatly appreciated.
bool __fastcall TRANSPORT::Establish (const char *host, int port, int timeout)
{
bool rFlag;
int rval;
rFlag = false;
DiscoverWinsockLib();
if( WSH )
{
hostEntry = gethostbyname(host);
if( !hostEntry )
{
LastErrorCode = lpfn_WSAGetLastError();
lpfn_WSACleanup();
SetErrorMsg();
}
else
{
CSocket = lpfn_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (CSocket == INVALID_SOCKET)
{
LastErrorCode = lpfn_WSAGetLastError();
SetErrorMsg();
lpfn_WSACleanup();
}
else
{
RxDataBuf.len = RXDATA_BUFSIZE;
RxDataBuf.buf = RxBuffer;
RxOverlapped.hEvent = lpfn_WSACreateEvent();
if(RxOverlapped.hEvent == WSA_INVALID_EVENT)
{
LastErrorCode = lpfn_WSAGetLastError();
SetErrorMsg();
SocketShutdown();
//lpfn_closesocket(CSocket);
}
else
{
if(lpfn_WSAEventSelect(CSocket, RxOverlapped.hEvent, FD_ALL_EVENTS) == SOCKET_ERROR)
{
LastErrorCode = lpfn_WSAGetLastError();
SetErrorMsg();
lpfn_closesocket(CSocket);
lpfn_WSACloseEvent(RxOverlapped.hEvent);
}
else
{
hThreadIO = CreateThread(0, 0, ProcessEvents, (void *)this, 0, &ThreadID);
// Try to connect to the server
serverInfo.sin_family = AF_INET;
serverInfo.sin_addr = *((LPIN_ADDR)*hostEntry->h_addr_list);
serverInfo.sin_port = htons(port);
if( lpfn_connect(CSocket, (LPSOCKADDR)&serverInfo, sizeof(struct sockaddr)) == SOCKET_ERROR )
{
LastErrorCode = lpfn_WSAGetLastError();
if( LastErrorCode != WSAEWOULDBLOCK )
{
SetErrorMsg();
SocketShutdown();
}
else
rFlag = true;
}
else
rFlag = true;
}
}
}
}
}
return(rFlag);
}
And here is the Thread referenced above:
DWORD WINAPI ProcessEvents(void *pParam)
{
TRANSPORT *T;
WSANETWORKEVENTS NetEvents;
DWORD EIndex;
DWORD rc;
bool Failure;
T = (TRANSPORT *)pParam;
Failure = false;
do
{
EIndex = T->lpfn_WSAWaitForMultipleEvents( 1, &T->RxOverlapp开发者_C百科ed.hEvent, false, 3000, true );
if( EIndex == WSA_WAIT_FAILED )
{
T->LastErrorCode = T->lpfn_WSAGetLastError();
T->SetErrorMsg();
Failure = true;
}
if( EIndex == WSA_WAIT_TIMEOUT )
{
if( T->OnConnectTimeout )
T->OnConnectTimeout(T);
Failure = true;
}
}while( EIndex != WAIT_IO_COMPLETION && !Failure );
if( Failure )
return(EIndex);
// Get the event(s) that occurred and their associated error array
if(T->lpfn_WSAEnumNetworkEvents(T->CSocket, T->RxOverlapped.hEvent, &NetEvents) == SOCKET_ERROR)
{
T->LastErrorCode = T->lpfn_WSAGetLastError();
T->SetErrorMsg();
return(EIndex);
}
// =================================================================
// Code above fetches the event that woke this thread up
// Code below deals with the events as they are detected
// =================================================================
if( NetEvents.lNetworkEvents & FD_CONNECT )
{
if( T->OnConnect )
T->OnConnect(T);
T->lpfn_WSAResetEvent(T->RxOverlapped.hEvent);
}
else if( ( NetEvents.lNetworkEvents & FD_READ) )
{
rc = T->lpfn_WSARecv(T->CSocket, &T->RxDataBuf, 1, &T->RxBytes, &T->Flags, &T->RxOverlapped, NULL);
EIndex = T->lpfn_WSAGetLastError();
if( (rc == SOCKET_ERROR) && (EIndex != WSA_IO_PENDING || EIndex != WSAEWOULDBLOCK ) )
{
T->LastErrorCode = EIndex;
T->SetErrorMsg();
}
else
{
rc = T->lpfn_WSAWaitForMultipleEvents(1, &T->RxOverlapped.hEvent, true, INFINITE, true);
if(rc == WSA_WAIT_FAILED)
{
T->LastErrorCode = T->lpfn_WSAGetLastError();
T->SetErrorMsg();
}
else
{
rc = T->lpfn_WSAGetOverlappedResult(T->CSocket, &T->RxOverlapped, &T->RxBytes, false, &T->Flags);
if(!rc)
{
T->LastErrorCode = T->lpfn_WSAGetLastError();
T->SetErrorMsg();
}
else
{
if( T->RxBytes > 0 && T->OnReceive )
T->OnReceive(T);
T->lpfn_WSAResetEvent(T->RxOverlapped.hEvent);
}
}
}
}
return(rc);
}
** UPDATE ** I'm finding that the call to EIndex = T->lpfn_WSAWaitForMultipleEvents( 1, &T->RxOverlapped.hEvent, false, 3000, true ); inside the Thread function is returning WSA_WAIT_FAILED
And if I disable the thread function and check the return value of lpfn_WSAWaitForMultipleEvents, outside the thread, right after the connect call, I get a valid return value of WSAEWOULDBLOCK.
Thinking I might have a problem taking the address-of from inside the thread, I changed the thread code to read as follows:
DWORD WINAPI ProcessEvents(void *pParam)
{
...
WSAEVENT events[1];
T = (TRANSPORT *)pParam;
Failure = false;
do
{
events[0] = T->RxOverlapped.hEvent;
EIndex = T->lpfn_WSAWaitForMultipleEvents( 1, events, false, 3000, true );
....
and I still cannot manage to make WSAWaitForMultipleEvents happy!
any thoughts/suggestions on this?
If connect() fails, you are calling SocketShutdown()
. Presumably, it closes the socket (you did not show that code), but does it terminate the thread first if it is running? Otherwise, you could be closing the socket behind the thread's back.
精彩评论