[C/WIN32] PROXY AVEC THREAD

ymca2003 Messages postés 2070 Date d'inscription mardi 22 avril 2003 Statut Membre Dernière intervention 3 juillet 2006 - 18 avril 2006 à 23:22
petitmoustique Messages postés 52 Date d'inscription mardi 13 novembre 2007 Statut Membre Dernière intervention 26 janvier 2011 - 11 janv. 2011 à 13:48
Cette discussion concerne un article du site. Pour la consulter dans son contexte d'origine, cliquez sur le lien ci-dessous.

https://codes-sources.commentcamarche.net/source/37134-c-win32-proxy-avec-thread

petitmoustique Messages postés 52 Date d'inscription mardi 13 novembre 2007 Statut Membre Dernière intervention 26 janvier 2011 15
11 janv. 2011 à 13:48
Merci beaucoup, merci vraiment.

9/10 car j'ai pas encore tout lu, mais que l'EXE m'affiche exactement ce que je veux modifier
ombr0 Messages postés 21 Date d'inscription samedi 30 avril 2005 Statut Membre Dernière intervention 6 décembre 2008
6 déc. 2008 à 09:18
Ok merci, en fait en bidouillant ta source j'arrive a afficher la requette post mais pas à la transféré.... si tu peux ajoute moi a msn ombr@hotmail.fr

Merci
psyphi Messages postés 51 Date d'inscription lundi 16 août 2004 Statut Membre Dernière intervention 12 août 2010
6 déc. 2008 à 00:31
J'ai bien recu ton mail et y ait même répondu.

Oui il y a un problème au niveau des requetes POST, je ne me souviens plus exactement pourquoi. Je dois checker sur mon vieux PC si j'ai toujours les sources et si elles sont plus récentes qu'ici.
ombr0 Messages postés 21 Date d'inscription samedi 30 avril 2005 Statut Membre Dernière intervention 6 décembre 2008
5 déc. 2008 à 23:50
J'ai continuer mon investigation,.... après bidouillage de ton code.... j'ai remarqué que tu ne renvoyait pas les requètes dans leur intégralitée.... en particulier les requètses POST....
Est-ce que tu pourrais entrer en contact avec moi ?? ombr@ombr.net ??
J'ai déjà essayé de t'envoyer un mail mais apparament ton adresse ne fonctionne plus....

Merci
ombr0 Messages postés 21 Date d'inscription samedi 30 avril 2005 Statut Membre Dernière intervention 6 décembre 2008
29 nov. 2008 à 13:56
Salut,

Après test du proxy, j'ai remarqué qu'il ne gère pas les requètes post de flash... aurais tu une explication ? exemple sur mon site : www.ombr.fr

