Showing posts with label tcp. Show all posts
Showing posts with label tcp. Show all posts

Tuesday, January 05, 2010

sgIP_TCP: either buggy or awkward

L'implémentation de TCP sur DS me surprend un peu, et pourrait bien expliquer les "fuites de données" observées pendant les transfers DS->PC. Ou les "deadlocks" qui se produisent en cours de transmission". Sur la sellette, la gestion des ACK, ces signaux qui indiquent qu'un paquet a bien été reçu.
I've never seen a TCP implementation behaving like dswifi, and chances are that it might explain the "data losses" and deadlocks I'm experiencing with runme uploads recently. I've compared my version (2005-2006) against the latest version in devkitpro and did not noticed significant changes in the TCP protocol handling.
What looks odd is the management of ACKnowledgements, those little packets that just tell the sender that "okay, i've got your data, go ahead". First, the DS seems to acknowledge everything, including ACKs from the PC. Moreover, it doesn't look to take all ACKs into account when sending a packet, but only the oldest one ...

  • d'abord, la DS émet un ACK même pour un paquet qui ne contenait aucune donnée (un ACK du PC, par exemple)
  • ensuite, elle ne semble pas tenir compte du dernier ACK reçu au moment de renvoyer des données, si bien que la DS réémet des données que le PC a déjà acquittées.
Mon analyse est encore un peu imparfaite (la DS a-t-elle ou non reçu les ACK du PC ? difficile à dire)
En regardant les lignes 4060 et 4061 de la capture, il est évident que la DS a reçu un ack du PC, puisque le n° de séquence évolue pour la 1ere fois depuis la ligne 4050, mais alors que le PC vient de valider tous les bytes jusqu'à 101796 (compris), la DS retransmet tout de même à partir de 100633 (ç.a.d. seulement 256 bytes plus loin que le packet précédent).

Je travaille toujours avec la version 2005-2006 de la bibliothèque dswifi de Stephen Stair. Je devrais sans doute tenter une mise à jour.

edit: the third pass on my own code revealed a subtle error on how I handled "EWOULDBLOCK" when uploading from a file. sgIP_TCP thus did not lose any data and is just a bit awkward. Sgstair himself took the time to point me out that there are much more levels of queueing in the DS networking stack (including hardware buffers), which sheds another light on the problem ... I think I can live with small performance issues. But I'll keep on investigating the issue anyway.

Thursday, May 28, 2009

sendall

J'ai toujours été intrigué par cette fonction "sendall" du Beej Network Programming Guide. Selon Beej, un appel à send pour transmettre des données pourrait ne pas nécessairement envoyer autant de données que prévu. J'ai toujours trouvé ça un peu surprenant et je n'avais personnellement jamais été témoins d'une telle chose jusqu'à aujourd'hui.

Corrigeant les TP de programmation de BitTorrent, j'ai un strace ouvert aussi sur le client initial dans un "environnement de test contrôlé" et voilà que j'aperçois la séquence suivante:

send(10, "\0\0\200\t\7\0\0\0(\0\0\0\0\2619\r\222\265\315r\264a\363"..., 32781, 0) = 32781
send(10, "\0\0\200\t\7\0\0\0(\0\1\0\0\340\306\335\246\17\r\377\265"..., 32781, 0) = 32781
send(10, "\0\0\200\t\7\0\0\0(\0\2\0\0\233\257\314\25P\322\2363\316"..., 32781, 0) = 32781
send(10, "\0\0\200\t\7\0\0\0(\0\3\0\0002\235\311\36yyzt\322\363$"..., 32781, 0) = 28790
send(10, "UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU"..., 3991, 0) = 3991


Le programme tente d'envoyer des données de 32K accompagnées de 13 bytes de contrôle. Le plus souvent, celà signifie qu'un buffer de 32781 bytes est passé à l'appel-système send (cf. le 3eme argument) et que 32781 bytes ont effectivement été envoyés (cf. la valeur de retour, après le '='). Sauf pour les deux derniers, où si on a bien 32K+7 soumis, seuls 28790 bytes ont pu effectivement être "envoyés" ... Je devrais plutôt dire "pris en charge par le protocole TCP". Effectivement, TCP a sa propre mémoire-tampon dans laquelle il conserve les données à envoyer, mais elle n'est pas infinie. Si a un moment donné elle "déborde", TCP prend le plus de données possibles mais signale à l'application qu'une partie n'a pas pu être traitée.

On aurait pu préférer une approche "l'appel va être bloquant jusqu'à ce que tous les bytes soumis soient traités". Bin ce n'est pas forcément le cas, et ce n'est pas plus mal: l'application a peut-être quelque-chose de plus utile à faire avant de ré-envoyer le reste.

Comme j'ai de temps en temps des fichiers qui "passent mal" avec les transfers wifi de runme, je regarderai à l'occasion si je ne ferais pas bien de rajouter un "sendall" ici ou là.

PS: au passage, Beej a finalement fait une version "bouquin" de son superbe tutoriel.