l3.xsock/lib/xsock_udp_reliable.cpp
2006-01-10 12:29:13 +00:00

532 lines
23 KiB
C++

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