Anyways, the problem I am having is that AcceptEx is not adding a message to the IOCP queue when a client tries to connect to it. When I attempt to connect to the server via the telnet client packaged with Windows, I still do not receive any messages. I made sure that the initial calls to AcceptEx are successful, and although it does return FALSE, WSAGetLastError() yields the value of WSA_IO_PENDING, which, to my understanding, is a good value.
I am not exactly certain whether this is due to a bug in the API, or me just misusing the API (likely the latter), but I cannot find any more information on the matter.
In advance, brace yourselves. This example has been hacked together in hopes of at least getting something on screen. I cut out the seemingly irrelevant parts of the code.
I'm running Windows 7. I hope I have provided enough information.
void LoadFunctions(SOCKET listen){ GUID accept_ex_guid = WSAID_ACCEPTEX; GUID get_accept_ex_sockaddrs_guid = WSAID_GETACCEPTEXSOCKADDRS; int result; DWORD bytes; result = WSAIoctl(listen, SIO_GET_EXTENSION_FUNCTION_POINTER, &accept_ex_guid, sizeof(GUID), &accept_ex, sizeof(LPFN_ACCEPTEX), &bytes, nullptr, nullptr); assert(result != SOCKET_ERROR); result = WSAIoctl(listen, SIO_GET_EXTENSION_FUNCTION_POINTER, &get_accept_ex_sockaddrs_guid, sizeof(GUID), &get_accept_ex_sockaddrs, sizeof(LPFN_GETACCEPTEXSOCKADDRS), &bytes, nullptr, nullptr); assert(result != SOCKET_ERROR);}std::deque<SOCKET> clients;int main(int argc, char** argv){ SOCKET listen_socket; std::vector<std::thread> threads; std::vector<HANDLE> ports; for(size_t i = 0; i < NUM_THREADS; i++) threads.push_back(std::thread(WorkerThread, nullptr)); Network::Initialize(); listen_socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert(listen_socket != INVALID_SOCKET); CreateListener(listen_socket); LoadFunctions(listen_socket); iocp_handle = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, nullptr, 0, NUM_THREADS); assert(iocp_handle); while(true) { BOOL result = FALSE; assert(listen(listen_socket, 256) == 0); while(clients.size() < 10) { context_info_t* info = new context_info_t; SOCKET client_socket = INVALID_SOCKET; int wsa_error; memset(info, 0, sizeof(context_info_t)); info->buffer.size = ARRAYSIZE(info->buffer.buffer); client_socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert(client_socket != INVALID_SOCKET); info->state = SOCKET_DISCONNECTED; info->client_socket = client_socket; info->listen_socket = listen_socket; if((result = PostAccept(info, iocp_handle))) { wsa_error = WSAGetLastError(); if(wsa_error == WSA_IO_PENDING) clients.push_back(info->client_socket); } } } for(size_t i = 0; i < NUM_THREADS; i++) threads[i].join(); CloseHandle(iocp_handle); ::shutdown(listen_socket, SD_BOTH); ::closesocket(listen_socket); Network::Shutdown(); return 0;}static bool PostAccept(context_info_t* info, HANDLE iocp_handle){ BOOL result; DWORD nb; int wsa_error; result = accept_ex(info->listen_socket, info->client_socket, &info->buffer.buffer, info->buffer.size - ((sizeof(sockaddr_in) + 16) * 2), sizeof(sockaddr_in) + 16, sizeof(sockaddr_in) + 16, &nb, &info->overlapped); wsa_error = WSAGetLastError(); if((!result) && (wsa_error != WSA_IO_PENDING)) { std::cout << "Error: " << WSAGetLastError() << std::endl; return false; } return true;}static HANDLE HandleAccept(context_info_t* info, HANDLE iocp_handle){ int result; sockaddr_in* local; sockaddr_in* remote; int locallen; int remotelen; HANDLE handle; IoEvent* io_event = new IoEvent; io_event->type = EVENT_ACCEPT; io_event->info = info; if(result == SOCKET_ERROR) { std::cout << "Network Failure - setsockopt returned SOCKET_ERROR: " << WSAGetLastError() << "\n"; abort(); } handle = CreateIoCompletionPort(reinterpret_cast<HANDLE>(info->client_socket), iocp_handle, reinterpret_cast<LONG_PTR>(io_event), NUM_THREADS); get_accept_ex_sockaddrs(info->buffer.buffer, info->buffer.size, sizeof(sockaddr_in) + 16, sizeof(sockaddr_in) + 16, reinterpret_cast<sockaddr**>(&local), &locallen, reinterpret_cast<sockaddr**>(&remote), &remotelen); std::cout << "Connecting to client at " << inet_ntoa(remote->sin_addr) << std::endl; auto& it = std::find(clients.begin(), clients.end(), info->client_socket); if(it != clients.end()) clients.erase(it); return handle;}static DWORD WINAPI WorkerThread(void* parameter){ DWORD size = 0; ULONG_PTR key = 0; OVERLAPPED* overlapped = nullptr; IoEvent* io_event = nullptr; for(;;) { BOOL status; int result; overlapped = nullptr; status = GetQueuedCompletionStatus(iocp_handle, &size, &key, &overlapped, INFINITE); io_event = reinterpret_cast<IoEvent*>(key); //assert(overlapped != nullptr); if(key == (DWORD)-1) break; if(!status) { } if(io_event) { switch(io_event->type) { case EVENT_ACCEPT: std::cout << "EVENT_ACCEPT\n"; io_event->info->state = SOCKET_ACCEPTED; result = setsockopt(io_event->info->client_socket, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, reinterpret_cast<char*>(&io_event->info->listen_socket), sizeof(SOCKET)); assert(result != SOCKET_ERROR); //HandleAccept(io_event->info, iocp_handle); break; } } delete io_event; } return 0;}