I'm trying to do a stress test in case attackers try to attempt a lot of TCP connections to my C++ game server at once.
I made a simple program that connects 1000 times via the TCP port to my game server. Here is where my server accepts connections:
bool serverIsOn = true;
double listen = tcplisten(12345, 30000, 1);
setnagle(listen, true);
...
while(serverIsOn){
double playerSocket = tcpaccept(listen, 1);
if(playerSocket > -1){
cout << "Got a new connection, socket ID: " << playerSocket << endl;
std::string ip = tcpip(playerSocket);
if(ipIsBanned(ip))
closesocket(playerSocket);
}
}
Here are the definitions of tcplisten and tcpaccept:
double tcplisten(double port, double max, double mode)
{
CSocket* sock = new CSocket();
if(sock->tcplisten((int)port, (int)max,(int)mode))
return AddSocket(sock);
delete sock;
return -1;
}
double tcpaccept(double sockid, double mode)
{
CSocket*sock = (CSocket*)sockets.item((int)sockid);
if(sock == NULL)return -1;
CSocket*sock2 = sock->tcpaccept((int)mode);
if(sock2 != NULL)return AddSocket(sock2);
return -1;
}
The problem: The server stops accepting connections after my test program has ended. For example, if I connect on my game after (which only requests one connection as opposed to my test-attack program which requests 1000 connections), the game can not even connect. I also do not see any connections via console output on my server anymore. The last connection made was from the attack program. It's as if it can't accept anymore and something has crashed but I can't figure out what, no exceptions or errors.
This is a huge problem for my server as anyone can easily just crash the server and force it to have to restart to start accepting new connections again.
What can I do to combat this? I mean I tried even setting the max number of connections at once to 30,000 but that didn't work. Even if it did work, someone could just try to connect more than 30,000 times making that useless.
EDIT:
More in-depth definitions of tcplisten and tcpaccept functions above:
bool CSocket::tcplisten(int port, int max, int mode)
{
if((sockid = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) return false;
SOCKADDR_IN addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(port);
if(mode)setsync(1);
if(bind(sockid, (LPSOCKADDR)&addr, sizeof(SOCKADDR_IN)) == SOCKET_ERROR)
{
closesocket(sockid);
return false;
}
if(listen(sockid, max) == SOCKET_ERROR)
{
closesocket(sockid);
//TEMP ADD
sockid = INVALID_SOCKET;
return false;
}
return true;
}
CSocket* CSocket::tcpaccept(int mode)
{
//TEMP REMOVE: if(sockid<0)return NULL;
if(sockid == INVALID_SOCKET) return NULL;
SOCKET sock2;
if((sock2 = accept(sockid, (SOCKADDR *)&SenderAddr, &SenderAddrSize)) != INVALID_SOCKET)
{
CSocket*sockit = new CSocket(sock2);
if(mode >=1)sockit->setsync(1);
return sockit;
}
return NULL;
}
EDIT 2: Here is the definition of AddSocket:
int AddSocket(CSocket*b)
{
for(int i = 0; i < sockets.count; i ++)
{
if(sockets[i] == NULL)
{
sockets.set(i, b);
return i;
}
}
sockets.Add(b);
return sockets.count-1;
}
closesocket(sockid), make sure to also setsockid = INVALID_SOCKETafterwards. Andsockid<0should besockid == INVALID_SOCKET. And why are you usingdoubleto represent sockets instead of usingSOCKETor at leastint?SOCKEThandles are not floating-point values. An what doesAddSocket()actually return? You are passing that value directly toclosesocket()if the IP is banned. Why are you not cleaning up yourCSocketobject for that client? - Remy Lebeaumaxvalue you pass tolisten()does not control how many clients can be connected at a time, it controls how many clients can be pending in the socket's backlog waiting foraccept()to accept them. You have to use your own logic to control the number of max clients connected at a time. Ifaccept()returns an accepted client, and you have exceeded your max limit, close the socket immediately. Or useWSAAccept()instead ofaccept()so you can use a callback function that rejects pending clients when your max limit has been reached. - Remy Lebeauwhile(serverIsOn)loop has stopped running, oraccept()is blocked waiting for new clients that never arrive. But you have no output when socket functions fail, or any output after your loop ends. Add those messages and then see what happens. - Remy Lebeau