Package de.sosd.mediaserver.service.dlna

Source Code of de.sosd.mediaserver.service.dlna.UPNPNetwork

package de.sosd.mediaserver.service.dlna;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import de.sosd.mediaserver.bean.NetworkDeviceBean;
import de.sosd.mediaserver.controller.dlna.DLNAController;
import de.sosd.mediaserver.service.MediaserverConfiguration;
import de.sosd.mediaserver.service.NetworkDeviceService;

@Service
public class UPNPNetwork {

  public static final String URN_X_MS_MEDIA_RECEIVER_REGISTRAR_1 = "urn:microsoft.com:service:X_MS_MediaReceiverRegistrar:1";
  public static final String URN_SCHEMAS_CONNECTION_MANAGER = "urn:schemas-upnp-org:service:ConnectionManager:1";
  public static final String URN_SCHEMAS_CONTENT_DIRECTORY = "urn:schemas-upnp-org:service:ContentDirectory:1";
  public static final String URN_SCHEMAS_MEDIA_SERVER = "urn:schemas-upnp-org:device:MediaServer:1";
  public static final String UPNP_ROOTDEVICE = "upnp:rootdevice";
  public final static String UPNP_HOST = "239.255.255.250";
  public final static byte[] UPNP_HOST_ADDRESS = {(byte) 239, (byte) 255, (byte) 255, (byte) 250 };
  public final static int UPNP_PORT = 1900;
  public final static String BYEBYE = "ssdp:byebye";
  public final static String ALIVE = "ssdp:alive";
  public static final String CRLF = "\r\n";


  private final static Log logger = LogFactory.getLog(UPNPNetwork.class);

  private static SimpleDateFormat sdf = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss", Locale.US);

  @Autowired
  private MediaserverConfiguration cfg;
 
  @Autowired
  private NetworkDeviceService network;
 
  private InetAddress upnpGroup;

  private boolean offline = false;
  private MSearchThread listenerThread;
 
 
  private MulticastSocket getNewMulticastSocket() throws IOException {
    return getNewMulticastSocket(0);
  }

  private MulticastSocket getNewMulticastSocket(final int port)
      throws IOException {
    MulticastSocket ssdpSocket;
    if (port == 0) {
      ssdpSocket = new MulticastSocket();
    } else {
      ssdpSocket = new MulticastSocket(port);
    }
    ssdpSocket.setReuseAddress(true);
//    ssdpSocket.setInterface(address);
//    logger.trace("Sending message from multicast socket on network interface: "
//        + ssdpSocket.getNetworkInterface());
//    logger.trace("Multicast socket is on interface: "
//        + ssdpSocket.getInterface());
    ssdpSocket.setTimeToLive(32);
    // ssdpSocket.setLoopbackMode(true);
    this.upnpGroup = InetAddress.getByAddress(UPNP_HOST, UPNP_HOST_ADDRESS);
    ssdpSocket.joinGroup(this.upnpGroup);
    logger.trace("Socket Timeout: " + ssdpSocket.getSoTimeout());
    logger.trace("Socket TTL: " + ssdpSocket.getTimeToLive());

    return ssdpSocket;
  }

  private MulticastSocket getNewMulticastListenSocket() throws IOException {
    return getNewMulticastSocket(UPNP_PORT);
  }

  /**
    NOTIFY * HTTP/1.1
    Host:[FF02::C]:1900
    NT:uuid:39eb073b-14a7-4d00-a3c7-91ee88978a77
    NTS:ssdp:byebye
    Location:http://[fe80::6503:d31b:18c7:2f69]:2869/upnphost/udhisapi.dll?content=uuid:39eb073b-14a7-4d00-a3c7-91ee88978a77
    USN:uuid:39eb073b-14a7-4d00-a3c7-91ee88978a77
    Cache-Control:max-age=1800
    Server:Microsoft-Windows-NT/5.1 UPnP/1.0 UPnP-Device-Host/1.0
    OPT:"http://schemas.upnp.org/upnp/1/0/"; ns=01
    01-NLS:bb72a37c619b42ac9f26689d1980cd7d
   **/
  public void sendByeBye() {
    logger.debug("Sending ByeBye...");
    sendStatus(BYEBYE);
    this.offline = true;
  }   
 