Merci d'avance
victorcoasne Messages postés 1101 Date d'inscription jeudi 24 avril 2003 Statut Membre Dernière intervention 23 juillet 2023 7
13 juil. 2007 à 01:47
J'ai rencontré le même problème quand j'ai fabriqué mon propre proxy.
Cela vient de la spécification HTTP qui autorise un navigateur qui transmet à un proxy à inclure l'adresse avec http:// mais qui ne l'autorise pas à la transmettre avec les http:// au serveur qui fourni l'adresse (sur ebay Microsoft IIS).
victorcoasne Messages postés 1101 Date d'inscription jeudi 24 avril 2003 Statut Membre Dernière intervention 23 juillet 2023 7
11 juil. 2007 à 23:22
Essaye ebay.fr et tu vas rire ;)
psyphi Messages postés 51 Date d'inscription lundi 16 août 2004 Statut Membre Dernière intervention 12 août 2010
10 févr. 2007 à 15:35
Voila la nouvelle version est postée j'attends vos retours :)
psyphi Messages postés 51 Date d'inscription lundi 16 août 2004 Statut Membre Dernière intervention 12 août 2010
8 févr. 2007 à 20:44
Ok bon là j'ai essayé de compiler avec Visual Studio 2005, j'ai eu pas mal d'erreurs, j'en ai corrigé pas mal, dès que tout est propre je poste le .zip
xav987 Messages postés 6 Date d'inscription jeudi 26 janvier 2006 Statut Membre Dernière intervention 18 mai 2007
8 févr. 2007 à 17:13
J'ai testé avec :
- GCC de DevCpp (version 3.4.quelque chose !) qui à l'avantage d'etre multiplateforme (mais ma version est un peu vielle,
- Le compilo de Borland C++ 6
- Le compilo de Visual Studio 2005 (et je ne suis pas specialement partisant des produits micro$oft, mais ça reste le meilleur compilo celon moi.

L'interface de Code::Block est sympa, mais son compilo par default (mais on peu en parametrer un autre) est vraiment à chier (enfin, c'est mon avis) ! Il laisse passer plein de Warning, et pire de quelques erreurs.
Et l'outils de debogage n'est pas top (j'aurais jamais trouvé les erreurs d'allocations et d'ecrasement de données dans les buffer avec code block).
psyphi Messages postés 51 Date d'inscription lundi 16 août 2004 Statut Membre Dernière intervention 12 août 2010
8 févr. 2007 à 11:55
Tu compiles avec quel compilateur et quelle version?
xav987 Messages postés 6 Date d'inscription jeudi 26 janvier 2006 Statut Membre Dernière intervention 18 mai 2007
8 févr. 2007 à 11:31
Autres petits details (mais là c'est vraiment un tres petit detail) :
le QUARTER_SIZE n'est jamais utilisé,
Le HALF_SIZE pour l'host c'est un peu juste, j'ai eu des erreurs pour afficher certains site où ce n'etait pas suffisant (sur 01.net par exemple il ont des url tres longues).

Mais c'est vraiment la seul source de Proxy que j'ai trouver sur le net qui fonctionne aussi bien... Encore felicitation !
xav987 Messages postés 6 Date d'inscription jeudi 26 janvier 2006 Statut Membre Dernière intervention 18 mai 2007
8 févr. 2007 à 11:13
Pour l'erreur du Wiki, j'ai trouvé à quoi elle est liée :
Quand on affiche la page du Wiki et qu'on la ferme avant qu'elle ne soit pas totalement apparut, il genere une erreur dans la fonction send(). Sa ne le fait que pour le Wiki, je ne sait pas pourquoi.

Sous CodeBlock, sa continue de tourné, mais sous d'autre compilo, il genere une erreur a cause du free(port). En effet juste avant tu as "port = "80"" donc tu libere un espace qui n'a pas été aloué dynamiquement.
Tu as le meme probleme avec le "free(httpRequest);" qu'on retrouve assez souvent alors qu'il n'a pas encore été declaré...
J'ai remplacé "port = "80"" par "strcpy(port, "80");" et sa passe sans probleme.

Pour la lisibilité, c'est surtout une question de gout personnel. Je n'aime pas mais certains doivent apprecier ta façon de presenter ton code, c'etait juste une petite remarque et pas du tout un reproche, et ce n'est valable que pour moi.
psyphi Messages postés 51 Date d'inscription lundi 16 août 2004 Statut Membre Dernière intervention 12 août 2010
8 févr. 2007 à 10:11
Salut XAV97, merci de t'intéresser à mon programme :).
Voici effectivement quelques corrections:
- Rajout de +1 à la taille des buffers pour le '\0' de fin de chaine ^^.

char buffer[KB_SIZE*16+1]; // 16 ko pour la requete http
char buffer2[KB_SIZE*4+1]; // 4 ko pour les paquet de transfert

- Correction du nombre d'octet reçu par les fonctions recv() en ajoutant un -1 après les sizeof().
int size = recv(socket_client, buffer, sizeof(buffer)-1, 0);
size = recv(envoi, buffer2, sizeof(buffer2)-1,0)

Maintenant on a bien des échanges de 16ko et 4ko au maximum. Il ne faut en effet pas oublié que les fonctions send et recv ne transmette pas les '\0' de fin de chaine, il faut donc laisser une case de libre dans les chaines de buffer pour les acceuillir. Ce que j'avais oublié de faire :-S.

Merci de tes remarques, maintenant tout devrait mieux fonctionner.
Je mets le zip à jour dès que j'ai le temps.

Désolé pour la lecture du programme mais au fur et à mesure de son amélioration il est devenu de plus en plus complexe et difficile à lire :-/ .
xav987 Messages postés 6 Date d'inscription jeudi 26 janvier 2006 Statut Membre Dernière intervention 18 mai 2007
8 févr. 2007 à 09:49
Il y a un petit bug qui fait que certains compilo retournent une erreur. CodeBock, qui est moins rigoureux, ne signale rien :
Dans ta fonction proxy() tu fais un "buffer2[size]='\0';", donc tu ecrases le dernier octet du buffer2. Sa provoque un stack arround.
Moi j'ai mis "buffer2[KB_SIZE*4+1]" dans la declaration de buffer2 et "sizeof(buffer2)-1" dans la declaration de "size", comme ça on reste dans des echanges de 4096 octet.
Sinon, sur certains site (genre Wikipedia), j'ai un message d'erreur avec la fonction send() et la page ne s'affiche pas, j'ai pas encore trouvé la raison.

A part ça, magnifique programme, difficilement lisible, je trouve, mais qui me servira beaucoup ! 9* =)
cs_bloom1 Messages postés 328 Date d'inscription jeudi 26 août 2004 Statut Membre Dernière intervention 8 mars 2007
13 août 2006 à 07:13
Chez moi il fonctionne nikel, il recoit tout et n'as pas encore planté (3 site que je visites à date)

Donc merci :)
bipbip45 Messages postés 4 Date d'inscription lundi 12 septembre 2005 Statut Membre Dernière intervention 3 mai 2006
3 mai 2006 à 17:12
J'ai enfin fini de lire le code (pas encore exécuté car suis sous Linux). Et voici quelques autres commentaires:

> en mode thread, il me semble que lorsqu'un thread, réalise un exit, c'est l'ensemble des threads et donc ton programme qui réalise un exit. En conséquence, je pense que tu devrais éviter de faire des appels à exit(1) (en ligne 204, 282 ...) lorsqu'une erreur est rencontrée. Mieux vaut propager l'erreur vers les fonctions appelantes avec return EXIT_FAILURE, qui, si c'est la fonction principale du thread mettra fin à celui-ci.

> la fonction proxy() est critique: en effet dans cette fonction, tu alloues l'ensemble des buffers ... Je pense qu'il faudrait réaliser la désallocation de l'ensemble des buffers avant de faire return, qu'un erreur se soit produite ou non. Donc tous les appels à calloc() qui ont eu lieu dans cette fonction ou dans les fonctions appellées (ex: port (l387) ou hostname alloué par gethost() ...)

> fonction send (ex: l.441, l.449): il se peut que send ne parviennent pas à transmettre une requete. C'est pouquoi cette fonction a une code de retour correspondant au nombre de caractères écrits dans la socket. Il convient donc à mon avis de l'exploiter.

> closesocket (l.502, l.516): ici tu fais un close(socket_client) en cas d'erreur. Je pense que c'est un lapsus et qu'il s'agit de socket_local. En effet, socket_local n'existe qu'après l'appel accept (l.512).

> l.529 et l.541 return EXIT_FAILURE: tu as oublié de fermer les sockets avant de sortir.

> enfin je ne connais pas l'API des threads windows mais la version POSIX indique qu'il faut explicitement les détacher si on se moque de leur code de retour car dans le cas contraire, on risque une fuite de ressource. Ici tu ne le fais pas (cf man pthread_join,pthread_detach).

Bon courage pour tes partiels.
psyphi Messages postés 51 Date d'inscription lundi 16 août 2004 Statut Membre Dernière intervention 12 août 2010
2 mai 2006 à 18:53
A non pas du tout tes commentaires ne me gêne pas au contraire, sinon je posterais pas mon proxy en OpenSource ;-).
Merci de tes conseils et remarques, qui je pense, sont sensées. Je vais m'atteler à la correction dès que j'aurai un peu plus de temps et moins de partiels :-/ .
C'est peut-être pour l'une des raisons que tu as cité que parfois mon proxy plante sans raison, ce qui est très embêtant; lol.
Si t'as encore d'autres remarques n'hésite pas, merci.
bipbip45 Messages postés 4 Date d'inscription lundi 12 septembre 2005 Statut Membre Dernière intervention 3 mai 2006
2 mai 2006 à 17:06
J'ai commencé à lire ton code un peu plus dans le détail et voici quelques éléments qui 'mont surpris en dehors de ceux précités:
> on trouve dans le code, par exemple en ligne 97-98 beaucoup de boucles du type:
while(buffer[i]!='car')
i++;
Il se peut que le proxy recoive des paquets malformés voire forgés. Dans ce cas, et sans limite d'indice, il y a de grande chance qu'à force d'incrémenter i, on obtienne une erreur de segmentation due à une lecture arbitraire sur une zone mémoire interdite. (idem ligne 15-116,134-138,164-168,...)

