Friday, September 08, 2023

operator sockaddr*()

J'ai passé un peu de temps cet été dans du code third-party qui avait un autre dialecte c++ que moi. En particulier, ils aimaient bien faire des objets-wrappers métamorphes. Prenons par exemple une adresse réseau. C'est pénible: on peut l'avoir sous forme ASCII ou dans un entier 32-bit (ou un gros blob si on est en IPv6). Et de toutes façons, pour s'en servir il faudra qu'elle soit emballée dans un sockaddr, seule connue de l'API socket, qui reprend un identifiant de 'famille de protocole' et un numéro de port.

Tout ça semble justifier une classe NetAddress qui aurait des constructeurs NetAddress(std::string fromUserInterface) et NetAddress(uint32_t fromProtocolMessage). Très bien. On peut aussi en faire en réalité un wrapper de `struct sockaddr_storage`, et remplir les différents champs au moment de l'appel. Avec éventuellement un NetAddress.setPort() pour faire bonne mesure.

Mais ce n'est pas ça qui va changer le fait que connect() et bind() travaillent exclusivement avec des sockaddr. Là où j'ai été surpris, c'est qu'au lieu d'un NetAddress.getSockAddr(), j'ai eu droit à

operator sockaddr*() {
    return reinterpret_cast<const sockaddr*>(&address);
}

Séduisant a priori. Elégant, même. Mais à l'usage (et surtout à la lecture), ça s'est avéré être un fiasco. Je tombais sur du code du genre connect(toServer, myServerAddress, options) suffisament loin de la définition de myServerAddress et je zappais qu'il ne s'agissait pas d'un sockaddr classique, mais de l'objet emballant. Particulièrement piégeux quand on essaie de découvrir d'où provient l'exception InvalidArgument que rien dans le code de connect ne semble pouvoir générer.

Et ç'aurait pu être encore pire si myServerAddress avait été un pointeur vers une NetAddress ... Là, on aurait dû écrire connect(toServer, *myServerAddress, options), parce que c'est un NetAddress-même que le compilateur a appris à "traduire" en sockaddr* à l'aide de l'opérateur. Pas un pointeur de NetAddress. Perturbant au possible quand on se souvient qu'en C on aurait écrit connect(toServer, &server_address, opts);

...

Sinon, vous, l'été, ça a été ?

No comments: