mud++0.35/etc/
mud++0.35/etc/guilds/
mud++0.35/help/propert/
mud++0.35/mudC/
mud++0.35/player/
mud++0.35/src/interface/
mud++0.35/src/os/cygwin32/
mud++0.35/src/os/win32/
mud++0.35/src/os/win32/bcppbuilder/
mud++0.35/src/osaddon/
mud++0.35/src/util/
/*
....[@@@..[@@@..............[@.................. MUD++ is a written from
....[@..[@..[@..[@..[@..[@@@@@....[@......[@.... scratch multi-user swords and
....[@..[@..[@..[@..[@..[@..[@..[@@@@@..[@@@@@.. sorcery game written in C++.
....[@......[@..[@..[@..[@..[@....[@......[@.... This server is an ongoing
....[@......[@..[@@@@@..[@@@@@.................. development project.  All 
................................................ contributions are welcome. 
....Copyright(C).1995.Melvin.Smith.............. Enjoy. 
------------------------------------------------------------------------------
Melvin Smith (aka Fusion)         msmith@hom.net 
MUD++ development mailing list    mudpp@van.ml.org
------------------------------------------------------------------------------
socket.cc
*/

#include <ctype.h>
#include "config.h"
#include "socket.h"

// This is the beginning of redesigning the Server and all IO classes
// The Socket class should be in the Stream class hierarchy but as
// I have the hierarchy now, it is not easy to insert Socket since
// Sockets can't be memory mapped so the MPPIStream class wont work with it.
// The Read(), Write() functions are the same as Server:: functions and
// will replace them when Socket class is done. The Server will then
// have a slightly different role.

/*
Structures describing an Internet socket address
from sys/in.h

INADDR_ANY is 0.0.0.0 which means accept all incoming
#define INADDR_ANY ((unsigned long int) 0x00000000)

struct in_addr
{
	__u32 s_addr;
};

struct sockaddr_in
{
	short int sin_family;          Address family
	unsigned short int sin_port;   Port number ( network byte order )
	struct in_addr sin_addr;       IP address

	unsigned char __pad[ XXX ];    Pads to size of sockaddr
};
*/


int Descriptor::write( const char * buf, int size )
{
#ifndef WIN32 // UNIX
	int error;
	int bytes = 0;
	int max_write = 1024;

	if( size < max_write )
		max_write = size;

	while( 1 )
	{
		if( ( error = ::write( fd, ( buf + bytes ), max_write ) ) >= 0 )
		{
			bytes += error;
			if( bytes >= size )
				return bytes;
			else
				max_write = size - bytes;
			continue;
		}
		else
		{
			if( errno == EAGAIN || errno == EINTR )
				continue;
			else
				return -1;
		}
	}
	return -1;
#else // WIN32
	int error;
	int bytes = 0;
	int max_write = 1024;

	if( size < max_write )
		max_write = size;

	while( 1 )
	{
		if( ( error = send( fd, (buf + bytes ), max_write, 0 ) )
						!= SOCKET_ERROR )
		{
			bytes += error;
			if( bytes >= size )
				return bytes;
			else
				max_write = size - bytes;
			continue;
		}
		else
		{
			int errcode = WSAGetLastError();
			if( errcode == WSAEINTR || errcode == WSAEWOULDBLOCK )
				continue;
			else
				break;
		}
        break;
	}
	return -1;
#endif
}


int Descriptor::read( char * buf, int max )
{
#ifndef WIN32  // UNIX
	int bytes = 0;
	int error;
	while( 1 )
	{
		if( ( error = ::read( fd, buf + bytes, ( max - bytes ) ) ) > 0 )
			bytes += error;
		else if( !error )
		{
			eofd = true;
			return bytes;
		}
		else
		{
			if( errno == EAGAIN || errno == EWOULDBLOCK )
				return bytes;
			else if( errno == ECONNRESET )
			{
				eofd = true;
				return 0;
			}
			else if( errno == EINTR )
				continue;
			return error;
		}
	}
	return -1;
#else // WIN32
	int bytes = 0;
	int error;
	while( 1 )
	{
		if( ( error = recv( fd, buf + bytes, ( max - bytes ), 0 ) )
								!= SOCKET_ERROR )
		{
			if( error > 0 )
				bytes += error;
			else if( !error )
			{
				eofd = true;
				return bytes;
			}
		}
		else
		{
			int errcode = WSAGetLastError();
			if( errcode == WSAEWOULDBLOCK )
				return bytes;
			else if( errcode == WSAECONNRESET )
			{
				eofd = true;
				return 0;
			}
			else if( errcode == WSAEINTR )
				continue;
			return error;
		}
        break;
	}
	return -1;
#endif // WIN32
}