> la fonction get_header_if_exist renvoie un code de retour de type short qui n'est pas exploité lors des appels dans la fonction parse_http_request.

> dans la fonction get_content_lenth : dans le cas ou tu recois un paquet malforme ou le champ "Content" comprend plus de 10 caracteres, ton buffer vas exploser ce qui entrainera au mieux une erreur de segmentation et au pire l'écrasement des données suivantes dans la pile. Peut etre vaudrait-il mieux realiser le calloc un fois que tu sais combien il faut allouer (size-i+1 je crois). De plus, une fois que size est calcule, c'est que ContentLength termine par '\0' (sinon strlen echoue) et donc on pourrait directement ecrire size=atoi(ContentLength+(i+1)).

>lorsque tu emploies la fonction strstr, je pense qu'il faudrait se méfier; en effet en lisant la documentation de strstr(), si la fonction ne trouve pas la sous-chaine, elle renvoie NULL. Je pense que, en ligne 134 par exemple, il faudrait faire une verfication de buffer avant d'effectuer buffer[i] en sortie de strstr.

Voila, j'espere ne pas d'embeter avec ces commentaires; n'hesite pas a me le dire si c est le cas et je me rendrai silencieux.
psyphi Messages postés 51 Date d'inscription lundi 16 août 2004 Statut Membre Dernière intervention 12 août 2010
30 avril 2006 à 23:07
Merci beaucoup de ta remarque, je vais essayer d'en tenir compte.
bipbip45 Messages postés 4 Date d'inscription lundi 12 septembre 2005 Statut Membre Dernière intervention 3 mai 2006
30 avril 2006 à 18:51
En fait snprintf te permet de formater une chaîne de caractères de la même manière que printf, mais au lieu que ce soit vers la sortie standard de l'exécutable, c'est dans un buffer délimité en taille (afin de se prémunir des buffer overflow comme strncat).
Voici son prototype:
int snprintf (char *str, size_t size, const char *format, ...)
Pour plus d'info sur snprintf, un page de manuel en français se trouve à l'URL : http://dpobel.free.fr/man/html/affiche_man.php/3369/man/snprintf/

