Last active
February 27, 2019 01:20
-
-
Save lawgimenez/66cabf092bda78f1b1ac8f94389d7559 to your computer and use it in GitHub Desktop.
SSDP Android Snippet
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package com.somfy.android.utils; | |
| import android.content.Context; | |
| import android.net.wifi.WifiManager; | |
| import com.somfy.android.BridgeApplication; | |
| import java.io.IOException; | |
| import java.net.DatagramPacket; | |
| import java.net.InetAddress; | |
| import java.net.MulticastSocket; | |
| import java.util.ArrayList; | |
| /** | |
| * This class handles the LAN Discovery protocol. | |
| * Also implements the sending and receiving of packets using | |
| * SSDP multicast. | |
| * | |
| * Created by Lawrence Gimenez on 2/16/15. | |
| */ | |
| public class BridgeLan { | |
| private static final String TAG = "BridgeLan"; | |
| // Newline | |
| private static final String NEWLINE = "\r\n"; | |
| // Notify | |
| //private static final String NOTIFY = "NOTIFY * HTTP/1.1"; | |
| // OK | |
| private static final String HTTP_OK = "HTTP/1.1 200 OK"; | |
| // M-SEARCH | |
| private static final String M_SEARCH = "M-SEARCH * HTTP/1.1"; | |
| // IP address of the Bridge Server | |
| private static final String IP_ADDRESS = "239.255.255.250"; | |
| // Port of the Bridge Server | |
| private static final int PORT = 1900; | |
| // Cache control | |
| private static final String CACHE_CONTROL = "CACHE-CONTROL: max-age = 60"; | |
| // Notification Type | |
| // NT:urn:schemas-wifialliance-org:service:WFAWLANConfig:1 | |
| private static final String NT = "NT:urn:somfy.com:device:swf-ha-bridge:1"; | |
| // Unique Service Name | |
| private static final String USN = "USN: "; | |
| // Location of the API | |
| private static final String LOCATION = "LOCATION:"; | |
| // MAN SSDP Discover | |
| private static final String MAN_DISCOVER = "MAN: \"ssdp:discover\""; | |
| // MX = 1 | |
| private static final String MX = "MX: 3"; | |
| // Search Target = ST | |
| private static final String ST = "ST: urn:somfy.com:device:swf-ha-bridge:1"; | |
| // Device identifier for identifying packet responses that it | |
| // came from Somfy Bridge | |
| private static final String DEVICE_TYPE = "urn:somfy.com:device:swf-ha-bridge:1"; | |
| // private static final String ST = "ST:ssdp:all"; | |
| private static final String NTS_ALIVE = "NTS: ssdp:alive"; | |
| private static final String NTS_BYEBYE = "NTS: ssdp:byebye"; | |
| // Global state of our Application | |
| private BridgeApplication mApplication; | |
| // Implements a multicast socket for sending and receiving IP multicast datagram packets. | |
| private MulticastSocket mMulticastSocket; | |
| // Allows an application to receive Wifi Multicast packets. | |
| private WifiManager.MulticastLock mMulticastLock; | |
| private InetAddress mInetAddress; | |
| public static boolean mIsReceiving; | |
| private ArrayList<String> mListBridgesFound; | |
| /** | |
| * @param context - Represents the application environment, so we can access to | |
| * app specific resources and methods. | |
| * | |
| * @throws IOException | |
| */ | |
| public BridgeLan(Context context) throws IOException{ | |
| // Get a reference to our Global state | |
| mApplication = BridgeApplication.getInstance(); | |
| mListBridgesFound = new ArrayList<>(); | |
| //Log.i(TAG, "Instantiating Bridge LAN helper"); | |
| mMulticastSocket = new MulticastSocket(null); | |
| // Represents IP Protocol | |
| mInetAddress = InetAddress.getByName(IP_ADDRESS); | |
| // Signals that this device will join the multicast group. | |
| mMulticastSocket.setReuseAddress(true); | |
| mMulticastSocket.joinGroup(mInetAddress); | |
| mMulticastSocket.setTimeToLive(200); | |
| mMulticastSocket.setLoopbackMode(true); | |
| //mMulticastSocket.bind(new InetSocketAddress(PORT)); | |
| // For managing all aspects of Wi-Fi connectivity | |
| WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); | |
| if(wifiManager != null) { | |
| // We will acquire a lock so application can receive | |
| // packets | |
| mMulticastLock = wifiManager.createMulticastLock("TagMulticast"); | |
| mMulticastLock.setReferenceCounted(true); | |
| mMulticastLock.acquire(); | |
| } | |
| } | |
| /** | |
| * Sends a SSDP alive packet to the Bridge. | |
| * @throws IOException | |
| */ | |
| /*public void notifySSDPAlive() throws IOException { | |
| StringBuilder notify = new StringBuilder(); | |
| // Construct Notify 1st line | |
| notify.append(NOTIFY + NEWLINE); | |
| // Construct Host 2nd line | |
| notify.append("HOST: " + IP_ADDRESS + ":" + PORT + NEWLINE); | |
| // Construct cache control 3rd line | |
| notify.append(CACHE_CONTROL + NEWLINE); | |
| // Construct NT 4th line | |
| notify.append(NT + NEWLINE); | |
| // Construct NTS 5th line with alive | |
| notify.append(NTS_ALIVE + NEWLINE); | |
| // Construct USN | |
| notify.append(USN).append(mApplication.getUUID() + NEWLINE + NEWLINE); | |
| // Get the final String for our Notify SSDP Alive | |
| String dataSsdpAlive = notify.toString(); | |
| Log.i(TAG, "NotifyAlive: \n" + dataSsdpAlive); | |
| // Send packet to the Bridge | |
| sendPacket(dataSsdpAlive); | |
| }*/ | |
| /** | |
| * Sends a SSDP byebye packet to the Bridge | |
| * @throws IOException | |
| */ | |
| /*public void notifySSDPBye() throws IOException { | |
| StringBuilder notify = new StringBuilder(); | |
| // Construct Notify 1st line | |
| notify.append(NOTIFY + NEWLINE); | |
| // Construct Host 2nd line | |
| notify.append("HOST: " + IP_ADDRESS + ":" + PORT + NEWLINE); | |
| // Construct NT 3rd line | |
| notify.append(NT + NEWLINE); | |
| // Construct NTS 4th line with byebye | |
| notify.append("NTS: " + NTS_BYEBYE + NEWLINE); | |
| // Construct USN | |
| notify.append(USN).append(mApplication.getUUID() + NEWLINE + NEWLINE); | |
| // Get the final String for our Notify SSDP byebye | |
| String dataSsdpBye = notify.toString(); | |
| // Send packet to the Bridge | |
| sendPacket(dataSsdpBye); | |
| }*/ | |
| /** | |
| * When the device desires to search for Bridge devices on the network. | |
| * @throws IOException | |
| */ | |
| public boolean searchDiscover() throws IOException { | |
| StringBuilder search = new StringBuilder(); | |
| // Construct M-SEARCH 1st line | |
| search.append(M_SEARCH + NEWLINE); | |
| // Construct Host 2nd line | |
| search.append("HOST: " + IP_ADDRESS + ":" + PORT + NEWLINE); | |
| // Construct MAN 3rd line | |
| search.append(MAN_DISCOVER + NEWLINE); | |
| // Construct MX 4th line | |
| search.append(MX + NEWLINE); | |
| // Construct ST 5th line | |
| search.append(ST + NEWLINE + NEWLINE); | |
| // Get the final String for our M-SEARCH multicast discover | |
| String dataMSearchDiscover = search.toString(); | |
| //Log.i(TAG, "searchDiscover: " + dataMSearchDiscover); | |
| return sendPacket(dataMSearchDiscover); | |
| } | |
| /** | |
| * When the device desires to search for a specific device | |
| * on the network. | |
| * @throws IOException | |
| */ | |
| public boolean searchUnicast() throws IOException { | |
| StringBuilder search = new StringBuilder(); | |
| // Construct M-SEARCH 1st line | |
| search.append(M_SEARCH + NEWLINE); | |
| // Construct Host 2nd line | |
| search.append("HOST: " + IP_ADDRESS + ":" + PORT + NEWLINE); | |
| // | |
| search.append(ST + NEWLINE + NEWLINE); | |
| // Construct MAN 3rd line | |
| search.append(MAN_DISCOVER + NEWLINE); | |
| // Construct ST 4th line | |
| search.append(MX); | |
| // Get the final String for M-SEARCH unicast | |
| String dataMSearchUnicast = search.toString(); | |
| //Log.i(TAG, "searchUnicast: " + dataMSearchUnicast); | |
| // Send packet to the Bridge | |
| return sendPacket(dataMSearchUnicast); | |
| } | |
| /** | |
| * Handles the received SSDP packet from the network. | |
| * @return - Datagram Packet from the Bridge device | |
| * @throws IOException | |
| */ | |
| /*public DatagramPacket receive() throws IOException { | |
| byte[] buffer = new byte[1024]; | |
| DatagramPacket datagramPacket = new DatagramPacket(buffer, buffer.length); | |
| mMulticastSocket.receive(datagramPacket); | |
| return datagramPacket; | |
| }*/ | |
| /** | |
| * Sends a SSDP Packet to the Bridge | |
| * @param data - data to be send through SSDP | |
| * @throws IOException | |
| */ | |
| private boolean sendPacket(String data) throws IOException { | |
| // Create a new datagram packet to be send to the network | |
| DatagramPacket datagramPacket = new DatagramPacket(data.getBytes(), | |
| data.length(), mInetAddress, PORT); | |
| mMulticastSocket.setTimeToLive(200); | |
| mMulticastSocket.setLoopbackMode(true); | |
| //Log.i(TAG, "Host address: " + mInetAddress.getHostAddress()); | |
| //Log.i(TAG, "Is multicast address: " + mInetAddress.isMulticastAddress()); | |
| // Send the datagram packet to the Multicast IP and Port | |
| mMulticastSocket.send(datagramPacket); | |
| mIsReceiving = true; | |
| return true; | |
| } | |
| /** | |
| * Called to start receiving Multicast packets | |
| * | |
| * @throws IOException | |
| */ | |
| public void startReceiving() throws IOException { | |
| // Get response from the server | |
| byte[] buffer = new byte[500]; | |
| mIsReceiving = true; | |
| //Log.i(TAG, "isReceiving?" + mIsReceiving); | |
| while(mIsReceiving) { | |
| // Create a new datagram packet received from the server | |
| DatagramPacket packetReceived = new DatagramPacket(buffer, buffer.length); | |
| // Receive the datagram packet | |
| mMulticastSocket.receive(packetReceived); | |
| String dataReceived = new String(packetReceived.getData()).trim(); | |
| //Log.i(TAG, "Response: " + dataReceived.trim()); | |
| //Log.i(TAG, "Response from: " + packetReceived.getAddress()); | |
| // If there are no more packet received, end listening for packets | |
| if(packetReceived.getData() == null) { | |
| mIsReceiving = false; | |
| //Log.i(TAG, "No more packets"); | |
| } else { | |
| //Log.i(TAG, "Found some packets"); | |
| // If packet has been received, check if packet came from Somfy device | |
| // and at the same is an HTTP/1.1 200 OK header response. | |
| if(dataReceived.contains(HTTP_OK) && dataReceived.contains(DEVICE_TYPE)) { | |
| String[] packetElements = dataReceived.split(NEWLINE); | |
| //Log.i(TAG, "Element NTS: " + packetElements[3]); | |
| // If everything is OK, get the IP address of where | |
| // this packet came from. | |
| String bridgeLocation = packetReceived.getAddress().getHostAddress(); | |
| //Log.i(TAG, "Packet Location IP: " + packetReceived.getAddress().getHostAddress()); | |
| //Log.i(TAG, "Packet Location Port: " + packetReceived.getPort()); | |
| boolean isPresent = false; | |
| // Check if the recently captured Bridge IP address location is | |
| // already in our list. | |
| for(int i=0; i<mListBridgesFound.size(); i++) { | |
| if(bridgeLocation.equals(mListBridgesFound.get(i))) { | |
| isPresent = true; | |
| } | |
| } | |
| // If recently captured Bridge IP address location is not found on | |
| // our list, add the Bridge IP address location. | |
| if(!isPresent) { | |
| mListBridgesFound.add(bridgeLocation); | |
| } | |
| // Add the list of Bridges found to our global state. | |
| mApplication.setBridgesFound(mListBridgesFound); | |
| } | |
| } | |
| //Log.i(TAG, "isReceiving: " + mIsReceiving); | |
| } | |
| //Log.i(TAG, "isReceivingAfterThread?" + mIsReceiving); | |
| } | |
| /** | |
| * Called to stop receiving Multicast packets | |
| */ | |
| public void stopMulticasting() { | |
| // Log.i(TAG, "Stop multicasting"); | |
| // Close socket, we're done | |
| if(mMulticastSocket != null) { | |
| mMulticastSocket.close(); | |
| mMulticastSocket = null; | |
| } | |
| if(mMulticastLock.isHeld()) { | |
| mMulticastLock.release(); | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment