This commit is contained in:
glenux 2006-01-10 10:42:33 +00:00
commit 79936bfa0c
23 changed files with 1356 additions and 0 deletions

0
AUTHORS Normal file
View file

0
COPYING Normal file
View file

0
ChangeLog Normal file
View file

0
Doxyfile Normal file
View file

0
INSTALL Normal file
View file

3
Makefile.am Normal file
View file

@ -0,0 +1,3 @@
SUBDIRS = src
EXTRA_DIST = doc INSTALL README Doxyfile autogen.sh

0
NEWS Normal file
View file

0
README Normal file
View file

11
autogen.sh Executable file
View file

@ -0,0 +1,11 @@
echo "libtoolize..."
libtoolize
echo "aclocal..."
aclocal
echo "autoheader..."
autoheader
echo "autoconf..."
autoconf
echo "automake..."
automake -a
echo "ok."

61
config.h.in Normal file
View file

@ -0,0 +1,61 @@
/* config.h.in. Generated from configure.in by autoheader. */
/* Define to 1 if you have the <dlfcn.h> header file. */
#undef HAVE_DLFCN_H
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
/* Define to 1 if you have the <iostream> header file. */
#undef HAVE_IOSTREAM
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
/* Define to 1 if you have the <sstream> header file. */
#undef HAVE_SSTREAM
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H
/* Define to 1 if you have the <stdlib.h> header file. */
#undef HAVE_STDLIB_H
/* Define to 1 if you have the <strings.h> header file. */
#undef HAVE_STRINGS_H
/* Define to 1 if you have the <string.h> header file. */
#undef HAVE_STRING_H
/* Define to 1 if you have the <sys/stat.h> header file. */
#undef HAVE_SYS_STAT_H
/* Define to 1 if you have the <sys/types.h> header file. */
#undef HAVE_SYS_TYPES_H
/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
/* Name of package */
#undef PACKAGE
/* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT
/* Define to the full name of this package. */
#undef PACKAGE_NAME
/* Define to the full name and version of this package. */
#undef PACKAGE_STRING
/* Define to the one symbol short name of this package. */
#undef PACKAGE_TARNAME
/* Define to the version of this package. */
#undef PACKAGE_VERSION
/* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS
/* Version number of package */
#undef VERSION

35
configure.in Normal file
View file

@ -0,0 +1,35 @@
AC_INIT([xsock], [0.5], [shamox@free.fr,glenux@gmail.com])
AC_PREREQ(2.50)
AC_CANONICAL_HOST
AC_CANONICAL_TARGET
AM_INIT_AUTOMAKE([xsock],[0.5])
AM_CONFIG_HEADER(config.h)
AC_CONFIG_SRCDIR([src/XSock.h])
AC_PROG_INSTALL
AC_ISC_POSIX
AC_PROG_CC
AC_PROG_CXX
AC_PROG_CPP
AC_PROG_CXXCPP
AC_PROG_INSTALL
AC_LANG_SAVE
AC_LANG_CPLUSPLUS
AC_HEADER_STDC([stdio.h stdlib.h string.h unistd.h math.h time.h fcntl.h sys/stat.h sys/socket.h sys/errno.h sys/time.h sys/types.h netinet/in.h netdb.h arpa/inet.h])
AC_CHECK_HEADERS([iostream sstream],,AC_MSG_ERROR([You need to have the libstdc++ headers installed]))
AM_PROG_LIBTOOL
AC_CONFIG_FILES([Makefile src/Makefile])
AC_OUTPUT

28
src/Makefile.am Normal file
View file

@ -0,0 +1,28 @@
SUBDIRS = .
lib_LTLIBRARIES = libXSock.la
#bin_PROGRAMS = libulm.o
libXSock_la_SOURCES = \
XSock.cpp \
XSockTCP.cpp \
XSockUDP.cpp \
XSockUDP_RELIABLE.cpp
libXSock_la_SOURCES += \
xsock.h \
introspect.h \
command.h \
macrocommand.h \
singleton.h \
identifiable.h
libXSock_la_CFLAGS = -DTRACE -static
libXSock_la_LDFLAGS = \
-version-info 0:1:0 -no-undefined
INCLUDES= \
-I../

276
src/XSock.cpp Normal file
View file

