Can I use IdUDPClient to send M-SEARCH request?
Asked Answered
G

3

5

There are few uPNP devices in my network. I am trying to send M-SEARCH request to the network and hope receiving some responses from it. This is what I am trying:

var sIP, sOut: string;
    iPort: Word;
    S: TStringBuilder;
begin
  S := TStringBuilder.Create;
  try
    S.Append('M-SEARCH * HTTP/1.1').AppendLine
     .Append('HOST: 239.255.255.250:1900').AppendLine
     .Append('MAN: "ssdp:discover"').AppendLine
     .Append('MX: 10').AppendLine
     .Append('ST: ssdp:all').AppendLine;

    IdUDPClient1.ReceiveTimeout := 3000;
    IdUDPClient1.Broadcast(S.ToString, 1900, '239.255.255.250');
    sOut := IdUDPClient1.ReceiveString(sIP, iPort);
    Memo1.Lines.Add(sIP);
    Memo1.Lines.Add(IntToStr(iPort));
    Memo1.Lines.Add(sOut);
  finally
    S.Free;
  end;
end;

I receive nothing from the UDP client. I use Wireshark to monitor network traffic and no message was send out from my host.

Any ideas? Thank you.

I found the answer finally:

uses
  System.SysUtils, IdUDPClient, IdStack;

var S: TStringBuilder;
    U: TIdUDPClient;
    iPeerPort: Word;
    sPeerIP, sResponse: string;
begin
  U := TIdUDPClient.Create(nil);
  S := TStringBuilder.Create;
  try
    S.Append('M-SEARCH * HTTP/1.1').AppendLine
     .Append('HOST: 239.255.255.250:1900').AppendLine
     .Append('MAN: "ssdp:discover"').AppendLine
     .Append('MX: 3').AppendLine
     .Append('ST: ssdp:all').AppendLine
     .AppendLine;

    U.BoundIP := GStack.LocalAddress;
    U.Send('239.255.255.250', 1900, S.ToString);

    U.ReceiveTimeout := 1000;
    repeat
      sResponse := U.ReceiveString(sPeerIP, iPeerPort);
      if iPeerPort <> 0 then begin
        WriteLn(Format('%s:%d', [sPeerIP, iPeerPort]));
        WriteLn(sResponse);
      end;
    until iPeerPort = 0;
    ReadLn;
  finally
    S.Free;
    U.Free;
  end;
end.
Gustavo answered 6/6, 2012 at 6:52 Comment(0)
B
6

Call AppendLine() twice at the end of the string builder. HTTP request headers are terminated by two CRLF pairs, but you are only appending one pair, so you are sending an incomplete request.

Beatification answered 6/6, 2012 at 20:19 Comment(5)
I add a new AppendLine() to stringbuilder object, but I didn't receive any response too. I also didn't notice the request send out from my host when monitor the traffic via WireShark.Gustavo
Are you sure that 239.255.255.250 is the correct broadcast IP for your LAN? What local IP and subnet is assigned to your client's PC?Beatification
If I broadcast to 239.255.255.255, I can see the traffic sent out from my host. But broadcast to 239.255.255.250, no traffic was detected.Gustavo
I am not sure if 239.255.255.250 is the address I should broadcast. I am trying to send the m-search packet to 239.255.255.250 in order to receive some replies of available uPNP devices in my network. How to do it with IdUDPClient? Should I broadcast or send?Gustavo
I found out the problem. I should set BoundIP to my adapter's IP. The uPNP Device Host Service doesn't listen to 0.0.0.0. It listen to host's adapter's IP only.Gustavo
C
3

Quick and Dirty solution using TIdUDPServer (Indy 9).

Drop the TIdUDPServer component on the form, and using Object Inspector set Bindings to your local IP eg. 10.1.0.78:0, set BroadcastEnabled and Active to true. Drop a TMemo and TButton on the form.

Complete the OnClick and UDPRead Events as follows:

uses IdSocketHandle;
...
procedure TForm1.Button1Click(Sender: TObject);
begin
  IdUDPServer1.Send('239.255.255.250', 1900, 'M-SEARCH * HTTP/1.1' + #13#10 +
     'HOST: 239.255.255.250:1900' + #13#10 +
     'MAN: "ssdp:discover"'+ #13#10 +
     'MX: 3'+ #13#10 +
     'ST: ssdp:all'+ #13#10 +
     #13#10);
end;

procedure TForm1.IdUDPServer1UDPRead(Sender: TObject; AData: TStream; ABinding: TIdSocketHandle);
var 
   data: string;
begin

   setlength(data, Adata.Size - AData.Position); //No fragmentation :)        
   AData.ReadBuffer(data[1], length(data));

   memo1.Lines.Add('Read: ' + inttostr(AData.Position) + ' / ' + inttostr(AData.Size) + ' PeerIP: ' + ABinding.PeerIP);       
   memo1.Lines.Add(data);
end;

Save, Run and Bob's your uncle.

Capstone answered 6/12, 2012 at 15:28 Comment(0)
S
0

For multicast M-SEARCH, the message format is defined below. Values between * * are placeholders for actual values.

M-SEARCH * HTTP/1.1
HOST: 239.255.255.250:1900
MAN: "ssdp:discover"
MX: *seconds to delay response*
ST: *search target*
USER-AGENT: *OS/version UPnP/1.1 product/version*

So you need to fix ReceiveTimeout to

U.ReceiveTimeout := 3000;

It should be at least equal to delay in your request (MX:3) 3 sec = 3000 milliseconds

Sandoval answered 26/4, 2017 at 21:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.