  private void sendStatus(final String state) {
   
   
      MulticastSocket ssdpSocket = null;
      try {
        logger.trace("create alive-socket");
        ssdpSocket = getNewMulticastSocket();
        for (NetworkDeviceBean ndb : network.getActiveDevices()) {
 
    //      sendMessage(ssdpSocket, buildDiscoverMsg(URN_SCHEMAS_MEDIA_SERVER));
    //      sendMessage(ssdpSocket, buildMsg(UPNP_ROOTDEVICE, ALIVE, true));
    //      sendMessage(ssdpSocket, buildMsg(null, ALIVE, true));
          sendMessage(ssdpSocket, buildNotifyMsg(ndb.getIpAddress(),URN_SCHEMAS_MEDIA_SERVER, state));
    //      sendMessage(ssdpSocket,
    //          buildMsg(URN_SCHEMAS_CONTENT_DIRECTORY, ALIVE, true));
    //      sendMessage(ssdpSocket,
    //          buildMsg(URN_SCHEMAS_CONNECTION_MANAGER, ALIVE, true));
    //      sendMessage(ssdpSocket, buildMsg( URN_X_MS_MEDIA_RECEIVER_REGISTRAR_1,  ALIVE,true));
   
          //ssdpSocket.leaveGroup(upnpGroup);
        }
      } catch (final IOException e) {
        logger.error("io-error while sending " + state);
      } finally {
        if (ssdpSocket != null) {
          logger.trace("close alive-socket");
          ssdpSocket.close();
        }
      }
   
  }

  public void sendAlive() throws IOException {
    if (! this.offline) {
      logger.debug("Sending ALIVE...");
      sendStatus(ALIVE);
    }
  }

  /**
  HTTP/1.1 200 OK
  CACHE-CONTROL:max-age=1200
  DATE:Sat, 23 Jul 2011 22:13:42 GMT
  LOCATION:http://192.168.101.227:9090/MediaserverWeb/dlna/description/fetch
  SERVER:Mediaserver
  ST:urn:schemas-upnp-org:device:MediaServer:1
  EXT:
  USN:uuid:614146ca-f169-3d3c-b228-87a712faf143::urn:schemas-upnp-org:device:MediaServer:1
  Content-Length:0
   **/
 
  /**
  HTTP/1.1 200 OK 
  ST:urn:schemas-upnp-org:device:MediaServer:1 
  USN:uuid:cdca376d-cb81-4b2e-95a7-9bf7dd2347a3::urn:schemas-upnp-org:device:MediaServer:1 
  Location:http://192.168.101.227:2869/upnphost/udhisapi.dll?content=uuid:cdca376d-cb81-4b2e-95a7-9bf7dd2347a3 
  OPT:"http://schemas.upnp.org/upnp/1/0/"; ns=01 
  01-NLS:b6d7028a8b1e541d7e757d0b6db33a00 
  Cache-Control:max-age=900 
  Server:Microsoft-Windows-NT/5.1 UPnP/1.0 UPnP-Device-Host/1.0 
  Ext:
   **/ 


  private void sendReply(final InetAddress remoteAddress, final int port, final String msg)
      throws IOException {
    DatagramSocket socket = null;
    try {
      logger.trace("create reply-socket");
      socket = new DatagramSocket();

      final DatagramPacket dgmPacket = new DatagramPacket(msg.getBytes(),
          msg.length(), remoteAddress, port);

      socket.send(dgmPacket);
     
      logger.debug("replied ["+remoteAddress + ":" + port +"] ->\n" + msg);
    } finally {
      if (socket != null) {
        logger.trace("close reply-socket");
        socket.close();
      }
    }
  }

  private void sendMessage(final MulticastSocket ssdpSocket, final String msg)
      throws IOException {
    final DatagramPacket ssdpPacket = new DatagramPacket(msg.getBytes(),
        msg.length(), this.upnpGroup, UPNP_PORT);
    ssdpSocket.send(ssdpPacket);
    logger.trace("send message ["+this.upnpGroup + ":" + UPNP_PORT +"] -> " + msg);
  }