@ -0,0 +1,276 @@
/*!
* \ file XSock.cpp bal bla
*
*/
#include "XSock.h"
/*!
* \def VERBOSE Active ou pas le mode verbeux
*/
#define VERBOSE 0
// constantes utilisées dans XSock.cpp et dans XSockUDP.cpp
#define NBPORTSPUB 64512
#define PNUMPORTPUB 1025
#define GETPORTPUB() PNUMPORTPUB+(rand()%NBPORTSPUB)
using namespace std;
using namespace XSockExcept;
namespace XSock {
XSock::XSock (xsock_role role,protocol proto){
/* initialise la structure d'addresse */
/* on commence par vider la structure pour éviter les déchets... */
memset(&this->_server, 0, sizeof(this->_server));
memset(&this->_client, 0, sizeof(this->_client));
this->_client.sin_family=AF_INET;
this->_server.sin_family=AF_INET;
/* on initialise le systèmes de nombres aléatoires */
srand(time(NULL));
/* on initialise avec des addresses locales au cas où... */
this->_client.sin_addr.s_addr=htonl(INADDR_LOOPBACK);
this->_server.sin_addr.s_addr=htonl(INADDR_LOOPBACK);
/* et les ports au hasard */
this->_client.sin_port=htons(0);
this->_server.sin_port=htons(0);
/* calcule la taille de la table des descripteurs */
this->_sockSetDSize = getdtablesize();
this->_role=role;
this->_proto=proto;
this->_client_length = sizeof(this->_client);
this->_server_length = sizeof(this->_server);
}
/*!
* Indique le port à utiliser sur le serveur.
*/
void XSock::port(u_short port){
switch(this->_role){
case CLIENT:
this->_server.sin_port=htons(port);
break;
case SERVER:
this->_server.sin_port=htons(port);
break;
default:
throw eUnknownXSockRole();
break;
}
}
/*!
* Fixe la taille de la queue d'attente de connexion
*/
void XSock::backlog(int size){
this->_backlog=size;
}
/*!
* Indique l'addresse IP du serveur.
*/
void XSock::ip(int ip){
switch (this->_role){
case CLIENT:
this->_server.sin_addr.s_addr=htonl(ip);
break;
case SERVER:
this->_server.sin_addr.s_addr=htonl(ip);
break;
default:
throw eUnknownXSockRole();
break;
}
}
void XSock::dns(string dns){
struct hostent *he;
if ((he = gethostbyname(dns.c_str())) == NULL) {
throw eUnableToResolveName();
}
memcpy(&(this->_server.sin_addr.s_addr), he->h_addr_list[0], he->h_length);
switch (this->_role){
case CLIENT:
break;
case SERVER:
break;
default:
throw eUnknownXSockRole();
break;
}
}
/*!
* Connecte XSock au réseau.
*/
void XSock::dump_info(){
if (VERBOSE>=1){
printf("XSock server : %d\n",this->_server.sin_addr.s_addr);
printf("XSock client : %d\n",this->_client.sin_addr.s_addr);
printf("XSock server port : %d\n",this->_server.sin_port);
printf("XSock client port : %d\n",this->_client.sin_port);
}
}
char * XSock::getClientAddress(){
return inet_ntoa(this->_client.sin_addr);
}
char * XSock::getServerAddress(){
return inet_ntoa(this->_server.sin_addr);
}
void XSock::launch(){
this->dump_info();
switch (this->_role){
case CLIENT:
switch (this->_proto){
case TCP:
this->launch_tcp_client();
break;
case UDP:
this->launch_udp_client();
break;
case UDP_RELIABLE:
this->launch_udp_reliable_client();
break;
default:
throw eUnknownProtocol();
break;
}
break;
case SERVER:
switch (this->_proto){
case TCP:
this->launch_tcp_server();
break;
case UDP:
this->launch_udp_server();
break;
case UDP_RELIABLE:
this->launch_udp_reliable_server();
break;
default:
throw eUnknownProtocol();
break;
}
break;
default:
throw eUnknownXSockRole();
break;
}
}
/*!
* Demande a XSock de recevoir des informations.
* \param bufferData buffer de données.
* \param size taille du buffer.
*/
ssize_t XSock::recv(void *bufferData, ssize_t size){
switch(this->_proto){
case TCP:
return this->recv_tcp(bufferData, size);
break;
case UDP:
return this->recv_udp(bufferData, size);
break;
case UDP_RELIABLE:
return this->recv_udp_reliable(bufferData, size);
break;
default:
throw eUnknownProtocol();
break;
}
}
ssize_t XSock::send(const void *bufferData, ssize_t size){
switch(this->_proto){
case TCP:
return this->send_tcp(bufferData, size);
break;
case UDP:
return this->send_udp(bufferData, size);
break;
case UDP_RELIABLE:
return this->send_udp_reliable(bufferData, size);
break;
default:
throw eUnknownProtocol();
break;
}
}
XSock XSock::accept(){
XSock result(CLIENT,this->_proto);
switch (this->_role){
case CLIENT:
// TODO: râler, car le client ne recoit pas de
// connexions...
break;
case SERVER:
switch (this->_proto){
case TCP:
result=this->accept_tcp();
break;
case UDP:
result=this->accept_udp();
break;
case UDP_RELIABLE:
result=this->accept_udp_reliable();
break;
default:
throw eUnknownProtocol();
break;
}
break;
default:
throw eUnknownXSockRole();
break;
}
return result;
}
void XSock::close(){
switch (this->_proto){
case TCP:
this->close_tcp();
break;
case UDP:
this->close_udp();
break;
case UDP_RELIABLE:
this->close_udp_reliable();
break;
default:
throw eUnknownProtocol();
break;
}
//TODO: a faire...
}
} // end namespace

110
src/XSock.h Normal file
View file

@ -0,0 +1,110 @@
/*!
* \file XSock.hpp blabla
*
*/
#ifndef _XIONFS_XSOCK
#define _XIONFS_XSOCK 1
#include "XSock_errors.h"
#include "XSock_global.h"
#include "XSock_iface.h"
using namespace std;
using namespace XSockExcept;
namespace XSock {
/*
* XSock permet de gérer une connexion TCP ou UDP.
*/
class XSock {
private:
protocol _proto;
xsock_role _role;
/* descripteur de la socket principale */
int _sockFd;
/* taille de la table des descripteurs */
int _sockSetDSize;
/* ensemble de sockets ouverts */
fd_set _openSockFdSet;
/* ensemble de sockets ouverts qui attendent d'être lus */
fd_set _openSockFdSet_R;
/* fixer la taille de la queue d'attente de connexions*/
int _backlog;
/* membres à ajouter pour les service par dessus udp */
// numéros de séquence entrante
u_int _secnumrecv;
// numéros de séquence sortante
u_int _secnumsend;
/* structure d'addresse du client */
struct sockaddr_in _client;
socklen_t _client_length;
/* structure d'addresse du serveur */
struct sockaddr_in _server;
socklen_t _server_length;
void launch_tcp_client();
void launch_udp_client();
void launch_udp_reliable_client();
void launch_tcp_server();
void launch_udp_server();
void launch_udp_reliable_server();
XSock accept_udp();
XSock accept_udp_reliable();
XSock accept_tcp();
int sockFdTab_newPlace();
int sockFdTab_getPlace(int);
unsigned short XSock::getAvailablePortPub();
void backlog(int );
ssize_t send_udp(const void *, ssize_t );
ssize_t send_udp_reliable(const void *, ssize_t );
ssize_t send_tcp(const void *, ssize_t );
ssize_t recv_udp(void *, ssize_t );
ssize_t recv_udp_reliable(void *, ssize_t );
ssize_t recv_tcp(void *, ssize_t );
void close_tcp();
void close_udp();
void close_udp_reliable();
public:
XSock(xsock_role, protocol);
void port(u_short ); // client
void ip(int );
void dns(string );
XSock accept();
void launch();
void close();
ssize_t send(const void *, ssize_t );
ssize_t recv(void *, ssize_t );
char * getClientAddress();
char * getServerAddress();
u_short get_local_port();
u_short get_server_port();
string get_server_dns();
string get_server_ip();
string get_client_dns();
string get_client_ip();
void dump_info();
}; // end class
} // end namespace
#endif

