Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I use IdUDPClient to send M-SEARCH request?

Tags:

delphi

indy

ssdp

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.
like image 429
Chau Chee Yang Avatar asked Jun 06 '12 06:06

Chau Chee Yang


2 Answers

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.

like image 63
Remy Lebeau Avatar answered Sep 30 '22 03:09

Remy Lebeau


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.

like image 21
Noener Avatar answered Sep 30 '22 02:09

Noener