  private String buildNotifyMsg(String address, String nt, final String message) {
    final StringBuilder sb = new StringBuilder();

    sb.append("NOTIFY * HTTP/1.1");
    sb.append(CRLF);
    sb.append("Host: " + UPNP_HOST + ":" + UPNP_PORT);
    sb.append(CRLF);
    String usn = "uuid:" + this.cfg.getUSN();
    if ((nt == null) || (nt.length() == 0)) {
      nt = usn;
    } else {
      usn += "::" + nt;
    }
    sb.append("NT: " + nt)
    sb.append(CRLF);
    sb.append("NTS: " + message);
    sb.append(CRLF);
    sb.append("Location: " + this.cfg.getWebappLocation(address).getUrlString() + DLNAController.getDescriptionRef());
    sb.append(CRLF);   
    sb.append("USN: " + usn);
    sb.append(CRLF);
    sb.append("Cache-Control: max-age=1800");
    sb.append(CRLF);
    sb.append("Server: " + this.cfg.getServerName());
    sb.append(CRLF);
    sb.append(CRLF);
    return sb.toString();
  }
 
  private String buildDiscoverMsg(String address, final String st) {
   
    sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
    final StringBuilder sb = new StringBuilder();
    String usn = this.cfg.getUSN();
    if (st.equals(usn)) {
      usn = "";
    } else {
      usn = "uuid:" + usn + "::";
    }
   
    sb.append("HTTP/1.1 200 OK");
    sb.append(CRLF);
    sb.append("ST:");
    if ((st != null) && (st.length() > 0)) {
      sb.append(st);
   
    sb.append(CRLF);   
    sb.append("USN:");
    sb.append(usn);
    sb.append(st);
    sb.append(CRLF);
    sb.append("Location:" + this.cfg.getWebappLocation(address).getUrlString() + DLNAController.getDescriptionRef());
    sb.append(CRLF);   
    sb.append("Cache-Control:max-age=1200");
    sb.append(CRLF);
    sb.append("Server:" + this.cfg.getServerName());
    sb.append(CRLF);
    sb.append("Date:" + sdf.format(new Date(System.currentTimeMillis()))
        + " GMT");
    sb.append(CRLF);
    sb.append("EXT:");
    sb.append(CRLF);

    sb.append("Content-Length:0");
    sb.append(CRLF);
    sb.append(CRLF);
   
    return sb.toString();
  }

  private class MSearchThread extends Thread {
   
    private MulticastSocket listener;

    @Override
    public void run() {
      setName("UPnP M-Search");
      super.run();
        while (!UPNPNetwork.this.offline) {
          try {
            if (this.listener == null) {
              this.listener = getNewMulticastListenSocket();
            }

            final DatagramPacket data = new DatagramPacket(new byte[4096], 4096);
           
            this.listener.receive(data);
            final String text = new String(data.getData());
            boolean answered = true;
            if (text.contains("M-SEARCH")) {
              answered = false;
              for (final String schema : new String[]{URN_SCHEMAS_CONTENT_DIRECTORY, URN_SCHEMAS_MEDIA_SERVER, UPNP_ROOTDEVICE, URN_X_MS_MEDIA_RECEIVER_REGISTRAR_1, UPNPNetwork.this.cfg.getUSN()}) {
                if (text.contains(schema)) {
                  sendReply(data.getAddress(), data.getPort(), buildDiscoverMsg(data.getAddress().getHostAddress(),schema));
                  answered = true;
                }
              }
              if (! answered) {
                logger.trace("ignored m-search : " + text);
              }
            }
       
          } catch (final Throwable e) {
            if (this.listener != null) {
              this.listener.close();
              this.listener = null;
            }
            logger.error("error while reading from upnp-network",e);
          }
        }
 
      if (this.listener != null) {
        this.listener.close();
        this.listener = null;
      }

    }
   
  }
 
  public void startListening() {
    if (this.listenerThread == null) {
      this.listenerThread = new MSearchThread();
      this.offline = false;
      this.listenerThread.start();
    }
  }

  public void stopListening() {
    this.offline = true;
    if (this.listenerThread != null) {
      this.listenerThread.interrupt();
    }
    this.listenerThread = null;
  }
 
}
TOP

Related Classes of de.sosd.mediaserver.service.dlna.UPNPNetwork

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.