102
src/XSockTCP.cpp Normal file
View file

@ -0,0 +1,102 @@
#include "XSock.h"
#define VERBOSE 0
#define VERBOSETCP 0
using namespace std;
using namespace XSockExcept;
namespace XSock {
void XSock::close_tcp(){
::close(this->_sockFd);
}
void XSock::launch_tcp_client(){
if((this->_sockFd=socket(AF_INET, SOCK_STREAM,0))==-1){
perror("socket");
throw eInvalidSocket();
}
if (connect(this->_sockFd,
(struct sockaddr *)&this->_server,
this->_server_length) < 0) {
::close(this->_sockFd);
perror("connect");
throw eUnableToConnect();
}
}
void XSock::launch_tcp_server(){
if((this->_sockFd=socket(AF_INET, SOCK_STREAM,0))==-1){
throw eInvalidSocket();
}
if (bind(this->_sockFd,
(struct sockaddr*)&this->_server,
sizeof(this->_server))==-1)
{
throw eUnableToBind();
}
/*
FD_ZERO(&this->_openSockFdSet);
FD_SET(this->_sockFd, &this->_openSockFdSet);
*/
if (listen(this->_sockFd,this->_backlog)==-1){
throw eUnableToListen();
}
}
XSock XSock::accept_tcp(){
XSock *nXSock = new XSock(CLIENT,this->_proto);
if((nXSock->_sockFd = ::accept(this->_sockFd,
(struct sockaddr *) &nXSock->_client,
&nXSock->_client_length)) == -1){
if(VERBOSETCP>=1){perror("accept");}
throw eUnableToAccept();
}
return *nXSock;
}
ssize_t XSock::recv_tcp(void *bufferData, ssize_t size){
//TODO: commenter
ssize_t p = read(this->_sockFd,bufferData,size);
if(p == -1)
throw XSockExcept::eSockUnreadable();
return p;
}
ssize_t XSock::send_tcp(const void *bufferData, ssize_t size){
//TODO : commenter
ssize_t p = write(this->_sockFd,bufferData,size);
if(p == -1)
throw XSockExcept::eSockUnwritable();
return p;
}
string XSock::get_client_ip(){
return string(inet_ntoa(this->_client.sin_addr));
}
string XSock::get_client_dns(){
//TODO: tout
return string("");
}
string XSock::get_server_ip(){
return string(inet_ntoa(this->_server.sin_addr));
}
string XSock::get_server_dns(){
//TODO: tout
return string("");
}
}

83
src/XSockUDP.cpp Normal file
View file

@ -0,0 +1,83 @@
#include "XSock.h"
// constantes utilisées dans XSock.cpp et dans XSockUDP.cpp
#define NBPORTSPUB 64512
#define PNUMPORTPUB 1025
#define GETPORTPUB() PNUMPORTPUB+(rand()%NBPORTSPUB)
#define VERBGAPP 0
#define VERBACCEPT 0
#define VERBLAUNCHCLI 0
#define VERBSEND 0
#define VERBRECV 0
#define VERBOSE 1
#define ACK 0
#define NON_ACK 1
#define HI 2
#define BYE 3
#define SIZEADD 2*sizeof(u_short) + 2*sizeof(u_int)
#define SIZESTART 2*sizeof(u_short) + sizeof(u_int)
#define NBMAXTENTATIVES 16
#define TIMERBASE 10000
using namespace std;
using namespace XSockExcept;
namespace XSock {
/*
extern u_int nbConn;
void XSock::AddConnectionToManage(int desc){
}*/
void XSock::close_udp(){
::close(this->_sockFd);
}
void XSock::launch_udp_client(){
if(VERBLAUNCHCLI >=1){cout << "--> launch_udp_client\n\tentree dans launch_udp_client" << endl;}
if(this->_server.sin_port == htons(0)){
throw eXSockNotReady();
}else{
// rien a faire... je crois
}
}
void XSock::launch_udp_server(){
/* TODO: choisir mono ou multi-processus */
/* meme remarque que dans TCP */
if((this->_sockFd=socket(AF_INET, SOCK_DGRAM,IPPROTO_UDP))==-1){
perror("eInvalidSocket");
throw eInvalidSocket();
}
if (bind(this->_sockFd,
(struct sockaddr*)&this->_server,
sizeof(this->_server))==-1)
{
perror("eUnableToBind");
throw eUnableToBind();
}
}
XSock XSock::accept_udp(){
// rien a faire
}
ssize_t XSock::recv_udp(void *bufferData, ssize_t size){
ssize_t p = read(this->_sockFd, bufferData, size);
// traiter les erreurs...
return p;
}
ssize_t XSock::send_udp(const void *bufferData, ssize_t size){
ssize_t p = write(this->_sockFd, bufferData, size);
// traiter les erreurs...
return p;
}
}

531
src/XSockUDP_RELIABLE.cpp Normal file
View file

