WSARecvFrom blocking - c++

For some reason when I call WSARecvFrom the function does not return until something is received.
_socket = WSASocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP, NULL, NULL, WS_OVERLAPPED);
...
sockaddr_in addr = ...
if(bind(_socket, (const sockaddr*)&addr, sizeof(addr)) != EXIT_SUCCESS) { ... }
...
HANDLE _handle = CreateIoCompletionPort((HANDLE)_socket, _ioHandle, NULL, NULL);
...
_recvOverlap->OVERLAP.hEvent = WSACreateEvent();
DWORD sz = 0, flag = 0;
return WSARecvFrom(_socket, _recvBuf, 1, &sz, &flag, (sockaddr*)_recvAddr, &_recvAddrSz, (LPWSAOVERLAPPED)_recvOverlap, NULL);

Change WS_OVERLAPPED (which as a value of 0) to WSA_FLAG_OVERLAPPED (which has a value of 1) instead. You are not creating an overlapped socket correctly, so _recvOverlap is being ignored by WSARecvFrom().

Related

WSASendMsg return error if set UDP source address

Similar to: Howto set the UDP source address on Windows It doesn't work for me. Unable to setup source port and get error:
I have created socket:
bool CUDPTransport::OpenConnection(void) {
// Create UDP socket
this->m_hSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (this->m_hSocket == INVALID_SOCKET) {
return false;
}
// Success
return true;
}
and I am able to send by UDP transport:
bool CUDPTransport::SendMessage(const CString& sBuffer, const CSyslogOptions& oSyslogOptions) {
// Convert using the local code page
CT2A sASCII(sBuffer);
// Create address
struct sockaddr_in sin;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(this->m_nPort);
sin.sin_addr.s_addr = htonl(this->m_nCollectorIPv4);
// Create buffer to send
WSABUF oBuffer;
oBuffer.buf = sASCII.m_psz;
oBuffer.len = (int)strlen(sASCII.m_psz);
// Declare
char aControlData[WSA_CMSG_SPACE(sizeof(struct in_pktinfo))];
memset(&aControlData, 0, sizeof(aControlData));
// Create a message
WSAMSG oMessage;
memset(&oMessage, 0, sizeof(oMessage));
oMessage.name = (struct sockaddr*)&sin;
oMessage.namelen = sizeof(sin);
oMessage.lpBuffers = &oBuffer;
oMessage.dwBufferCount = 1;
/* TODO: set source address
oMessage.Control.buf = (char*)&aControlData;
oMessage.Control.len = sizeof(aControlData);
// Create messge header
WSACMSGHDR* oHeader = WSA_CMSG_FIRSTHDR(&oMessage);
// memset(oHeader, 0, WSA_CMSG_SPACE(sizeof(struct in_pktinfo)));
oHeader->cmsg_level = IPPROTO_IP;
oHeader->cmsg_type = IP_PKTINFO;
oHeader->cmsg_len = WSA_CMSG_LEN(sizeof(struct in_pktinfo));
struct in_pktinfo* pktinfo = (struct in_pktinfo*)WSA_CMSG_DATA(oHeader);
pktinfo->ipi_addr.s_addr = htonl(oSyslogOptions.m_nSenderIPv4);
*/
// Declare variable
unsigned long nSentBytes = 0;
// Send an initial buffer
int nResult = WSASendMsg(this->m_hSocket, &oMessage, 0, &nSentBytes, NULL, NULL);
if (nResult == SOCKET_ERROR) {
int nErrorNo = this->getSocketLastOSErrorNo();
CString sErrorMsg = this->getSocketLastOSErrorString(nErrorNo);
closesocket(this->m_hSocket);
return false;
}
return true;
}
When I wish to set up source IP address I uncomment working with control data
bool CUDPTransport::SendMessage(const CString& sBuffer, const CSyslogOptions& oSyslogOptions) {
// Convert using the local code page
CT2A sASCII(sBuffer);
// Create address
struct sockaddr_in sin;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(this->m_nPort);
sin.sin_addr.s_addr = htonl(this->m_nCollectorIPv4);
// Create buffer to send
WSABUF oBuffer;
oBuffer.buf = sASCII.m_psz;
oBuffer.len = (int)strlen(sASCII.m_psz);
// Declare
char aControlData[WSA_CMSG_SPACE(sizeof(struct in_pktinfo))];
memset(&aControlData, 0, sizeof(aControlData));
// Create a message
WSAMSG oMessage;
memset(&oMessage, 0, sizeof(oMessage));
oMessage.name = (struct sockaddr*)&sin;
oMessage.namelen = sizeof(sin);
oMessage.lpBuffers = &oBuffer;
oMessage.dwBufferCount = 1;
oMessage.Control.buf = (char*)&aControlData;
oMessage.Control.len = sizeof(aControlData);
// Create messge header
WSACMSGHDR* oHeader = WSA_CMSG_FIRSTHDR(&oMessage);
// memset(oHeader, 0, WSA_CMSG_SPACE(sizeof(struct in_pktinfo)));
oHeader->cmsg_level = IPPROTO_IP;
oHeader->cmsg_type = IP_PKTINFO;
oHeader->cmsg_len = WSA_CMSG_LEN(sizeof(struct in_pktinfo));
struct in_pktinfo* pktinfo = (struct in_pktinfo*)WSA_CMSG_DATA(oHeader);
pktinfo->ipi_addr.s_addr = htonl(oSyslogOptions.m_nSenderIPv4);
// Declare variable
unsigned long nSentBytes = 0;
// Send an initial buffer
int nResult = WSASendMsg(this->m_hSocket, &oMessage, 0, &nSentBytes, NULL, NULL);
if (nResult == SOCKET_ERROR) {
int nErrorNo = this->getSocketLastOSErrorNo();
CString sErrorMsg = this->getSocketLastOSErrorString(nErrorNo);
closesocket(this->m_hSocket);
return false;
}
return true;
}
and get error with errno: 10022 and message: "An invalid argument was supplied". Does anybody can help me to understand the problem? Thanks!
-1.Error resolved by bind:
bool CUDPTransport::OpenConnection(void) {
// Create UDP socket
this->m_hSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (this->m_hSocket == INVALID_SOCKET) {
return false;
}
// Create source address (2130706433 = 127.0.0.1)
struct sockaddr_in sin;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = 0;
sin.sin_addr.s_addr = htonl(2130706433);
// Bind socker
int nResult = bind(this->m_hSocket, (struct sockaddr*)&sin, sizeof(sin));
if (nResult == SOCKET_ERROR) {
int nErrorNo = this->getSocketLastOSErrorNo();
CString sErrorMsg = this->getSocketLastOSErrorString(nErrorNo);
closesocket(this->m_hSocket);
return false;
}
// Success
return true;
}
-2.Send method is working fine.
bool CUDPTransport::SendMessage(const CString& sBuffer, const CSyslogOptions& oSyslogOptions) {
// Convert using the local code page
CT2A sASCII(sBuffer);
// Create address
struct sockaddr_in sin;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(this->m_nPort);
sin.sin_addr.s_addr = htonl(this->m_nCollectorIPv4);
// Create buffer to send
WSABUF oBuffer;
oBuffer.buf = sASCII.m_psz;
oBuffer.len = (int)strlen(sASCII.m_psz);
// Declare
char aControlData[WSA_CMSG_SPACE(sizeof(struct in_pktinfo))];
memset(&aControlData, 0, sizeof(aControlData));
// Create a message
WSAMSG oMessage;
memset(&oMessage, 0, sizeof(oMessage));
oMessage.name = (struct sockaddr*)&sin;
oMessage.namelen = sizeof(sin);
oMessage.lpBuffers = &oBuffer;
oMessage.dwBufferCount = 1;
oMessage.Control.buf = (char*)&aControlData;
oMessage.Control.len = sizeof(aControlData);
// Create message header
WSACMSGHDR* oHeader = WSA_CMSG_FIRSTHDR(&oMessage);
memset(oHeader, 0, WSA_CMSG_SPACE(sizeof(struct in_pktinfo)));
oHeader->cmsg_level = IPPROTO_IP;
oHeader->cmsg_type = IP_PKTINFO;
oHeader->cmsg_len = WSA_CMSG_LEN(sizeof(struct in_pktinfo));
struct in_pktinfo* pktinfo = (struct in_pktinfo*)WSA_CMSG_DATA(oHeader);
pktinfo->ipi_addr.s_addr = htonl(oSyslogOptions.m_nSenderIPv4);
// Declare variable
unsigned long nSentBytes = 0;
// Send an initial buffer
int nResult = WSASendMsg(this->m_hSocket, &oMessage, 0, &nSentBytes, NULL, NULL);
if (nResult == SOCKET_ERROR) {
int nErrorNo = this->getSocketLastOSErrorNo();
CString sErrorMsg = this->getSocketLastOSErrorString(nErrorNo);
closesocket(this->m_hSocket);
return false;
}
return true;
}
-3.But source ip address is not changed due to https://security.stackexchange.com/questions/184001/is-ip-spoofing-possible-in-windows-desktop-with-user-privileges

