I'm trying to learn the basics of network programming by using Winsock2 API. I've had success connecting through LAN IP addresses, but I've been struggling for over a day now trying to get the client to connect to my server through its public IP.
I have already set up port forwarding on my router and have even used Wireshark to watch for client connection requests. I'm seeing the requests in Wireshark, but it never connects to the server and eventually, I get a timeout error.
I'm at a loss, I appreciate anyone who can point me in the right direction!
This is the client implementation:
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#pragma comment(lib, "Ws2_32.lib")
#define DEFAULT_PORT //MY PORT
#define DEFAULT_BUFLEN 512
#define SERVER_IPV4 //"MY PUBLIC IP STRING"
int main(int argc, char **argv)
{
//wsaData to hold Winsock dll information
WSADATA wsaData;
WORD wVersionRequired = MAKEWORD(2, 2);
//Attempts to load winsock dll matching required version and fills WSADATA object
int wsaInit = WSAStartup(wVersionRequired, &wsaData);
if(wsaInit != 0)
{
printf("WSAStartup failed with error code: %d\n", wsaInit);
}
//If dll fails to load correct version free winsock dll resources
if(wsaData.wHighVersion != wVersionRequired)
{
printf("No usable version of Winsock.dll found\n");
WSACleanup();
return 1;
}
else
{
printf("Winsock dll 2.2 loaded correctly\n");
}
/**********************Socket Code Here**********************/
SOCKADDR_IN SockAddrIP4;
SockAddrIP4.sin_family = AF_INET;
SockAddrIP4.sin_addr.s_addr = inet_addr(SERVER_IPV4);
SockAddrIP4.sin_port = htons(DEFAULT_PORT);
/**************Create Socket****************/
//INVALID_SOCKET used like NULL
SOCKET ConnectSocket = INVALID_SOCKET;
// TODO(baruch): Only supporting IP_V4
ConnectSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(ConnectSocket == INVALID_SOCKET)
{
printf("socket() error: %ld\n", WSAGetLastError());
//clean up address info after getaddrinfo function when socket fails
WSACleanup();
return 1;
}
/*****************Connect to socket**************/
int connectResult = connect(ConnectSocket, (SOCKADDR*)&SockAddrIP4, sizeof(SOCKADDR_IN));
if(connectResult == SOCKET_ERROR)
{
printf("Connect failed with error: %d\n", WSAGetLastError());
closesocket(ConnectSocket);
ConnectSocket = INVALID_SOCKET;
}
else
{
printf("Connected with server: %s\n", SERVER_IPV4);
}
if(ConnectSocket == INVALID_SOCKET)
{
printf("Unable to connect with server\n");
WSACleanup();
return 1;
}
/*************END of Socket CODE CLEANUP********/
// TODO(baruch): close socket
WSACleanup();
}
And this is the server:
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#pragma comment(lib, "Ws2_32.lib")
// TODO(baruch): Only supporting ascii consider Unicode later
#undef UNICODE
#define DEFAULT_PORT //My Port
#define DEFAULT_BUFLEN 512
int main(int argc, char **argv)
{
//wsaData to hold Winsock dll information
WSADATA wsaData;
WORD wVersionRequired = MAKEWORD(2, 2);
int wsaInit = WSAStartup(wVersionRequired, &wsaData);
if(wsaInit != 0)
{
printf("WSAStartup failed with error code: %d\n", wsaInit);
}
//If dll fails to load correct version free winsock dll resources
if(wsaData.wHighVersion != wVersionRequired)
{
printf("No usable version of Winsock.dll found\n");
WSACleanup();
return 1;
}
else
{
printf("Winsock dll 2.2 loaded correctly\n");
}
/**********************Socket Code Here**********************/
/**************Create Socket****************/
SOCKADDR_IN SockAddrIP4;
SockAddrIP4.sin_family = AF_INET;
SockAddrIP4.sin_addr.s_addr = INADDR_ANY;
SockAddrIP4.sin_port = htons(DEFAULT_PORT);
//INVALID_SOCKET used like NULL
SOCKET ListenSocket = INVALID_SOCKET;
// TODO(baruch): Only supporting IP_V4
// Socket for server to listen on for client connections
ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(ListenSocket == INVALID_SOCKET)
{
printf("socket() error: %ld\n", WSAGetLastError());
//clean up address info after getaddrinfo function when socket fails
WSACleanup();
return 1;
}
/**************Bind Socket******************/
int bindResult = bind(ListenSocket, (SOCKADDR*)&SockAddrIP4, sizeof(SOCKADDR_IN));
if(bindResult == SOCKET_ERROR)
{
printf("failed to bind with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
/************Listen for Connections**********/
int listenResult = listen(ListenSocket, SOMAXCONN);
if(listenResult == SOCKET_ERROR)
{
printf("Listen failed, error: %d\n", WSAGetLastError() );
WSACleanup();
return 1;
}
else
{
printf("Now listening for client connections...\n");
}
/************Accept and Handle CLient Connections***********/
// TODO(baruch): For testing, only allowing a single client. Eventually need to create a loop to handle all client connections.
SOCKET ClientSocket;
SOCKADDR_IN connectedAddress;
int addressLength = sizeof(connectedAddress);
ClientSocket = accept(ListenSocket, (SOCKADDR *) &connectedAddress, &addressLength);
if(ClientSocket == SOCKET_ERROR)
{
printf("Accept failed, error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
else
{
//inet_ntoa converts ip address to binary format.
char *clientIp = inet_ntoa(connectedAddress.sin_addr);
// TODO(baruch): Make sure this string correctly prints address
printf("Client connection from: %s accepted\n", clientIp);
}
/**********Handle inbound and outbound data**********/
char inBuf[DEFAULT_BUFLEN];
int dataBufLen = DEFAULT_BUFLEN;
int inDataResult, outDataResult;
do
{
inDataResult = recv(ClientSocket, inBuf, dataBufLen, 0);
if(inDataResult > 0)
{
printf("Number of bytes received: %d", inDataResult);
//Confirm to client message received
char confirmReceipt[] = "\nMessage received!\n";
outDataResult =
send(ClientSocket, confirmReceipt, sizeof(confirmReceipt), 0);
if(outDataResult == SOCKET_ERROR)
{
printf("Confirmation message failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}
else
{
printf("Confirmation message sent\n");
}
}
else if(inDataResult == 0)
{
printf("Connection closing\n");
}
else
{
printf("Data receipt failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}
} while(inDataResult > 0);
//Shutdown sending portion of socket, can still receive data
int shutDownResult = shutdown(ClientSocket, SD_SEND);
if(shutDownResult == SOCKET_ERROR)
{
printf("Shutdown failure, error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}
/*************End Socket Code Clean up Winsock dll**********/
closesocket(ClientSocket);
WSACleanup();
}