@ -0,0 +1,531 @@
#include "XSock.h"
// constantes utilisées dans XSock.cpp et dans XSockUDP_RELIABLE.cpp
#define NBPORTSPUB 64512
#define PNUMPORTPUB 1025
#define GETPORTPUB() PNUMPORTPUB+(rand()%NBPORTSPUB)
#define VERBGAPP 0
#define VERBACCEPT 0
#define VERBLAUNCHCLI 0
#define VERBSEND 0
#define VERBRECV 0
#define VERBOSE 1
#define ACK 0
#define NON_ACK 1
#define HI 2
#define BYE 3
#define SIZEADD 2*sizeof(u_short) + 2*sizeof(u_int)
#define SIZESTART 2*sizeof(u_short) + sizeof(u_int)
#define NBMAXTENTATIVES 16
#define TIMERBASE 10000
using namespace std;
using namespace XSockExcept;
/* Fonction permettant de faire simplement un appel select avec un seul
* descripteur.
*/
int uniselect(int desc, struct timeval timer){
fd_set *rfdset = (fd_set *)malloc(sizeof(fd_set));
bzero((char *)rfdset,sizeof(fd_set));
//fd_set rfdset;
// initialisation des ensembles de descripteur
FD_ZERO(rfdset);
FD_SET(desc, rfdset);
return select(desc+1, rfdset, NULL, NULL, &timer);
}
namespace XSock {
/*
extern u_int nbConn;
void XSock::AddConnectionToManage(int desc){
}*/
void XSock::close_udp_reliable(){
::close(this->_sockFd);
}
u_short XSock::getAvailablePortPub(){
if(VERBGAPP==1){cout << "--> getAvailablePortPub\n\tdebut" << endl;}
this->_server.sin_port = htons(GETPORTPUB());
if(VERBGAPP==1){cout << "--> getAvailablePortPub\n\t\tpremier port aleatoire obtenu : ";}
if(VERBGAPP==1){cout << this->_server.sin_port << endl;}
while((::bind(this->_sockFd, (struct sockaddr*)&this->_server, sizeof(this->_server))) == -1){
if(VERBGAPP==1){cout << "--> getAvailablePortPub\n\t\t while bind" << endl;}
if(errno != EADDRINUSE){
if(VERBGAPP==1){cout << "--> getAvailablePortPub\n\t\t bind err non! : " << endl;}
if(VERBOSE == 1){perror("bind");}
throw eUnableToBind();
}else{
if(VERBGAPP==1){cout << "--> getAvailablePortPub\n\t\t bind non!" << endl;}
this->_server.sin_port = htons(GETPORTPUB());
if(VERBGAPP==1){cout << "--> getAvailablePortPub\n\t\t premier port aléatoire obtenu : " << ntohs(this->_server.sin_port) << endl;}
}
}
if(VERBGAPP==1){cout << "--> getAvailablePortPub\n\t\t fin while" << endl;}
if(VERBGAPP==1){cout << "--> getAvailablePortPub\n\treturn " << ntohs(this->_server.sin_port) << endl;}
return this->_server.sin_port;
}
void XSock::launch_udp_reliable_client(){
/* par définition, le client est mono-processus */
if(VERBLAUNCHCLI >=1){cout << "--> launch_udp_reliable_client\n\tentree dans launch_udp_reliable_client" << endl;}
if(this->_server.sin_port == htons(0)){
throw eXSockNotReady();
}else{
if(VERBLAUNCHCLI >=1){cout << "--> launch_udp_reliable_client\n\t" << endl;}
if((this->_sockFd=socket(AF_INET, SOCK_DGRAM,IPPROTO_UDP))==-1){
throw eInvalidSocket();
}
if(VERBLAUNCHCLI >=1){cout << "--> launch_udp_reliable_client\n\tdebut..." << endl;}
int fait = 0;
void *sbuffer = malloc(SIZESTART), *rbuffer = malloc(SIZESTART);
u_short *ussbuffer = (u_short *)sbuffer, *usrbuffer = (u_short *)rbuffer;
u_int *ulsbuffer = (u_int *)sbuffer, *ulrbuffer = (u_int *)rbuffer;
int srecv, sel, tentatives;
//struct sockaddr_in client;
struct timeval timer;
timer.tv_sec = 0;
timer.tv_usec = TIMERBASE;
//socklen_t* lenclient = (socklen_t*)malloc(sizeof(socklen_t));
ussbuffer[0] = htons(HI);
ussbuffer[1] = 0;
this->_secnumrecv = rand();
ulsbuffer[1] = htonl(this->_secnumrecv);
if(VERBLAUNCHCLI >=2){cout << "\t\tsec client : " << this->_secnumrecv << endl;}
if(VERBLAUNCHCLI >=1){cout << "--> launch_udp_reliable_client\n\t\tfin init" << endl;}
::sendto(this->_sockFd, sbuffer, SIZESTART, 0,
(struct sockaddr*)&this->_server, sizeof(this->_server));
if(VERBLAUNCHCLI >=1){cout << "--> launch_udp_reliable_client\n\t\tsendto1" << endl;}
tentatives = 0;
while(((tentatives < NBMAXTENTATIVES) && (fait <= 0))
&& (((sel = uniselect(this->_sockFd,timer)) == 0) || (sel == 1)))
{
if(VERBLAUNCHCLI >=1){cout << "--> launch_udp_reliable_client\n\t\twhile tentatives " << tentatives << endl;}
while((sel == 1 && (fait <= 0))){// il y a quelque chose à lire
if(VERBLAUNCHCLI >=1){cout << "--> launch_udp_reliable_client\n\t\t while" << endl;}
srecv = ::recv(this->_sockFd, rbuffer, SIZESTART, 0);
if(VERBLAUNCHCLI >=1){cout << "--> launch_udp_reliable_client\n\t\t recvfrom" << endl;}
if(VERBLAUNCHCLI >=2){printf("rbuffer : 0x%08x %08x\n",ulrbuffer[0],ulrbuffer[1]);}
if(srecv == SIZESTART){ // c'est pas trop petit
if(VERBLAUNCHCLI >=1){cout << "--> launch_udp_reliable_client\n\t\t test taille oui!" << endl;}
if(HI == ntohs(usrbuffer[0])){ // c'est bien un message d'ouverture de connexion
if(VERBLAUNCHCLI >=1){cout << "--> launch_udp_reliable_client\n\t\t test ack oui!" << endl;}
this->_secnumsend = ntohl(ulrbuffer[1]);
if(VERBLAUNCHCLI >=2){cout << "\n\t\t\tsec serveur : " << this->_secnumsend << endl;}
this->_server.sin_port = usrbuffer[1];
if(VERBLAUNCHCLI >=2){cout << "\n\t\t\tport serveur : " << ntohs(this->_server.sin_port) << endl;}
if(VERBLAUNCHCLI >=1){cout << "--> launch_udp_reliable_client\n\t\t recupe valeurs serveur port : " << ntohs(this->_server.sin_port) << endl;}
::sendto(this->_sockFd, rbuffer, SIZESTART, 0,
(struct sockaddr*)&this->_server, sizeof(this->_server));
if(VERBLAUNCHCLI >=1){cout << "--> launch_udp_reliable_client\n\t\t sendto confirmation" << endl;}
timer.tv_usec+=timer.tv_usec/4;
if((sel = uniselect(this->_sockFd,timer)) == 0){
if(VERBLAUNCHCLI >=1){cout << "--> launch_udp_reliable_client\n\t\t plus qu'a sortir" << endl;}
fait = 10;
}else{
timer.tv_usec = timer.tv_usec / 2;
}
}else{ // c'est pas un message d'ouverture de connexion, donc on jete.
if(VERBLAUNCHCLI >=1){cout << "--> launch_udp_reliable_client\n\t\t test ack non!" << endl;}
}
}else{ // c'est trop petit, donc on jete.
if(VERBLAUNCHCLI >=1){cout << "--> launch_udp_reliable_client\n\t\t test taille non!" << endl;}
}
sel = 0;
}
if((sel == 0) && (fait <= 0)){
tentatives++;
::sendto(this->_sockFd, sbuffer, SIZESTART, 0,
(struct sockaddr*)&this->_server, sizeof(this->_server));
if(VERBLAUNCHCLI >=1){cout << "--> launch_udp_reliable_client\n\t\tresend1" << endl;}
}else{
if(VERBLAUNCHCLI >=1){cout << "--> launch_udp_reliable_client\n\t\t fin while" << endl;}
}
}
if(tentatives >= NBMAXTENTATIVES){
if(VERBLAUNCHCLI >=1){cout << "--> launch_udp_reliable_client\n\t\tfin while tentatives == " << tentatives << endl;}
throw eUnableToAccept();
}
if(VERBLAUNCHCLI >=1){cout << "--> launch_udp_reliable_client\n\t\tfin while" << endl;}
this->_client.sin_addr.s_addr = this->_server.sin_addr.s_addr;
this->_client.sin_port = this->_server.sin_port;
}
}
void XSock::launch_udp_reliable_server(){
/* TODO: choisir mono ou multi-processus */
/* même remarque que dans TCP */
if((this->_sockFd=socket(AF_INET, SOCK_DGRAM,IPPROTO_UDP))==-1){
perror("eInvalidSocket");
throw eInvalidSocket();
}
if (bind(this->_sockFd,
(struct sockaddr*)&this->_server,
sizeof(this->_server))==-1)
{
perror("eUnableToBind");
throw eUnableToBind();
}
}
XSock XSock::accept_udp_reliable(){
//TODO: remplir
if(VERBACCEPT >=1){cout << "--> accept_udp_reliable\n\tdebut" << endl;}
XSock *nSock;
void *buffer = malloc(SIZESTART);
u_short *usbuffer = (u_short *)buffer;
u_int *ulbuffer = (u_int *)buffer;
int srecv;
struct sockaddr_in client;
struct timeval timer;
timer.tv_sec = 0;
timer.tv_usec = TIMERBASE;
socklen_t lenclient = sizeof(struct sockaddr_in);
if(VERBACCEPT >=1){cout << "--> accept_udp_reliable\n\t\tfin init" << endl;}
while((srecv = ::recvfrom(this->_sockFd,buffer,SIZESTART, 0,
(struct sockaddr*)&client, &lenclient)) != 0){
if(VERBACCEPT >=1){cout << "--> accept_udp_reliable\n\t\twhile recvfrom" << endl;}
if(srecv == -1)
throw eSockUnreadable();
else {
if(VERBACCEPT >=1){cout << "--> accept_udp_reliable\n\t\t test srecv oui!" << endl;}
if(srecv == SIZESTART){
if(VERBACCEPT >=1){cout << "--> accept_udp_reliable\n\t\t test taille oui!" << endl;}
u_short ack = ntohs(*usbuffer);
if(ack == HI){
if(VERBACCEPT >=1){cout << "--> accept_udp_reliable\n\t\t test ack oui!" << endl;}
//initialisation du nouveau XSock
nSock = new XSock(CLIENT,this->_proto);
nSock->_secnumsend = ntohl(ulbuffer[1]);
if(VERBACCEPT >=2){cout << "\n\t\t\tsec client = " << nSock->_secnumsend << endl;}
if(VERBACCEPT >=1){cout << "--> accept_udp_reliable\n\t\t new sock cree" << endl;}
if((nSock->_sockFd = ::socket(AF_INET, SOCK_DGRAM,IPPROTO_UDP)) == -1){
throw eInvalidSocket();
}
if(VERBACCEPT <= -1){cout << "--> accept_udp_reliable\n\t nSock->_sockFd : " << nSock->_sockFd << endl;}
if(VERBACCEPT >=1){cout << "--> accept_udp_reliable\n\t\t test socket ok!" << endl;}
nSock->_client.sin_addr.s_addr = client.sin_addr.s_addr;
if(VERBACCEPT >=2){cout << "\n\t\t\tadresse client : " << inet_ntoa(nSock->_client.sin_addr) << endl;}
nSock->_client.sin_port = client.sin_port;
if(VERBACCEPT >=2){cout << "\n\t\t\tport client : " << ntohs(nSock->_client.sin_port) << endl;}
u_short port = nSock->getAvailablePortPub();
if(VERBACCEPT >=1){cout << "--> accept_udp_reliable\n\t\t new port ok!" << endl;}
// prépare message avec port + numseqence
ulbuffer[0] = htonl(HI*0x10000+port);
nSock->_secnumrecv = rand();
ulbuffer[1] = htonl(nSock->_secnumrecv);
//(u_short)buffer[sizeof(u_short) + sizeof(u_int)] = (u_short)htons(port);
if(VERBACCEPT >=1){cout << "--> accept_udp_reliable\n\t\t init buffer\n\t\t\tack = " << *(u_short*)buffer;}
if(VERBACCEPT >=2){cout << "\n\t\t\tsecnum serveur = " << nSock->_secnumrecv;}
if(VERBACCEPT >=2){cout << "\n\t\t\tport serveur = " << port << endl;}
if(VERBACCEPT >=2){printf("message envoye : 0x%08x %08x ==\t ack|port : 0x%08x sec : 0x%08x\n",
ulbuffer[0],ulbuffer[1],
htonl(HI*0x10000+port),
htonl(nSock->_secnumrecv));}
// envoie du message et attente de confirmation.
::sendto(nSock->_sockFd, buffer, SIZESTART, 0,
(struct sockaddr*)&nSock->_client, nSock->_client_length);
if(VERBACCEPT >=1){cout << "--> accept_udp_reliable\n\t\t sendto" << endl;}
void *rbuffer = malloc(SIZESTART);
u_short *usrbuffer = (u_short *)rbuffer;
u_int *ulrbuffer = (u_int *)rbuffer;
int sel,tentatives = 0;
struct sockaddr_in client2;
while((tentatives < NBMAXTENTATIVES)
&& (((sel = uniselect(nSock->_sockFd,timer)) == 0) || (sel == 1)))
{
if(VERBACCEPT >=1){cout << "--> accept_udp_reliable\n\t\t while tentative " << tentatives << endl;}
if(sel == 1){
if(VERBACCEPT >=1){cout << "--> accept_udp_reliable\n\t\t test sel oui!" << endl;}
lenclient = sizeof(client2);
srecv = ::recvfrom(nSock->_sockFd, rbuffer, SIZESTART, 0,
(struct sockaddr*)&client2, &lenclient);
if(VERBACCEPT >=1){cout << "--> accept_udp_reliable\n\t\t recvfrom" << endl;}
if((client2.sin_addr.s_addr == nSock->_client.sin_addr.s_addr)
&& (client2.sin_port == nSock->_client.sin_port))
{
if(VERBACCEPT >=1){cout << "--> accept_udp_reliable\n\t\t test bon client oui!" << endl;}
if((usrbuffer[0] == htons(HI)) &&
(usrbuffer[1] == usbuffer[1]) &&
(ulrbuffer[1] == ulbuffer[1]))
{
if(VERBACCEPT >=1){cout << "--> accept_udp_reliable\n\t\t test ack oui!" << endl;}
break;
}
}
}else{
if(VERBACCEPT >=1){cout << "--> accept_udp_reliable\n\t\t test sel non!" << endl;}
::sendto(nSock->_sockFd, buffer, SIZESTART, 0,
(struct sockaddr*)&nSock->_client, nSock->_client_length);
if(VERBACCEPT >=1){cout << "--> accept_udp_reliable\n\t\t sendto" << endl;}
}
tentatives++;
}
if(tentatives == NBMAXTENTATIVES){
break;
}
if(VERBACCEPT >=1){cout << "--> accept_udp_reliable\n\t\t fin while\n\t\tretour ok!" << endl;}
// on attend car en face il attend voir si on renvoie pas un message...
usleep(timer.tv_usec*2);
return *nSock;// à remplacer plus tard en renvoyant le pointeur direct
}
}
}
}
if(VERBACCEPT >=1){cout << "--> accept_udp_reliable\n\t\t probleme!!" << endl;}
throw eUnableToAccept();
}
ssize_t XSock::recv_udp_reliable(void *bufferData, ssize_t size){
//TODO : le ACK est fait avec une fentre de 1
// il y a plein de problèmes générés par ce système très incomplet.
// mettre un système de timer évolutif
u_int tentatives =16;
if(VERBRECV==1){cout << "--> recv_udp_reliable\n\tdebut" << endl;}
ssize_t p = 0;
struct timeval timer;
char *cbufferData = (char*)bufferData;
timer.tv_sec = 0;
timer.tv_usec = TIMERBASE;
ssize_t sizet = SIZEADD + size;
void *rbuffer = malloc(sizet), *sbuffer = malloc(SIZEADD);
u_int *ulrbuffer = (u_int *)rbuffer, *ulsbuffer = (u_int *)sbuffer;
u_short *usrbuffer = (u_short *)rbuffer, *ussbuffer = (u_short *)sbuffer;
char *crbuffer = (char*)rbuffer;
if(VERBRECV>=1){cout << "--> recv_udp_reliable\n\tfin init" << endl;}
if(VERBRECV>=2){
cout << "--> recv_udp_reliable\n\t this->_sockFd = " << this->_sockFd << endl;
}
if((p = ::recv(this->_sockFd,rbuffer,sizet,0)) == -1){
if(VERBRECV>=1){perror("XSock::recv{recv}");}
throw eSockUnreadable();
}
if(VERBRECV>=1){cout << "--> recv_udp_reliable\n\t\trecv ok! p = " << p << endl;}
p-=SIZEADD;
if(VERBRECV>=2){cout << "--> recv_udp_reliable\n\t\t p-SIZEADD = " << p << endl;}
int renv = 0, recevoir = 0, env = 0;
tentatives = 16;
while((tentatives > 0) && (p >= 0)){
tentatives--;
switch (usrbuffer[0]){
case ACK :
{
if(VERBRECV>=1){cout << "--> recv_udp_reliable\n\t ack == ack alors qu'on est dans le recv" << endl;}
recevoir = 10;
break;
}
case NON_ACK :
{
if((this->_secnumrecv > ntohl(ulrbuffer[1])) || (this->_secnumrecv < ntohl(ulrbuffer[1]))){
if(VERBRECV>=1){cout << "--> recv_udp_reliable\n\t secnum >< recu" << endl;}
ussbuffer[0] = htons(ACK);
ulsbuffer[1] = htonl(this->_secnumrecv);
renv = 10;
recevoir = 10;
}else{
if(VERBRECV>=1){cout << "--> recv_udp_reliable\n\t secnum == recu (= " << this->_secnumrecv << ")" << endl;}
ussbuffer[0] = htons(ACK);
this->_secnumrecv+=p;
ulsbuffer[1] = htonl(this->_secnumrecv);
if(VERBRECV>=2){cout << "--> recv_udp_reliable\n\t nouv secnum = " << this->_secnumrecv << endl;}
env = 10;
}
break;
}
case BYE :
{//fermeture de la connexion
::sendto(this->_sockFd, rbuffer, SIZEADD, 0, (struct sockaddr*)&this->_client, this->_client_length);
while((uniselect(this->_sockFd,timer)) == 1){
::sendto(this->_sockFd, rbuffer, SIZEADD, 0, (struct sockaddr*)&this->_client, this->_client_length);
}
throw eConnectionClosedByPeer();
break;
}
default :
{
if(VERBRECV>=1){cout << "--> recv_udp_reliable\n\t ack inconnu ou HI en pleine connection..." << endl;}
throw eSockUnreadable();
}
}
if(renv == 10){
::sendto(this->_sockFd, sbuffer, SIZEADD, 0, (struct sockaddr*)&this->_client, this->_client_length);
if(VERBRECV>=1){cout << "--> recv_udp_reliable\n\t resend data" << endl;}
}
if(recevoir == 10){
if((p = ::recv(this->_sockFd,rbuffer,sizet,0)) == -1){
if(VERBRECV>=1){perror("XSock::recv{recv}");}
throw eSockUnreadable();
}
if(VERBRECV>=1){cout << "--> recv_udp_reliable\n\t\t recv ok! p = " << p << endl;}
p-=SIZEADD;
}
if(env == 10){
::sendto(this->_sockFd, sbuffer, SIZEADD, 0, (struct sockaddr*)&this->_client, this->_client_length);
if(VERBRECV>=1){cout << "--> recv_udp_reliable\n\t send ack" << endl;}
break;
}
}
if(tentatives==0){
throw eConnectionClosedByPeer();
}
//recopie des données
if(VERBRECV>=1){cout << "--> recv_udp_reliable\n\trempli bufferData" << endl;}
for(int i = 0;((i < p) || (i < size)); i++){
cbufferData[i] = crbuffer[i+SIZEADD];
if(VERBRECV>=3){printf("%02x -> %02x\n", crbuffer[i+SIZEADD], cbufferData[i]);}
}
if(VERBRECV>=1){cout << "--> recv_udp_reliable\n\t fin while" << endl;}
timer.tv_usec+=timer.tv_usec/2;
if(VERBRECV>=1){cout << "--> recv_udp_reliable\n\ttimer = "<<timer.tv_sec<<"."<< timer.tv_usec<< endl;}
tentatives =16;
while((tentatives > 0) && ((uniselect(this->_sockFd, timer)) == 1)){
tentatives--;
if((p = ::recv(this->_sockFd,rbuffer,sizet,0)) == -1){
if(VERBRECV>=1){perror("XSock::recv{recv}");}
throw eSockUnreadable();
}
if(ulrbuffer[1] == this->_secnumrecv){
if(VERBRECV>=1){cout <<"--> recv_udp_reliable\n\t recu nouvelles donnees avec bon ack recv. on sort"<<endl;}
break;
}
::sendto(this->_sockFd, sbuffer, SIZEADD, 0, (struct sockaddr*)&this->_client, this->_client_length);
if(VERBRECV>=1){cout << "--> recv_udp_reliable\n\tresend ack" << endl;}
if(VERBRECV>=1){cout << "--> recv_udp_reliable\n\ttimer = "<<timer.tv_sec<<"."<< timer.tv_usec<< endl;}
}
if(tentatives==0){
throw eConnectionClosedByPeer();
}
p-=SIZEADD;
if(VERBRECV>=1){cout << "--> recv_udp_reliable\n\treturning..." << endl;}
//usleep(timer.tv_usec);
return p;
}
ssize_t XSock::send_udp_reliable(const void *bufferData, ssize_t size){
//TODO : mettre un système de timer évolutif
if(VERBSEND>=1){cout << "--> send_udp_reliable\n\tdebut" << endl;}
struct timeval timer;
u_int tentatives = 16;
char *cbufferData = (char *)bufferData;
timer.tv_sec = 0;
timer.tv_usec = TIMERBASE;
int sel;
//---
ssize_t p = 0, sizet = size+SIZEADD, srecv;
void *sbuffer = malloc(sizet), *rbuffer = malloc(SIZEADD);
if(VERBSEND>=1){cout << "--> send_udp_reliable\n\tpreparing buffer of "<<sizet<<" bytes" << endl;}
u_int *ulsbuffer = (u_int *)sbuffer, *ulrbuffer = (u_int *)rbuffer;
u_short *ussbuffer = (u_short *)sbuffer, *usrbuffer = (u_short *)rbuffer;
char *csbuffer = (char*)sbuffer;
if(VERBSEND>=1){cout << "--> send_udp_reliable\n\tfin init" << endl;}
for(int i = 0; i < size; i++){
csbuffer[i+SIZEADD] = cbufferData[i];
}
ussbuffer[0] = htons(NON_ACK);
ulsbuffer[1] = htonl(this->_secnumsend);
ulsbuffer[2] = htonl(this->_secnumrecv);
if(VERBSEND>=1){cout << "--> send_udp_reliable\n\tfin prepare sbuffer with secnum = " << this->_secnumsend << endl;}
if(VERBSEND>=2){cout << "size of data to send : " << size << endl;}
if(VERBSEND>=3){
cout << "data to send :" << endl;
for(int i = 0; i < sizet;i++){
printf("%02x ", (char)csbuffer[i]);
}
}
srecv=0;
p = ::sendto(this->_sockFd, sbuffer, sizet, 0, (struct sockaddr*)&this->_client, this->_client_length);
if(VERBSEND>=1){cout << "--> send_udp_reliable\n\tsend" << endl;}
if(VERBSEND>=2){cout << "size of data sent : " << (p-SIZEADD) << endl;}
tentatives = 16;
while((tentatives > 0) && (sel = uniselect(this->_sockFd,timer)) == 0){
tentatives--;
if(VERBSEND>=1){cout << "--> send_udp_reliable\n\t resend data" << endl;}
p = ::sendto(this->_sockFd, sbuffer, sizet, 0, (struct sockaddr*)&this->_client, this->_client_length);
}
if(tentatives==0){
throw eConnectionClosedByPeer();
}
p-=SIZEADD;
if(VERBSEND>=1){cout << "--> send_udp_reliable\n\t fin while" << endl;}
if(sel == -1){
if(VERBSEND>=1){perror("XSock::send_udp_reliable{sel}");}
throw eSockUnreadable();
}
if((srecv = ::recv(this->_sockFd, rbuffer, SIZEADD,0)) == -1){
if(VERBSEND>=1){perror("XSock::send_udp_reliable{recv}");}
throw eSockUnreadable();
}
if(VERBSEND>=1){cout << "--> send_udp_reliable\n\trecv ok!" << endl;}
if(VERBSEND>=2){cout << "--> send_udp_reliable\n\t size = " << srecv << endl;}
if(VERBSEND>=2){cout << "--> send_udp_reliable\n\t ack = " << ntohs(usrbuffer[0]) << endl;}
if(VERBSEND>=2){cout << "--> send_udp_reliable\n\t sec = " << ntohl(ulrbuffer[1]) << endl;}
u_int secawaited = this->_secnumsend + p;
if(VERBSEND>=2){cout << "--> send_udp_reliable\n\t sec awaited = " << secawaited << endl;}
tentatives = 16;
while((tentatives > 0) && ((srecv != SIZEADD) || (ntohs(usrbuffer[0]) != ACK) || (secawaited != ntohl(ulrbuffer[1]))))
{
tentatives--;
if(VERBSEND>=1){cout << "--> send_udp_reliable\n\t while" << endl;}
if(srecv == SIZEADD){
if(ntohs(usrbuffer[0]) == NON_ACK){
// on remarque que si le message envoyé continet le ack du message précédent
// ie this->_secnumsend == ulrbuffer[2] alors c'est comme un acquittement
// on drop tout de meme le paquet.
//if(secawaited == ulrbuffer[2]){
// if(VERBSEND>=1){cout << "--> send_udp_reliable\n\t acked with send action" << endl;}
// this->_secnumsend =secawaited;
// return p;
//}
if(VERBSEND>=1){cout << "--> send_udp_reliable\n\t dead lock" << endl;}
throw eDeadLock();
}
}
p = ::sendto(this->_sockFd, sbuffer, sizet, 0, (struct sockaddr*)&this->_client, this->_client_length);
while((sel = uniselect(this->_sockFd,timer)) == 0){
if(VERBSEND>=1){cout << "--> send_udp_reliable\n\t resend data" << endl;}
p = ::sendto(this->_sockFd, sbuffer, sizet, 0, (struct sockaddr*)&this->_client, this->_client_length);
}
p-=SIZEADD;
if((srecv = ::recv(this->_sockFd, rbuffer, SIZEADD,0)) == -1){
if(VERBSEND>=1){perror("XSock::send_udp_reliable{recv}");}
throw eSockUnreadable();
}
}
if(tentatives==0){
throw eConnectionClosedByPeer();
}
if(srecv == SIZEADD){
if(VERBSEND>=1){cout << "--> send_udp_reliable\n\t verif taille ok!" << endl;}
if(ntohs(usrbuffer[0]) == ACK){// on est content
if(VERBSEND>=1){cout << "--> send_udp_reliable\n\t verif ACK ok!" << endl;}
if(this->_secnumsend + p == ntohl(ulrbuffer[1])){
if(VERBSEND>=1){cout << "--> send_udp_reliable\n\t verif secnum ok! returning..." << endl;}
//c'est bon !
usleep(timer.tv_usec);
this->_secnumsend+=p;
return p;
}
}
}
//impossible d'arriver ici normalement
if(VERBSEND>=1){cout << "--> send_udp_reliable\n\t soucis!!!" << endl;}
return p;
}
}

