IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Développement Discussion :

[C]Proxy send sur un socket fermé par un RST


Sujet :

Développement

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    150
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 150
    Points : 111
    Points
    111
    Par défaut [C]Proxy send sur un socket fermé par un RST
    Bonjour je réalise un proxy en C,

    Celui ci commence à être opérationel, mais j'ai un bug qui m'ennuie pas mal et qui m'empêche d'aller plus loin dans son développement, voici quelques explications.

    J'utilise firefox pour me connecter à mon proxy, je demande un site et j'appuie immédiatement sur la croix rouge, Boum le proxy plante.

    J'ai utilisé ethereal pour voir ce qu'il se passe, et en faite le fait d'appuyer sur la croix rouge de firefox envoie un paquet avec le flag RST, pour couper brutalement la connexion.

    Le proxy lui était déjà en train de m'envoyer le corp de la page html lorsqu'il recoit le paquet avec le flag RST, cela a pour effet de le faire planter. Au moment où il recoit ce paquet, il est en train d'utiliser la fonction send.

    J'ai mis en gras l'endroit où le programme plante.

    Comment detecter si le socket est toujours ouvert avant d'envoyer les données ? (select sur un send? j'ai essayé a tout hasard mais c'est la même chose).

    La fonction send ne me renvoie jamais 0 ou -1, même lorsque le socket sur lequel elle effectue l'envoie est fermé.

    A part ce problème le proxy fonctionne bien et je n'ai pas trouvé d'autre bug.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <netdb.h>
    #include <string.h>
    #include <pthread.h>
    #include "socketFunction.h"
    
    #define MAX_RECV_TIMEOUT 10000	//ms
    
    void traitement_client(int);
    int doProxy(int ,int,unsigned long ,int ,char * );
    
    int main(int argc,char *argv[]){
    	int port;
    	unsigned int lenAccept;
    	int sckListen,sckAccept;
    	struct sockaddr_in adrAccept;
    	pthread_t th;
    	pthread_attr_t attr;
    
    	//Sélection du port
    	if(argc == 2){
    		port = atoi(argv[1]);
    	}else
    		port = 3125;
    
    	 //sem_init()
    
    	 //On détache le serveur de la console
    	#ifndef DEBUG
    	if(fork()!=0)
    		exit(1);
    	if(setsid()==-1)
    		exit(2);
    	#endif
    
    	//On créer la structure d'attribut qui créer un thread détaché automatiquement
    	pthread_attr_init(&attr);
    	pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
    
    	if((sckListen=createSocketListener(port))<0){
    		exit(3);
    	}
    
    	 while(1){
    			//Réinitialisation de la longueur (sinon accept peut planter)
    			lenAccept = sizeof(adrAccept);
    			//sem_wait
    			//Et on attend les clients
    			if((sckAccept = accept(sckListen,(struct sockaddr*)&adrAccept,&lenAccept))==-1){
    				exit(4);
    			}
    
    			//On traite chaque client dans un thread séparé
    			if(pthread_create(&th,&attr,(void*)traitement_client,(void*)sckAccept)!=0){
    			 	exit(5);
    			}			
    	 }
    
    }
    
    void traitement_client(int sck){
    	char * header,*host;
    	int method,port;
    	unsigned long ip;
    
    	printf("DEBUT THREAD\n");
    
    	//Récupérer le header	
    	if((header=recvHeader(sck))!=NULL){
    		
    		//On récupére le champ host
    		if((host=getField(header,"Host"))!=NULL){
    
    			 if(getIpPortFromHost(host,&ip,&port)>0){
    				 setField(&header,"Connection","Close");
    				 rmField(&header,"Proxy-Connection");
    				 rmField(&header,"Keep-Alive");
    				 setField(&header,"user-agent","super pingouin le gros sexuel");
    				 
    				//On récupére le type de requète
    				switch(method=getMethod(header)){
    					case GET :
    					case HEAD :
    						doProxy(sck,method,ip,port,header);
    						break;
    					default :
    						//			methode inconnue ou non implemen
    						//send501();
    						break;
    				}
    			 }
    			 free(host);
    		}		
    		free(header);
    	}
    	close(sck);
    	//sem_post()
    	printf("FIN THREAD\n");
    }
    
    int doProxy(int sck,int method,unsigned long ip,int port,char * header){
    	struct sockaddr_in server;
    	int sckServer,len;
    	char * headerServer;
    	char c;
    
    	// Connexion au serveur
    
    	if((sckServer = socket(AF_INET,SOCK_STREAM,0))==SOCKET_ERROR){
    		printf("SOCKET\n");
    		return -1;
    	}
    
    	server.sin_addr.s_addr = ip;
    	server.sin_family = AF_INET;
    	server.sin_port = htons(port);
    	len=sizeof(server);
    
    	//Remplacer par myconnect avec timeout
    	if(connect(sckServer,(struct sockaddr*)&server,len)==SOCKET_ERROR){
    		perror("CONNECT\n");
    		return -1;
    	}
    
    	//Envoie du header	client au serveur
    	send(sckServer,header,strlen(header),0);
    
    	//POST [...]
    
    	//reception et envoie du header	serveur au client
    	if((headerServer = recvHeader(sckServer))!=NULL){
    	
    		if(send(sck,headerServer,strlen(headerServer),0) == strlen(headerServer)){
    
    			while((len=myrecv(sckServer,&c,1,0,TIMEOUT))>0) {
    				printf("RECV %c\n",c);
    				if((len=send(sck,&c,1,0))<=0)
    					printf("! SEND\n");//Quitte la boucle
    
    				printf("SEND %d\n",len);
    			}
    
    		}
    
    		free(headerServer);
    	}
    	close(sckServer);
    	return 1;
    }
    Fichiers attachés Fichiers attachés

  2. #2
    Membre régulier
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    150
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 150
    Points : 111
    Points
    111
    Par défaut La solution
    J'ai zappé un detail : lorsque l'on coupe une connexion, cela envoie des données, il faut donc regarder s'il n y a pas de données qui sont arrivées sur le socketclient avant d'en envoyer sur ce même socket.

    En effet on n'attend plus de données sur ce socket sachant qu'on a déjà recu le header et les données en post, donc si on recoit des données, c'est que le client s'est deconnecté ou qu'il ne respecte pas le protocole HTTP. Dans les 2 cas on ferme la connexion et on évite ainsi le plantage.

    Voici la solution :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    			while((len=myrecv(sckServer,&c,1,0,TIMEOUT))>0) {
    					struct timeval to;	
    					fd_set myset;
    					
    					to.tv_sec = 0;
    					to.tv_usec =0;	//microseconde
    					
    					FD_ZERO(&myset);
    					FD_SET(sck,&myset);
    
    					if(select(sck+1,&myset,NULL,&myset,&to) == 1){
    						printf("EVENEMENT !\n");
    						break;
    					}
    
    					if((len=send(sck,&c,1,0))<=0){
    						printf("! SEND\n");
    						break;
    					}
    			}



    Note : Quand même brutal un plantage de programme juste car on envoie des données sur un socket fermé :/.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 9
    Dernier message: 23/03/2010, 10h14
  2. SocketChannel.write sur un socket fermé
    Par hermes1983 dans le forum Entrée/Sortie
    Réponses: 1
    Dernier message: 25/02/2010, 12h50
  3. Réponses: 9
    Dernier message: 14/10/2008, 19h47
  4. [PHP-JS] Problème de socket, passer par un proxy
    Par Kruggs dans le forum Langage
    Réponses: 1
    Dernier message: 13/07/2007, 01h15
  5. Envoyer un fichier sur un serveur FTP par proxy
    Par Tierisa dans le forum Access
    Réponses: 4
    Dernier message: 13/12/2005, 16h39

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo