Winsock - WSAENOBUFS error

EDN Admin

Well-known member
Joined
Aug 7, 2010
Messages
12,794
Location
In the Machine
After a random period of time (normally 2-8 hours) I get a WSAENOBUFS error as a result of WSASend (see !!!!!!!!!!!!!!!!!!! in code below).<br/> <br/> If I am running multiple clients they all return the error at the same time.<br/> <br/> I switched to overlapped calls in an attempt to fix the issue, but it continues. I do not understand how I can get WSAENOBUFS errors when I am using my own stack allocated buffers.<br/> <br/> <br/> ------<br/> <br/>
<pre lang=x-cpp>#include "stdafx.h" // PRECOMPILED HEADER


#include "Connection.h"


Connection::Connection() :
m_socket(INVALID_SOCKET),
m_connected(false),
m_socketEvent(NULL)
{
// Initialize Winsock
WSADATA wsaData;
int iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if ( iResult != 0 )
gprintf("ERROR: WSAStartup failed: %dn", iResult);

m_socketEvent = WSACreateEvent();
m_sentEvent = CreateEvent(NULL, false, false, NULL);
m_closedEvent = CreateEvent(NULL, false, false, NULL);
}

Connection::~Connection()
{
LOCK ( &m_socketMutex )
{
if ( m_socket != INVALID_SOCKET )
_close();

// TODO: Wait for the connection to close and the thread to terminate

CloseHandle(m_closedEvent);
CloseHandle(m_sentEvent);
CloseHandle(m_socketEvent);
}

// Unload winsock
WSACleanup();
}

bool Connection::open(string address, string port)
{
LOCK ( &m_socketMutex )
{
if ( m_socket != INVALID_SOCKET )
{
gprintf("ERROR: Connection already openn");
return false;
}

m_address = address;
m_port = port;
}

start();

return true;
}

void Connection::send(string msg)
{
LOCK ( &m_socketMutex )
{
if ( m_sendBuf.size() + msg.size()+1 > m_sendBuf.max_size() )
{
gprintf("ERROR: cannot push message, buffer fulln");
return;
}

for ( unsigned int i=0; i < msg.size()+1; i++ )
{
m_sendBuf.push_back(msg.c_str());
}
}

SetEvent(m_sentEvent);
}

void Connection::close()
{
SetEvent(m_closedEvent);
}

bool Connection::isConnected()
{
LOCK ( &m_socketMutex )
{
return ( m_socket != INVALID_SOCKET && m_connected );
}

return false;
}

void Connection::threadEntryPoint()
{
gprintf("Connection thread started...n");

// Open the connection
if ( !_open() )
return;

// Loop until the connection is closed
while ( true )
{
HANDLE waitObjects[3] = {m_socketEvent, m_sentEvent, m_closedEvent};
DWORD waitObjectIndex = WaitForMultipleObjects(3, waitObjects, false, INFINITE);
HANDLE waitObject = waitObjects[waitObjectIndex - WAIT_OBJECT_0];

LOCK ( &m_socketMutex )
{
if ( m_socket == INVALID_SOCKET )
{
gprintf("ERROR: Invalid socketn");
goto close;
}

// Socket event
if ( waitObject == m_socketEvent )
{
WSANETWORKEVENTS eventBits;
WSAEnumNetworkEvents(m_socket, m_socketEvent, &eventBits);

// Connect event
if ( eventBits.lNetworkEvents & FD_CONNECT )
{
if ( !_connect(eventBits.iErrorCode[FD_CONNECT_BIT]) )
goto close;
}
// Write event
else if ( eventBits.lNetworkEvents & FD_WRITE )
{
_send();
}
// Read event
else if ( eventBits.lNetworkEvents & FD_READ )
{
_receive();
}
// Close event
else if ( eventBits.lNetworkEvents & FD_CLOSE )
{
goto close;
}

}
// Sent event
else if ( waitObject == m_sentEvent )
{
_send();
}
// Closed event
else if ( waitObject == m_closedEvent )
{
goto close;
}
}
}

close:

// Close the connection
_close();
}