Setting timeout to recv function

I read from socket using recv function. I have problem when no data available for reading. My programm just stops. I found that I can set timeout using select function. But looks that timeout affects select function itself and recv that goes after select still waits uncontinuously.
fd_set set;
struct timeval timeout;
FD_ZERO(&set); /* clear the set */
FD_SET(s, &set); /* add our file descriptor to the set */
timeout.tv_sec = SOCKET_READ_TIMEOUT_SEC;
timeout.tv_usec = 0;
int rv = select(s, &set, NULL, NULL, &timeout);
if((recv_size = recv(s , rx_tmp , bufSize ,0)) == SOCKET_ERROR)
{
...
}
How to ask recv function return after some timout?
Another way to set a timeout on recv() itself without using select() is to use setsockopt() to set the socket's SO_RCVTIMEO option (on platforms that support it).
On Windows, the code would look like this:
DWORD timeout = SOCKET_READ_TIMEOUT_SEC * 1000;
setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout));
//...
recv_size = recv(s, rx_tmp, bufSize, 0);
if (recv_size == SOCKET_ERROR)
{
if (WSAGetLastError() != WSAETIMEDOUT)
//...
}
On other platforms, the code would look like this instead:
struct timeval timeout;
timeout.tv_sec = SOCKET_READ_TIMEOUT_SEC;
timeout.tv_usec = 0;
setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
//...
recv_size = recv(s, rx_tmp, bufSize, 0);
if (recv_size == -1)
{
if ((errno != EAGAIN) && (errno != EWOULDBLOCK))
//...
}
You should check return value of select. select will return 0 in case timeout expired, so you should check for error and call recv only if select returned positive value:
On success, select() and pselect() return the number of file descriptors contained in the three returned descriptor sets (that is, the total number of bits that are set in readfds, writefds, exceptfds) which may be zero if the timeout expires before anything interesting happens.
int rv = select(s + 1, &set, NULL, NULL, &timeout);
if (rv == SOCKET_ERROR)
{
// select error...
}
else if (rv == 0)
{
// timeout, socket does not have anything to read
}
else
{
// socket has something to read
recv_size = recv(s, rx_tmp, bufSize, 0);
if (recv_size == SOCKET_ERROR)
{
// read failed...
}
else if (recv_size == 0)
{
// peer disconnected...
}
else
{
// read successful...
}
}
use the FD_ISSET() macro to test whether there is data to read. If it returns false, don't do the read.
http://linux.die.net/man/3/fd_set

