More than one connection from same IP causing error

Started by
1 comment, last by Blaste 20 years, 10 months ago
I've been writing a simple telnet server to relay messages back and forth between users as network programming practice, but somehow I skrewed up. The code below buggs out if more than one user from the same IP address logs in, or if someone continuously opens connections from a win2k telnet without closing them. Help appreciated. Any suggestions to the code would be great too.

/************************************************************************/
/* Implementation Variables - Static Declarations                       */
/************************************************************************/

static WSADATA net_wsaData;
static unsigned short net_port = 8451; 
static net_sock net_listen;
static int net_userCount = 0;
static net_sock* index = NULL;
static net_sock* root = NULL;
static int net_sizeSockAddr = sizeof(sockaddr);

/************************************************************************/
/* Interface Variables - Global Declarations                            */
/************************************************************************/

/************************************************************************/
/* Implementation Function Headers                                      */
/************************************************************************/

static void newConnection(void);
static void remConnection(net_sock* newCon);
static void addUser(net_sock* newCon);
static void remUser(SOCKET s);
static net_sock* findUser(SOCKET s);
static void remAllUsers(void);

/************************************************************************/
/* Implementation Functions - Static Declarations (or WinMain)          */
/************************************************************************/

// Order of a new connection is as follows: newConnection()

//                                          addUser()

// Order of closing a connection: remUser()

//                                remConnection()


// Handles initialization and connection of the new user, and adds if acceptable

// Checks for max connections and if the user, or site is banned

static void newConnection(void)
{
	// Create the socket

	net_sock* newCon = SYS_MALLOC(net_sock, 1);

	// If there is no root, it should be null, so this is safe no matter what

	newCon->next = root;
	newCon->prev = NULL;

	// Initiate the socket and all

	newCon->sock = accept(net_listen.sock, (sockaddr*)&newCon->addr, &net_sizeSockAddr);
	if(newCon->sock == INVALID_SOCKET)
	{
		SYS_Error("addUser: Attempting to accept invalid socket: %i", WSAGetLastError());
	}
	DBG_Print("New connection from %s\n", inet_ntoa(newCon->addr.sin_addr));
	if(net_userCount >= NET_MAXCON)
	{
		NET_SendToCon(newCon, "Sorry, the server is full right now. Try connecting again later.");
		remConnection(newCon);
	}
	else
	{
		addUser(newCon);
	}
}

// Adds a confirmed user to the list of users

static void addUser(net_sock* newCon)
{
	// Reassign the root and index

	root = newCon;
	index = root;
	net_userCount++;
	DBG_Print("Adding user from %s.\n    %i connections.\n", inet_ntoa(index->addr.sin_addr), net_userCount);
}

// Removes a user from the list and then disconnects

static void remUser(SOCKET s)
{
	// Re-link the list

	net_sock* rem = findUser(s);
	if(rem == NULL)
	{
		SYS_Error("removeUser: Attempting to remove user which does not exist.");
	}

	if(rem->prev == NULL && rem->next == NULL)
	{
		root = NULL;
	}
	else if(rem->prev == NULL)
	{
		rem->next->prev = NULL;
		root = rem->next;
	}
	else if(rem->next == NULL)
	{
		rem->prev->next = NULL;
	}
	else
	{
		rem->prev->next = rem->next;
		rem->next->prev = rem->prev;
	}
	net_userCount--;
	DBG_Print("Removing user from %s\n    %i connections.\n", inet_ntoa(rem->addr.sin_addr), net_userCount);
	remConnection(rem);
	SYS_FREE(rem);
}

// Closes a connection

static void remConnection(net_sock* remCon)
{
	// Shutdown the socket

	shutdown(remCon->sock, SD_SEND);
	closesocket(remCon->sock);
}

// Returns the index of the socket requested

static net_sock* findUser(SOCKET s)
{
	// Loop through the list until the object is found

	index = root;
	while((index->sock != s) && (index->next != NULL))
	{
		index = index->next;
	}
	if(index->sock == s)
	{
		return index;
	}
	else
	{
		return NULL;
	}
}

// Remove all users

static void remAllUsers(void)
{
	while(root != NULL)
	{
		remUser(root->sock);
	}
}

/************************************************************************/
/* Interface Functions - Global Declarations                            */
/************************************************************************/

// Initiates WinSock 2.2

