News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Multicast to find UPnP server on local lan

Started by fearless, May 17, 2011, 06:03:03 PM

Previous topic - Next topic

fearless

Ive been playing around with sockets etc in an attempt to discover a upnp media server on my Qnap NAS which is on the same local subnet.

From reading bits and pieces on the web i found couple of references that outline the process required: http://www.upnp-hacks.org/upnp.html

So it appears that i need to connect to port 239.255.255.255 on port 1900 using UDP, then send some data in the form of:

M-SEARCH * HTTP/1.1
HOST: 239.255.255.250:1900
MAN: ssdp:discover
MX: 10
ST: ssdp:all


which the UPnP servers are supposed to respond to with a message that has an xml file location that contains some info about the media server (name, model, version etc etc)

Tried a few things but havnt been able to get it to work, so wondering if anyone has any ideas on where im going wrong, here is the code im using so far (using debug.lib printtext macro in a few places to help tell me how far ive got - seems to connect ok, but cant seem to recieve any data, tried with and without WSAAsyncSelect, but tbh not sure how that works or if its needed in this case)


UPnP_Discovery  PROC   
   
    LOCAL sock:DWORD
    LOCAL SocketAddress:sockaddr_in
   
invoke  WSAStartup, 0002h, addr wsaData
.IF eax != 0
Invoke WSAGetLastError
PrintText 'Failed to Initialize Winsock'
PrintDec eax
mov eax, FALSE
ret
.ENDIF
; Check Winsock Version
mov al,  byte ptr [wsaData.wVersion]
.IF al < 2 ; Requested winsock level lower than 2, so quit out
PrintText 'Winsock Version 2 Required'
invoke  WSACleanup
.IF eax == SOCKET_ERROR
Invoke WSAGetLastError
PrintText 'WS_VER:Winsock Cleanup Failed'
PrintDec eax
.ENDIF
mov eax, FALSE
ret
.ENDIF

invoke socket, AF_INET, SOCK_DGRAM, IPPROTO_UDP ; HTTP over UDP for multicast
.IF eax == INVALID_SOCKET
    mov eax, FALSE
    ret
.endif

mov sock, eax

invoke inet_addr, Addr UPNP_DISCOVERY_ADDR
    mov SocketAddress.sin_addr,eax
    mov SocketAddress.sin_family,PF_INET
    invoke htons,UPNP_DISCOVERY_PORT   ; port in network byte order
    mov SocketAddress.sin_port,ax
   ; invoke WSAAsyncSelect,sock,hWnd,WM_SOCKET,\     ; We choose to receive notification about successful connection,
    ;                   FD_CONNECT or FD_READ or FD_CLOSE ; incoming data, and when the socket is closed
    invoke connect,sock,addr SocketAddress,sizeof SocketAddress
    .if eax==SOCKET_ERROR   
        PrintText 'connect SOCKET_ERROR'
        mov eax, FALSE
        ret
    .ENDIF

Invoke sendto, sock, Addr UPNP_DISCOVERY_PACKET, sizeof UPNP_DISCOVERY_PACKET, 0, Addr SocketAddress, sizeof SocketAddress
    .if eax==SOCKET_ERROR   
        PrintText 'sendto SOCKET_ERROR'
        mov eax, FALSE
        ret
    .ENDIF
   
    Invoke recv, sock, Addr hInternetBuffer, SIZEOF hInternetBuffer, 0
   
    PrintString hInternetBuffer
    Invoke closesocket, sock
    Invoke WSACleanup
   
mov eax, TRUE
    ret

UPnP_Discovery endp


Some other info in the .data and .data? section is:

UPNP_DISCOVERY_PACKET   db "M-SEARCH * HTTP/1.1",10
                        db "HOST: 239.255.255.250:1900",10
                        db "MAN: ssdp:discover",10
                        db "MX: 10",10
                        db "ST: ssdp:all"

UPNP_DISCOVERY_ADDR     db "239.255.255.250",0
UPNP_DISCOVERY_PORT     dd 1900

.data?
hInternetBuffer     db 2056 dup (?)
ƒearless

Tedd

More likely...

UPNP_DISCOVERY_PACKET   db "M-SEARCH * HTTP/1.1",13,10
                        db "HOST: 239.255.255.250:1900",13,10
                        db "MAN: ssdp:discover",13,10
                        db "MX: 10",13,10
                        db "ST: ssdp:all",13,10
                        db 13,10
No snowflake in an avalanche feels responsible.

fearless

Thanks Tedd, spotted that the other day, tried with just the line feeds and with carriage returns.

I think i have it sending ok, but not receiving, have to go back and look at maybe bind function and setting up for receiving in a thread perhaps. Anyways im going to read thru the winsock tut on madwizard.org again to see if i can figure out how to send and receive properly. Done a lot of searching on google and codeproject and codeguru to see if there are some examples in c that can be used as a template, closest one i could fine was http://www.codeproject.com/KB/IP/iocp-multicast-udp.aspx (IP Multicasting - Using I/O completion ports with UDP)  and this one http://ntrg.cs.tcd.ie/undergrad/4ba2/multicast/antony/ talks about joining multicast group to receive. Tbh not sure which is the best model to use for what i want.

ƒearless

Tedd

I did a quick test and it works fine (request data as in my post) - I got 15 service replies. Check you actually have UPNP enabled.

1. create your socket
2. set its timeout to something low (10-30 seconds)
3. use sendto (UDP is connectionless - there's no need to connect)
4. use recvfrom (512 bytes is more than enough for each message)
5. do what you want with the returned data (you'll need a SOAP library to do anything useful)
6. repeat from 4 until the socket times out (i.e. no more replies)

Sockets are blocking by default, which makes it all a lot simpler in this case; but you'd be waiting forever when there are no more replies - hence the low timeout value.
No snowflake in an avalanche feels responsible.