#if defined (WIN32)
#include <winsock.h>
#define EWOULDBLOCK EAGAIN
#else
#define closesocket close
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#endif
#include <string>
#include <iostream> #include <cstdarg>
#include <cstdio>
#include <cerrno>
#include <fcntl.h>
#include "socket.h"
#include <time.h>
#define BACKLOG 15
const int defaultPort = 3000; using namespace std;
Socket::Socket( ) {
_disconnected = false;
_gotInput = false;
}
Socket::~Socket( ){
SocketServer::Instance()._socketList.remove( this );
SocketServer::Instance().KillSocket( this );
}
int Socket::GetDescriptor( ) {
return _sockfd;
}
void Socket::SetDescriptor( int desc ) {
_sockfd = desc;
}
string Socket::GetSocketIP( ) {
return _ipAddress;
}
void Socket::SetSocketIP( const string &ip ) {
_ipAddress = ip;
}
string Socket::GetSocketHost( ) {
return _host;
}
void Socket::SetSocketHost( const string &host ) {
_host = host;
}
void Socket::SetDisconnected( bool value ) {
_disconnected = value;
}
bool Socket::IsDisconnected( ) {
return _disconnected;
}
void Socket::SetGotInput( bool value ) {
_gotInput = value;
}
bool Socket::GotInput( ) {
return _gotInput;
}
string Socket::GetInput( ) {
return _input;
}
string Socket::GetOutput( ) {
return _output;
}
void Socket::FlushOutput( ) {
_output.erase();
}
void Socket::FlushInput( ) {
_gotInput = false;
_input.erase();
}
void Socket::SetInput( const string &input ) {
_input = input;
}
void Socket::SetOutput( const string &output ) {
_output = output;
}
void Socket::Send( char * message, ... ) {
va_list args;
char buf[MAX_BUFFER];
string buf2;
va_start( args, message );
vsprintf( buf, message, args);
buf2 = buf;
_output.append( buf2 );
va_end( args );
}
void Socket::Send( const std::string &message ) {
_output.append( message );
}
SocketServer::SocketServer( ) {
_defaultPort = defaultPort;
_newConnection = false;
#if defined WIN32
InitWinsock(); #endif
}
SocketServer::~SocketServer( ) {
#if defined WIN32
DeInitWinsock();
#endif
}
#if defined WIN32
void SocketServer::InitWinsock( ) {
WSADATA wsaData;
if ( WSAStartup( MAKEWORD( 1, 1 ), &wsaData ) != 0 ) {
fprintf( stderr, "WSAStartup failed.\n" );
exit( 1 );
}
}
void SocketServer::DeInitWinsock( ) {
WSACleanup();
}
#endif
bool SocketServer::CreateSocket( ) {
if ( ( _sockfd = socket( AF_INET, SOCK_STREAM, 0 ) ) == -1 ) {
perror( "CreateSocket::socket " );
return false;
}
return true;
}
bool SocketServer::ReuseAddress( ) {
int yes = 1;
if ( setsockopt( _sockfd, SOL_SOCKET, SO_REUSEADDR, ( const char * )&yes, sizeof(int) ) == -1 ) {
perror( "ReuseAddress::setsockopt " ); return false;
}
return true;
}
bool SocketServer::BindSocket( int port ) {
sockaddr_in my_addr;
if ( ( port < 1024 ) || ( 65535 < port ) ) {
cout << "Port " << port << " out of range.\n";
cout << "Defaulting to port" << _defaultPort << endl;
port = _defaultPort; }
if ( !ReuseAddress() )
return false;
my_addr.sin_family = AF_INET; my_addr.sin_port = htons( port ); my_addr.sin_addr.s_addr = htonl( INADDR_ANY ); memset( &( my_addr.sin_zero ), '\0', 8 ); if ( ( bind( _sockfd, ( struct sockaddr * )&my_addr, sizeof( struct sockaddr ) ) ) == -1 ) {
perror( "BindSocket::bind " );
return false;
}
return true;
}
bool SocketServer::ListenSocket( ) {
if ( listen( _sockfd, BACKLOG ) == -1 ) {
perror( "listenSocket::listen " );
return false;
}
return true;
}
void SocketServer::KillSocket( Socket * socket ) {
shutdown( socket->GetDescriptor(), 2 ); closesocket( socket->GetDescriptor() ); return;
}
void SocketServer::KillDisconnectedSockets( ) {
list< Socket * >::iterator sock;
Socket *socket;
for ( sock = _socketList.begin(); sock != _socketList.end(); ) {
socket = (*sock);
if ( socket->IsDisconnected() ) {
sock = _socketList.erase( sock );
KillSocket( socket );
cout << socket->GetSocketIP() << " has disconnected.\n\r";
} else {
++sock;
}
}
}
void SocketServer::ConceiveConnection( ) {
char buf[MAX_BUFFER];
string buf2;
struct sockaddr_in sock;
Socket * socket;
int sock_fd;
int size;
int addr;
size = sizeof( struct sockaddr_in );
#if defined (WIN32)
if ( ( sock_fd = accept( _sockfd, ( struct sockaddr* ) &sock, &size ) ) == -1 ) {
perror( "ConceiveConnection::accept " );
return;
}
#else
if ( ( sock_fd = accept( _sockfd, ( struct sockaddr* ) &sock, ( socklen_t* ) &size ) ) == -1 ) {
perror( "ConceiveConnection::accept " );
return;
}
#endif
addr = ntohl( sock.sin_addr.s_addr );
sprintf( buf, "%d.%d.%d.%d",
( addr >> 24 ) & 0xFF, ( addr >> 16 ) & 0xFF,
( addr >> 8 ) & 0xFF, ( addr ) & 0xFF
);
cout << "New connection from: " << buf << endl;
socket = new Socket;
socket->SetDescriptor( sock_fd );
socket->SetSocketIP( buf ); _socketList.push_back( socket );
_newConnection = true;
}
void SocketServer::ChaperoneConnections( ) {
int stuff;
list< Socket * >::iterator sock; int high = _sockfd;
FD_ZERO( &_fd_read );
FD_ZERO( &_fd_exc );
FD_SET( _sockfd, &_fd_read );
for ( sock = _socketList.begin(); sock != _socketList.end(); ++sock ) {
if ( SendOutput( (*sock) ) != true ) { (*sock)->SetDisconnected( true );
}
if( (*sock)->GetDescriptor() > high )
high = (*sock)->GetDescriptor();
FD_SET( (*sock)->GetDescriptor(), &_fd_read );
FD_SET( (*sock)->GetDescriptor(), &_fd_exc );
}
if ( select( high + 1, &_fd_read, NULL, &_fd_exc, 0 ) < 0 ){
perror("select: ");
return;
}
if ( FD_ISSET( _sockfd, &_fd_read ) ) {
ConceiveConnection();
}
for ( sock = _socketList.begin(); sock != _socketList.end(); ++sock ) {
if ( FD_ISSET( (*sock)->GetDescriptor(), &_fd_exc ) ) {
(*sock)->SetDisconnected( true );
continue;
}
if( FD_ISSET( (*sock)->GetDescriptor(), &_fd_read ) ) {
if ( (*sock)->GetDescriptor() == _sockfd ) {
ConceiveConnection(); } else { if ( ( stuff = RecieveInput( (*sock) ) ) == Disconnected ) { (*sock)->SetDisconnected( true );
continue;
} else if ( stuff == Complete ) {
(*sock)->SetGotInput( true );
}
}
}
}
KillDisconnectedSockets();
return;
}
int SocketServer::RecieveInput( Socket * socket ) {
string::iterator cChar;
string buf2;
string input;
long len = 0;
long result = 0;
char buf[MAX_BUFFER];
buf[0] = '\0';
strncpy( buf, "\0", sizeof( buf ) );
input = socket->GetInput();
if ( ( ( result = recv( socket->GetDescriptor(), buf + len, sizeof( buf ) - len, 0 ) ) <= 0 ) ) {
if ( result == 0 ) {
} else if ( errno == EWOULDBLOCK ) {
input.append( buf );
socket->SetInput( input );
for ( cChar = input.begin(); cChar != input.end(); ++cChar ) {
if ( (*cChar) == '\n' || (*cChar) == '\r' ) {
return Complete;
}
}
return Incomplete;
} else {
perror( "RecieveInput::recv " );
}
return Disconnected;
}
len += result;
if ( buf[len-1] == 8 || buf[len-1] == 127 ) {
if ( strlen( buf ) > 0) {
buf[len-1] = '\0';
buf[len-2] = '\0';
len -= 2;
} else {
buf[len-1] = '\0';
len--;
}
}
input.append( buf );
socket->SetInput( input );
for ( cChar = input.begin(); cChar != input.end(); ++cChar ) {
if ( (*cChar) == '\n' || (*cChar) == '\r' ) {
return Complete;
}
}
return Incomplete;
}
bool SocketServer::SendOutput( Socket * socket ) {
string buf;
string buf2;
if ( socket->GetOutput().empty() )
return true;
buf = socket->GetOutput();
if ( send( socket->GetDescriptor(), buf.c_str(), buf.length(), 0 ) < 0 ) {
perror( "SendOutput::send " );
return false;
}
socket->FlushOutput();
return true;
}
int SocketServer::GetHostSocket( ) {
return _sockfd;
}
void SocketServer::SetHostSocket( int sockfd ) {
_sockfd = sockfd;
}
void SocketServer::Start( ) {
CreateSocket( ); BindSocket( _defaultPort ); ListenSocket( ); }
void SocketServer::Start( int port ) {
CreateSocket( ); BindSocket( port ); ListenSocket( ); }
bool SocketServer::Monitor ( ) {
ChaperoneConnections();
if ( _newConnection ) {
_newConnection = false;
return true;
}
return false;
}