void NET_Init(void)
{
	// Initiate WinSock 2.2

	int errNum= WSAStartup(MAKEWORD(2, 2), &net_wsaData);
	if(errNum != 0)
	{
		SYS_Error("NET_Init: Unable to initiate WinSock: %i", errNum);
	}
	DBG_Print("WinSock v2.2 Initiated\n");

	// Create the listen socket

	net_listen.sock = socket(AF_INET, SOCK_STREAM, 0);
	if(net_listen.sock == INVALID_SOCKET)
	{
		SYS_Error("NET_Init: Unable to create listen socket: %i", WSAGetLastError());
	}

	// Setup the listen address

	net_listen.addr.sin_family = AF_INET;
	net_listen.addr.sin_port = htons(net_port);
	net_listen.addr.sin_addr.s_addr = htonl(INADDR_ANY);
	memset(&(net_listen.addr.sin_zero), '\0', 8);
	
	// Bind the socket

	if(bind(net_listen.sock, (sockaddr*)&net_listen.addr, sizeof(sockaddr)) == SOCKET_ERROR)
	{
		SYS_Error("NET_Init: Unable to bind listen socket: %i", WSAGetLastError());
	}

	// Convert socket to listen socket

	if(listen(net_listen.sock, NET_BACKLOG) == SOCKET_ERROR)
	{
		SYS_Error("NET_Init: Unable to set listen socket to listen: %i", WSAGetLastError());
	}

	// Convert to asyncronous socket (sends windows messages)

	if(WSAAsyncSelect(net_listen.sock, sys_hwnd, NET_WINSOCK, (FD_READ | FD_ACCEPT | FD_CLOSE)) == SOCKET_ERROR)
	{
		SYS_Error("Net_Init: Unable to convert listen socket to asyncronous socket: %i", WSAGetLastError());
	}
	DBG_Print("Listen socket ready to rock on port %i.\n", ntohs(net_listen.addr.sin_port));
}

// Shuts down the listen socket, disconnects all users

void NET_Shutdown(void)
{
	// Disconnect all current connections

	remAllUsers();
	// Close down the listen socket

	shutdown(net_listen.sock, SD_SEND);
	closesocket(net_listen.sock);
	// Close down winsock

	WSACleanup();
	DBG_Print("WinSock v2.2 shutdown");
}

// The "message loop" of the net work code

void NET_Control(LPARAM lParam, WPARAM wParam)
{
	switch(WSAGETSELECTEVENT(lParam))
	{
	case FD_ACCEPT:
		newConnection();
		break;

	case FD_READ:
		// Not in use yet...

		break;

	case FD_CLOSE:
		remUser(wParam);
		break;
	}
}

// Sends text to a socket

void NET_SendToSock(SOCKET s, char* buf)
{
	int err = send(s, buf, strlen(buf), 0);
	if(err == SOCKET_ERROR && err != WSAEWOULDBLOCK)
	{
		SYS_Error("NET_SendToSock: Could not send message: %i", WSAGetLastError());
	}
}

// Sends text to a connection

void NET_SendToCon(net_sock* con, char* buf)
{
	int err = send(con->sock, buf, strlen(buf), 0);
	if(err == SOCKET_ERROR && err != WSAEWOULDBLOCK)
	{
		SYS_Error("NET_SendToCon: Could not send message: %i", WSAGetLastError());
	}
}
I know thats a lot of code, and I'm sorry. The error that hits "Attempting to remove user which does not exist" error, which occurs because I was not able to find a user based on the socket. There are a few macros and constants in there that may confuse a little but, but SYS_Error, and DBG_Print are both just error prevention and whatnot. There are prototypes for the interface functions in the header. Thanks ahead of time. ~Blaste [edited by - Blaste on June 3, 2003 12:05:19 AM]
Advertisement
I figured I''d bump this once just to see if I could get an answer before I start all over again.
some suggestions for your code:
-pass port number as a parameter rather than using it as a global variable.
-for global variables that must indeed be global, append some notation that tells the reader that they are indeed global e.g. (g_Root rather than just ''root''). In general, the liberal use of global data is frowned upon, as it makes maintenance (and debugging!) a pain in the rump.
-remUser(SOCKET s) you are using a global variable that contains this data, why are you using a parameter?

As far as debugging, I would recommend that you put a break point on the line that is printing the error message, then go back through your call stack to find out exactly where it gets called. It could be caused by a bad list pointer caused by errant modification of your global ''root''.

Good luck.

This topic is closed to new replies.

Advertisement