c++udpmulticastwinsock2ssdp

Response doesn't reach socket on multicast in Windows


I'm trying to get a little SSDP client / server up and running. So far the server is working just fine, responding to my M-SEARCH (according to wireshark). The client code is written in Visual Studio using Winsock2 (see code below). The problem is that the response never reaches my recv call when i send the search to the multicast address.

I already tried sending and receiving directly to the server ip address, which will generate a response that reaches my recv call correctly. However, when i change the ip to the multicast addess, it doesn't work (even though i can see the response on Wireshark!). So for some reason the socket (on OS level?) refuses to pass it on to the application.

I should note that the response is always unicast.

Here's my code:

#include <Winsock2.h> // before Windows.h, else Winsock 1 conflict
#include <Ws2tcpip.h> // needed for ip_mreq definition for multicast
#include <Windows.h>

#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#define SERVERPORT 1900
char buff[] = "M-SEARCH * HTTP/1.1\r\nHOST: 239.255.255.250:1900\r\nMAN: ssdp:discover\r\nST: ssdp:all\r\n\r\n";

int main()
{
    char rcvdbuff[1000];
    int len, Ret = 2;

    WSADATA wsaData;
    if (WSAStartup(0x0101, &wsaData)) {
        perror("WSAStartup");
        return 1;
    }

    struct sockaddr_in their_addr;
    SOCKET sock;

    sock = socket(AF_INET, SOCK_DGRAM, 0);

    their_addr.sin_family = AF_INET;
    ////THIS APPROACH DOES NOT WORK
    their_addr.sin_addr.s_addr = inet_addr("239.255.255.250");
    //THIS APPROACH WORKS - SOMEHOW THE SOCKET IS BOUND TO THIS IP AND CAN THUS RECEIVE
    //their_addr.sin_addr.s_addr = inet_addr("192.168.3.90");
    their_addr.sin_port = htons(SERVERPORT);
    len = sizeof(struct sockaddr_in);

    while (1)
    {
        printf("buff:\n%s\n", buff);
        Ret = sendto(sock, buff, strlen(buff), 0, (struct sockaddr*)&their_addr, len);
        if (Ret < 0)
        {
            printf("error in SENDTO() function");
            closesocket(sock);
            return 0;
        }

        //Receiving Text from server
        printf("\n\nwaiting to recv:\n");
        memset(rcvdbuff, 0, sizeof(rcvdbuff));
        Ret = recvfrom(sock, rcvdbuff, sizeof(rcvdbuff), 0, (struct sockaddr *)&their_addr, &len);
        if (Ret < 0)
        {
            printf("Error in Receiving");
            return 0;
        }
        rcvdbuff[Ret - 1] = '\0';
        printf("RECEIVED MESSAGE FROM SERVER\t: %s\n", rcvdbuff);

        //Delay for testing purpose
        Sleep(3 * 1000);
    }
    closesocket(sock);
    WSACleanup();
}

I tried one interesting thing (without restarting the application!):

1) First send to the direct ip address (192.168.3.90)

2) Get response

3) Now send to the multicast address

4) Now the response gets back just fine!

It's as if the socket somehow 'knows' the unicast address from the first send/recv call.

Does anyone know what to do or how to debug?


Solution

  • I think I've found the solution to the question: Windows Firewall. Here's a quote over from Quora:

    Only connections that are explicitly allowed, using firewall rules, are permitted. Windows Firewall, by default, allows all outboundconnections, and permits only established inbound connections (that is, an inbound connection that is in direct response to an outbound connection initiated from your computer or network).

    This is exactly the situation: We've not established an outbound connection, and thus it's blocked by Windows Firewall!

    In the other case, when I first send directly, Windows Firewall opens up for that exact inbound connection and therefore the subsequent multicast send gets a response.