Win32 CreateThread() Arguments Zero'ed? - c++

Situation
Up until yesterday, my thread code was working fine. Now though, my thread arguments are being zeroed and moved as they are passed into the thread.
Relevant code in main.cpp
//First socket: UDP | Second Socket: TCP
std::pair<SOCKET, SOCKET> ServerSockets = Network::Operations::Server();
SOCKET UDPSocket = ServerSockets.first;
//Need to pass two arguments to the thread, when it only accepts one pointer. So create a struct and send the pointer.
ListenData UDPServ;
UDPServ.pNetwork = &Network;
UDPServ.LocalUDPSocket = UDPSocket;
//Set up the listener.
HANDLE UDPListener = Network::Operations::UDPListen(UDPServ);
At this stage UDPSocket is the correct value (e.g. 103), and pNetwork is also correct.
Relevant code in UDPListen()
static HANDLE UDPListen(ListenData UDPListenData)
{
HANDLE NetworkThread;
NetworkThread = CreateThread(
NULL, //Default security
0, //Default thread stack size
Network::Operations::Listen, //Thread function name
&UDPListenData, //Thread arguments
0, //Default creation flags
NULL);
//CloseHandle(NetworkThread);
return NetworkThread;
}
At this state, the values are as they should be.
Relevant code in Listen()
static DWORD WINAPI Listen(void *param)
{
ListenData *UDPServ = (ListenData*)param;
SOCKET Socket = UDPServ->LocalUDPSocket;
std::vector<Net> *Network = UDPServ->pNetwork;
Now however, UDPSocket is zero, and pNetwork is 103. This is a mystery.
The only code I've really changed is the code to initialise the server, which I modified to incorporate binding a TCP socket. The function used to return a single SOCKET but now returns an std::pair<SOCKET, SOCKET>.

you pass pointer to local data in stack - &UDPListenData - but this data is become undefined just after UDPListen return. you may be need code like
ListenData* UDPServ = new ListenData;
// init UDPServ
HANDLE NetworkThread = CreateThread(
NULL, //Default security
0, //Default thread stack size
Network::Operations::Listen, //Thread function name
UDPServ, //Thread arguments
0, //Default creation flags
NULL);
if (!NetworkThread) delete UDPServ;
//...
static DWORD WINAPI Listen(void *param)
{
ListenData *UDPServ = (ListenData*)param;
SOCKET Socket = UDPServ->LocalUDPSocket;
std::vector<Net> *Network = UDPServ->pNetwork;
//...
delete UDPServ;
}

Related

Passing data to another thread in a C++ winsock app

So I have this winsock application (a server, able to accept multiple clients), where in the main thread I setup the socket and create another thread where I listen for clients (listen_for_clients function).
I also constantly receive data from a device in the main thread, which I afterwards concatenate to char arrays (buffers) of Client objects (BroadcastSample function). Currently I create a thread for each connected client (ProcessClient function), where I initialize a Client object and push it to a global vector of clients after which I send data to this client through the socket whenever the buffer in the corresponding Client object exceeds 4000 characters.
Is there a way I can send data from the main thread to the separate client threads so I don't have to use structs/classes (also to send a green light if I want to send the already accumulated data) and also if I'm going to keep a global container of objects, what is a good way to remove a disconnected client object from it without crashing the program because another thread is using the same container?
struct Client{
int buffer_len;
char current_buffer[5000];
SOCKET s;
};
std::vector<Client*> clientBuffers;
DWORD WINAPI listen_for_clients(LPVOID Param)
{
SOCKET client;
sockaddr_in from;
int fromlen = sizeof(from);
char buf[100];
while(true)
{
client = accept(ListenSocket,(struct sockaddr*)&from,&fromlen);
if(client != INVALID_SOCKET)
{
printf("Client connected\n");
unsigned dwThreadId;
HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, &ProcessClient, (void*)client, 0, &dwThreadId);
}
}
closesocket(ListenSocket);
WSACleanup();
ExitThread(0);
}
unsigned __stdcall ProcessClient(void *data)
{
SOCKET ClientSocket = (SOCKET)data;
Client * a = new Client();
a->current_buffer[0] = '\0';
a->buffer_len = 0;
a->s = ClientSocket;
clientBuffers.push_back(a);
char szBuffer[255];
while(true)
{
if(a->buffer_len > 4000)
{
send(ClientSocket,a->current_buffer,sizeof(a->current_buffer),0);
memset(a->current_buffer,0,5000);
a->buffer_len = 0;
a->current_buffer[0] = '\0';
}
}
exit(1);
}
//function below is called only in main thread, about every 100ms
void BroadcastSample(Sample s)
{
for(std::vector<Client*>::iterator it = clientBuffers.begin(); it != clientBuffers.end(); it++)
{
strcat((*it)->current_buffer,s.to_string);
(*it)->buffer_len += strlen(s.to_string);
}
}
This link has some Microsoft documentation on MS-style mutexes (muticies?).
This other link has some general info on mutexes.
Mutexes are the general mechanism for protecting data which is accessed by multiple threads. There are data structures with built-in thread safety, but in my experience, they usually have caveats that you'll eventually miss. That's just my two cents.
Also, for the record, you shouldn't use strcat, but rather strncat. Also, if one of your client servicing threads accesses one of those buffers after strncat overwrites the old '\0' but before it appends the new one, you'll have a buffer overread (read past end of allocated buffer).
Mutexes will also solve your current busy-waiting problem. I'm not currently near a windows compiler, or I'd try to help more.

