This section of the archives stores flipcode's complete Developer Toolbox collection, featuring a variety of mini-articles and source code contributions from our readers.

| Server Socket Wrapper Submitted by

This is a socket wrapper that me and a friend wrote for use in a MUD. For our senior year in High School we have to complete a project that shows what we learned there, well a MUD shows SOME of what we learned there(we all know you can't learn anything new about computers in High School :p). The MUD is going to be sci-fi and we are working on the design doc. Anyway, the MUD was being developed in windows and the production machine is running FreeBSD 4.5. We needed a socket wrapper to allow us to debug the MUD in Windows(gotta love VC++) and would work the same(hopefully) in BSD without changing code. We also went the extra mile to ensure that it worked with other BSD OS' as well. So far the socket wrapper compiles 100% fine in the following OS': Windows 9x/NT 4 & 5/XP and FreeBSD 4.3 & 4.5. I hope someone may be able to find a use for thise code. A little about the authors, we both attend New Century Technology High School in Alabama and are in the Computer Science strand. Ben Everett works for C3 Interactive developing 3D plugins and anything else they want him to do. Chris Horlick gets to sit on his ass all day at the community pool, collect money, and tell kids not to run(with the occasional coding spree). Currently the wrapper does NOT support address banning or binary transfer, but it shouldn't be too much of a pain to add in support for these very quickly. Obike

Currently browsing [SocketWrapper.zip] (13,279 bytes) - [Socket Wrapper/Includes/BSDSocket.h] - (813 bytes)

    #ifndef __BSD_SOCKET_H_
    #define __BSD_SOCKET_H_

    namespace CPPMUD
    {
    	#ifndef _WIN32
    	// *NIX

    	class CBSDSocket : public CServerSocket
    	{
    	public:
    		// Constructor & Deconstructor
    		CBSDSocket();
    		virtual ~CBSDSocket();

    		// Public Accessor Functions

    		// Public Functions
    		virtual ErrRet CloseClient(int nClientID);
    		virtual ErrRet CloseSockets();
    		virtual ErrRet Connect(int nPort);
    		virtual ErrRet InitSockets();
    		virtual ErrRet Listen(int nPort);
    		virtual ErrRet ReadData(char *czData, int nBufferSize, int nClientID);
    		virtual void NonBlocking(SOCKET sSocket);

    		// Public Variables

    	protected:
    		// Protected Functions
    		virtual ErrRet CloseSocket(SOCKET sSocket);
    		virtual ErrRet SendData(int nClientID);

    		// Protected Variables
    	};

    	#endif
    };

    #endif

Currently browsing [SocketWrapper.zip] (13,279 bytes) - [Socket Wrapper/Includes/ENGCore.h] - (552 bytes)

    #ifndef __ENG_CORE_H_
    #define __ENG_CORE_H_

    namespace CPPMUD
    {
    	#ifdef _WIN32
    	// Windows
    	#if _MSC_VER > 1000
    	#pragma once
    	#endif
    	#else
    	// *NIX

    	#endif

    	class CENGCore
    	{
    	public:
    		// Constructor & Deconstructor
    		CENGCore();
    		virtual ~CENGCore();

    		// Public Accessor Functions
    		void Quit() { m_bQuit = true; }

    		// Public Functions
    		void EngineLoop();

    		// Public Variables

    	protected:
    		// Protected Functions

    		// Protected Variables
    		bool m_bQuit;
    		CServerSocket *m_pSocket;
    	};
    };

    #endif

Currently browsing [SocketWrapper.zip] (13,279 bytes) - [Socket Wrapper/Includes/Enums.h] - (591 bytes)

    #ifndef __ENUMS_H_
    #define __ENUMS_H_

    namespace CPPMUD
    {
    	#ifdef _WIN32
    	// Windows
    	#if _MSC_VER > 1000
    	#pragma once
    	#endif
    	#else
    	// *NIX
    	#endif

    	enum ConnState
    	{
    		csConnected,
    		csConnecting,
    		csDisconnecting,
    		csException,
    		csOverflow,
    		csTimeOut
    	};

    	enum ErrRet
    	{
    		errNone = 0,
    		errClientFullBuffer,
    		errSocketException,
    		errSocketFailClientConn,
    		errSocketFailCreate,
    		errSocketFailListen,
    		errSocketFailRead,
    		errSocketFailSelect,
    		errSocketFailWrite,
    		errSocketTimeOut,
    		errUnknownClient
    	};
    };

    #endif

Currently browsing [SocketWrapper.zip] (13,279 bytes) - [Socket Wrapper/Includes/pch.h] - (300 bytes)

    #ifndef __PCH_H_
    #define __PCH_H_

    #ifdef _WIN32
    // Windows
    #if _MSC_VER > 1000
    #pragma once
    #endif
    #else
    // *NIX
    typedef unsigned int SOCKET;
    #endif

    #include <iostream>
    #include <vector>

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>

    #include "Enums.h"

    #endif

Currently browsing [SocketWrapper.zip] (13,279 bytes) - [Socket Wrapper/Includes/Socket.h] - (2,593 bytes)

    #ifndef __SOCKET_H_
    #define __SOCKET_H_

    namespace CPPMUD
    {
    	#ifdef _WIN32
    	// Windows
    	#if _MSC_VER > 1000
    	#pragma once
    	#endif

    	#include <winsock2.h>
    	#else
    	// *NIX
    	#include <errno.h>
    	#include <fcntl.h>
    	#include <signal.h>
    	#include <unistd.h>
    	#include <sys/types.h>
    	#include <sys/socket.h>
    	#include <sys/wait.h>
    	#include <netinet/in.h>
    	#include <netdb.h>
    	#endif

    	class CClientDescriptor
    	{
    		friend class CBSDSocket;
    		friend class CServerSocket;
    		friend class CWinSocket;

    	public:
    		// Constructor & Deconstructor
    		CClientDescriptor();
    		~CClientDescriptor();

    		// Public Accessor Functions
    		const bool IsInputPending() { return m_bInputPending; }
    		const char *GetInputBuffer() { return m_czIncomingData; }
    		const ConnState GetConnState() { return m_csState; }
    		const int GetClientID() { return m_nClientID; }
    		const int GetLineFromInputBuffer(char *czOutput, int nMaxLength);
    		const SOCKET GetSocket() { return m_sSocket; }
    		const void SetConnState(ConnState csState) { m_csState = csState; }

    		// Public Functions

    		// Public Variables

    	protected:
    		// Protected Functions

    		// Protected Variables
    		bool m_bInputPending;
    		char m_czIncomingData[2048];
    		char m_czOutgoingData[2048];
    		ConnState m_csState;
    		int m_nClientID;
    		sockaddr_in m_saClientInf;
    		SOCKET m_sSocket;
    	};

    	class CServerSocket
    	{
    	public:
    		// Constructor & Deconstructor
    		CServerSocket();
    		virtual ~CServerSocket();

    		// Public Accessor Functions
    		const int GetMaxClients() { return m_nMaxClients; }
    		const int GetNumClients() { return m_vecClients.size(); }
    		void SetMaxClients(int nMaxClients) { m_nMaxClients = nMaxClients; }

    		// Public Functions
    		ErrRet CheckForNewData();
    		ErrRet SendData(char *czData, int nBufferSize, int nClientID);
    		virtual ErrRet CloseClient(int nClientID) = 0;
    		virtual ErrRet CloseSockets() = 0;
    		virtual ErrRet Connect(int nPort) = 0;
    		virtual ErrRet InitSockets() = 0;
    		virtual ErrRet Listen(int nPort) = 0;
    		virtual ErrRet ReadData(char *czData, int nBufferSize, int nClientID) = 0;
    		virtual void NonBlocking(SOCKET sSocket) = 0;

    		// Public Variables
    		std::vector<CClientDescriptor> m_vecClients;

    	protected:
    		// Protected Functions
    		ErrRet NewClient();
    		int GetIndexFromClientID(int nClientID);
    		virtual ErrRet CloseSocket(SOCKET sSocket) = 0;
    		virtual ErrRet SendData(int nClientID) = 0;

    		// Protected Variables
    		int m_nMaxClients;
    		int m_nNextClientID;
    		sockaddr_in m_saAddress;
    		SOCKET m_sSocket;
    	};
    };

    #endif

Currently browsing [SocketWrapper.zip] (13,279 bytes) - [Socket Wrapper/Includes/WinSocket.h] - (883 bytes)

    #ifndef __WIN_SOCKET_H_
    #define __WIN_SOCKET_H_

    namespace CPPMUD
    {
    	#ifdef _WIN32
    	// Windows
    	#if _MSC_VER > 1000
    	#pragma once
    	#endif

    	class CWinSocket : public CServerSocket
    	{
    	public:
    		// Constructor & Deconstructor
    		CWinSocket();
    		virtual ~CWinSocket();

    		// Public Accessor Functions

    		// Public Functions
    		virtual ErrRet CloseClient(int nClientID);
    		virtual ErrRet CloseSockets();
    		virtual ErrRet Connect(int nPort);
    		virtual ErrRet InitSockets();
    		virtual ErrRet Listen(int nPort);
    		virtual ErrRet ReadData(char *czData, int nBufferSize, int nClientID);
    		virtual void NonBlocking(SOCKET sSocket);

    		// Public Variables

    	protected:
    		// Protected Functions
    		virtual ErrRet CloseSocket(SOCKET sSocket);
    		virtual ErrRet SendData(int nClientID);

    		// Protected Variables
    		WSADATA m_wsaData;
    	};

    	#endif
    };

    #endif

Currently browsing [SocketWrapper.zip] (13,279 bytes) - [Socket Wrapper/Source/BSDSocket.cpp] - (5,518 bytes)

    /*
    	BSDSocket.cpp
    	This file serves as the wrapper for all sockets in *NIX.
    	Copyright© 2002 Ben Everett and Chris Horlick.
    	All Rights Reserved.
    */

    #include "pch.h"

    #ifndef _WIN32
    // *NIX

    // Engine Includes
    #include "Socket.h"
    #include "BSDSocket.h"

    using namespace CPPMUD;

    // Constructor & Deconstructor
    CBSDSocket::CBSDSocket()
    {
    }

    CBSDSocket::~CBSDSocket()
    {
    }

    // Functions
    ErrRet CBSDSocket::CloseClient(int nClientID)
    /*
    	Closes a client's connection by their client descriptor.
    	PRE: Server has been initialized properly, pClient is a valid pointer to a client descriptor.
    	POST: Client's connection closed.
    */
    {
    	std::vector<CClientDescriptor>::iterator itRem = m_vecClients.begin();

    	// Remove the client from the client list.
    	for (int i = 0; i < m_vecClients.size(); ++i, ++itRem)
    	{
    		if (nClientID == m_vecClients[i].m_nClientID)
    		{
    			std::cout << "Closing client #" << m_vecClients[i].m_nClientID << "'s connection." <<
    				std::endl;

    			// Close the socket.
    			close(m_vecClients[i].m_sSocket);

    			m_vecClients.erase(itRem);
    		}
    	}

    	return errNone;
    }

    ErrRet CBSDSocket::CloseSocket(SOCKET sSocket)
    /*
    	Closes a client's connection by their socket descriptor.
    	PRE: Server has been initialized properly, sSocket is a valid socket descriptor.
    	POST: Client's connection closed.
    */
    {
    	std::cout << "Closing socket, connection timed out." << std::endl;

    	// Close the socket.
    	close(sSocket);

    	return errNone;
    }

    ErrRet CBSDSocket::CloseSockets()
    /*
    	Closes all client sockets and finally the server socket.
    	PRE: Server was initialized properly.
    	POST: All sockets closed properly.
    */
    {
    	// Close all client's connections.
    	for (int i = 0; i < m_vecClients.size(); ++i)
    		close(m_vecClients[i].m_sSocket);

    	// Close the server socket so no-one else can connect.
    	close(m_sSocket);

    	// Clear the client list.
    	m_vecClients.clear();

    	return errNone;
    }

    ErrRet CBSDSocket::Connect(int nPort)
    /*
    	Connects to a server on the given port.
    	PRE: Server socket has been initialized properly, nPort is a valid port.
    	POST: Server is connected to a remote server.
    */
    {
    	// For future use, to allow servers to be inter-connected.

    	return errNone;
    }

    ErrRet CBSDSocket::InitSockets()
    /*
    	Initializes the server socket.
    	PRE: None.
    	POST: Server socket initialized.
    */
    {
    	int nReuseAddr = 1;

    	// Obtain the server socket.
    	m_sSocket = socket(AF_INET, SOCK_STREAM, 0);
    	if (m_sSocket < 0)
    		return errSocketFailCreate;

    	// Setup non-blocking on the socket
    	NonBlocking(m_sSocket);

    	return errNone;
    }

    ErrRet CBSDSocket::Listen(int nPort)
    /*
    	Listens for client connections on the given port.
    	PRE: Server has been initialized properly, nPort is a valid port.
    	POST: Server is listening for incoming client connections.
    */
    {
    	m_saAddress.sin_family = AF_INET;
    	m_saAddress.sin_addr.s_addr = htonl(INADDR_ANY);
    	m_saAddress.sin_port = htons(nPort);

    	// Bind the socket.
    	if (bind(m_sSocket, (sockaddr*)&m_saAddress, sizeof(m_saAddress)) < 0)
    	{
    		close(m_sSocket);

    		return errSocketFailCreate;
    	}

    	// Listen for any incoming connections.
    	if (listen(m_sSocket, 10) != 0)
    	{
    		close(m_sSocket);

    		return errSocketFailListen;
    	}

    	return errNone;
    }

    ErrRet CBSDSocket::ReadData(char *czData, int nBufferSize, int nClientID)
    /*
    	Reads data from the client descriptor and copies it into czData.
    	PRE: Server has been initialized properly, czData is a valid pointer to the read buffer,
    		pClient is a valid pointer to a client descriptor, nBufferSize is the length of czData..
    	POST: Client data has been read.
    */
    {
    	int nIndex = GetIndexFromClientID(nClientID);
    	int nRead = 0;

    	if (nIndex < 0)
    		return errUnknownClient;

    	nRead = recv(m_vecClients[nIndex].m_sSocket, czData, nBufferSize, 0);

    	if (nRead < 0)
    		return errSocketTimeOut;
    	else if (nRead == 0)
    		return errSocketFailRead;

    	return errNone;
    }

    ErrRet CWinSocket::SendData(int nClientID)
    /*
    	Sends as much data as possible in nClientID's outgoing buffer.
    	PRE: Server has been initialized properly, nClientID is a valid client ID.
    	POST: As much data as possible is sent from the client's outgoing buffer.
    */
    {
    	int nIndex = GetIndexFromClientID(nClientID);
    	int nLen = strlen(m_vecClients[nIndex].m_czOutgoingData);
    	int nSent = 0;

    	// Send as much data as possible to the client.
    	nSent = write(m_vecClients[nIndex].m_sSocket, m_vecClients[nIndex].m_czOutgoingData,
    		strlen(m_vecClients[nIndex].m_czOutgoingData), 0);

    	// If nSent is < 0 the socket timed out, if it = 0 there was an error somewhere, if > 0 nSent
    	//    removes that many char's from the outgoing buffer.
    	if (nSent < 0)
    		return errSocketTimeOut;
    	else if (nSent == 0)
    		return errSocketFailWrite;
    	else
    	{
    		memmove(m_vecClients[nIndex].m_czOutgoingData, m_vecClients[nIndex].m_czOutgoingData +
    			nSent, 2048 - nSent);
    		memset(m_vecClients[nIndex].m_czOutgoingData + (nLen - nSent), 0, sizeof(char) *
    			(nLen - nSent));
    	}

    	return errNone;
    }

    void CBSDSocket::NonBlocking(SOCKET sSocket)
    /*
    	Sets the given socket to non-blocking mode.
    	PRE: Server has been initialized properly, sSocket is a valid socket descriptor.
    	POST: Socket set to non-blocking mode.
    */
    {
    	int nOptions = fcntl(sSocket, F_GETFL);

    	if (nOptions < 0)
    		return;

    	nOptions |= O_NONBLOCK;
    	if (fcntl(sSocket, F_SETFL, nOptions) < 0)
    		return;
    }

    #endif

Currently browsing [SocketWrapper.zip] (13,279 bytes) - [Socket Wrapper/Source/ENGCore.cpp] - (2,035 bytes)

    /*
    	ENGCore.cpp
    	This file serves as the core for the engine, performing the engine loop.
    	Copyright© 2002 Ben Everett and Chris Horlick.
    	All Rights Reserved.
    */

    #include "pch.h"

    // Engine Includes
    #include "Socket.h"
    #include "BSDSocket.h"
    #include "WinSocket.h"
    #include "ENGCore.h"

    using namespace CPPMUD;

    // Constructor & Deconstructor
    CENGCore::CENGCore()
    {
    	m_bQuit = false;
    	m_pSocket = NULL;
    }

    CENGCore::~CENGCore()
    {
    	if (m_pSocket)
    		delete m_pSocket;

    	m_pSocket = NULL;
    }

    // Functions
    void CENGCore::EngineLoop()
    {
    	char czMessage[] = "You alive?\r\n";
    #ifdef _WIN32
    	m_pSocket = new CWinSocket;
    #else
    	m_pSocket = new CBSDSocket;
    #endif

    	if (!m_pSocket)
    		return;

    	// Unable to initialize sockets.
    	if (m_pSocket->InitSockets() != errNone)
    	{
    		if (m_pSocket)
    			delete m_pSocket;

    		m_pSocket = NULL;

    		return;
    	}

    	// Unable to listen on port 8000.
    	if (m_pSocket->Listen(8000) != errNone)
    	{
    		if (m_pSocket)
    			delete m_pSocket;

    		m_pSocket = NULL;

    		return;
    	}

    	// Engine loop.
    	while (!m_bQuit)
    	{
    		char czCommand[1024] = "";

    		memset(czCommand, 0, sizeof(char) * 1024);

    		if (m_pSocket->CheckForNewData() != errNone)
    			break;

    		for (int i = 0; i < m_pSocket->m_vecClients.size(); ++i)
    		{
    			int nLen = 0;

    			if (m_pSocket->m_vecClients[i].IsInputPending())
    			{
    				nLen = m_pSocket->m_vecClients[i].GetLineFromInputBuffer(czCommand, 1024);

    				m_pSocket->SendData(czCommand, nLen, m_pSocket->m_vecClients[i].GetClientID());

    				memset(czCommand, 0, sizeof(char) * 1024);
    			}
    		}

    		// Sleep for 100 milliseconds, to simulate ~10FPS... don't want to take up the entire CPU.
    		// *NOTE* Change this for your purposes, we just threw this in here for this wrapper
    		//    example. Our architecture is different from this examples. :)
    		Sleep(100);
    	}

    	// Close all sockets.
    	m_pSocket->CloseSockets();

    	// De-allocate the socket.
    	if (m_pSocket)
    		delete m_pSocket;

    	m_pSocket = NULL;
    }

Currently browsing [SocketWrapper.zip] (13,279 bytes) - [Socket Wrapper/Source/Main.cpp] - (804 bytes)

    /*
    	Main.cpp
    	This file serves as the main entry point for the MUD.
    	Copyright© 2002 Ben Everett and Chris Horlick.
    	All Rights Reserved.
    */

    #include "pch.h"

    // Engine Includes
    #include "Socket.h"
    #include "BSDSocket.h"
    #include "WinSocket.h"
    #include "ENGCore.h"

    using namespace std;

    // Functions
    int main(int argc, char *argv[])
    {
    	CPPMUD::CENGCore *pCore = NULL;

    	cout << "C++ MUD Base Code v0.1" << endl;
    	cout << "Allocating engine... ";

    	pCore = new CPPMUD::CENGCore;
    	if (!pCore)
    	{
    		cout << "failed." << endl;

    		return -1;
    	}

    	cout << "done." << endl << endl << "Entering game loop..." << endl << endl;

    	pCore->EngineLoop();

    	cout << endl << "Game loop complete, exiting." << endl;

    	if (pCore)
    		delete pCore;

    	pCore = NULL;

    	return 0;
    }

Currently browsing [SocketWrapper.zip] (13,279 bytes) - [Socket Wrapper/Source/pch.cpp] - (16 bytes)

    #include "pch.h"

Currently browsing [SocketWrapper.zip] (13,279 bytes) - [Socket Wrapper/Source/Socket.cpp] - (7,033 bytes)

    /*
    	Socket.cpp
    	This file serves as the base for all sockets.
    	Copyright© 2002 Ben Everett and Chris Horlick.
    	All Rights Reserved.
    */

    #include "pch.h"

    // Engine Includes
    #include "Socket.h"

    using namespace CPPMUD;

    // Constructor & Deconstructor
    CClientDescriptor::CClientDescriptor()
    {
    }

    CClientDescriptor::~CClientDescriptor()
    {
    }

    CServerSocket::CServerSocket()
    {
    	m_nMaxClients = 1;
    	m_nNextClientID = 0;

    	m_vecClients.clear();
    }

    CServerSocket::~CServerSocket()
    {
    }

    // Functions
    const int CClientDescriptor::GetLineFromInputBuffer(char *czOutput, int nMaxLength)
    /*
    	Obtains an entire line from the incoming data buffer.
    	PRE: Server has been initialized properly, czOutput is a valid pointer to a character array,
    		nMaxLength is the amount of character's czOutput can hold.
    	POST: Line copied from incoming data buffer to czOutput and the length of the line returned.
    */
    {
    	char *cLineEnd = strstr(m_czIncomingData, "\n");
    	int nLen = strlen(m_czIncomingData);
    	int nLineEnd = cLineEnd - m_czIncomingData + 1;

    	// Make sure we found an line in the input buffer.
    	if (cLineEnd == NULL)
    		return 0;

    	// Copy the line from the input buffer to czOutput.
    	for (int i = 0; i < nLineEnd; ++i)
    	{
    		// Make sure we haven't surpassed the length of czOutput.
    		if (i >= nMaxLength)
    			break;

    		czOutput[i] = m_czIncomingData[i];
    	}

    	// Remove the line from the incoming data buffer.
    	// *NOTE* In the MUD we truncate all data that surpasses czOutput, you may want to change this
    	//    for your purposes.
    	memmove(m_czIncomingData, m_czIncomingData + nLineEnd, 2048 - nLineEnd);
    	memset(m_czIncomingData + (nLen - nLineEnd), 0, sizeof(char) * (nLen - nLineEnd));

    	return i;
    }

    ErrRet CServerSocket::CheckForNewData()
    /*
    	Checks for pending client connection attempts and incoming/outgoing client data.
    	PRE: Server has been initialized properly.
    	POST: New clients connected and incoming/outgoing data flags have been set for each client.
    */
    {
    	ErrRet retVal;
    	fd_set fdExcept, fdRead, fdWrite;
    	int i = 0;
    	SOCKET sMaxDesc;
    	timeval timeNone;

    	timeNone.tv_sec = timeNone.tv_usec = 0;

    	FD_ZERO(&fdExcept);
    	FD_ZERO(&fdRead);
    	FD_ZERO(&fdWrite);

    	FD_SET(m_sSocket, &fdExcept);
    	FD_SET(m_sSocket, &fdRead);
    	FD_SET(m_sSocket, &fdWrite);

    	sMaxDesc = m_sSocket;

    	for (i = 0; i < m_vecClients.size(); ++i)
    	{
    		FD_SET(m_vecClients[i].m_sSocket, &fdRead);
    		FD_SET(m_vecClients[i].m_sSocket, &fdWrite);

    		// Clear the incoming/outgoing data flags.
    		m_vecClients[i].m_bInputPending = false;

    		// Make sure we have the highest socket descriptor.
    		if (m_vecClients[i].m_sSocket > sMaxDesc)
    			sMaxDesc = m_vecClients[i].m_sSocket;
    	}

    	select(sMaxDesc + 1, &fdRead, &fdWrite, &fdExcept, &timeNone);

    	// Check to make sure the server socket hasn't had an exception.
    	if (FD_ISSET(m_sSocket, &fdExcept))
    	{
    		std::cout << "The server socket has encountered an exception, aborting..." << std::endl;

    		return errSocketException;
    	}

    	// Check for incoming connections.
    	if (FD_ISSET(m_sSocket, &fdRead))
    	{
    		retVal = NewClient();
    		if (retVal != errNone)
    			return retVal;
    	}

    	// Check all client sockets for incoming/outgoing data.
    	for (i = 0; i < m_vecClients.size(); ++i)
    	{
    		// Incoming data, set incoming data flag on client.
    		if (FD_ISSET(m_vecClients[i].m_sSocket, &fdRead))
    		{
    			m_vecClients[i].m_bInputPending = true;

    			retVal = ReadData(m_vecClients[i].m_czIncomingData, 2048, m_vecClients[i].m_nClientID);
    			if ((retVal != errNone) && (retVal == errSocketTimeOut))
    			{
    				CloseClient(m_vecClients[i].m_nClientID);

    				continue;
    			}
    		}

    		// Send as much outgoing data as possible to the client.
    		retVal = SendData(m_vecClients[i].m_nClientID);
    		if ((retVal != errNone) && (retVal == errSocketTimeOut))
    			{
    				CloseClient(m_vecClients[i].m_nClientID);

    				continue;
    			}

    		// Close the connection if the client is overflow and all data has been sent.
    		if (m_vecClients[i].m_csState == csOverflow)
    		{
    			if (strlen(m_vecClients[i].m_czOutgoingData) == 0)
    			{
    				CloseClient(m_vecClients[i].m_nClientID);

    				continue;
    			}
    		}
    	}

    	return errNone;
    }

    ErrRet CServerSocket::NewClient()
    /*
    	Handles a client connection to the server.
    	PRE: Server has been initialized properly.
    	POST: Client connected to the server.
    */
    {
    	CClientDescriptor cdClient;
    	char *czServerFull = "We are sorry for the inconvenience, but the server is currently full.\nPlease try again later.\n";
    	int nLen = sizeof(cdClient.m_saClientInf);

    	// Set the connection state and client ID.
    	cdClient.m_nClientID = m_nNextClientID++;

    	memset(cdClient.m_czIncomingData, 0, sizeof(char) * 2048);
    	memset(cdClient.m_czOutgoingData, 0, sizeof(char) * 2048);

    	// Accept the incoming connection.
    	// *NOTE* May want to make this a virtual function and let CBSDSocket and CWinSocket handle this.
    #ifdef _WIN32
    	cdClient.m_sSocket = accept(m_sSocket, (sockaddr*)&cdClient.m_saClientInf, &nLen);
    #else
    	cdClient.m_sSocket = accept(m_sSocket, (sockaddr*)&cdClient.m_saClientInf, (socklen_t*)&nLen);
    #endif

    	// Server is full, close the connection.
    	if (m_vecClients.size() >= m_nMaxClients)
    	{
    		std::cout << "Server full, refusing access to incoming client #" << cdClient.m_nClientID <<
    			"." << std::endl;

    		cdClient.m_csState = csOverflow;

    		strcpy(cdClient.m_czOutgoingData, czServerFull);
    	}
    	else
    	{
    		// Set the connection state to connected.
    		cdClient.m_csState = csConnected;

    		std::cout << "Access to incoming connection permitted, new client #" << cdClient.m_nClientID <<
    			"." << std::endl;

    		strcpy(cdClient.m_czOutgoingData, "Connected.\r\n");
    	}

    	// Set the client socket to non-blocking.
    	NonBlocking(cdClient.m_sSocket);

    	// Append the client to the client list.
    	m_vecClients.push_back(cdClient);

    	return errNone;
    }

    ErrRet CServerSocket::SendData(char *czData, int nBufferSize, int nClientID)
    /*
    	Appends data to a client's output buffer.
    	PRE: czData is a valid pointer to a character array, nBufferSize is the length of czData,
    		nClientID is whom the data is intended for.
    	POST: New clients connected and incoming/outgoing data flags have been set for each client.
    */
    {
    	int nIndex = GetIndexFromClientID(nClientID);
    	int nOutputLen = strlen(m_vecClients[nIndex].m_czOutgoingData);

    	// Make sure there is room for the outgoing data.
    	if ((nBufferSize + nOutputLen) > 2048)
    		return errClientFullBuffer;

    	sprintf(m_vecClients[nIndex].m_czOutgoingData + nOutputLen, "%s", czData);

    	return errNone;
    }

    int CServerSocket::GetIndexFromClientID(int nClientID)
    /*
    	Returns an index into the client vector.
    	PRE: None.
    	POST: A index is returned from the client ID.
    */
    {
    	// Find the index from the client ID.
    	for (int i = 0; i < m_vecClients.size(); ++i)
    	{
    		if (m_vecClients[i].m_nClientID == nClientID)
    			return i;
    	}

    	return -1;
    }

Currently browsing [SocketWrapper.zip] (13,279 bytes) - [Socket Wrapper/Source/WinSocket.cpp] - (5,961 bytes)

    /*
    	WinSocket.cpp
    	This file serves as the wrapper for all sockets in *NIX.
    	Copyright© 2002 Ben Everett and Chris Horlick.
    	All Rights Reserved.
    */

    #include "pch.h"

    #ifdef _WIN32
    // Windows

    // Engine Includes
    #include "Socket.h"
    #include "WinSocket.h"

    using namespace CPPMUD;

    // Constructor & Deconstructor
    CWinSocket::CWinSocket()
    {
    }

    CWinSocket::~CWinSocket()
    {
    }

    // Functions
    ErrRet CWinSocket::CloseClient(int nClientID)
    /*
    	Closes a client's connection by their client descriptor.
    	PRE: Server has been initialized properly, pClient is a valid pointer to a client descriptor.
    	POST: Client's connection closed.
    */
    {
    	std::vector<CClientDescriptor>::iterator itRem = m_vecClients.begin();

    	// Remove the client from the client list.
    	for (int i = 0; i < m_vecClients.size(); ++i, ++itRem)
    	{
    		if (nClientID == m_vecClients[i].m_nClientID)
    		{
    			std::cout << "Closing client #" << m_vecClients[i].m_nClientID << "'s connection." <<
    				std::endl;

    			// Close the socket.
    			shutdown(m_vecClients[i].m_sSocket, SD_BOTH);
    			closesocket(m_vecClients[i].m_sSocket);

    			m_vecClients.erase(itRem);
    		}
    	}

    	return errNone;
    }

    ErrRet CWinSocket::CloseSocket(SOCKET sSocket)
    /*
    	Closes a client's connection by their socket descriptor.
    	PRE: Server has been initialized properly, sSocket is a valid socket descriptor.
    	POST: Client's connection closed.
    */
    {
    	std::cout << "Closing socket, connection timed out." << std::endl;

    	// Close the socket.
    	shutdown(sSocket, SD_BOTH);
    	closesocket(sSocket);

    	return errNone;
    }

    ErrRet CWinSocket::CloseSockets()
    /*
    	Closes all client sockets and finally the server socket.
    	PRE: Server was initialized properly.
    	POST: All sockets closed properly.
    */
    {
    	// Close all client's connections.
    	for (int i = 0; i < m_vecClients.size(); ++i)
    	{
    		shutdown(m_vecClients[i].m_sSocket, SD_BOTH);
    		closesocket(m_vecClients[i].m_sSocket);
    	}

    	// Close the server socket so no-one else can connect.
    	shutdown(m_sSocket, SD_BOTH);
    	closesocket(m_sSocket);

    	// Clear the client list.
    	m_vecClients.clear();

    	return errNone;
    }

    ErrRet CWinSocket::Connect(int nPort)
    /*
    	Connects to a server on the given port.
    	PRE: Server socket has been initialized properly, nPort is a valid port.
    	POST: Server is connected to a remote server.
    */
    {
    	return errNone;
    }

    ErrRet CWinSocket::InitSockets()
    /*
    	Initializes the server socket.
    	PRE: None.
    	POST: Server socket initialized.
    */
    {
    	// Start WinSock.
    	if (WSAStartup(0x0202, &m_wsaData))
    	{
    		printf("Failed.\nFailed to initialize WinSock 2.\n");

    		return errSocketFailCreate;
    	}

    	// Make sure we are running WinSock v2.
    	if (m_wsaData.wVersion != 0x0202)
    	{
    		printf("Failed.\nInvalid version of WinSock.\n");

    		return errSocketFailCreate;
    	}

    	// Initialize the socket.
    	m_sSocket = socket(AF_INET, SOCK_STREAM, 0);

    	// Setup non-blocking on the socket.
    	NonBlocking(m_sSocket);

    	return errNone;
    }

    ErrRet CWinSocket::Listen(int nPort)
    /*
    	Listens for client connections on the given port.
    	PRE: Server has been initialized properly, nPort is a valid port.
    	POST: Server is listening for incoming client connections.
    */
    {
    	m_saAddress.sin_family = AF_INET;
    	m_saAddress.sin_port = htons(nPort);
    	m_saAddress.sin_addr.s_addr = htonl(INADDR_ANY);

    	// Bind the socket.
    	if (bind(m_sSocket, (LPSOCKADDR)&m_saAddress, sizeof(m_saAddress)) == SOCKET_ERROR)
    	{
    		printf("Failed.\nUnable to bind port.\n");

    		return errSocketFailCreate;
    	}

    	// Listen for any incoming connections.
    	if (listen(m_sSocket, 10) == SOCKET_ERROR)
    	{
    		printf("Failed.\nUnable to listen for incoming connections.\n");

    		return errSocketFailListen;
    	}

    	return errNone;
    }

    ErrRet CWinSocket::ReadData(char *czData, int nBufferSize, int nClientID)
    /*
    	Reads data from the client descriptor and copies it into czData.
    	PRE: Server has been initialized properly, czData is a valid pointer to the read buffer,
    		pClient is a valid pointer to a client descriptor, nBufferSize is the length of czData..
    	POST: Client data has been read.
    */
    {
    	int nIndex = GetIndexFromClientID(nClientID);
    	int nRead = 0;

    	if (nIndex < 0)
    		return errUnknownClient;

    	nRead = recv(m_vecClients[nIndex].m_sSocket, czData, nBufferSize, 0);

    	if (nRead < 0)
    		return errSocketTimeOut;
    	else if (nRead == 0)
    		return errSocketFailRead;

    	return errNone;
    }

    ErrRet CWinSocket::SendData(int nClientID)
    /*
    	Sends as much data as possible in nClientID's outgoing buffer.
    	PRE: Server has been initialized properly, nClientID is a valid client ID.
    	POST: As much data as possible is sent from the client's outgoing buffer.
    */
    {
    	int nIndex = GetIndexFromClientID(nClientID);
    	int nSent = 0;
    	int nLen = strlen(m_vecClients[nIndex].m_czOutgoingData);

    	// Send as much data as possible to the client.
    	nSent = send(m_vecClients[nIndex].m_sSocket, m_vecClients[nIndex].m_czOutgoingData,
    		strlen(m_vecClients[nIndex].m_czOutgoingData), 0);

    	// If nSent is < 0 the socket timed out, if it = 0 there was an error somewhere, if > 0 nSent
    	//    removes that many char's from the outgoing buffer.
    	if (nSent < 0)
    		return errSocketTimeOut;
    	else if (nSent == 0)
    		return errSocketFailWrite;
    	else
    	{
    		memmove(m_vecClients[nIndex].m_czOutgoingData, m_vecClients[nIndex].m_czOutgoingData +
    			nSent, 2048 - nSent);
    		memset(m_vecClients[nIndex].m_czOutgoingData + (nLen - nSent), 0, sizeof(char) * (nLen -
    			nSent));
    	}

    	return errNone;
    }

    void CWinSocket::NonBlocking(SOCKET sSocket)
    /*
    	Sets the given socket to non-blocking mode.
    	PRE: Server has been initialized properly, sSocket is a valid socket descriptor.
    	POST: Socket set to non-blocking mode.
    */
    {
    	unsigned long lNonBlocking = 1;

    	// Set the socket to non-blocking.
    	ioctlsocket(sSocket, FIONBIO, &lNonBlocking);
    }

    #endif

The zip file viewer built into the Developer Toolbox made use of the zlib library, as well as the zlibdll source additions.

Copyright 1999-2008 (C) FLIPCODE.COM and/or the original content author(s). All rights reserved.
Please read our Terms, Conditions, and Privacy information.