// UDP stuff not finished, just cutting and pasting from
// the TCP code, will finish soon.
int Descriptor::sendto( const char * buf, int size, int flags,
		const struct sockaddr * to, int tolen )
{
#if !defined(WIN32)
	int error;
	int bytes = 0;
	int max_write = 1024;

	if( size < max_write )
		max_write = size;

	while( 1 )
	{
		if( ( error = ::sendto( fd, ( buf + bytes ), max_write, flags,
					to, tolen ) ) >= 0 )
		{
			bytes += error;
			if( bytes >= size )
				return bytes;
			else
				max_write = size - bytes;
			continue;
		}
		else
		{
			if( errno == EAGAIN || errno == EINTR )
				continue;
			else
				return -1;
		}
	}
	return -1;
#else //WIN32
    return -1; //for now
#endif
}


// UDP stuff not finished, just cutting and pasting from
// the TCP code, will finish soon.
int Descriptor::recvfrom( char * buf, int max, int flags,
			struct sockaddr * from, int * fromlen )
{
#if !defined(WIN32)
	int bytes = 0;
	int error;
	while( 1 )
	{
		if( ( error = ::recvfrom( fd, buf + bytes, ( max - bytes ),
						flags, from, fromlen ) ) > 0 )
			bytes += error;
		else if( !error )
		{
			eofd = true;
			return bytes;
		}
		else
		{
			if( errno == EAGAIN || errno == EWOULDBLOCK )
				return bytes;
			else if( errno == ECONNRESET )
			{
				eofd = true;
				return 0;
			}
			else if( errno == EINTR )
				continue;
			return error;
		}
	}
	return -1;
#else //WIN32
    return -1;//for now
#endif
}


int Descriptor::noDelay()
{
#ifndef WIN32
	return fcntl( fd, F_SETFL, FNDELAY );
#else
	return 0;  // no corresponding function in winsock
#endif // WIN32 
}


int Descriptor::nonBlock()
{
#ifndef WIN32
	return fcntl( fd, F_SETFL, O_NONBLOCK );
#else
	u_long tempBlockVal = true;
	return ioctlsocket( fd, FIONBIO, &tempBlockVal ); //supposed to do same thing, to block change 1 to 0
#endif // WIN32 
}


#ifdef WIN32
WSADATA Socket::winfo;
#endif

Socket::Socket( int type, int port )
{
	if( type != SOCK_STREAM && type != SOCK_DGRAM )
	{
		printf( "Invalid socket type.\n" );
		mudpp_exit(0);
	}
	sock_type = type;

#ifndef WIN32
	if( ( sock = ::socket( AF_INET, sock_type, 0 ) ) == -1 )
	{
		err = SOCK_NOT_CREATED;
		return;
	}
#else
	// winsock SOCKET type is unsigned so INVALID_SOCKET e.g.(~0) is used
	if( ( sock = ::socket( AF_INET, sock_type, 0 ) ) == INVALID_SOCKET )
	{
		// Be nice and try to init winsock for the lazy programmer
		// I am the lazy type myself. -Melvin
		if( WSAGetLastError() == WSANOTINITIALISED ) 
		{
			startupWinsock();
			if( ( sock = socket( AF_INET, sock_type, 0 ) ) == INVALID_SOCKET )
			{
				Cout << "Error starting winsock.\n";
				err = SOCK_NOT_CREATED;
				return;
			}
		}
		else
		{
			err = SOCK_NOT_CREATED;
			return;
		}
	}
#endif // WIN32
	strcpy( ip, "0.0.0.0" );
	sin_port = htons( port );
	sin_family = AF_INET;
	sin_addr.s_addr = htonl( INADDR_ANY );
	err = 0;
}


