/*
....[@@@..[@@@..............[@.................. 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@falcon.mercer.peachnet.edu 
MUD++ development mailing list    mudpp-list@spice.com
------------------------------------------------------------------------------
socket.h
*/

#ifndef _SOCKET_H
#define _SOCKET_H
#include "config.h"

#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <signal.h>
#include <string.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <arpa/telnet.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netdb.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 IStream 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
};
*/

#if defined( ultrix )
extern "C"
{
int socket( int, int, int );
int setsockopt( int, int, int, void *, int );
int connect( int, struct sockaddr *, int );
int accept( int, struct sockaddr *, int * );
int bind( int, struct sockaddr *, int );
int listen( int, int );
int select( int, fd_set *, fd_set *, fd_set *, struct timeval * );
int getsockname( int, struct sockaddr *, int * );
int getpeername( int, struct sockaddr *, int * );
void bzero( char *, int );
}
#endif

#ifndef FNDELAY
#define FNDELAY O_NDELAY
#endif

#ifndef EWOULDBLOCK
#define EWOULDBLOCK EGAIN
#endif


#define MAX_READ	256
#define MAX_WRITE	4096


// Telnet codes.
const char REQ_ECHO_OFF [] =
{
	(char)	IAC,
	(char)	WILL,
	(char)	TELOPT_ECHO,
	(char)	0
};

const char REQ_ECHO_ON [] =
{
	(char)	IAC,
	(char)	WONT,
	(char)	TELOPT_ECHO,
	(char)	0
};

const char TELNET_GA [] =
{
	(char)	IAC,
	(char)	GA,
	(char)	0
};

 

// These codes aren't really accurate but it is enough for the class to work
#define SOCK_NOT_CREATED		1
#define SOCK_FCNTL_ERR			2
#define SOCK_UNKNOWN_HOST		3
#define SOCK_BAD_ADDRESS		4
#define SOCK_NOT_CONNECTED		5
#define SOCK_SOCKOPT_ERR		6
#define SOCK_EOF			    7	

class Socket : public sockaddr_in
{
	protected:
		int err;
		int sock;
		char ip[ 128 ];  // char string version of ip address.

	public:

		Socket()
		:	err(0), sock(-1)
		{
			strcpy( ip, "0.0.0.0" );  // 0.0.0.0 = INADDR_ANY
			sin_port = 0;
			sin_family = AF_INET;
			sin_addr.s_addr = htonl( INADDR_ANY );
		}

		Socket( int port );
		Socket( char * address, int port );
		Socket( char * address, int port, int desc );

		~Socket()
		{
			if( sock >= 0 )
				::close( sock );
		}

		void close()
		{
			if( sock >= 0 )
				::close( sock );
			sock = -1;
		}

		int error() { return err; }
		int eof() { return ( err == SOCK_EOF ); }
		char *getHostName() { return ip; }
		int getFamily() { return sin_family; }
		void setDesc( int x ) { sock = x; }
		int getDesc() { return sock; }
		int reuseAddr();
		int noDelay();
		int nonBlock();
		int getPort() { return ntohs( sin_port ); }
		int listen();
		Socket * accept();
		int resolveIP();
		int connect();
		int getPeerName();
		int write( const char * );	
		int write( const char *, int );	
		int read( char *, int );	
		int read( char * );	
		int echoOff();
		int echoOn();
};

inline int Socket::read( char *buf )
{
	return read( buf, 1024 );
}
#endif