Voici un exemple de remplacement de deux strncat par un snprintf:
strncat(httpRequest, header, strlen(header)); strncat(httpRequest, "\r\n", 2);

snprintf(httpRequest,sizeof(httpRequest),"%s\r\n",header);

Néanmoins cela nécessiterait que tu revoies toute la gestion de ton buffer httpRequest; car au lieu d'ajouter en fin de buffer comme le fait strncat, snprintf repart du début du buffer.
Cela aurait pu simplifier l'écriture de la fonction "build_post_request". En effet, ce que tu réalises avec l'appel à moulte strncat (un strcat s'est perdu dans la fonction par ailleurs), aurait pu être remplacer par un unique snprintf.

En terme de performances, il faut voir que chaque appel de fonction implique de placer dans la pile les arguments et donc une consommation de mémoire ce qui est assez critique pour un serveur.

Voilà, ce n'était par pour pinailler mais juste pour apporter une briquette à ton édifice.
psyphi Messages postés 51 Date d'inscription lundi 16 août 2004 Statut Membre Dernière intervention 12 août 2010
25 avril 2006 à 23:38
@Stormy: J'ai essayé de compiler avec Visual C++ 6, je n'ai pas réussis, je n'ai pas trop compris pourquoi. Essaye code::block et mingw
http://prdownloads.sourceforge.net/codeblocks/codeblocks-1.0rc2_mingw.exe?download
@BIPBIP45: j'étais justement en train de corriger les erreurs dont tu me fesais part. calloc et équivalent à malloc + memset, il alloue et initialize le contenu.
Sinon en quoi snprintf est plus simple que strncat?
Pour finir je viens de faire une nouvelle mise à jour.
bipbip45 Messages postés 4 Date d'inscription lundi 12 septembre 2005 Statut Membre Dernière intervention 3 mai 2006
24 avril 2006 à 20:43
Je ne connais pas calloc. Dans la mesure où c'est équivalent à malloc, je pense qu'il conviendrait de vérifier le code de retour de cette fonction avant de considérer le pointeur comme alloué:
if(buf==NULL) {
desallocation des autres buffers et fermeture des fd
return EXIT_FAILURE;
}

suite du code

Par ailleurs, juste histoire de simplifier le code, tu aurais peut-être pu utiliser snprintf plutot que de multiplier l'emploi de strncat.

Dans tous les cas, merci pour ton code.
cs_Stormy Messages postés 255 Date d'inscription samedi 20 avril 2002 Statut Membre Dernière intervention 16 janvier 2007
24 avril 2006 à 19:32
J'aimerais le compiler sous Win32 avec VC6. Penses-tu que c'est possible? J'ai beaucoup d'erreurs provoquées par 'redefinition; different linkage'.
psyphi Messages postés 51 Date d'inscription lundi 16 août 2004 Statut Membre Dernière intervention 12 août 2010
24 avril 2006 à 00:29
J'ai corrigé l'erreur du multithreading, c bon.
psyphi Messages postés 51 Date d'inscription lundi 16 août 2004 Statut Membre Dernière intervention 12 août 2010
23 avril 2006 à 00:39
J'ai un nouveau problème, encore un :-S. Depuis que j'ai rajouté mes fonctions de parse de requete HTTP, le nombre de site qui fonctionne est bien meilleur qu'auparavant mais par contre le multithreading plante !!
J'ai des erreurs du type:
0x0040155f emploie l'adresse mémoire 0x0014a0000. La mémoire ne peut pas être "read".
Quelqu'un saurait me dire de quoi cela peut provenir.
PS: si vous voulez une source fonctionnel commenté CreateThread et décommenté la ligne du dessous.
psyphi Messages postés 51 Date d'inscription lundi 16 août 2004 Statut Membre Dernière intervention 12 août 2010
22 avril 2006 à 18:08
Merci de t'interessé à ma source.
Question débordement je ne pense pas, car dans quand je reçois les données avec la fonction recv(), le troisième argument sert à définir la longueur maximal du message reçu en octet, donc si je définit comme longueur maximale la taille de mon tampon, je ne pense pas qu'il y ait de problème.
Pour la taille des buffers par contre je ne sais pas trop qu'elle est la meilleur taille à utiliser pour des transferts de données, on m'a dit sur un forum d'utiliser des buffers de 4ko ou 16ko, si qqun à des propositions avec explications je suis preneur.
Peut être qu'il y a encore des erreurs dans la reception des requêtes, il faudrait peut être que je rajoute un filtre spéciale, car on n'est pas à l'abris que quelqu'un forge sa propre requête avec des commandes fallacieuses.
cs_Stormy Messages postés 255 Date d'inscription samedi 20 avril 2002 Statut Membre Dernière intervention 16 janvier 2007
22 avril 2006 à 08:40
Pour ce qui est de la réception des données dans les tampons (buffer1 et buffer2), je vois que tu fixes une limite importante de 4 et 2 Ko. Néanmoins, n'as-tu pas peur d'éventuels débordements? Le risque est-il possible?
En tout cas cette source est très intéressante ++
psyphi Messages postés 51 Date d'inscription lundi 16 août 2004 Statut Membre Dernière intervention 12 août 2010
18 avril 2006 à 23:55
Ouki, c'est en fonction du bus d'adresse du processeur 2^32 = 4294967296 adresses possibles. Il faut donc une capacité de 4 octets (32bits) [Tout ca pour un processeur 32bits] c'est là encore logique ;-) merci BruNews de m'avoir éclairé.
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
18 avril 2006 à 23:41
La taille du DWORD 'machine' (taille registre du cpu), permet d'adresser sur une plage 4 Go (32 bits full sur 32 bits) et en téra (à calculer) sur 64 bits, sinon un pointeur ne serait pas valide pour référencer une adresse mémoire.
psyphi Messages postés 51 Date d'inscription lundi 16 août 2004 Statut Membre Dernière intervention 12 août 2010
18 avril 2006 à 23:37
Oki merci bien, au fond ca semble logique en plus.
Sinon pourquoi 4 octets pour un pointeur?
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
18 avril 2006 à 23:33
L'éternel piège du sizeof qu'on répète à longueur de forum.
sizeof ne donnera la taille d'une variable que si elle est de taille fixe et connue dans la portée de la fonction ou globale mais dans la cas d'un pointeur c'est, comme dit plus haut, 4 en sytème 32 bits et 8 en système 64 bits.
psyphi Messages postés 51 Date d'inscription lundi 16 août 2004 Statut Membre Dernière intervention 12 août 2010
18 avril 2006 à 23:26
Merci de ton aide :D
>Comment se fait-il que sizeof(host) renvoie 4 ?
>Tu peux m'expliquer un peu plus cet histoire de prototype?
>Toujours pas d'idées quant a mon histore de buffer2?
ymca2003 Messages postés 2070 Date d'inscription mardi 22 avril 2003 Statut Membre Dernière intervention 3 juillet 2006 7
18 avril 2006 à 23:22
char * host = (char *)malloc(256 * sizeof(char));
memset(host, '\0', sizeof(host));
=> ne va initialiser q'une partie du buffer alloué car sizeof(host) va renvoyer 4 sur plateforme 32 bits
memset(host, '\0', 256*sizeof(char)); met tout le buffer à 0

int proxy(SOCKET socket_client)
=> pas le bon prototype il faut :
DWORD CALLBACK proxy(LPVOID)
ou au moins
int CALLBACK proxy(SOCKET socket_client)