WinSock2 IOCP WSARecv GetQueuedCompletionStatus: data (automatically) ends up in char*buffer, not WSABUF.buf...why?

While debugging, when WSARecv is called, I supply the function with the address of the PerIoData->WSABUF structure. This should assign the sent data to the WSABUF.buf char* array, which it seems to. When The worker thread loops back to the waiting GetQueuedCompletionStatus, it seems to somehow (magically) send that data to PerIoData.Buffer (char* array). So essentially, the PerIoData.Buffer and PerIoData.WSABUF.buf both equal the same char* array. When I remove the PerIoData.Buffer from the PER_IO_DATA Struct (and all references to it), the GetQueuedCompletionStaus never returns when the client sends data though i know the WSABUF.buf should be populated with data.
The pertinent information:
I'm implementing the Completion Port Model found in "Network Programming for Microsoft Windows" (p.157). Though the examples in that book left much to be independently discovered, my code works fine now.
In the while loop of the ServerWorkerThread: GetQueuedCompletionStatus , called first, receives per_handle_data, and per_io_data
per_io_data struct is as such:
struct _PER_IO_DATA{ //in the interests of an efficient question, i'm omitting the
//constructor/destructor code
public:
OVERLAPPED Overlapped;
WSABUF DataBuf;
char myBuffer[BUFFER_LENGTH];
int BufferLen;
int OperationType;
};
typedef _PER_IO_DATA PER_IO_DATA;
typedef _PER_IO_DATA *PPER_IO_DATA;
My GetQueuedCompletionStatus function is called like so:
ret = GetQueuedCompletionStatus(CompletionPort,
&BytesTransferred,
(LPDWORD)&PerHandleData,
(LPOVERLAPPED *)&PerIoData,
INFINITE);
My WSARecv Function is called like so:
WSARecv(PerHandleData->Socket, &(PerIoData->DataBuf), 1, NULL, &Flags, ((LPWSAOVERLAPPED)&PerIoData->Overlapped), NULL);
//i know casting the Overlapped structure as LPWSAOVERLAPPED is unnecessary, but I was tweaking the
//code when I didn't fully understand the problems I was having.
My problem is that I never explicitly assign anything to the PerIoData->Buffer yet it seems to always get populated with the sent data. I'm lead to believe GetQueuedCompletionStatus "knows" to send this data to that PerIoData->Buffer though it's expecting a pointer to a LPOVERLAPPED structure (to which i pass my PerIoData struct instance containing the Buffer char array in question). It's really bugging me... Maybe it's not behaving like I'm thinking it is, but the only place I can see the PerIoData->Buffer being populated is from within the GetQueuedCompletionStatus method. If that's not the case, then PerIoData->Buffer seems to be populated from nowhere? I've scoured MSDN and google for days. I'll continue looking and if I find the answer I'll post an update. Please Help? Thanks in advance!
*Note: I would've created the tags WSABUF and GetQueuedCompletionStatus, but this is my first post.
--EDIT: I'm posting the structs and worker thread, leaving out all other unrelated code.--
You'll notice that _PER_IO_DATA::DataBuf.buf is allocated memory, then zeroed out. Not pointing to the myBuffer array....
#include "stdafx.h"
#define SEND_POSTED 1
#define RECV_POSTED 2
#define BUFFER_LENGTH 1024
HANDLE CompletionPort;
SOCKADDR_IN serverAddress, *clientAddress;
SOCKET listener, client;
unsigned short port = 5000;
SYSTEM_INFO SystemInfo;
int i;
struct _PER_HANDLE_DATA{//Per handle data structure
SOCKET Socket;
SOCKADDR_STORAGE Address;
_PER_HANDLE_DATA(){
Socket = 0;
ZeroMemory(&Address, sizeof(SOCKADDR_STORAGE));
}
~_PER_HANDLE_DATA(){
Socket = NULL;
ZeroMemory(&Address, sizeof(SOCKADDR_STORAGE));
}
};typedef _PER_HANDLE_DATA PER_HANDLE_DATA;typedef _PER_HANDLE_DATA *PPER_HANDLE_DATA;
struct _PER_IO_DATA{
public:
OVERLAPPED Overlapped;
WSABUF DataBuf;
char myBuffer[BUFFER_LENGTH];
int BufferLen;
int OperationType;
_PER_IO_DATA(){
OperationType = 0;
DataBuf.len = BUFFER_LENGTH;
DataBuf.buf = (char*)malloc(BUFFER_LENGTH+1);
BufferLen = BUFFER_LENGTH;
ZeroMemory(DataBuf.buf, (sizeof(BUFFER_LENGTH+1)));
ZeroMemory(&myBuffer, (sizeof(char)*BUFFER_LENGTH));
SecureZeroMemory((PVOID)&Overlapped, sizeof(Overlapped));
}
~_PER_IO_DATA(){
free(&DataBuf.buf);
}
};
typedef _PER_IO_DATA PER_IO_DATA;
typedef _PER_IO_DATA *PPER_IO_DATA;
unsigned _stdcall ServerWorkerThread(LPVOID CompletionPortID);
int _tmain(int argc, _TCHAR* argv[])
{
/*
INITIALIZE WINSOCK AND COMPLETION PORT, AND ACCEPT CONNECTIONS
*/
}
unsigned _stdcall ServerWorkerThread(LPVOID CompletionPortID){
printf("ServerWorkerThread(%d) Working\n", GetCurrentThreadId());
HANDLE CompletionPort = (HANDLE) CompletionPortID;
DWORD BytesTransferred;
PPER_HANDLE_DATA PerHandleData = new PER_HANDLE_DATA;
PPER_IO_DATA PerIoData = new PER_IO_DATA;
DWORD SendBytes = 0, RecvBytes = 0;
DWORD Flags;
BOOL ret;
Sleep(2000);
while(TRUE){
ret = GetQueuedCompletionStatus(CompletionPort,
&BytesTransferred,
(LPDWORD)&PerHandleData,
(LPOVERLAPPED *)&PerIoData,
INFINITE);
//printf("\n\nBytesTransferred: %d\n\n", BytesTransferred);
if(BytesTransferred == 0 && (PerIoData->OperationType == RECV_POSTED || PerIoData->OperationType == SEND_POSTED)){
closesocket(PerHandleData->Socket);
GlobalFree(PerHandleData);
GlobalFree(PerIoData);
continue;
}
if(PerIoData->OperationType == RECV_POSTED){
//output received data
if(!strcmp(PerIoData->DataBuf.buf, "Disconnect") || !strcmp(PerIoData->DataBuf.buf, "disconnect")){
printf("Disconnecting...\n");
if(!shutdown(PerHandleData->Socket, SD_BOTH)){
closesocket(PerHandleData->Socket);
delete(PerHandleData);
}
}else{
printf("RECV_POSTED: %s\n", PerIoData->DataBuf.buf);
}
}
Flags = 0;
SecureZeroMemory((PVOID)&PerIoData->Overlapped, sizeof(WSAOVERLAPPED));
PerIoData->DataBuf.len = BUFFER_LENGTH;
//***************************************************************************
//Even though the following is commented out, PerIoData->DataBuf.buf
//is still being populated and so is PerIoData-myBuffer
//So why is myBuffer being populated with data when DataBuf.buf is not pointing to it??
//PerIoData->DataBuf.buf = PerIoData->myBuffer;
//Also, if you comment out all references of myBuffer, GetQueuedCompletionStatus(),
//will never return if myBuffer doesn't exist...how does it seem to be 'aware' of myBuffer?
//***************************************************************************
PerIoData->OperationType = RECV_POSTED;
WSARecv(PerHandleData->Socket, &(PerIoData->DataBuf), 1, NULL, &Flags, ((LPWSAOVERLAPPED)&PerIoData->Overlapped), NULL);
}
return 0;
}