Socket::Socket( int type, const char * address, int port )
{
	strcpy( ip, address );
	sin_port = htons( port );
	sin_family = AF_INET;

	if( type != SOCK_STREAM && type != SOCK_DGRAM )
	{
		printf( "Invalid socket type.\n" );
		mudpp_exit(0);
	}
	sock_type = type;

	if( isdigit( *address ) )
	{
		if( ( sin_addr.s_addr = inet_addr( address ) ) == (unsigned int)-1 )
		{
			perror( "inet_addr" );
			err = SOCK_BAD_ADDRESS;
			return;
		}
	}
	else
	{
		struct hostent *he = ::gethostbyname( address );
		if( !he )
		{
#ifndef WIN32
			perror( "gethostbyname" );
			err = SOCK_UNKNOWN_HOST;
			return;
#else
            if( WSAGetLastError() == WSANOTINITIALISED )
            {
				startupWinsock();
				he = ::gethostbyname( address );
                if( !he )
                {
					err = SOCK_NOT_CREATED;
					Cout << "gethostbyname winsock error " << WSAGetLastError()
                    	<< endl;
                    return;
                }
            }
            else
            {
				err = SOCK_NOT_CREATED;
                Cout << "gethostbyname winsock error " << WSAGetLastError()
                   	<< endl;
                return;
            }
#endif
		}

		memcpy( (char*)&sin_addr, he->h_addr, sizeof( sin_addr ) );
	}

#ifndef WIN32
	if( ( sock = ::socket( AF_INET, sock_type, 0 ) ) == -1 )
	{
		perror( "socket" );
		err = SOCK_NOT_CREATED;
		return;
	}
#else
	if( ( sock = ::socket( AF_INET, sock_type, 0 ) ) == INVALID_SOCKET )
	{
		// Be nice and try to init winsock for the lazy programmer
		// I am the lazy type myself. -Melvin
		if( WSAGetLastError() == WSANOTINITIALISED )
		{
			startupWinsock();
			if( ( sock = socket( AF_INET, sock_type, 0 ) ) == INVALID_SOCKET )
			{
				Cout << "Error starting winsock.\n";
				err = SOCK_NOT_CREATED;
				return;
			}
		}
		else
		{
			err = SOCK_NOT_CREATED;
			return;
		}
	}
#endif // WIN32
	err = 0;
}


// This is for recreating a socket on a live TCP connection after a
// reboot.
Socket::Socket( const char *address, int port, int desc )
{
	sock = desc;
	sin_port = htons( port );
	sin_family = AF_INET;
	
	sock_type = SOCK_STREAM;
	if( !*address || !strcmp( address, "0.0.0.0" ) )
	{
		strcpy( ip, "0.0.0.0" );
		return;
	}

	strcpy( ip, address );

	// These two calls don't necessarily stop the show if they fail
	// but some things might not work as planned. Need to think
	// more about how to handle failures here.
	getSockName();
	getPeerName();
/*
	Testing - getSockName() should now take care of this.
	if( isdigit( *ip ) )
	{
		if( ( sin_addr.s_addr = inet_addr( ip ) ) == (unsigned int)-1 )
		{
			perror( "inet_addr" );
			err = SOCK_BAD_ADDRESS;
			return;
		}
	}
	else
	{
		struct hostent *he;
		if( !( he = ::gethostbyname( address ) ) )
		{
			perror( "gethostbyname" );
			err = SOCK_UNKNOWN_HOST;
			return;
		}

		memcpy( (char*)&sin_addr, he->h_addr, sizeof( sin_addr ) );
	}
*/
}


#ifdef WIN32
int Socket::startupWinsock()
{
	// winsock ver 1.1
	//WORD ver = 0x0101;
	err = WSAStartup( (WORD)0x0101, &winfo );
	if( err != 0 )
	{
		Cout << "Winsock startup error " << WSAGetLastError() << endl;
		return -1;
	}
	return 0;
}
#endif


int Socket::open()
{
#ifndef WIN32
	if( ( ::bind( (int)sock,
				( sockaddr * )this, sizeof( sockaddr_in ) ) ) == -1 )
#else
	if( ( ::bind( (int)sock,
				( sockaddr * )this, sizeof( sockaddr_in ) ) ) == SOCKET_ERROR )
#endif // WIN32 
	{
		// err = SOCK_CANT_BIND;
		return -1;
	}

	// Skip listen() call for UDP sockets
	if( sock_type == SOCK_DGRAM )
		return 0;

	if( ( ::listen( (int)sock, 5 ) ) == -1 )
	{
		// err = SOCK_CANT_LISTEN;
		return -1;
	}

	return 0;
}


Socket * Socket::accept()
{
	Socket * newSock = new Socket;
	int desc;
	int size = sizeof( sockaddr_in );

	if( ( desc = ::accept( sock, ( sockaddr * ) newSock, &size ) ) < 0 )
	{
		// err = SOCK_CANT_ACCEPT;
		delete newSock;
		return 0;
	}

	newSock->setDescriptor( desc );

	if( newSock->getFamily() != AF_INET )
	{
		// err = SOCK_INVALID_ADDRESS;
		newSock->close();
		delete newSock;
		return 0;
	}

	if( newSock->noDelay() == -1 )
	{
		// err = SOCK_CANT_SET_NODELAY;
		newSock->close();
		delete newSock;
		return 0;
	}

	// Now get info for new connection
	if( newSock->getPeerName() == -1 )
	{
		// err = SOCK_CANT_GET_PEER_NAME;
		delete newSock;
		return 0;
	}

	if( newSock->resolveIP() == -1 )
	{
		delete newSock;
		return 0;
	}

	return newSock;
}