connecting GUI to pipeline in Qt and standard c++

My question is about linking Qt and win32 application
The problem is this:
My colleague wrote a special program which uses pipeline. This pipeline is used to send special messages to GUI. And GUI must show these messages on display. The pipe line program has a thread inside it. This thread always is running and listening to internal messages. Whenever a message received it create a new thread and this thread must comminucate with GUI and display the message, then killed (He said this routine must be followed).
This is his code for such using
DWORD WINAPI PipeThread( void* pContext )
{
BOOL fConnected = FALSE;
DWORD dwThreadId = 0;
HANDLE hPipe = INVALID_HANDLE_VALUE, hThread = NULL;
LPTSTR lpszPipename = TEXT("\\\\.\\pipe\\InterfacePipe");
SECURITY_ATTRIBUTES sa;
sa.lpSecurityDescriptor = (PSECURITY_DESCRIPTOR)malloc(SECURITY_DESCRIPTOR_MIN_LENGTH);
if (!InitializeSecurityDescriptor(sa.lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION))
{
DWORD er = ::GetLastError();
}
if (!SetSecurityDescriptorDacl(sa.lpSecurityDescriptor, TRUE, (PACL)0, FALSE))
{
DWORD er = ::GetLastError();
}
sa.nLength = sizeof sa;
sa.bInheritHandle = TRUE;
for (;;)
{
//_tprintf( TEXT("\nPipe Server: Main thread awaiting client connection on %s\n"), lpszPipename);
hPipe = CreateNamedPipe(
lpszPipename, // pipe name
PIPE_ACCESS_DUPLEX, // read/write access
PIPE_TYPE_MESSAGE | // message type pipe
PIPE_READMODE_MESSAGE | // message-read mode
PIPE_WAIT, // blocking mode
PIPE_UNLIMITED_INSTANCES, // max. instances
BUFFER_SIZE, // output buffer size
BUFFER_SIZE, // input buffer size
0, // client time-out
&sa); // default security attribute
if (hPipe == INVALID_HANDLE_VALUE)
{
//_tprintf(TEXT("CreateNamedPipe failed, GLE=%d.\n"), GetLastError());
return -1;
}
// Wait for the client to connect; if it succeeds,
// the function returns a nonzero value. If the function
// returns zero, GetLastError returns ERROR_PIPE_CONNECTED.
fConnected = ConnectNamedPipe(hPipe, NULL) ?
TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
if (fConnected)
{
// Create a thread for this client.
hThread = CreateThread(
NULL, // no security attribute
0, // default stack size
InstanceThread, // thread proc
(LPVOID) hPipe, // thread parameter
0, // not suspended
&dwThreadId); // returns thread ID
if (hThread == NULL)
{
return -1;
}
else CloseHandle(hThread);
}
else
// The client could not connect, so close the pipe.
CloseHandle(hPipe);
}
return ERROR_SUCCESS;
}
And the code which uses to display message on MFC dialog is this:
DWORD WINAPI InstanceThread(LPVOID lpvParam)
// This routine is a thread processing function to read from and reply to a client
// via the open pipe connection passed from the main loop. Note this allows
// the main loop to continue executing, potentially creating more threads of
// of this procedure to run concurrently, depending on the number of incoming
// client connections.
{
HANDLE hHeap = GetProcessHeap();
TCHAR* pchRequest = (TCHAR*)HeapAlloc(hHeap, 0, BUFFER_SIZE*sizeof(TCHAR));
TCHAR* pchReply = (TCHAR*)HeapAlloc(hHeap, 0, BUFFER_SIZE*sizeof(TCHAR));
DWORD cbBytesRead = 0, cbReplyBytes = 0, cbWritten = 0;
BOOL fSuccess = FALSE;
HANDLE hPipe = NULL;
// Do some extra error checking since the app will keep running even if this
// thread fails.z
if (lpvParam == NULL)
{
if (pchReply != NULL) HeapFree(hHeap, 0, pchReply);
if (pchRequest != NULL) HeapFree(hHeap, 0, pchRequest);
return (DWORD)-1;
}
if (pchRequest == NULL)
{
if (pchReply != NULL) HeapFree(hHeap, 0, pchReply);
return (DWORD)-1;
}
if (pchReply == NULL)
{
if (pchRequest != NULL) HeapFree(hHeap, 0, pchRequest);
return (DWORD)-1;
}
// Print verbose messages. In production code, this should be for debugging only.
// The thread's parameter is a handle to a pipe object instance.
hPipe = (HANDLE) lpvParam;
// Loop until done reading
while (1)
{
// Read client requests from the pipe. This simplistic code only allows messages
// up to BUFSIZE characters in length.
fSuccess = ReadFile(
hPipe, // handle to pipe
pchRequest, // buffer to receive data
BUFFER_SIZE*sizeof(TCHAR), // size of buffer
&cbBytesRead, // number of bytes read
NULL); // not overlapped I/O
if (!fSuccess || cbBytesRead == 0)
{
break;
}
MyData* data = new MyData;
data->client_Param = pchRequest;
HWND handle = FindWindow(NULL,CStringW("MFCApplication1"));
PostMessage(handle, WM_YOU_HANVE_DATA, reinterpret_cast<WPARAM>(data) ,NULL);
// Process the incoming message.
//GetAnswerToRequest(pchRequest, pchReply, &cbReplyBytes);
if (wcscmp(pchRequest,L"msg1")==0)
StringCchCopy( pchReply, BUFFER_SIZE, TEXT("Hi"));
else
StringCchCopy( pchReply, BUFFER_SIZE, TEXT("default echo answer"));
cbReplyBytes = (lstrlen(pchReply)+1)*sizeof(TCHAR);
// Write the reply to the pipe.
fSuccess = WriteFile(
hPipe, // handle to pipe
pchReply, // buffer to write from
cbReplyBytes, // number of bytes to write
&cbWritten, // number of bytes written
NULL); // not overlapped I/O
if (!fSuccess || cbReplyBytes != cbWritten)
{
break;
}
}
// Flush the pipe to allow the client to read the pipe's contents
// before disconnecting. Then disconnect the pipe, and close the
// handle to this pipe instance.
FlushFileBuffers(hPipe);
DisconnectNamedPipe(hPipe);
CloseHandle(hPipe);
HeapFree(hHeap, 0, pchRequest);
HeapFree(hHeap, 0, pchReply);
return 1;
}
As you see he use function instead of method. I create a class and push his methods and use signal and slot to get the goal.
But it breaks down. The reason is that createThread method must get the name of function not the name of method. So I create the method as static method but another error raise. Signal and slot should use a real object(in moc file it use “this” keyword which is not compatible with this method)
How should I overcome this problem
PipeCreator::PipeCreator(QObject *parent = 0) :
QObject(parent)
{
HANDLE hPipeThread = CreateThread( NULL, 0, PipeCreator::PipeThread, NULL, 0, NULL );
}
DWORD PipeCreator::PipeThread(void *pContext)
{
BOOL fConnected = FALSE;
DWORD dwThreadId = 0;
HANDLE hPipe = INVALID_HANDLE_VALUE, hThread = NULL;
LPTSTR lpszPipename = TEXT("\\\\.\\pipe\\InterfacePipe");
// The main loop creates an instance of the named pipe and
// then waits for a client to connect to it. When the client
// connects, a thread is created to handle communications
// with that client, and this loop is free to wait for the
// next client connect request. It is an infinite loop.
SECURITY_ATTRIBUTES sa;
sa.lpSecurityDescriptor = (PSECURITY_DESCRIPTOR)malloc(SECURITY_DESCRIPTOR_MIN_LENGTH);
if (!InitializeSecurityDescriptor(sa.lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION))
{
DWORD er = ::GetLastError();
}
if (!SetSecurityDescriptorDacl(sa.lpSecurityDescriptor, TRUE, (PACL)0, FALSE))
{
DWORD er = ::GetLastError();
}
sa.nLength = sizeof sa;
sa.bInheritHandle = TRUE;
for (;;)
{
hPipe = CreateNamedPipe(
lpszPipename, // pipe name
PIPE_ACCESS_DUPLEX, // read/write access
PIPE_TYPE_MESSAGE | // message type pipe
PIPE_READMODE_MESSAGE | // message-read mode
PIPE_WAIT, // blocking mode
PIPE_UNLIMITED_INSTANCES, // max. instances
BUFFER_SIZE, // output buffer size
BUFFER_SIZE, // input buffer size
0, // client time-out
&sa); // default security attribute
if (hPipe == INVALID_HANDLE_VALUE)
{
return -1;
}
// Wait for the client to connect; if it succeeds,
// the function returns a nonzero value. If the function
// returns zero, GetLastError returns ERROR_PIPE_CONNECTED.
fConnected = ConnectNamedPipe(hPipe, NULL) ?
TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
if (fConnected)
{
this->instance =new InstanceCreator();
connect(this->instance,SIGNAL(NewDataAvailable(MyData)),this,SLOT(NewDataAvailableForGUI(MyData)));
// Create a thread for this client.
hThread = CreateThread(
NULL, // no security attribute
0, // default stack size
this->instance->InstanceThread, // thread proc
(LPVOID) hPipe, // thread parameter
0, // not suspended
&dwThreadId); // returns thread ID
if (hThread == NULL)
{
return -1;
}
else
{
//Here I should recieve the emmited signal
emit NewDataAvailableForGUI(this->newData);
CloseHandle(hThread);
}
}
else
// The client could not connect, so close the pipe.
CloseHandle(hPipe);
}
return ERROR_SUCCESS;
}
// This routine is a thread processing function to read from and reply to a client
// via the open pipe connection passed from the main loop. Note this allows
// the main loop to continue executing, potentially creating more threads of
// of this procedure to run concurrently, depending on the number of incoming
// client connections.
DWORD InstanceCreator::InstanceThread(LPVOID lpvParam)
{
HANDLE hHeap = GetProcessHeap();
TCHAR* pchRequest = (TCHAR*)HeapAlloc(hHeap, 0, BUFFER_SIZE*sizeof(TCHAR));
TCHAR* pchReply = (TCHAR*)HeapAlloc(hHeap, 0, BUFFER_SIZE*sizeof(TCHAR));
DWORD cbBytesRead = 0, cbReplyBytes = 0, cbWritten = 0;
BOOL fSuccess = FALSE;
HANDLE hPipe = NULL;
// Do some extra error checking since the app will keep running even if this
// thread fails.z
//PostMessage((HWND)CMFCApplication1Dlg->textBox3->Handle.ToPointer(), WM_SETTEXT, 0, (LPARAM)L"TestDLL Try");
if (lpvParam == NULL)
{
if (pchReply != NULL) HeapFree(hHeap, 0, pchReply);
if (pchRequest != NULL) HeapFree(hHeap, 0, pchRequest);
return (DWORD)-1;
}
if (pchRequest == NULL)
{
if (pchReply != NULL) HeapFree(hHeap, 0, pchReply);
return (DWORD)-1;
}
if (pchReply == NULL)
{
if (pchRequest != NULL) HeapFree(hHeap, 0, pchRequest);
return (DWORD)-1;
}
// Print verbose messages. In production code, this should be for debugging only.
// The thread's parameter is a handle to a pipe object instance.
hPipe = (HANDLE) lpvParam;
// Loop until done reading
while (1)
{
// Read client requests from the pipe. This simplistic code only allows messages
// up to BUFSIZE characters in length.
fSuccess = ReadFile(
hPipe, // handle to pipe
pchRequest, // buffer to receive data
BUFFER_SIZE*sizeof(TCHAR), // size of buffer
&cbBytesRead, // number of bytes read
NULL); // not overlapped I/O
if (!fSuccess || cbBytesRead == 0)
{
break;
}
MyData data;
data.data=QString::fromStdWString(pchRequest);
emit NewDataAvailable(data);
// Process the incoming message.
//GetAnswerToRequest(pchRequest, pchReply, &cbReplyBytes);
if (wcscmp(pchRequest,L"msg1")==0)
StringCchCopy( pchReply, BUFFER_SIZE, TEXT("Hi"));
else
StringCchCopy( pchReply, BUFFER_SIZE, TEXT("default echo answer"));
cbReplyBytes = (lstrlen(pchReply)+1)*sizeof(TCHAR);
// Write the reply to the pipe.
fSuccess = WriteFile(
hPipe, // handle to pipe
pchReply, // buffer to write from
cbReplyBytes, // number of bytes to write
&cbWritten, // number of bytes written
NULL); // not overlapped I/O
if (!fSuccess || cbReplyBytes != cbWritten)
{
break;
}
}
// Flush the pipe to allow the client to read the pipe's contents
// before disconnecting. Then disconnect the pipe, and close the
// handle to this pipe instance.
FlushFileBuffers(hPipe);
DisconnectNamedPipe(hPipe);
CloseHandle(hPipe);
HeapFree(hHeap, 0, pchRequest);
HeapFree(hHeap, 0, pchReply);
return 1;
}

