Ssdp Broadcast avec winsock2

Fermé
Rémy - 8 janv. 2013 à 22:01
 Rémy - 21 janv. 2013 à 20:39
Bonjour,

Je suis en train de faire un petit programme qui a pour but de récupérer quelque information sur un routeur. Mon programme renvoi le paquet de broadcast tant qu'il n'a pas reçut de réponse et parfois la réponse et immédiate et d'autre foi il doit envoyer plusieurs centaines de paquet avant de recevoir une réponse. Le sniffer que j'utilise m'indique que seul les paquets qui ont reçu une réponse ont réellement été envoyer alors que mon programme me dit qu'ils ont tous été envoyé.

le code exécuté en boucle:


    char broadcast1 = true;
    SOCKET sock;
    SOCKADDR_IN sin;

   sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
   bind(sock, (struct sockaddr *)&sin,sizeof(sin));

    unsigned long addr = inet_addr("239.255.255.250");
    setsockopt(sock, SOL_SOCKET, 10, (char*)&broadcast1, sizeof(broadcast1));
    setsockopt(sock, SOL_SOCKET, 9, (char *)&addr, sizeof(addr));


    sin.sin_addr.s_addr    = inet_addr("239.255.255.250");
    sin.sin_family         = AF_INET;
    sin.sin_port           = htons(1900);

    sendto(sock, data, size, 0, (sockaddr*)&sin, sizeof(sin));


J'ai l'impression que ce sont les autres programmes qui utilisent le broadcast ssdp qui bloquent les envoient de mon programme car lorsque je kill les processus qui utilisent le ssdp, ça marche, les paquets sont envoyés du premier coup à chaque fois.

Merci pour vos réponses
A voir également:

15 réponses

totof31 Messages postés 163 Date d'inscription lundi 29 octobre 2012 Statut Membre Dernière intervention 30 avril 2013 74
9 janv. 2013 à 11:21
Bonjour,

J'ai l'impression que ce sont les autres programmes qui utilisent le broadcast ssdp qui bloquent les envoient de mon programme


C'est possible si les autres applis ssdp ont fait un bind avec l'adresse multicast 239.255.255.250

Dans ce cas, l'OS détermine que l'adresse est locale et il ne l'envoie pas physiquement sur le réseau mais à l'appli locale uniquement.

Ce qui me surprend, c'est que tu dis que de temps en temps la requête passe...

PS : rassure moi, dans le code ci-dessus, tu initialises bien sin avant de faire le bind ?
0
Merci pour ta réponse, en effet je n'initialise pas sin avant de faire le bind mais j'ai remarqué que le bind ne servait à rien.

Sinon connais-tu une solution pour savoir si un autre programme a fait un bind avec l'adresse multicast et/ou demander à l'OS de l'envoyer physiquement sur le réseau ?
0
totof31 Messages postés 163 Date d'inscription lundi 29 octobre 2012 Statut Membre Dernière intervention 30 avril 2013 74
9 janv. 2013 à 15:34
Merci pour ta réponse, en effet je n'initialise pas sin avant de faire le bind mais j'ai remarqué que le bind ne servait à rien.

C'est peut-être là l'erreur !!! Le bind sert entre autre :
- à fixer le numéro de port à utiliser
- potentiellement, à associer le socket (virtuel) à une interface réseau (physique) (particulièrement utile si ta machine comporte plusieurs interfaces réseau).

Si tu fais un bind avec une structure non initialisée, ça revient à faire un bind avec des paramètres incorrects et potentiellement invalides... (en particulier le port 0 est-il valide ? L'interface 0 ?...)

Sinon connais-tu une solution pour savoir si un autre programme a fait un bind avec l'adresse multicast

Essaie de regarder les options de "netstat"

et/ou demander à l'OS de l'envoyer physiquement sur le réseau ?

Comme ça, finement, je ne vois pas. Mais si tu le sens, tu peux regarder du côté de winpcap. C'est la librairie utilisée par Wireshark pour capturer le trafic, et qui permet également d'accéder à la carte en mode RAW. C'est très pratique mais l'inconvénient c'est que tu court-circuites la pile IP. Il faut donc utiliser ta propre pile (ceci dit, une pile simplifiée peut peut-être suffire à ton utilisation)
0
Lorsque je bind ma socket avec l'adresse 239.255.255.250 j'obtien l'erreur 10049(WSAEADDRNOTAVAIL) qui veut dire (si j'ai bien compris) que le port ou l'adresse est invalide.

Quand je dis : "envoyer physiquement sur le réseau" je veux dire que je voudrais que le paquet soit envoyé alors que l'adresse a déjà été binder.

j'ai observé certain logiciel qui envoient un broadcast ssdp lorsque je les lance alors que juste avant mon programme lui n'y arrive pas, il y a donc un moyen d'envoyer une requête alors que l'adresse a déjà été binder.
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
totof31 Messages postés 163 Date d'inscription lundi 29 octobre 2012 Statut Membre Dernière intervention 30 avril 2013 74
9 janv. 2013 à 17:12
Lorsque je bind ma socket avec l'adresse 239.255.255.250 j'obtien l'erreur 10049(WSAEADDRNOTAVAIL) qui veut dire (si j'ai bien compris) que le port ou l'adresse est invalide.

Ben ça me semble normal. 239.255.255.250 c'est l'adresse de destination. bind sert à associer le socket avec la carte d'émission (donc avec l'adresse source). Or cette adresse est multicast, elle ne correspond pas à une adresse physique.