int Socket::resolveIP()
{
	struct hostent * he = ::gethostbyaddr( (char *) &sin_addr,
								sizeof( sin_addr ), AF_INET );

	if( he )
		strcpy( ip, he->h_name );
	else
	{
#ifdef WIN32
#ifdef _DEBUG
		printf ("Socket::resolveIP:gethostbyaddr error: %i\n", WSAGetLastError());
#endif // _DEBUG 
#endif // WIN32 
		unsigned long addr = ntohl( sin_addr.s_addr );
		if( (long) addr == -1 )
		{
			*ip = '\0';
			return -1;
		}

		sprintf( ip, "%ld.%ld.%ld.%ld", ( addr >> 24 ) & 0x000000ff,
					( addr >> 16 ) & 0x000000ff,
					( addr >> 8  ) & 0x000000ff,
					( addr       ) & 0x000000ff  );
	}

	return 0;
}


int Socket::getSockName()
{
	int size = sizeof( sockaddr );
	if( ::getsockname( sock, (sockaddr *)this, &size ) == -1 )
	{
		perror( "Socket::getsockname" );
		return -1;
	}

	return 0;
}


int Socket::getPeerName()
{
	int size = sizeof( sockaddr );
	if( ::getpeername( sock, (sockaddr *)this, &size ) == -1 )
	{
		perror( "Socket::getPeerName" );
		return -1;
	}

	return 0;
}


int Socket::reuseAddr()
{
	int i;
	if( ::setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, (char *)&i, sizeof(i) ) == -1 )
	{
		err = SOCK_SOCKOPT_ERR;
		return -1;
	}

	return 0;
}


int Socket::connect()
{
	if( sock_type != SOCK_STREAM )
	{
		printf( "connect: socket is not TCP.\n" );
		mudpp_exit(0);
	}

	if( ::connect( sock, (sockaddr *)this, sizeof( sockaddr ) ) )
	{
#ifdef WIN32
		err = WSAGetLastError();
        if( err != WSAEWOULDBLOCK )
        {
            Cout << "connect: winsock error " << err << endl;
			err = SOCK_NOT_CONNECTED;
#else
		if( errno != EWOULDBLOCK )
		{
			err = SOCK_NOT_CONNECTED;
#endif
			return -1;
        }
	}

	return 0;
}

int Socket::willEcho()
	{	return write( WILL_ECHO, 3 );	}

int Socket::willSuppressGA()
	{	return write( WILL_SUPPRESS_GA, 3 );	}

int Socket::wontEcho()
	{	return write( WONT_ECHO, 3 );	}

int Socket::wontSuppressGA()
	{	return write( WONT_SUPPRESS_GA, 3 );	}


bool Buf::setSize( long size )
{
	char * temp = _buf;
    _buf = new char[ size ];
	if( ! _buf )
	{
		_buf = temp;
		return false;
	}

	_buf_size = size;
	_front = _buf;
	return false;
}


// buf must be null terminated.
// use add( buf, size ) for better performance
void Buf::add( char * buf )
{
	strcpy( _front + _bytes, buf );
	_bytes += strlen( buf );
}

// buf does not have to be null terminated
// this is the fastest way to add to buffer
void Buf::add( char * buf, long bytes )
{
	// add checks for overflow and resize
	memcpy( _front + _bytes, buf, bytes );
	_bytes += bytes;
}


void Buf::filter_isprint()
{

}

char * Buf::getLine( char * line )
{
	char * ptr = line;
	char * save = _front;
	if( _bytes == 0 )
		return 0;

	for( ; _bytes > 0 && *_front != '\n'; _front++, ptr++, _bytes-- )
		*ptr = *_front;
	if( *_front != '\n' )
	{
		_front = save;
		return 0;
	}

	*(++ptr) = 0;
	if( _bytes )
		if( --_bytes && *(++_front) == '\r' )
			_bytes--, _front++;
	return line;
}

// Add support for wildcards with %
bool Buf::findLine( const char * line )
{
	return false;
}

// Add support for wildcards with %
bool Buf::findStr( const char * str )
{
	if( _bytes <= 0 )
		return false;

	int count = _bytes;
	int count2;
	const char * ptr1;
	char * ptr2 = _front;
	while( count )
	{
		ptr1 = str;
		while( count && *ptr2 != *ptr1 )
			ptr2++, count--;

		if( !count )
			return false;

 		count2 = strlen( str ) - 1;
		for( ; ; ptr1++, ptr2++, count--, count2-- )
		{
			if( !count2 )
				return true;
			if( !count )
				return false;
			if( *ptr1 != *ptr2 )
				break;
		}
	}

	return false;
}


long SocketBuf::readBuf()
{
	long bytes;
	char buf[ 4096 ];
	bytes = Socket::read( buf, 4095 );
	if( bytes > 0 )
		_inbuf.add( buf, bytes );
	return bytes;
}