33
src/XSock_errors.h Normal file
View file

@ -0,0 +1,33 @@
#ifndef _XSOCK_ERRORS
#define _XSOCK_ERRORS 1
namespace XSockExcept {
class eXSockExcept { };
class eInvalidSocket : eXSockExcept { };
class eUnknownProtocol : eXSockExcept { };
class eUnableToListen : eXSockExcept { };
class eUnableToConnect : eXSockExcept { };
class eUnableToAccept : eXSockExcept { };
class eUnableToBind : eXSockExcept { };
class eSockUnreadable : eXSockExcept { };
class eSockUnwritable : eXSockExcept { };
class eUnknownXSockRole : eXSockExcept { };
class eUnableToResolveName : eXSockExcept { };
class eXSockNotReady : eXSockExcept { };
class eConnectionClosedByPeer : eXSockExcept { };
class eDeadLock : eXSockExcept { };
class eUnableToLock : eXSockExcept { };
class eUnableToUnlock : eXSockExcept { };
class eUnableToCloseFile : eXSockExcept { };
class eUnableToOpenFile : eXSockExcept { };
class eUnableToStatFile : eXSockExcept { };
class eUnableToOpen2ndFile : eXSockExcept { };
class eUnableToCreateFile : eXSockExcept { };
class eUnableToDeleteFile : eXSockExcept { };
class eUnableToReadFile : eXSockExcept { };
class eUnableToWriteFile : eXSockExcept { };
/* définition des exceptions ici */
}
#endif