Dans ton cas, il me semble que bind devrait uniquement te servir à spécifier un port source pour l'envoi de ta requête, et laisser l'adresse ip par défaut de la carte.

Pour le reste, je comprends bien mais je n'ai pas la solution sous le coude...
0
OK, merci beaucoup de m'avoir aidé
0
Est-ce que quelqu'un connaîtrait une option pour ma socket ou une fonction qui permettrait d'envoyer un paquet alors que l'adresse de broadcast a déjà été binder par un autre programme ?
0
totof31 Messages postés 163 Date d'inscription lundi 29 octobre 2012 Statut Membre Dernière intervention 30 avril 2013 74
10 janv. 2013 à 09:54
Encore une remarque/question : es-tu certain des valeurs que tu passes en paramètres à setsockopt ? 9 et 10 ? Où as-tu trouvé ces valeurs ?
Pour le broadcast on/off, je trouve 32. Mais comme je l'ai dit plus haut, ton adresse est multicast, pas broadcast, je ne suis donc pas certain que ce soit utile.
Pour le 9, je n'ai pas trouvé l'utilité ?! Si ton but est d'envoyer un message broadcast, ça me semble inutile.

D'autre part, dans les exemples trouvés, j'ai plutôt vu :
int broadcast1 = 1;
(et pas char broadcast1 = true;)

Pense aussi à bien vérifier le code erreur en retour de ces fonctions !!!

Voici une partie de la liste trouvée dans mon winsock2.h :
#define SO_DEBUG 1
#define SO_ACCEPTCONN 2
#define SO_REUSEADDR 4
#define SO_KEEPALIVE 8
#define SO_DONTROUTE 16
#define SO_BROADCAST 32
#define SO_USELOOPBACK 64
#define SO_LINGER 128
#define SO_OOBINLINE 256

Quelques programmes exemples :
BroadcastSenderWS.c
BroadcastReceiverWS.c
MulticastSenderWS.c
MulticastReceiverWS.c
0
totof31 Messages postés 163 Date d'inscription lundi 29 octobre 2012 Statut Membre Dernière intervention 30 avril 2013 74
Modifié par totof31 le 10/01/2013 à 10:04
Petite remarques : les exemples donnés utilisent winsock.h et pas winsock2.h !
Attention aux #include donc. Par exemple pour IP_ADD_MEMBERSHIP, il faut inclure ws2tcpip.h en ws2
0
En fait j'ai utilisé toutes les options qui étaient susceptibles de régler mon problème et elles ne renvoient jamais d'erreur et ne change rien qu'elles soient activées ou non.
0
totof31 Messages postés 163 Date d'inscription lundi 29 octobre 2012 Statut Membre Dernière intervention 30 avril 2013 74
11 janv. 2013 à 17:32
Peux-tu mettre ton code complet ?...
0
int ret;
    SOCKADDR_IN csin;
    unsigned long addr = inet_addr("239.255.255.250");
    char TTLVal = 4,broad=1;
    closesocket(sock);
    sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

int iOptval = 1;

		std::cout << "setsockopt() error: " << WSAGetLastError()<<std::endl;*/
    if(setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, (char *)&addr, sizeof(addr)) == SOCKET_ERROR)
		std::cout << "setsockopt() error: " << WSAGetLastError()<<std::endl;
    if(setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&TTLVal, sizeof(TTLVal)) == SOCKET_ERROR)
		std::cout << "setsockopt() error: " << WSAGetLastError()<<std::endl;


    sin.sin_family = AF_INET;
	sin.sin_addr.s_addr = inet_addr("239.255.255.250");
	sin.sin_port = htons(1900);

    ret = sendto(sock, data, size, 0, (sockaddr*)&sin, sizeof(sin));


Sans les deux options mon programme fait exactement la même chose
0
totof31 Messages postés 163 Date d'inscription lundi 29 octobre 2012 Statut Membre Dernière intervention 30 avril 2013 74
11 janv. 2013 à 23:03
Voici un code qui fonctionne chez moi :
#include <winsock2.h>

using namespace std;

int main(int argc, char *argv[])
{
    int ret;
    SOCKADDR_IN sin;
    int sock;
    WSADATA WSAData;
    char data[100];
    
    data[0] = 123;
    data[1] = 231;
    
    WSAStartup( MAKEWORD(2,0), &WSAData );

    sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

    sin.sin_family = AF_INET;
    sin.sin_addr.s_addr = inet_addr("239.255.255.250");
    sin.sin_port = htons(1900);

    ret = sendto(sock, data, 2, 0, (sockaddr*)&sin, sizeof(sin));

    Sleep(1000);

    closesocket(sock);

    WSACleanup();

    return 0;
}


Et bien linker avec -lws2_32 !!!
0
J'obtient les même résultat avec ton code qu'avec le mien
0
J'ai enfin trouvé.
il faut binder la socket avec l'ip de la carte réseau avec laquelle on veut envoyer le paquet et il faut mettre l'option SO_REUSEADDR.

Merci beaucoup totof31 d'avoir passé autant de temp pour résoudre mon problème.
0
totof31 Messages postés 163 Date d'inscription lundi 29 octobre 2012 Statut Membre Dernière intervention 30 avril 2013 74
15 janv. 2013 à 10:36
Merci pour le retour.
Pour le bind, est-ce que ça veut dire que tu as plusieurs cartes réseau (par exemple une carte wifi et une carte ethernet) ?
0
Le bind me sert surtout pour choisir la carte réseau avec laquelle je veux envoyer le paquet donc si je veux l'envoyer en local ou avec ma carte ethernet.
0