bool Connection::_open()
{
gprintf("Connecting to %s...n", m_address.c_str());

if ( m_socket != INVALID_SOCKET )
{
gprintf("ERROR: Cannot open an already openned connectionn");
return false;
}

// Resolve address
struct addrinfo *addrInfoResult = NULL;
struct addrinfo *ptr = NULL;
struct addrinfo hints;
ZeroMemory( &hints, sizeof(hints) );
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;

int iResult;

// Resolve the server address and port
iResult = getaddrinfo(m_address.c_str(), m_port.c_str(), &hints, &addrInfoResult);
if (iResult != 0)
{
gprintf("ERROR: getaddrinfo failed(%ld)n", iResult);
return false;
}


// Attempt to connect to the first address returned by the call to getaddrinfo
ptr = addrInfoResult;

// Open a SOCKET for connecting to the server
m_socket = INVALID_SOCKET;
m_socket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
if ( m_socket == INVALID_SOCKET )
{
gprintf("ERROR: Failed to create socket(%ld)n", WSAGetLastError());
freeaddrinfo(addrInfoResult);
return false;
}

// Select the socket events and make the socket nonblocking
iResult = WSAEventSelect(m_socket, m_socketEvent, FD_READ | FD_CLOSE | FD_CONNECT | FD_WRITE);
if ( iResult == SOCKET_ERROR )
{
gprintf("ERROR: Failed to create socket event(%ld)n", WSAGetLastError());
_close();
freeaddrinfo(addrInfoResult);
return false;
}

// Set the send buffer size
int sndBufSize = 2048;
int sndBufSizeSize = sizeof(sndBufSize);
setsockopt(m_socket, SOL_SOCKET, SO_SNDBUF, (char*)&sndBufSize, sndBufSizeSize);

// Verify the buffer size
sndBufSizeSize = sizeof(sndBufSize);
getsockopt(m_socket, SOL_SOCKET, SO_SNDBUF, (char*)&sndBufSize, &sndBufSizeSize);
gprintf("Send Buffer Size: %in", sndBufSize);

// Connect to server
iResult = ::connect( m_socket, ptr->ai_addr, (int)ptr->ai_addrlen );
if ( iResult == SOCKET_ERROR && WSAGetLastError() != WSAEWOULDBLOCK )
{
gprintf("ERROR: Failed to connect socket(%ld)n", WSAGetLastError());
_close();
freeaddrinfo(addrInfoResult);
return false;
}

// Should really try the next address returned by getaddrinfo if the connect call fails
freeaddrinfo(addrInfoResult);

ZeroMemory(&m_recvOverlapped, sizeof(m_recvOverlapped));
m_recvOverlapped.hEvent = WSACreateEvent();
if ( m_recvOverlapped.hEvent == NULL )
gprintf("WSACreateEvent failed: %dn", WSAGetLastError());

ZeroMemory(&m_sendOverlapped, sizeof(m_sendOverlapped));
m_sendOverlapped.hEvent = WSACreateEvent();
if ( m_sendOverlapped.hEvent == NULL )
gprintf("WSACreateEvent failed: %dn", WSAGetLastError());

return true;
}

bool Connection::_connect(int errorCode)
{
m_connected = ( errorCode == 0 );

if ( m_connected )
gprintf("Successfully connectedn");
else
gprintf("ERROR: Failed to connect(%i)n", errorCode);

list<ConnectionListener*> listeners = lockListeners();
for ( list<ConnectionListener*>::iterator iListener = listeners.begin(); iListener != listeners.end(); iListener++ )
{
(*iListener)->openned(m_connected);
}
unlockListeners();

return m_connected;
}


bool Connection::_send()
{
while ( m_sendBuf.size() > 0 )
{
int size = m_sendBuf.size();

char sndBuf[256];
ZeroMemory(sndBuf, 256);
unsigned int sndBufSize = 0;

// Take at most 256 bytes from the sendBuffer
list<char>::iterator iChar = m_sendBuf.begin();
while ( iChar != m_sendBuf.end() && sndBufSize < 256 )
{
sndBuf[sndBufSize] = *iChar;
sndBufSize++;

iChar++;
}

WSABUF sndBufs;
sndBufs.buf = sndBuf;
sndBufs.len = sndBufSize;
DWORD sentBytes = 0;
DWORD flags = 0;

if ( WSASend(m_socket, &sndBufs, 1, &sentBytes, 0, &m_sendOverlapped, NULL) == SOCKET_ERROR
&& WSAGetLastError() != WSA_IO_PENDING )
{
if ( WSAGetLastError() == WSAEWOULDBLOCK )
{
return false;
}
else
{
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//ERROR: Failed to send data to socket(10055)
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

gprintf("ERROR: Failed to send data to socket(%ld)n", WSAGetLastError());
_close();
return false;
}
}

if ( WSAWaitForMultipleEvents(1, &m_sendOverlapped.hEvent, true, INFINITE, true) == WSA_WAIT_FAILED )
{
gprintf("ERROR: WSAWaitForMultipleEvents failed(%d)n", WSAGetLastError());
_close();
return false;
}

if ( !WSAGetOverlappedResult(m_socket, &m_sendOverlapped, &sentBytes, false, &flags) )
{
gprintf("ERROR: WSASend operation failed: %dn", WSAGetLastError());
WSAResetEvent(m_sendOverlapped.hEvent);
_close();
return false;
}


// Erase the sent characters from the buffer
unsigned int i = 0;
iChar = m_sendBuf.begin();
while ( iChar != m_sendBuf.end() && i < sentBytes )
{
list<char>::iterator iCharCpy = iChar++;
m_sendBuf.erase(iCharCpy);
i++;
}

WSAResetEvent(m_sendOverlapped.hEvent);
}


return true;
}


