Winsock and NAT (Network address translation)

I am using winsock to connect in the same application, divided into server and client. The application is an ActiveX control, viewed through IE browser. The connection is made using an IP address through NAT. I've made a special port for the server application that forwards the LAN external address to the internal one. Still, accept() wouldn't accept the connection while debugging and move on the next statement.

Code snippet from server:

struct sockaddr_in saServer;
hostent* localHost;
char* localIP;

localHost = gethostbyname("");
localIP = inet_ntoa (*(struct in_addr *)*localHost->h_addr_list);

// Set up the sockaddr structure
saServer.sin_family = AF_INET;
saServer.sin_addr.s_addr = inet_addr(localIP);
saServer.sin_port = htons(m_nPort);

// Create a SOCKET for connecting to server
//m_ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
m_ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (m_ListenSocket == INVALID_SOCKET) {
_stprintf(msg, _T("CServer::StartListening: socket failed: %ld\n"), WSAGetLastError());
g_err.ReportError(msg);
//freeaddrinfo(result);

return E_FAIL;
}

// Setup the TCP listening socket
//iResult = bind( m_ListenSocket, result->ai_addr, (int)result->ai_addrlen);
iResult = bind( m_ListenSocket, (SOCKADDR*) &saServer, sizeof(saServer));
if (iResult == SOCKET_ERROR && WSAGetLastError() != WSAEWOULDBLOCK) {
_stprintf(msg, _T("CServer::StartListening(): bind failed: %d\n"), WSAGetLastError());
g_err.ReportError(msg);
//freeaddrinfo(result);
closesocket(m_ListenSocket);

return E_FAIL;
}

////////////////////////////////////////////////////////////////

TCHAR msg[256];
HANDLE hEvAccept;
svr->m_bListening = TRUE;

int iResult = ::listen(svr->m_ListenSocket, SOMAXCONN);
if (iResult == SOCKET_ERROR) {
_stprintf(msg, _T("CServer::StartListening: listen failed: %d\n"), WSAGetLastError());
g_err.ReportError(msg);
closesocket(svr->m_ListenSocket);

return E_FAIL;
}
svr->m_bListening = FALSE;

// Accept a client socket
AfxMessageBox(_T("Establishing connection..."));

hEvAccept = ::CreateEvent(NULL, FALSE, FALSE, _T("ExpandifyServerAccept"));
::WSAEventSelect(svr->m_ListenSocket, hEvAccept, FD_ACCEPT);

sockaddr ClientAddr;
int nClientAddrLen = sizeof(sockaddr);
SOCKET ClientSocket = ::accept(svr->m_ListenSocket, &ClientAddr, &nClientAddrLen);
if (ClientSocket == INVALID_SOCKET && WSAGetLastError() != WSAEWOULDBLOCK) {
_stprintf(msg, _T("CServer::StartListening: accept failed: %d\n"), WSAGetLastError());
g_err.ReportError(msg);

return E_FAIL;
}

HANDLE handles[2];
handles[0] = hEvAccept;
handles[1] = svr->m_hCloseListener;
int res;
switch (res = ::WaitForMultipleObjectsEx(2, handles, FALSE, INFINITE, FALSE))
{
case WAIT_OBJECT_0:
AfxMessageBox(_T("Connection accepted"));
break;
case WAIT_OBJECT_0 + 1:
default:
::CloseHandle(hEvAccept);
return S_OK;
break;
}
::CloseHandle(hEvAccept);

BOOL bConnAccepted = FALSE;
if (ClientAddr.sa_family == AF_INET)
{
for (int iConn = 0; iConn < svr->m_Connections.size(); iConn++)
{
if (CompareAddrs(svr->m_Connections[iConn].addr, ClientAddr))
{
// Assert that a client IP is not accepted twice
if (svr->m_Connections[iConn].bConnected)
{
_stprintf(msg, _T("CServer::ServerListenAndAccept(): the same broadcast address was requested twice"));
g_err.ReportError(msg);
svr->m_Connections.erase(svr->m_Connections.begin() + iConn);
}
else
{
CClientConn conn;
conn.bConnected = TRUE;
conn.socket = ClientSocket;
bConnAccepted = TRUE;
AfxMessageBox(_T("Connection approved"));
//svr->SendOutOfBandData(OOB_STARTTIME, iConn);
}
}
}
}


Client:
/////////////////////////////////////////////////////////

saServer.sin_family = AF_INET;
saServer.sin_addr.s_addr = inet_addr(cl->m_sServerAddr);
saServer.sin_port = htons(cl->m_nPort);

// Create a SOCKET for connecting to server
AfxMessageBox(_T("socket..."));
cl->m_Conn.socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (cl->m_Conn.socket == INVALID_SOCKET) {
_stprintf(msg, _T("CClient::Connect: socket failed: %ld\n"), WSAGetLastError());
g_err.ReportError(msg);

return E_FAIL;
}

AfxMessageBox(_T("Establishing connection..."));

// Connect to server.
HANDLE hEvConnect = ::CreateEvent(NULL, FALSE, FALSE, _T("ExpandifyClientConnect"));
::WSAEventSelect(cl->m_Conn.socket, hEvConnect, FD_CONNECT);

iResult = connect(cl->m_Conn.socket, (SOCKADDR*) &saServer, sizeof(saServer));
if (iResult == SOCKET_ERROR && WSAGetLastError() != WSAEWOULDBLOCK) {
_stprintf(msg, _T("CClient::Connect: connect failed: %ld\n"), WSAGetLastError());
g_err.ReportError(msg);
closesocket(cl->m_Conn.socket);
cl->m_Conn.socket = INVALID_SOCKET;
return S_OK;
}

HANDLE handles[2];
handles[0] = hEvConnect;
handles[1] = cl->m_hEvCloseComm;
int res;
switch (res = ::WaitForMultipleObjects(2, handles, FALSE, INFINITE))
{
case WAIT_OBJECT_0:
break;
default:
::CloseHandle(hEvConnect);
return S_OK;
}
::CloseHandle(hEvConnect);

// Check for connection timeout or failure
if (WSAGetLastError() != 0 && WSAGetLastError() != WSAEWOULDBLOCK) {
_stprintf(msg, _T("CClient::Connect: connect failed: %ld\n"), WSAGetLastError());
g_err.ReportError(msg);
closesocket(cl->m_Conn.socket);
cl->m_Conn.socket = INVALID_SOCKET;
return S_OK;
}

cl->m_Conn.addr = *((SOCKADDR*) &saServer);
cl->m_Conn.bConnected = TRUE;

AfxMessageBox(_T("Connected!"));

Thank you for your kind help,
Elad Stern
Topic archived. No new replies allowed.