unblocking WSAccept for blocking TCP server sockets

I'm writing a TCP server (blocking socket model).
I'm having trouble implementing a valid normal program exit when the server is waiting (blocking) for new connection attempts on Accept (I use WSAccept).
The code for the server's listening socket is something like this (I omitted error handling and other irrelevant code):
int ErrCode = WSAStartup(MAKEWORD(2,2), &m_wsaData) ;
// Create a new socket to listen and accept new connection attempts
struct addrinfo hints, *res = NULL, *ptr = NULL ;
int rc, count = 0 ;
memset(&hints, 0, sizeof(hints)) ;
hints.ai_family = AF_UNSPEC ;
hints.ai_socktype = SOCK_STREAM ;
hints.ai_protocol = IPPROTO_TCP ;
hints.ai_flags = AI_PASSIVE ;
CString strPort ;
strPort.Format("%d", Port) ;
getaddrinfo(pLocalIp, strPort.GetBuffer(), &hints, &res) ;
strPort.ReleaseBuffer() ;
ptr = res ;
if ((m_Socket = WSASocket(res->ai_family, res->ai_socktype, res->ai_protocol, NULL, 0, 0)) == INVALID_SOCKET)
{
// some error
}
if(bind(m_Socket, (SOCKADDR *)res->ai_addr, res->ai_addrlen) == SOCKET_ERROR)
{
// some error
}
if (listen(m_Socket, SOMAXCONN) == SOCKET_ERROR)
{
// some error
}
So far so good... Then I implemented the WSAccept call inside a thread like this:
SOCKADDR_IN ClientAddr ;
int ClientAddrLen = sizeof(ClientAddr) ;
SOCKET TempS = WSAAccept(m_Socket, (SOCKADDR*) &ClientAddr, &ClientAddrLen, NULL, NULL);
Of course the WSAccept blocks until a new connection attempt is made but if I wish to exit
the program then i need some way to cause WSAccept to exit. I have tried several different approaches:
Attempt to call shutdown and/or closesocket with m_Socket from within another thread failed (program just hangs).
using WSAEventSelect indeed solves this issue but then WSAccept delivers only non-blocking sockets - which is not my intention. (Is there a way to make the sockets blocking?)
I Read about APC and tried to use something like QueueUserAPC(MyAPCProc, m_hThread, 1)) but it didn't work either.
What am I doing wrong ?
Is there a better way to cause this blocking WSAccept to exit ?
Use select() with a timeout to detect when a client connection is actually pending before then calling WSAAccept() to accept it. It works with blocking sockets without putting them into non-blocking mode. That will give your code more opportunities to check if the app is shutting down.
Go with non-blocking accepting socket (WSAEventSelect as you mentioned) and use non-blocking WSAccept. You can make a non-blocking socket that WSAccept returns into blocking socket with ioctlsocket (see msdn).
Do all the other stuff you absoultely have to on shutdown, (maybe you have DB connections to close, or files to flush?), and then call ExitProcess(0). That will stop your listening thread, no problem.
See log4cplus source for my take on this issue. I basically wait on two event objects, one is signaled when connection is being accepted (using WSAEventSelect()) and another is there to interrupt the waiting. The most relevant parts of the source is below. See ServerSocket::accept().
namespace {
static
bool
setSocketBlocking (SOCKET_TYPE s)
{
u_long val = 0;
int ret = ioctlsocket (to_os_socket (s), FIONBIO, &val);
if (ret == SOCKET_ERROR)
{
set_last_socket_error (WSAGetLastError ());
return false;
}
else
return true;
}
static
bool
removeSocketEvents (SOCKET_TYPE s, HANDLE ev)
{
// Clean up socket events handling.
int ret = WSAEventSelect (to_os_socket (s), ev, 0);
if (ret == SOCKET_ERROR)
{
set_last_socket_error (WSAGetLastError ());
return false;
}
else
return true;
}
static
bool
socketEventHandlingCleanup (SOCKET_TYPE s, HANDLE ev)
{
bool ret = removeSocketEvents (s, ev);
ret = setSocketBlocking (s) && ret;
ret = WSACloseEvent (ev) && ret;
return ret;
}
} // namespace
ServerSocket::ServerSocket(unsigned short port)
{
sock = openSocket (port, state);
if (sock == INVALID_SOCKET_VALUE)
{
err = get_last_socket_error ();
return;
}
HANDLE ev = WSACreateEvent ();
if (ev == WSA_INVALID_EVENT)
{
err = WSAGetLastError ();
closeSocket (sock);
sock = INVALID_SOCKET_VALUE;
}
else
{
assert (sizeof (std::ptrdiff_t) >= sizeof (HANDLE));
interruptHandles[0] = reinterpret_cast<std::ptrdiff_t>(ev);
}
}
Socket
ServerSocket::accept ()
{
int const N_EVENTS = 2;
HANDLE events[N_EVENTS] = {
reinterpret_cast<HANDLE>(interruptHandles[0]) };
HANDLE & accept_ev = events[1];
int ret;
// Create event and prime socket to set the event on FD_ACCEPT.
accept_ev = WSACreateEvent ();
if (accept_ev == WSA_INVALID_EVENT)
{
set_last_socket_error (WSAGetLastError ());
goto error;
}
ret = WSAEventSelect (to_os_socket (sock), accept_ev, FD_ACCEPT);
if (ret == SOCKET_ERROR)
{
set_last_socket_error (WSAGetLastError ());
goto error;
}
do
{
// Wait either for interrupt event or actual connection coming in.
DWORD wsawfme = WSAWaitForMultipleEvents (N_EVENTS, events, FALSE,
WSA_INFINITE, TRUE);
switch (wsawfme)
{
case WSA_WAIT_TIMEOUT:
case WSA_WAIT_IO_COMPLETION:
// Retry after timeout or APC.
continue;
// This is interrupt signal/event.
case WSA_WAIT_EVENT_0:
{
// Reset the interrupt event back to non-signalled state.
ret = WSAResetEvent (reinterpret_cast<HANDLE>(interruptHandles[0]));
// Clean up socket events handling.
ret = socketEventHandlingCleanup (sock, accept_ev);
// Return Socket with state set to accept_interrupted.
return Socket (INVALID_SOCKET_VALUE, accept_interrupted, 0);
}
// This is accept_ev.
case WSA_WAIT_EVENT_0 + 1:
{
// Clean up socket events handling.
ret = socketEventHandlingCleanup (sock, accept_ev);
// Finally, call accept().
SocketState st = not_opened;
SOCKET_TYPE clientSock = acceptSocket (sock, st);
int eno = 0;
if (clientSock == INVALID_SOCKET_VALUE)
eno = get_last_socket_error ();
return Socket (clientSock, st, eno);
}
case WSA_WAIT_FAILED:
default:
set_last_socket_error (WSAGetLastError ());
goto error;
}
}
while (true);
error:;
DWORD eno = get_last_socket_error ();
// Clean up socket events handling.
if (sock != INVALID_SOCKET_VALUE)
{
(void) removeSocketEvents (sock, accept_ev);
(void) setSocketBlocking (sock);
}
if (accept_ev != WSA_INVALID_EVENT)
WSACloseEvent (accept_ev);
set_last_socket_error (eno);
return Socket (INVALID_SOCKET_VALUE, not_opened, eno);
}
void
ServerSocket::interruptAccept ()
{
(void) WSASetEvent (reinterpret_cast<HANDLE>(interruptHandles[0]));
}
A not so neat way of solving this problem is by issuing a dummy WSAConnect request from the thread that needs to do the shutdown. If the dummy connect fails, you might resort to ExitProcess as suggested by Martin.
void Drain()
{
if (InterlockedIncrement(&drain) == 1)
{
// Make a dummy connection to unblock wsaaccept
SOCKET ConnectSocket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0);
if (ConnectSocket != INVALID_SOCKET) {
int iResult = WSAConnect(ConnectSocket, result->ai_addr, result->ai_addrlen, 0, 0, 0, 0);
if (iResult != 0) {
printf("Unable to connect to server! %d\n", WSAGetLastError());
}
else
{
closesocket(ConnectSocket);
}
}
}
}