Why would an Overlapped call to recv return ERROR_NO_MORE_ITEMS(259)?

I did a few tests with an I/O-Completion port and winsock sockets.
I encountered, that sometimes after I received data from a connection and then adjacently call WSARecv again on that socket it returns immediately with the error 259 (ERROR_NO_MORE_ITEMS).
I am wondering why the system flags the overlapped transaction with this error instead of keeping the recv call blocking/waiting for incoming data.
Do You know what´s the sense of this ?
I would be glad to hear about your thoughts.
Edit: Code
do
{
OVERLAPPED* pOverlapped = nullptr;
DWORD dwBytes = 0; ULONG_PTR ulKey = 0;
//Dequeue a completion packet
if(!m_pIOCP->GetCompletionStatus(&dwBytes, &ulKey, &pOverlapped, INFINITE))
DebugBreak();
//Evaluate
switch(((MYOVERLAPPED*)pOverlapped)->WorkType)
{
case ACCEPT_OVERLAPPED_TYPE:
{
//cast
ACCEPT_OVERLAPPED* pAccept = (ACCEPT_OVERLAPPED*)pOverlapped;
//Associate the newly accepted connection with the IOCP
if(!m_pIOCP->AssociateHandle((HANDLE)(pAccept->pSockClient)->operator SOCKET(), 1))
{
//Association failed: close the socket and and delte the overlapped strucuture
}
//Call recv
RECV_OVERLAPPED* pRecvAction = new RECV_OVERLAPPED;
pRecvAction->pSockClient = pAccept->pSockClient;
short s = (pRecvAction->pSockClient)->Recv(pRecvAction->strBuf, pRecvAction->pWSABuf, 10, pRecvAction);
if(s == Inc::REMOTECONNECTION_CLOSED)
{
//Error stuff
}
//Call accept again (create a new ACCEPT_OVERLAPPED to ensure overlapped being zeroed out)
ACCEPT_OVERLAPPED *pNewAccept = new ACCEPT_OVERLAPPED;
pNewAccept->pSockListen = pAccept->pSockListen;
pNewAccept->pSockClient = new Inc::CSocket((pNewAccept->pSockListen)->Accept(nullptr, nullptr, pNewAccept));
//delete the old overlapped struct
delete pAccept;
}
break;
case RECV_OVERLAPPED_TYPE:
{
RECV_OVERLAPPED* pOldRecvAction = (RECV_OVERLAPPED*)pOverlapped;
if(!pOldRecvAction->InternalHigh)
{
//Connection has been closed: delete the socket(implicitly closes the socket)
Inc::CSocket::freewsabuf(pOldRecvAction->pWSABuf); //free the wsabuf
delete pOldRecvAction->pSockClient;
}
else
{
//Call recv again (create a new RECV_OVERLAPPED)
RECV_OVERLAPPED* pNewRecvAction = new RECV_OVERLAPPED;
pNewRecvAction->pSockClient = pOldRecvAction->pSockClient;
short sRet2 = (pNewRecvAction->pSockClient)->Recv(pNewRecvAction->strBuf, pNewRecvAction->pWSABuf, 10, pNewRecvAction);
//Free the old wsabuf
Inc::CSocket::freewsabuf(pOldRecvAction->pWSABuf);
delete pOldRecvAction;
}
Cutted error checkings...
The Recv-member-function is a simple wrapper around the WSARecv-call which creates the WSABUF and the receiving buffer itself (which needs to be cleaned up by the user via freewsabuf - just to mention)...
It looks like I was sending less data than was requested by the receiving side.
But since it´s an overlapped operation receiving a small junk of the requested bunch via the TCP-connection would trigger the completion indication with the error ERROR_NO_MORE_ITEMS, meaning there was nothing more to recv than what it already had.

_beginthreadx and socket

i have a question about the _beginthreadx function In the third and fourth parameter:
if i have this line to create the thread
hThread=(HANDLE)_beginthreadex(0,0, &RunThread, &m_socket,CREATE_SUSPENDED,&threadID );
m_socket is the socket that i want inside the thread (fourth parameter)
and i have the RunThread function (third parameter) in this way
static unsigned __stdcall RunThread (void* ptr) {
return 0;
}
It is sufficient to create the thread independently if m_socket has something or not?
Thanks in advance
Thank you for the response Ciaran Keating helped me understand better the thread
I'll explain a little more the situation
I´m creating the tread in this function inside a class
public: void getClientsConnection()
{
numberOfClients = 1;
SOCKET temporalSocket = NULL;
firstClient = NULL;
secondClient = NULL;
while (numberOfClients < 2)
{
temporalSocket = SOCKET_ERROR;
while (temporalSocket == SOCKET_ERROR)
{
temporalSocket = accept(m_socket, NULL, NULL);
//-----------------------------------------------
HANDLE hThread;
unsigned threadID;
hThread=(HANDLE)_beginthreadex(0,0, &RunThread, &m_socket,CREATE_SUSPENDED,&threadID );
WaitForSingleObject( hThread, INFINITE );
if(!hThread)
printf("ERROR AL CREAR EL HILO: %ld\n", WSAGetLastError());
//-----------------------------------------------
}
if(firstClient == NULL)
{
firstClient = temporalSocket;
muebleC1 = temporalSocket;
actionC1 = temporalSocket;
++numberOfClients;
printf("CLIENTE 1 CONECTADO\n");
}
else
{
secondClient = temporalSocket;
muebleC2 = temporalSocket;
actionC2 = temporalSocket;
++numberOfClients;
printf("CLIENTE 2 CONECTADO\n");
}
}
}
What i'm trying to do is to have the socket inside the thread while wait for a client connection
Is this feasible as i have the code of the thread?
I can change the state of the thread that is not a problem
Thanks again
Yes, that will create the thread and pass it your socket handle. But by returning immediately from RunThread your new thread will terminate immediately after you resume it (you've created it suspended.) You'll need to put your socket handling code (read/write loop etc.) inside RunThread.
Some more tips:
You'll have to make sure that m_socket remains valid for the life of the thread, because you passed it by reference. You might prefer to pass it by value instead, and let ownership pass to the new thread, but of course in that case it probably wouldn't belong in your object instance (I infer from the m_ prefix.) Or you might prefer to leave the socket handle in the object instance, and pass a reference to the object to beginthread instead:
beginthread(...,&RunThread,this,...);
(With your new info, I can see that my other answer isn't what you need.)
If I understand you right, you just want to wait on the accept() call until a client connects. You don't need threads for that - there are native sockets ways to do it. One option is to make m_socket a blocking socket, so accept() doesn't return until a client connects. An easier way is to use the select() function to wait until the socket is ready to read, which in the case of a listening socket means that a client has connected.
fd_set fds;
FD_ZERO(&fds);
FD_SET(m_socket,&fds);
int ret = select(0,&fds,NULL,NULL,NULL); // will block
if(FD_ISSET(m_socket,&fds))
temporalSocket = accept(...);

How to pass user-defined data to a worker thread using IOCP?

Hey... I created a small test server using I/O completion ports and winsock.
I can successfully connect and associate a socket handle with the completion port.
But I don´t know how to pass user-defined data-structures into the wroker thread...
What I´ve tried so far was passing a user-structure as (ULONG_PTR)&structure as the Completion Key in the association-call of CreateIoCompletionPort()
But that did not work.
Now I tried defining my own OVERLAPPED-structure and using CONTAINING_RECORD() as described here http://msdn.microsoft.com/en-us/magazine/cc302334.aspx and http://msdn.microsoft.com/en-us/magazine/bb985148.aspx.
But that does not work, too. (I get freaky values for the contents of pHelper)
So my Question is: How can I pass data to the worker thread using WSARecv(), GetQueuedCompletionStatus() and the Completion packet or the OVERLAPPED-strucutre?
EDIT: How can I successfully transmit "per-connection-data"?... It seems like I got the art of doing it (like explained in the two links above) wrong.
Here goes my code: (Yes, its ugly and its only TEST-code)
struct helper
{
SOCKET m_sock;
unsigned int m_key;
OVERLAPPED over;
};
///////
SOCKET newSock = INVALID_SOCKET;
WSABUF wsabuffer;
char cbuf[250];
wsabuffer.buf = cbuf;
wsabuffer.len = 250;
DWORD flags, bytesrecvd;
while(true)
{
newSock = accept(AcceptorSock, NULL, NULL);
if(newSock == INVALID_SOCKET)
ErrorAbort("could not accept a connection");
//associate socket with the CP
if(CreateIoCompletionPort((HANDLE)newSock, hCompletionPort, 3,0) != hCompletionPort)
ErrorAbort("Wrong port associated with the connection");
else
cout << "New Connection made and associated\n";
helper* pHelper = new helper;
pHelper->m_key = 3;
pHelper->m_sock = newSock;
memset(&(pHelper->over), 0, sizeof(OVERLAPPED));
flags = 0;
bytesrecvd = 0;
if(WSARecv(newSock, &wsabuffer, 1, NULL, &flags, (OVERLAPPED*)pHelper, NULL) != 0)
{
if(WSAGetLastError() != WSA_IO_PENDING)
ErrorAbort("WSARecv didnt work");
}
}
//Cleanup
CloseHandle(hCompletionPort);
cin.get();
return 0;
}
DWORD WINAPI ThreadProc(HANDLE h)
{
DWORD dwNumberOfBytes = 0;
OVERLAPPED* pOver = nullptr;
helper* pHelper = nullptr;
WSABUF RecvBuf;
char cBuffer[250];
RecvBuf.buf = cBuffer;
RecvBuf.len = 250;
DWORD dwRecvBytes = 0;
DWORD dwFlags = 0;
ULONG_PTR Key = 0;
GetQueuedCompletionStatus(h, &dwNumberOfBytes, &Key, &pOver, INFINITE);
//Extract helper
pHelper = (helper*)CONTAINING_RECORD(pOver, helper, over);
cout << "Received Overlapped item" << endl;
if(WSARecv(pHelper->m_sock, &RecvBuf, 1, &dwRecvBytes, &dwFlags, pOver, NULL) != 0)
cout << "Could not receive data\n";
else
cout << "Data Received: " << RecvBuf.buf << endl;
ExitThread(0);
}
If you pass your struct like this it should work just fine:
helper* pHelper = new helper;
CreateIoCompletionPort((HANDLE)newSock, hCompletionPort, (ULONG_PTR)pHelper,0);
...
helper* pHelper=NULL;
GetQueuedCompletionStatus(h, &dwNumberOfBytes, (PULONG_PTR)&pHelper, &pOver, INFINITE);
Edit to add per IO data:
One of the frequently abused features of the asynchronous apis is they don't copy the OVERLAPPED struct, they simply use the provided one - hence the overlapped struct returned from GetQueuedCompletionStatus points to the originally provided struct. So:
struct helper {
OVERLAPPED m_over;
SOCKET m_socket;
UINT m_key;
};
if(WSARecv(newSock, &wsabuffer, 1, NULL, &flags, &pHelper->m_over, NULL) != 0)
Notice that, again, in your original sample, you were getting your casting wrong. (OVERLAPPED*)pHelper was passing a pointer to the START of the helper struct, but the OVERLAPPED part was declared last. I changed it to pass the address of the actual overlapped part, which means that the code compiles without a cast, which lets us know we are doing the correct thing. I also moved the overlapped struct to be the first member of the struct.
To catch the data on the other side:
OVERLAPPED* pOver;
ULONG_PTR key;
if(GetQueuedCompletionStatus(h,&dw,&key,&pOver,INFINITE))
{
// c cast
helper* pConnData = (helper*)pOver;
On this side it is particularly important that the overlapped struct is the first member of the helper struct, as that makes it easy to cast back from the OVERLAPPED* the api gives us, and the helper* we actually want.
You can send special-purpose data of your own to the completion port via PostQueuedCompletionStatus.
The I/O completion packet will satisfy
an outstanding call to the
GetQueuedCompletionStatus function.
This function returns with the three
values passed as the second, third,
and fourth parameters of the call to
PostQueuedCompletionStatus. The system
does not use or validate these values.
In particular, the lpOverlapped
parameter need not point to an
OVERLAPPED structure.
I use the standard socket routines (socket, closesocket, bind, accept, connect ...) for creating/destroying and ReadFile/WriteFile for I/O as they allow use of the OVERLAPPED structure.
After your socket has accepted or connected you should associate it with the session context that it services. Then you associate your socket to an IOCP and (in the third parameter) provide it with a reference to the session context. The IOCP does not know what this reference is and doesn't care either for that matter. The reference is for YOUR use so that when you get an IOC through GetQueuedCompletionStatus the variable pointed to by parameter 3 will be filled in with the reference so that you immediately find the context associated with the socket event and can begin servicing the event. I usually use an indexed structure containing (among other things) the socket declaration, the overlapped structure as well as other session-specific data. The reference I pass to CreateIoCompletionPort in parameter 3 will be the index to the structure member containing the socket.
You need to check if GetQueuedCompletionStatus returned a completion or a timeout. With a timeout you can run through your indexed structure and see (for example) if one of them has timed out or something else and take appropriate house-keeping actions.
The overlapped structure also needs to be checked to see that the I/O completed correctly.
The function servicing the IOCP should be a separate, multi-threaded entity. Use the same number of threads that you have cores in your system, or at least no more than that as it wastes system resources (you don't have more resources for servicing the event than the number of cores in your system, right?).
IOCPs really are the best of all worlds (too good to be true) and anyone who says "one thread per socket" or "wait on multiple-socket list in one function" don't know what they are talking about. The former stresses your scheduler and the latter is polling and polling is ALWAYS extremely wasteful.