#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;
	}
}