35
src/XSock_global.h Normal file
View file

@ -0,0 +1,35 @@
#ifndef _XSOCK_GLOBAL
#define _XSOCK_GLOBAL 1
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <sstream>
#include <syslog.h>
#include <stdio.h>
#include <stdlib.h>
#include <syslog.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/errno.h>
#include <sys/time.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <math.h>
#include <time.h>
#include <fcntl.h>
#include <sys/stat.h>
/* spécifie le nombre maximum de demandes de connexion en attente d'être acceptées. */
#define XSOCK_MESSAGES_LENGTH 128
#define XSOCK_CHUNK_LENGTH 4096
#define XSOCK_INVALID_SOCKET -1
#define MAXGAUCHE(X,Y) (X<Y)?Y:X
#ifndef MIN
#define MIN(X,Y) (X<Y)?X:Y
#endif
#endif

10
src/XSock_iface.h Normal file
View file

@ -0,0 +1,10 @@
#ifndef _XSOCK_INTERFACE
#define _XSOCK_INTERFACE 1
/* TYPEDEFS et autre trucs non objet */
namespace XSock {
typedef enum {TCP,UDP_RELIABLE,UDP} protocol;
typedef enum {SERVER,CLIENT} xsock_role;
}
#endif

2
src/test/Makefile.am Normal file
View file

@ -0,0 +1,2 @@
SUBDIRS =
client_echo_udp server_echo_udp

View file

@ -0,0 +1,18 @@
#AM_YFLAGS = -d -v
SUBDIRS = .
bin_PROGRAMS = client_udp
client_udp_SOURCES = client_udp.cpp
client_udp_SOURCES += client_udp.h
INCLUDES= -I../lib/ -I./
client_udp_LDADD = \
${top_builddir}/src/libXSock.la
client_udp_LDFLAGS = @LDFLAGS@

View file

@ -0,0 +1,18 @@
#AM_YFLAGS = -d -v
SUBDIRS = .
bin_PROGRAMS = server_udp
server_udp_SOURCES = server_udp.cpp
server_udp_SOURCES += server_udp.h
INCLUDES= -I../lib/ -I./
server_udp_LDADD = \
${top_builddir}/src/libXSock.la
server_udp_LDFLAGS = @LDFLAGS@