531 lines
23 KiB
C++
531 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;
|
|
}
|
|
}
|