bool Connection::_receive()
{
char recvBuf[DEFAULT_BUFLEN];
ZeroMemory(recvBuf, DEFAULT_BUFLEN);

WSABUF recvBufs;
recvBufs.buf = recvBuf;
recvBufs.len = DEFAULT_BUFLEN;

list<char> msgbuf;

DWORD recvBytes = 0;
DWORD flags = 0;

// Non-blocking, Overlapped Receive
if ( WSARecv(m_socket, &recvBufs, 1, &recvBytes, &flags, &m_recvOverlapped, NULL) == SOCKET_ERROR
&& WSAGetLastError() != WSA_IO_PENDING )
{
if ( WSAGetLastError() == WSAEWOULDBLOCK )
{
return false;
}
else
{
gprintf("ERROR: Failed to receive data from socket(%ld)n", WSAGetLastError());
_close();
return false;
}
}

// Wait for the overlapped recv event to finish
if ( WSAWaitForMultipleEvents(1, &m_recvOverlapped.hEvent, TRUE, INFINITE, TRUE) == WSA_WAIT_FAILED )
{
gprintf("ERROR: WSAWaitForMultipleEvents failed: %dn", WSAGetLastError());
return false;
}

// Get the results of the receive attempt
if ( WSAGetOverlappedResult(m_socket, &m_recvOverlapped, &recvBytes, FALSE, &flags) == FALSE )
{
gprintf("ERROR: WSARecv operation failed: %dn", WSAGetLastError());
WSAResetEvent(m_recvOverlapped.hEvent);
_close();
return false;
}

if ( recvBytes > 0 )
{
// Copy the recvbuf into the msgbuf
for ( unsigned int i = 0; i < recvBufs.len; i++ )
msgbuf.push_back( recvBufs.buf );

unsigned int i=0;
string msg("");
list<char>::iterator iMsgChar = msgbuf.begin();
while ( iMsgChar != msgbuf.end() )
{
list<char>::iterator iMsgCharCpy = iMsgChar++;

if ( (*iMsgCharCpy) != )
{
msg.append(1, (*iMsgCharCpy));
}
else
{
msgbuf.erase(msgbuf.begin(), iMsgCharCpy);

// Talk to the listeners
list<ConnectionListener*> listeners = lockListeners();
for ( list<ConnectionListener*>::iterator iListener = listeners.begin(); iListener != listeners.end(); iListener++ )
{
(*iListener)->read(msg);
}
unlockListeners();

msg.clear();
}
}
}
else if ( recvBytes == 0 )
{
WSAResetEvent(m_recvOverlapped.hEvent);
_close();
return false;
}

WSAResetEvent(m_recvOverlapped.hEvent);

return true;
}



bool Connection::_close()
{
gprintf("Closing socket...n");

if ( closesocket(m_socket) == SOCKET_ERROR )
{
gprintf("ERROR: Failed to close socket(%ld)n", WSAGetLastError());
return false;
}

WSACloseEvent(m_recvOverlapped.hEvent);
WSACloseEvent(m_sendOverlapped.hEvent);

m_socket = INVALID_SOCKET;
m_connected = false;

gprintf("Socket closedn");

list<ConnectionListener*> listeners = lockListeners();
for ( list<ConnectionListener*>::iterator iListener = listeners.begin(); iListener != listeners.end(); iListener++ )
{
(*iListener)->closed();
}
unlockListeners();

return true;
}

[/code]
<br/>

View the full article
 
Back
Top