How to Send M-SEARCH Query with Java
Asked Answered
H

1

6

I have a Roku device on my network and I want to be able to discover it programically. The official Roku documentation says:

There is a standard SSDP multicast address and port (239.255.255.250:1900) that is used for local network communication. The Roku responds to M-SEARCH queries on this ip address and port.

In order to query for the roku ip address, your program can send the following request using the http protocol to 239.255.255.250 port 1900:

They provide an example using netcat and they say that wireshark can be used to find the result. They also say:

The External Control Protocol enables the Roku to be controlled via the network. The External Control Service is discoverable via SSDP (Simple Service Discovery Protocol). The service is a simple RESTful API that can be accessed by programs in virtually any programming environment.

I have a java program that controls my Roku given its IP Address, and I would like to implement a function that discovers it on the network using this SSDP.

How do I send an M-SEARCH query with java? I have absolutely no conception of how to do this. Is it like an get/post request? If somebody could point me in the right direction I would be very grateful!

Halette answered 9/2, 2015 at 3:52 Comment(0)
H
6

I found a java solution:

/* multicast SSDP M-SEARCH example for 
 * finding the IP Address of a Roku
 * device. For more info go to: 
 * http://sdkdocs.roku.com/display/sdkdoc/External+Control+Guide 
 */

import java.io.*;
import java.net.*;

class msearchSSDPRequest {
    public static void main(String args[]) throws Exception {
        /* create byte arrays to hold our send and response data */
        byte[] sendData = new byte[1024];
        byte[] receiveData = new byte[1024];

        /* our M-SEARCH data as a byte array */
        String MSEARCH = "M-SEARCH * HTTP/1.1\nHost: 239.255.255.250:1900\nMan: \"ssdp:discover\"\nST: roku:ecp\n"; 
        sendData = MSEARCH.getBytes();

        /* create a packet from our data destined for 239.255.255.250:1900 */
        DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, InetAddress.getByName("239.255.255.250"), 1900);

        /* send packet to the socket we're creating */
        DatagramSocket clientSocket = new DatagramSocket();
        clientSocket.send(sendPacket);

        /* recieve response and store in our receivePacket */
        DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
        clientSocket.receive(receivePacket);

        /* get the response as a string */
        String response = new String(receivePacket.getData());

        /* print the response */
        System.out.println(response);

        /* close the socket */
        clientSocket.close();
    }
}
Halette answered 9/2, 2015 at 23:42 Comment(8)
Wasn't it necessary to add a second \n in the end of the MSEARCH string? It was in my case.Housewarming
@Housewarming Oh interesting, it works fine for me without the second newline, but it's good to know that in some cases it may be requiredHalette
well, according to the http spec, the Request (section 5) and Response (section 6) messages use the generic message format of RFC 822 [9] for transferring entities (the payload of the message). Both types of message consist of a start-line, zero or more header fields (also known as "headers"), an empty line (i.e., a line with nothing preceding the CRLF) indicating the end of the header fields, and possibly a message-body. So the empty line is mandatory and if not a body is present it marks the end of the message...Housewarming
I had to add "MX: 10" (without quotes) to the MSEARCH String value for it to work in macOS SierraDye
@Dye Oh interesting! You had to prepend with that? On its own line or anything?Halette
@JohnDorian I added the MX delay within the string in a new line after the Host IP addressDye
For other service such as DIAL, you need to do String MSEARCH = "M-SEARCH * HTTP/1.1\nMX: 5\nHost: 239.255.255.250:1900\nMan: \"ssdp:discover\"\nST: urn:dial-multiscreen-org:service:dial:1\n\n";, which MX: n must appear at least afterHTTP/1.1, and trailing extra \n is required. Change \n to \r\n is optional.Blackmun
I got Below Error java.io.IOException: sendto failed: EPERM (Operation not permitted) at libcore.io.IoBridge.maybeThrowAfterSendto(IoBridge.java:603) at libcore.io.IoBridge.sendto(IoBridge.java:571) at java.net.PlainDatagramSocketImpl.send(PlainDatagramSocketImpl.java:124) at java.net.DatagramSocket.send(DatagramSocket.java:721)Beauharnais

© 2022 - 2024 — McMap. All rights reserved.