IOCP C++ TCP client

I am having some trouble implementing TCP IOCP client. I have implemented kqueue on Mac OSX so was looking to do something similar on windows and my understanding is that IOCP is the closest thing. The main problem is that GetCompetetionStatus is never returning and always timeouts out. I assume I am missing something when creating the handle to monitor, but not sure what. This is where I have gotten so far:
My connect routine: (remove some error handling for clarity )
struct sockaddr_in server;
struct hostent *hp;
SOCKET sckfd;
WSADATA wsaData;
int iResult = WSAStartup( MAKEWORD(2,2), &wsaData );
if ((hp = gethostbyname(host)) == NULL)
return NULL;
WSASocket(AF_INET,SOCK_STREAM,0,NULL,0,WSA_FLAG_OVERLAPPED)
if ((sckfd = WSASocket(AF_INET,SOCK_STREAM,0, NULL, 0, WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET)
{
printf("Error at socket(): Socket\n");
WSACleanup();
return NULL;
}
server.sin_family = AF_INET;
server.sin_port = htons(port);
server.sin_addr = *((struct in_addr *)hp->h_addr);
memset(&(server.sin_zero), 0, 8);
//non zero means non blocking. 0 is blocking.
u_long iMode = -1;
iResult = ioctlsocket(sckfd, FIONBIO, &iMode);
if (iResult != NO_ERROR)
printf("ioctlsocket failed with error: %ld\n", iResult);
HANDLE hNewIOCP = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, ulKey, 0);
CreateIoCompletionPort((HANDLE)sckfd, hNewIOCP , ulKey, 0);
connect(sckfd, (struct sockaddr *)&server, sizeof(struct sockaddr));
//WSAConnect(sckfd, (struct sockaddr *)&server, sizeof(struct sockaddr),NULL,NULL,NULL,NULL);
return sckfd;
Here is the send routine: ( also remove some error handling for clarity )
IOPortConnect(int ServerSocket,int timeout,string& data){
char buf[BUFSIZE];
strcpy(buf,data.c_str());
WSABUF buffer = { BUFSIZE,buf };
DWORD bytes_recvd;
int r;
ULONG_PTR ulKey = 0;
OVERLAPPED overlapped;
OVERLAPPED* pov = NULL;
HANDLE port;
HANDLE hNewIOCP = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, ulKey, 0);
CreateIoCompletionPort((HANDLE)ServerSocket, hNewIOCP , ulKey, 0);
BOOL get = GetQueuedCompletionStatus(hNewIOCP,&bytes_recvd,&ulKey,&pov,timeout*1000);
if(!get)
printf("waiton server failed. Error: %d\n",WSAGetLastError());
if(!pov)
printf("waiton server failed. Error: %d\n",WSAGetLastError());
port = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, (u_long)0, 0);
SecureZeroMemory((PVOID) & overlapped, sizeof (WSAOVERLAPPED));
r = WSASend(ServerSocket, &buffer, 1, &bytes_recvd, NULL, &overlapped, NULL);
printf("WSA returned: %d WSALastError: %d\n",r,WSAGetLastError());
if(r != 0)
{
printf("WSASend failed %d\n",GetLastError());
printf("Bytes transfered: %d\n",bytes_recvd);
}
if (WSAGetLastError() == WSA_IO_PENDING)
printf("we are async.\n");
CreateIoCompletionPort(port, &overlapped.hEvent,ulKey, 0);
BOOL test = GetQueuedCompletionStatus(port,&bytes_recvd,&ulKey,&pov,timeout*1000);
CloseHandle(port);
return true;
}
Any insight would be appreciated.
You are associating the same socket with multiple IOCompletionPorts. I'm sure thats not valid. In your IOPortConnect function (Where you do the write) you call CreateIOCompletionPort 4 times passing in one shot handles.
My advice:
Create a single IOCompletion Port (that, ultimately, you associate numerous sockets with).
Create a pool of worker threads (by calling CreateThread) that each then block on the IOCompletionPort handle by calling GetQueuedCompletionStatus in a loop.
Create one or more WSA_OVERLAPPED sockets, and associate each one with the IOCompletionPort.
Use the WSA socket functions that take an OVERLAPPED* to trigger overlapped operations.
Process the completion of the issued requests as the worker threads return from GetQueuedCompletionStatus with the OVERLAPPED* you passed in to start the operation.
Note: WSASend returns both 0, and SOCKET_ERROR with WSAGetLastError() as WSA_IO_PENDING as codes to indicate that you will get an IO Completion Packet arriving at GetQueuedCompletionStatus. Any other error code means you should process the error immediately as an IO operation was not queued so there will be no further callbacks.
Note2: The OVERLAPPED* passed to the WSASend (or whatever) function is the OVERLAPPED* returned from GetQueuedCompletionStatus. You can use this fact to pass more context information with the call:
struct MYOVERLAPPED {
OVERLAPPED ovl;
};
MYOVERLAPPED ctx;
WSASend(...,&ctx.ovl);
...
OVERLAPPED* pov;
if(GetQueuedCompletionStatus(...,&pov,...)){
MYOVERLAPPED* pCtx = (MYOVERLAPPED*)pov;
Chris has dealt with most of the issues and you've probably already looked at plenty of example code, but...
I've got some free IOCP code that's available here: http://www.serverframework.com/products---the-free-framework.html
There are also several of my CodeProject articles on the subject linked from that page.