/************************************************************************/
/* 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]
More than one connection from same IP causing error
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.
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.
-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
Popular Topics
Advertisement