This just came rolling out my test lab, I haven't debugged it throughly and there are probably some bugs here and there, apart from that enjoy:
Documentation stops halfway through, I'm to lazy to keep it up.
Overview:
bool p2p_startup(); initializes WSA
bool p2p_cleanup(); closes WSA
class RAW_SOCKET:
Accepts a socket, or an address + port as arguments. Lets you send data over the network by RAW_SOCKET_SEND( char* data, int size ) and receive data (nonblocking) with RAW_SOCKET_RECV( char* data, int size ). good() returns false if the socket has an error, and failed() sets the error flag. Lastly there's RAW_SOCKET_OPEN which opens a socket.
class CSTD_SOCKET:
Accepts a socket or an address + port as arguments. Lets you send data over the network with CSTD_PRINTF_SEND( char* Format, ... ) which works just like printf(). Accepted format: %x %d %c %s, so no %ll %.8x.5d or anything else fancy. It lets you receive data with CSTD_GETC() which returns the next char in the network stack and CSTD_GETS( char* str, int length ) which fills str with a string ( = it stops reading at '\n', '\0' or when size = length )
class CPP_SOCKET:
Accepts a socket or an address + port as arguments. Lets you send data over the network like this:
CPP_SOCKT cpp;
cpp << "string"; // string
cpp << 102; // cpp<< 0x102;
cpp << 'c' // char
Lets you read like this:
cout << cpp;
char Buffer[1024];
cpp >> Buffer;
int Number;
cpp >> Number;
char c;
cpp >> c;
class SERVER_SOCKET:
Lets you setup a server, for example:
Code:
void My_callback( SOCKET *s ){
CPP_SOCKET cpp ( *s );
int a = 0;
cpp >> a;
cout << hex << a;
cpp.CPP_CLOSE();
return;
}
int main(){
if( !p2p_startup() ) { printf("WSA error\n"); return; }
SERVER_SOCKET SCHiMSocket( 4040 );
if( !SCHiMSocket.good() ) { printf("Error\n"); return; }
SCHiMSocket.Start_Listening();
while( SCHiMSocket.good() ){
SCHiMSocket.Accept( My_callback );
}
p2p_cleanup();
system("pause");
}
SERVER_SOCKET::Accept() expects a function pointer of type: void (*My_callback)(SOCKET* sock).
notes:
RAW_SOCKET::RECV() is non-blocking, it's timeout is 1 second, this means that if there's no data the function will return after one second. If there's data to be read it returns almost immediately.
SERVER_SOCKET::Accept()
is blocking, it won't return until a client has connected. This is by design so that you can limit the amount of users connected to your server.
Have fun.
p2p-class.h
Code:
#ifndef P2P_C_H
#define P2P_C_H
#include <Winsock2.h>
#include <iostream>
#include <string>
typedef sockaddr_in Socket_Address_info;
extern bool p2p_startup();
extern bool p2p_cleanup();
using namespace std;
class RAW_SOCKET{
SOCKET s;
bool fail;
public:
RAW_SOCKET( char* Address, int Port );
RAW_SOCKET( SOCKET s );
~RAW_SOCKET();
void RAW_SOCKET_OPEN( char* Address, int Port );
void RAW_SOCKET_SEND( void* Buffer, int Size );
void RAW_SOCKET_RECV( void* Buffer, int Size );
bool good();
void failed();
};
class CSTD_SOCKET : public RAW_SOCKET{
public:
CSTD_SOCKET( char* Address, int Port );
CSTD_SOCKET( SOCKET s );
~CSTD_SOCKET();
void CSTD_PRINTF_SEND( char* Format, ... );
char CSTD_GETC();
void CSTD_GETS( char* Buffer, int Size );
void CSTD_CLOSE();
};
class CPP_SOCKET : public CSTD_SOCKET {
public:
CPP_SOCKET( char* Address, int port );
CPP_SOCKET( SOCKET s );
~CPP_SOCKET();
friend istream& operator >>( istream &is, CPP_SOCKET &socket );
friend void operator >>( CPP_SOCKET &socket, char *Buffer );
friend void operator >>( CPP_SOCKET &socket, char &c );
friend void operator >>( CPP_SOCKET &socket, int &Number );
friend ostream& operator <<( ostream &os, CPP_SOCKET &socket );
friend void operator <<( CPP_SOCKET &socket, char* Buffer );
friend void operator <<( CPP_SOCKET &socket, char c );
friend void operator <<( CPP_SOCKET &socket, int i );
void CPP_CLOSE();
};
class SERVER_SOCKET{
SOCKET s;
bool fail;
public:
SERVER_SOCKET( int Port );
~SERVER_SOCKET();
void Start_Listening();
void Stop_Listenig();
void Accept( void (*My_callback)(SOCKET *s) );
bool good();
void failed();
};
#endif
p2p-class.cpp
Code:
#include <Winsock2.h>
#include <windows.h>
#include <iostream>
#include <string>
#include "p2p-class.h"
#pragma comment(lib, "ws2_32.lib")
using namespace std;
/***********************************************************************
bool p2p_startup( void ){
Constructor{
does nothing on error
} Returns true if wsa is turned on
}
************************************************************************/
bool p2p_startup(){
WSADATA WsaData;
if( !WSAStartup( MAKEWORD(2,2), &WsaData ) ) return true; else return false;
}
/***********************************************************************
bool p2p_cleanup( void ){
Destructor{
does nothing on error
} Returns true if wsa is turned off
}
************************************************************************/
bool p2p_cleanup(){
if( !WSACleanup() ) return true; else return false;
}
/***********************************************************************
bool check_ip( char * ){
Support{
does nothing on error
} returns true if p is an ip address
}
************************************************************************/
bool check_ip(char *p){
while(*p != '\0')
{
if(isxdigit(*p)==0)
{
if(ispunct(*p)==0)
{
return false;
}
}
p++;
}
return true;
}
/***********************************************************************
RAW_SOCKET::RAW_SOCKET( char*, int ) / ( SOCKET ){
Constructor{
Sets fail on error
} connects s to address;
}
************************************************************************/
RAW_SOCKET::RAW_SOCKET( char* Address, int port ){
RAW_SOCKET_OPEN( Address, port );
}
RAW_SOCKET::RAW_SOCKET( SOCKET ms ){
s = ms;
}
/***********************************************************************
RAW_SOCKET::RAW_SOCKET_OPEN( char*, int ){
Constructor{
Sets fail on error
} connects s to address;
}
************************************************************************/
void RAW_SOCKET::RAW_SOCKET_OPEN( char* Address, int Port ){
s = NULL;
Socket_Address_info Socket_address = { 0 };
fail = false;
//create a socket
s = socket(AF_INET, SOCK_STREAM, 0);
//This should never happen
if( s == INVALID_SOCKET ){
fail = true;
return;
}
//see if the argument is a ip address or an url
if( !check_ip( Address ) ){
//process a hostname here
hostent *h = gethostbyname( Address );
if( !h ){
// error occured
fail = true;
return;
}
// use the first ip address resolved
Socket_address.sin_addr.S_un.S_addr = inet_addr( inet_ntoa (*((struct in_addr *) h->h_addr_list[0])) );
} else {
// process a raw ip address here
Socket_address.sin_addr.S_un.S_addr = inet_addr( inet_ntoa (*((struct in_addr *) Address )));
}
// fill-out the last members of the struct
Socket_address.sin_family = AF_INET;
Socket_address.sin_port = htons( Port );
//try to connect the socket
if( connect(s, (SOCKADDR*) &Socket_address, sizeof(Socket_address) ) != SOCKET_ERROR ){
fail = false;
} else {
fail = true;
}
return;
}
/***********************************************************************
RAW_SOCKET::~RAW_SOCKET( void ){
Destructor{
can't fail
} returns returns nothing
}
************************************************************************/
RAW_SOCKET::~RAW_SOCKET(){
closesocket( s );
}
/***********************************************************************
RAW_SOCKET::RAW_SOCKET_SEND( char*, int ){
Functionality{
sets fail on error
} returns returns nothing
}
************************************************************************/
void RAW_SOCKET::RAW_SOCKET_SEND( void* Buffer, int Size ){
fail = false;
//Remove null pointers and a send size of 0
if( !Buffer || !Size ){ fail = true; return; }
//Verify we have access to the buffer
if( IsBadReadPtr( Buffer, Size ) ){ fail = true; return; }
//Send data over the line
if( send( s, reinterpret_cast< char* > ( Buffer ), Size, 0 ) == SOCKET_ERROR ) fail = true;
return;
}
/***********************************************************************
RAW_SOCKET::RAW_SOCKET_RECV( char*, int ){
Functionality{
sets fail on error
} returns returns nothing
}
************************************************************************/
void RAW_SOCKET::RAW_SOCKET_RECV( void* Buffer, int Size ){
fail = false;
//Remove null pinters and a read size of 0
if( !Buffer || !Size ){ fail = true; return; }
//Verify we can write to this buffer
if( IsBadWritePtr( Buffer, Size ) ){ fail = true; return; }
//Does this socket have any data?
fd_set r_socks, w_socks, err_socks;
FD_ZERO(&r_socks);
FD_ZERO(&w_socks);
FD_ZERO(&err_socks);
FD_SET(s, &r_socks);
timeval tTime = { 1, 0 };
int r = select( 0, &r_socks, &w_socks, &err_socks, &tTime );
if(r != 0 && r != SOCKET_ERROR ){
//Receive data on line
int r = recv( s, reinterpret_cast< char* > ( Buffer ), Size, 0 );
if( r == SOCKET_ERROR || r == 0 ) fail = true;
} else { fail = true; }
return;
}
/***********************************************************************
RAW_SOCKET::good( void ){
Error checking{
does nothing on error
} returns false if an error has previously occured
}
************************************************************************/
bool RAW_SOCKET::good(){
return !fail;
}
/***********************************************************************
RAW_SOCKET::failed( void ){
Error checking{
does nothing on error
} returns nothing
}
************************************************************************/
void RAW_SOCKET::failed(){
fail = true;
}
/***********************************************************************
CSTD_SOCKET::CSTD_SOCKET( void ){
Constructor{
does nothing on error
} returns nothing
}
************************************************************************/
CSTD_SOCKET::CSTD_SOCKET( char* Address, int Port ) : RAW_SOCKET( Address, Port ){}
CSTD_SOCKET::CSTD_SOCKET( SOCKET s ) : RAW_SOCKET( s ){}
/***********************************************************************
CSTD_SOCKET::~CSTD_SOCKET( void ){
Destructor{
does nothing on error
} returns nothing
}
************************************************************************/
CSTD_SOCKET::~CSTD_SOCKET(){}
/***********************************************************************
CSTD_SOCKET::CSTD_PRINTF_SEND( char*, ... ){
Functionality{
sets fail on error
} returns nothing
}
************************************************************************/
void CSTD_SOCKET::CSTD_PRINTF_SEND( char* Format, ... ){
//remove null pointers
if( !Format ){ failed(); return; }
const char *p;
int i = 0, Count = strlen( Format ), iTemp;
va_list argp;
va_start( argp, Format );
char *Stream = (char*) malloc( sizeof( char ) * Count ), *sTemp;
for(i = 0, p = Format; *p != '\0'; p++, i++){
if(*p != '%'){
Stream[ i ] = *p;
continue;
}
switch(*++p){
case 'c':
Count++;
Stream[ i ] = va_arg( argp, char );
break;
case 'd':
Count += 4;
Stream = (char*) realloc( Stream, sizeof( char ) * Count );
sTemp = new char[4];
iTemp = va_arg( argp, int );
_itoa_s( iTemp, sTemp, 4, 10 );
memcpy( &Stream[i], sTemp, strlen( sTemp ) );
i += strlen( sTemp )-1;
delete [] sTemp;
break;
case 's':
sTemp = va_arg(argp, char *);
Count += strlen( sTemp );
Stream = (char*) realloc( Stream, sizeof( char ) * Count );
memcpy( &Stream[i], sTemp, strlen( sTemp ) );
i += strlen( sTemp )-1;
break;
case 'x':
Count += 4;
Stream = (char*) realloc( Stream, sizeof( char ) * Count );
sTemp = new char[4];
iTemp = va_arg( argp, int );
_itoa_s( iTemp, sTemp, 4, 16 );
memcpy( &Stream[i], sTemp, strlen( sTemp ) );
i += strlen( sTemp )-1;
delete [] sTemp;
break;
case '%':
Count++;
Stream = (char*) realloc( Stream, sizeof( char ) * Count );
Stream[ i ] = '%';
break;
default:
Count++;
Stream = (char*) realloc( Stream, sizeof( char ) * Count );
Stream[ i ] = *p;
break;
}
}
va_end(argp);
if( Count > i )
memset( &Stream[i], 0, Count - (i+1) );
Count = strlen( Stream );
RAW_SOCKET_SEND( Stream, Count );
free( (void*) Stream );
return;
}
/***********************************************************************
CSTD_SOCKET::CSTD_GETC( void ){
Functionality{
sets fail on error
} returns a char
}
************************************************************************/
char CSTD_SOCKET::CSTD_GETC(){
char Buffer = 0 ;
RAW_SOCKET_RECV( (void*) &Buffer, 1 );
return Buffer ;
}
/***********************************************************************
CSTD_SOCKET::CSTD_GETS( char*, int ){
Functionality{
sets fail on error
} returns nothing, gets a string in buffer, breaks if the string is larger then size or on \n and \0
}
************************************************************************/
void CSTD_SOCKET::CSTD_GETS( char* Buffer, int Size ){
//remove null pointers and a buffer size of 0
if( !Buffer || !Size ){ failed(); return; }
//Verify we can write to this buffer
if( IsBadWritePtr( Buffer, Size ) ){ failed(); return; }
char* Line_Buffer = (char*) malloc( sizeof( char ) );
int i = 0;
for( i = 0; i < Size; i++){
Line_Buffer[i] = CSTD_GETC();
if( Line_Buffer[i] == '\n' || Line_Buffer[i] == '\0' )
break;
}
memcpy( Buffer, Line_Buffer, i );
}
/***********************************************************************
CSTD_SOCKET::CSTD_CLOSE( void ){
Functionality{
does nothing on error
closes connection
destroys object
} returns nothing
}
************************************************************************/
void CSTD_SOCKET::CSTD_CLOSE(){
CSTD_SOCKET::~CSTD_SOCKET();
}
CPP_SOCKET::CPP_SOCKET( char* Address, int Port ) : CSTD_SOCKET( Address, Port ) {}
CPP_SOCKET::CPP_SOCKET( SOCKET s ) : CSTD_SOCKET( s ) {}
CPP_SOCKET::~CPP_SOCKET() {}
istream& operator >>(istream &is,CPP_SOCKET &socket){
char* Buffer = 0;
int Lenght = 0;
is.seekg (0, ios::end);
Lenght = is.tellg();
is.seekg (0, ios::beg);
Buffer = new char[ Lenght ];
is >> Buffer;
socket.RAW_SOCKET_SEND( (void*)Buffer, Lenght );
delete [] Buffer;
return is;
}
void operator >>( CPP_SOCKET &socket, char* Buffer ){
int i = 0;
do{
Buffer[i++] = socket.CSTD_GETC();
} while ( socket.good() );
return;
}
void operator >>( CPP_SOCKET &socket, char &c ){
c = socket.CSTD_GETC();
return;
}
void operator >>( CPP_SOCKET &socket, int& Number ){
char* Buffer = new char[4];
socket.RAW_SOCKET_RECV( Buffer, 4 );
Number = strtol( Buffer, NULL, 16 );
delete [] Buffer;
return;
}
ostream& operator <<(ostream &os,CPP_SOCKET &socket){
do{
os << socket.CSTD_GETC();
} while ( socket.good() );
return os;
}
void operator <<( CPP_SOCKET &socket, char* Buffer ){
socket.RAW_SOCKET_SEND( (void*)Buffer, strlen( Buffer ) );
return;
}
void operator <<( CPP_SOCKET &socket, char c ){
socket.RAW_SOCKET_SEND( (void*)&c, 1 );
return;
}
void operator <<( CPP_SOCKET &socket, int i ){
char* Buffer = new char[4];
_itoa_s( i, Buffer, 4, 16 );
socket.RAW_SOCKET_SEND( (void*)Buffer, strlen( Buffer ) );
delete [] Buffer;
return;
}
void CPP_SOCKET::CPP_CLOSE(){
CPP_SOCKET::~CPP_SOCKET();
}
SERVER_SOCKET::SERVER_SOCKET( int Port ){
fail = false;
Socket_Address_info Socket_address = { 0 };
s = socket( AF_INET, SOCK_STREAM, 0 );
if( s == INVALID_SOCKET ){
failed();
return;
}
char *ac = new char[MAX_PATH];
if( gethostname(ac, MAX_PATH) == SOCKET_ERROR){
failed();
delete [] ac;
return ;
}
hostent *h = gethostbyname( ac );
delete [] ac;
if( !h ){
failed();
return;
}
Socket_address.sin_family = AF_INET;
Socket_address.sin_port = htons( Port );
Socket_address.sin_addr.S_un.S_addr = inet_addr( inet_ntoa (*((struct in_addr *) h->h_addr_list[0])) );
if( bind( s, (SOCKADDR*) &Socket_address, sizeof(Socket_address) ) == SOCKET_ERROR ){
failed();
return;
}
}
SERVER_SOCKET::~SERVER_SOCKET(){
closesocket( s );
}
void SERVER_SOCKET::Start_Listening(){
listen(s, SOMAXCONN);
}
void SERVER_SOCKET::Stop_Listenig(){
SERVER_SOCKET::~SERVER_SOCKET();
}
void SERVER_SOCKET::Accept( void (*My_callback)(SOCKET *Socket) ){
SOCKET *Callback_socket = new SOCKET;
if( Callback_socket != NULL ){
*Callback_socket = accept(s, NULL, NULL);
if( *Callback_socket == INVALID_SOCKET ){
failed();
return;
}
CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)My_callback, Callback_socket, 0, NULL);
} else {
failed();
}
return;
}
bool SERVER_SOCKET::good(){
return !fail;
}
void SERVER_SOCKET::failed(){
fail = true;
return;
}