@Override
  public DiscoveryResult createResult(ServiceInfo service) {

    if (service.getApplication().contains("mieleathome")) {
      ThingUID uid = getThingUID(service);

      if (uid != null) {
        Map<String, Object> properties = new HashMap<>(2);

        InetAddress[] addresses = service.getInetAddresses();
        if (addresses.length > 0 && addresses[0] != null) {
          properties.put(MieleBindingConstants.HOST, addresses[0].getHostAddress());

          Socket socket = null;
          try {
            socket = new Socket(addresses[0], 80);
            InetAddress ourAddress = socket.getLocalAddress();
            properties.put(MieleBindingConstants.INTERFACE, ourAddress.getHostAddress());
          } catch (IOException e) {
            logger.error(
                "An exception occurred while connecting to the Miele Gateway : '{}'",
                e.getMessage());
          }
        }

        return DiscoveryResultBuilder.create(uid)
            .withProperties(properties)
            .withRepresentationProperty(uid.getId())
            .withLabel("Miele XGW3000 Gateway")
            .build();
      }
    }
    return null;
  }
  /**
   * List published node(s) configuration in the network via multicast
   *
   * @param serviceName name of service published. (e.g. release version for installation)
   * @return node(s) configuration list
   */
  public Map<String, Map<String, String>> list(String serviceName) {
    Map<String, Map<String, String>> results = new HashMap<String, Map<String, String>>();
    ServiceInfo[] infos = jmdns.list("_" + serviceName + "._tcp.local.");
    for (ServiceInfo info : infos) {
      _log.info("ServiceInfo:{}", info);

      // Construct the key
      final String[] hostAddrs = info.getHostAddresses();
      final StringBuffer buf = new StringBuffer();
      for (String hostAddr : hostAddrs) {
        buf.append(hostAddr);
        buf.append(';');
      }
      final String key = buf.toString();
      _log.info("\tkey:{}", key);

      // Construct the values
      final Map<String, String> values = new HashMap<String, String>();
      for (Enumeration<String> e = info.getPropertyNames(); e.hasMoreElements(); ) {
        final String prop = e.nextElement();
        final String value = new String(info.getPropertyBytes(prop));
        _log.info("\tprop:{}, value:{}", prop, value);
        values.put(prop, value);
      }

      // Put <key,values> into the results
      if (values.isEmpty()) {
        _log.warn("values are empty for key: {}", key);
      }
      results.put(key, values.isEmpty() ? null : values);
    }
    return results;
  }
예제 #3
0
 @Override
 public void serviceAdded(ServiceEvent event) {
   Log.d(TAG, "serviceAdded:" + event);
   ZeroServiceInfo zsi = new ZeroServiceInfo(null, event);
   String name = event.getName();
   if (mName.equals(name)) {
     mZsinfo = zsi;
     if (null != mServiceListener) {
       mServiceListener.onServiceRegistered(zsi);
     }
   } else {
     ServiceInfo sinfo = event.getInfo();
     if (null != sinfo) {
       InetAddress[] addrs = sinfo.getInetAddresses();
       if (null != addrs && addrs.length > 0) {
         for (InetAddress addr : addrs) {
           Log.d(TAG, "the addr is:" + addr.getHostName());
         }
         if (null != mDiscoverListener) {
           mDiscoverListener.onServiceFound(zsi);
         }
       }
     }
   }
 }
  @Override
  public ThingUID getThingUID(ServiceInfo service) {

    if (service != null) {
      if (service.getType() != null) {
        if (service.getType().equals(getServiceType())) {
          logger.trace("Discovered a Miele@Home gateway thing with name '{}'", service.getName());
          return new ThingUID(
              MieleBindingConstants.THING_TYPE_XGW3000, service.getName().replace(" ", "_"));
        }
      }
    }

    return null;
  }
예제 #5
0
  public DNSMultiCast(Jenkins hudson) {
    if (disabled) return; // escape hatch

    try {
      this.jmdns = JmDNS.create();

      Map<String, String> props = new HashMap<String, String>();
      String rootURL = hudson.getRootUrl();
      if (rootURL != null) props.put("url", rootURL);
      try {
        props.put("version", String.valueOf(Jenkins.getVersion()));
      } catch (IllegalArgumentException e) {
        // failed to parse the version number
      }

      TcpSlaveAgentListener tal = hudson.getTcpSlaveAgentListener();
      if (tal != null) props.put("slave-port", String.valueOf(tal.getPort()));

      props.put("server-id", Util.getDigestOf(hudson.getSecretKey()));

      URL jenkins_url = new URL(rootURL);
      int jenkins_port = jenkins_url.getPort();
      if (jenkins_port == -1) {
        jenkins_port = 80;
      }
      if (jenkins_url.getPath().length() > 0) {
        props.put("path", jenkins_url.getPath());
      }

      jmdns.registerService(
          ServiceInfo.create(
              "_hudson._tcp.local.",
              "hudson",
              jenkins_port,
              0,
              0,
              props)); // for backward compatibility
      jmdns.registerService(
          ServiceInfo.create("_jenkins._tcp.local.", "jenkins", jenkins_port, 0, 0, props));

      // Make Jenkins appear in Safari's Bonjour bookmarks
      jmdns.registerService(
          ServiceInfo.create("_http._tcp.local.", "Jenkins", jenkins_port, 0, 0, props));
    } catch (IOException e) {
      LOGGER.log(Level.WARNING, "Failed to advertise the service to DNS multi-cast", e);
    }
  }
예제 #6
0
  /** Refreshes all known discovery managers. */
  private void refreshKnownDiscoveryManagers() {

    this.serviceInfosLock.lock();
    try {
      this.remoteManagersEndpoints.clear();

      // Check all service infos with discovery managers
      for (ServiceInfo serviceInfo : this.serviceInfos) {

        final InetAddress address = serviceInfo.getAddress();
        final int port = serviceInfo.getPort();

        System.out.println("mgr: " + address + " " + port);
        this.remoteManagersEndpoints.add(new RemoteManagerEndpoint(address, port));
      }
    } finally {
      this.serviceInfosLock.unlock();
    }
  }
  // Implementation methods
  // -------------------------------------------------------------------------
  protected ServiceInfo createServiceInfo(String name, Map map) {
    int port = MapHelper.getInt(map, "port", 0);

    String type = getType();

    if (LOG.isDebugEnabled()) {
      LOG.debug("Registering service type: " + type + " name: " + name + " details: " + map);
    }
    return ServiceInfo.create(type, name + "." + type, port, weight, priority, "");
  }
예제 #8
0
  /** Refreshes all known discovery managers. */
  private void refreshKnownDiscoveryManagers() {

    this.serviceInfosLock.lock();
    try {
      final List<RemoteManagerEndpoint> endpoints = new ArrayList<RemoteManagerEndpoint>();

      // Check all service infos with discovery managers
      for (final ServiceInfo serviceInfo : this.serviceInfos) {

        final InetAddress address = serviceInfo.getAddress();
        final int port = serviceInfo.getPort();

        endpoints.add(new RemoteManagerEndpoint(address, port));
      }

      // Eventually update the endpoints
      this.remoteManagersEndpoints = endpoints;
    } finally {
      this.serviceInfosLock.unlock();
    }
  }
  /**
   * Publish local node configuration via multicast
   *
   * @param serviceName name of service to be published. (e.g. release version for installation)
   *     instanceName name of instance which is publishing. (e.g. the local node id etc.) nodeConfig
   *     info to be published publishTime how long the info would be published
   */
  public void publish(
      String serviceName, String instanceName, Map<String, String> values, long publishTime)
      throws IOException {
    ServiceInfo info =
        ServiceInfo.create("_" + serviceName + "._tcp.local.", instanceName, 9999, 0, 0, values);
    this.jmdns.registerService(info);

    if (publishTime > 0) {
      sleep(publishTime);
      this.close();
    }
  }
예제 #10
0
  @SuppressWarnings("boxing")
  @Thread(isDaemonic = true)
  public void backgroundInit() {
    // (Ralf:) zomfg, this is one of the worst hacks i've done the last
    // couple of months. Deep within jmdns we placed a variable to
    // override a check if it is already save to transmit something. jmDNS
    // usually takes 5 seconds to reach that state, but that's
    // too long for us. If you set this variable the check will be skipped
    // and the request should take place much faster.
    // Appears to work(tm).
    ServiceResolver.ANNOUNCE_OVERRIDE = true;

    final PluginConfigurationUtil pcu = new PluginConfigurationUtil(this.pluginConfiguration);
    this.startupLock = pcu.getInt(RemoteDiscovery.class, "startup.locktime", 1000);
    this.lockMode = pcu.getString(RemoteDiscovery.class, "startup.lockmode", "onepass");

    // TODO put this in a thread
    this.checkCache.loadCache();

    try {
      this.jmdnsLock.lock();
      this.jmdns =
          JmDNS
              .create(); // Maybe init with local loopback in case no other network card is present,
      // otherwise returns null

      this.timeOfStartup = System.currentTimeMillis();

      final int port = getFreePort();
      final ServiceInfo service =
          ServiceInfo.create(TYPE, NAME + " @" + this.timeOfStartup, port, 0, 0, EXPORT_NAME);

      this.localManagerExportServer =
          Proxies.newServer(EXPORT_NAME, port, (DiscoveryManager) this.localManager);
      this.jmdns.registerService(service);

      // Set it again, this time for the lock below
      this.timeOfStartup = System.currentTimeMillis();
    } catch (IOException e) {
      e.printStackTrace();
    } catch (IllegalStateException e) {
      this.logger.warning("Error starting discovery.");
    } finally {
      this.startupLatch.countDown();
      this.jmdnsLock.unlock();
    }

    // and load our cache...
    // todo make this configurable...
    //		this.checkCache.loadCache(fileName)
  }
예제 #11
0
  @SuppressWarnings("boxing")
  public void backgroundInit() {
    // (Ralf:) zomfg, this is one of the worst hacks i've done the last years. Deep within  jmdns we
    // placed a variable to
    // override a check if it is already safe to transmit something. jmDNS usually takes 5 seconds
    // to reach that state, but that's
    // too long for us. If you set this variable the check will be skipped and the request should
    // take place much faster.
    // Appears to work(tm).
    ServiceResolver.ANNOUNCE_OVERRIDE = true;

    this.logger.status("backgroundinit/start");

    final PluginConfigurationUtil pcu = new PluginConfigurationUtil(this.pluginConfiguration);
    this.startupLock = pcu.getInt(RemoteDiscovery.class, "startup.locktime", 1000);
    this.lockMode = pcu.getString(RemoteDiscovery.class, "startup.lockmode", "onepass");

    try {
      this.logger.status("backgroundinit/lock");

      this.jmdnsLock.lock();
      this.jmdns =
          JmDNS
              .create(); // Maybe init with local loopback in case no other network card is present,
      // otherwise returns null

      this.timeOfStartup = System.currentTimeMillis();

      final int port = RemoteDiscoveryImpl.getFreePort();
      final ServiceInfo service =
          ServiceInfo.create(TYPE, NAME + " @" + this.timeOfStartup, port, 0, 0, EXPORT_NAME);
      this.logger.status("backgroundinit/export", "port", port);
      this.localManagerExportServer =
          Proxies.newServer(EXPORT_NAME, port, (DiscoveryManager) this.localTCPIPManager);
      this.logger.status("backgroundinit/announce", "port", port);
      this.jmdns.registerService(service);

      // Set it again, this time for the lock below
      this.timeOfStartup = System.currentTimeMillis();
    } catch (final IOException e) {
      e.printStackTrace();
    } catch (final IllegalStateException e) {
      this.logger.status("backgroundinit/exception/illegalstate", "message", e.getMessage());
    } finally {
      this.logger.status("backgroundinit/unlock");
      this.startupLatch.countDown();
      this.jmdnsLock.unlock();
    }

    this.logger.status("backgroundinit/end");
  }
예제 #12
0
 /** @{inheritDoc} */
 public void unregisterService(ServiceDescription description) {
   ServiceInfo serviceInfo =
       ServiceInfo.create(
           description.serviceType,
           description.serviceName,
           description.servicePort,
           0,
           0,
           description.serviceProperties);
   logger.debug(
       "Unregistering service "
           + description.serviceType
           + " at port "
           + String.valueOf(description.servicePort));
   jmdns.unregisterService(serviceInfo);
 }
예제 #13
0
  @Override
  public void createService(String name, String type, int port) {
    if (!type.contains(TYPE_PADDING)) {
      type = type + TYPE_PADDING;
    }
    mType = type;

    acquireMulticastLock();
    try {
      if (null != mJmDNS) {
        destroyService(null, false);
      }
      if (mHost) {
        mJmDNS = JmDNS.create(mWifiEnable);
      } else {
        if (null != mAddress) {
          mJmDNS = JmDNS.create(mAddress, name);
        } else {
          mJmDNS = JmDNS.create(mWifiEnable);
        }
      }
    } catch (Exception e) {
      Log.e(TAG, "failed to create the service", e);
      if (null != mServiceListener) {
        mServiceListener.onServiceRegisteredFailed(new ZeroServiceInfo(null, null));
      }
    }
    if (null != mJmDNS) {
      try {
        ServiceInfo si =
            ServiceInfo.create(
                mType,
                name,
                port,
                LOCAL_SERVER_WEIGHT,
                LOCAL_SERVER_PROIORITY,
                true,
                "android_jmdns_service");
        mJmDNS.registerService(si);
      } catch (Exception e) {
        Log.e(TAG, "failed to cast the service", e);
      }
    }
  }
예제 #14
0
 /**
  * Create a ZeroConfService. The property <i>version</i> is added or replaced with the current
  * JMRI version as its value. The property <i>jmri</i> is added or replaced with the JMRI
  * major.minor.test version string as its value.
  *
  * <p>If a service with the same key as the new service is already published, the original service
  * is returned unmodified.
  *
  * @param type The service protocol
  * @param name The name of the JMRI server listed on client devices
  * @param port The port the service runs over
  * @param weight Default value is 0
  * @param priority Default value is 0
  * @param properties Additional information to be listed in service advertisement
  * @return An unpublished ZeroConfService
  */
 public static ZeroConfService create(
     String type,
     String name,
     int port,
     int weight,
     int priority,
     HashMap<String, String> properties) {
   ZeroConfService s;
   if (ZeroConfService.services().containsKey(ZeroConfService.key(type, name))) {
     s = ZeroConfService.services().get(ZeroConfService.key(type, name));
     log.debug("Using existing ZeroConfService {}", s.key());
   } else {
     properties.put("version", jmri.Version.name());
     // use the major.minor.test version string for jmri since we have potentially
     // tight space constraints in terms of the number of bytes that properties
     // can use, and there are some unconstrained properties that we would like to use.
     properties.put("jmri", jmri.Version.getCanonicalVersion());
     properties.put("node", NodeIdentity.identity());
     s = new ZeroConfService(ServiceInfo.create(type, name, port, weight, priority, properties));
     log.debug("Creating new ZeroConfService {} with properties {}", s.key(), properties);
   }
   return s;
 }
예제 #15
0
  @Override
  public PluginResult execute(String action, JSONArray data, String callbackId) {
    // Log.d("OSCManager", "executing something " + action);
    PluginResult result = null;
    try {
      System.out.println("EXECUTING BONJOUR ********************************************");
      if (action.equals("start") || action.equals("browse")) {
        System.out.println("STARTING BONJOUR ********************************************");

        ServiceInfo[] infos = jmdns.list("_osc._udp.local.");
        for (int i = 0; i < infos.length; i++) {
          String jsString =
              "javascript:destinationManager.addDestination('"
                  + infos[i].getHostAddress()
                  + "',"
                  + infos[i].getPort()
                  + ", 0, 0);";
          System.out.println(jsString);
          webView.loadUrl(jsString);
          System.out.println("after sending to js");
        }
        if (action.equals("start")) {
          ServiceInfo serviceInfo =
              ServiceInfo.create(
                  "_osc._udp.local.",
                  "Control_" + (Math.round(Math.random() * 100000)),
                  8080,
                  "OSC reception for device running Control");
          jmdns.registerService(serviceInfo);
        }
      }
    } catch (Exception e) {
      System.out.println("after sending to js");
    }
    return result;
  }
  @Override
  public void serviceResolved(ServiceEvent serviceEvent) {
    ServiceInfo info = serviceEvent.getInfo();
    for (InetAddress inetAddress : info.getInet4Addresses()) {
      bonour newItem = new bonour();
      newItem.address = inetAddress.getHostAddress();
      newItem.name = serviceEvent.getName();
      if (info.hasData()) {
        newItem.board = info.getPropertyString("board"); // $NON-NLS-1$
        newItem.distroversion = info.getPropertyString("distro_version"); // $NON-NLS-1$
        newItem.name = info.getServer();
      }
      while (newItem.name.endsWith(".")) { // $NON-NLS-1$
        newItem.name = newItem.name.substring(0, newItem.name.length() - 1);
      }
      newItem.port = Integer.toString(info.getPort());

      synchronized (this) {
        removeBoardswithSameAdress(newItem);
        this.myComPorts.add(newItem);
      }
    }
  }
예제 #17
0
 /**
  * During recovery we need to duplicate service info to reregister them
  *
  * @param info
  */
 ServiceInfoImpl(ServiceInfo info) {
   this._ipv4Addresses = Collections.synchronizedSet(new LinkedHashSet<Inet4Address>());
   this._ipv6Addresses = Collections.synchronizedSet(new LinkedHashSet<Inet6Address>());
   if (info != null) {
     this._domain = info.getDomain();
     this._protocol = info.getProtocol();
     this._application = info.getApplication();
     this._name = info.getName();
     this._subtype = info.getSubtype();
     this._port = info.getPort();
     this._weight = info.getWeight();
     this._priority = info.getPriority();
     this._text = info.getTextBytes();
     this._persistent = info.isPersistent();
     Inet6Address[] ipv6Addresses = info.getInet6Addresses();
     for (Inet6Address address : ipv6Addresses) {
       this._ipv6Addresses.add(address);
     }
     Inet4Address[] ipv4Addresses = info.getInet4Addresses();
     for (Inet4Address address : ipv4Addresses) {
       this._ipv4Addresses.add(address);
     }
   }
   this._state = new ServiceInfoState(this);
 }
예제 #18
0
  public static void main(final String[] args) throws Exception {
    /* Make sure AirReceiver shuts down gracefully */
    Runtime.getRuntime()
        .addShutdownHook(
            new Thread(
                new Runnable() {
                  @Override
                  public void run() {
                    onShutdown();
                  }
                }));

    /* Create about dialog */
    final Dialog aboutDialog = new Dialog((Dialog) null);
    final GridBagLayout aboutLayout = new GridBagLayout();
    aboutDialog.setLayout(aboutLayout);
    aboutDialog.setVisible(false);
    aboutDialog.setTitle("About AirReceiver");
    aboutDialog.setResizable(false);
    {
      /* Message */
      final TextArea title = new TextArea(AboutMessage.split("\n").length + 1, 64);
      title.setText(AboutMessage);
      title.setEditable(false);
      final GridBagConstraints titleConstraints = new GridBagConstraints();
      titleConstraints.gridx = 1;
      titleConstraints.gridy = 1;
      titleConstraints.fill = GridBagConstraints.HORIZONTAL;
      titleConstraints.insets = new Insets(0, 0, 0, 0);
      aboutLayout.setConstraints(title, titleConstraints);
      aboutDialog.add(title);
    }
    {
      /* Done button */
      final Button aboutDoneButton = new Button("Done");
      aboutDoneButton.addActionListener(
          new ActionListener() {
            @Override
            public void actionPerformed(final ActionEvent evt) {
              aboutDialog.setVisible(false);
            }
          });
      final GridBagConstraints aboutDoneConstraints = new GridBagConstraints();
      aboutDoneConstraints.gridx = 1;
      aboutDoneConstraints.gridy = 2;
      aboutDoneConstraints.anchor = GridBagConstraints.PAGE_END;
      aboutDoneConstraints.fill = GridBagConstraints.NONE;
      aboutDoneConstraints.insets = new Insets(0, 0, 0, 0);
      aboutLayout.setConstraints(aboutDoneButton, aboutDoneConstraints);
      aboutDialog.add(aboutDoneButton);
    }
    aboutDialog.setVisible(false);
    aboutDialog.setLocationByPlatform(true);
    aboutDialog.pack();

    /* Create tray icon */
    final URL trayIconUrl = AirReceiver.class.getClassLoader().getResource("icon_32.png");
    final TrayIcon trayIcon = new TrayIcon((new ImageIcon(trayIconUrl, "AirReceiver").getImage()));
    trayIcon.setToolTip("AirReceiver");
    trayIcon.setImageAutoSize(true);
    final PopupMenu popupMenu = new PopupMenu();
    final MenuItem aboutMenuItem = new MenuItem("About");
    aboutMenuItem.addActionListener(
        new ActionListener() {
          @Override
          public void actionPerformed(final ActionEvent evt) {
            aboutDialog.setLocationByPlatform(true);
            aboutDialog.setVisible(true);
          }
        });
    popupMenu.add(aboutMenuItem);
    final MenuItem exitMenuItem = new MenuItem("Quit");
    exitMenuItem.addActionListener(
        new ActionListener() {
          @Override
          public void actionPerformed(final ActionEvent evt) {
            onShutdown();
            System.exit(0);
          }
        });
    popupMenu.add(exitMenuItem);
    trayIcon.setPopupMenu(popupMenu);
    SystemTray.getSystemTray().add(trayIcon);

    /* Create AirTunes RTSP server */
    final ServerBootstrap airTunesRtspBootstrap =
        new ServerBootstrap(new NioServerSocketChannelFactory(ExecutorService, ExecutorService));
    airTunesRtspBootstrap.setPipelineFactory(new RaopRtspPipelineFactory());
    airTunesRtspBootstrap.setOption("reuseAddress", true);
    airTunesRtspBootstrap.setOption("child.tcpNoDelay", true);
    airTunesRtspBootstrap.setOption("child.keepAlive", true);
    s_allChannels.add(
        airTunesRtspBootstrap.bind(
            new InetSocketAddress(Inet4Address.getByName("0.0.0.0"), AirtunesServiceRTSPPort)));
    s_logger.info("Launched RTSP service on port " + AirtunesServiceRTSPPort);

    /* Create mDNS responders. */
    synchronized (s_jmDNSInstances) {
      for (final NetworkInterface iface :
          Collections.list(NetworkInterface.getNetworkInterfaces())) {
        if (iface.isLoopback()) continue;
        if (iface.isPointToPoint()) continue;
        if (!iface.isUp()) continue;

        for (final InetAddress addr : Collections.list(iface.getInetAddresses())) {
          if (!(addr instanceof Inet4Address) && !(addr instanceof Inet6Address)) continue;

          try {
            /* Create mDNS responder for address */
            final JmDNS jmDNS = JmDNS.create(addr, HostName + "-jmdns");
            s_jmDNSInstances.add(jmDNS);

            /* Publish RAOP service */
            final ServiceInfo airTunesServiceInfo =
                ServiceInfo.create(
                    AirtunesServiceType,
                    HardwareAddressString + "@" + HostName + " (" + iface.getName() + ")",
                    AirtunesServiceRTSPPort,
                    0 /* weight */,
                    0 /* priority */,
                    AirtunesServiceProperties);
            jmDNS.registerService(airTunesServiceInfo);
            s_logger.info(
                "Registered AirTunes service '" + airTunesServiceInfo.getName() + "' on " + addr);
          } catch (final Throwable e) {
            s_logger.log(Level.SEVERE, "Failed to publish service on " + addr, e);
          }
        }
      }
    }
  }
예제 #19
0
  @Override
  public void run() {
    try {
      final JmDNS jmdns = JmDNS.create();
      jmdns.addServiceListener(TOUCH_ABLE_TYPE, this);
      jmdns.addServiceListener(DACP_TYPE, this);

      final HashMap<String, String> values = new HashMap<String, String>();
      byte[] number = new byte[4];
      random.nextBytes(number);
      values.put("DvNm", "Android-" + toHex(number));
      values.put("RemV", "10000");
      values.put("DvTy", "iPod");
      values.put("RemN", "Remote");
      values.put("txtvers", "1");
      byte[] pair = new byte[8];
      random.nextBytes(pair);
      values.put("Pair", toHex(pair));

      while (_running) {
        ServerSocket server = new ServerSocket(0);

        byte[] name = new byte[20];
        random.nextBytes(name);
        System.out.println("Requesting pairing for " + toHex(name));
        ServiceInfo pairservice =
            ServiceInfo.create(REMOTE_TYPE, toHex(name), server.getLocalPort(), 0, 0, values);
        jmdns.registerService(pairservice);

        System.out.println("Waiting for pass code");
        final Socket socket = server.accept();
        OutputStream output = null;

        try {
          output = socket.getOutputStream();

          // output the contents for debugging
          final BufferedReader br =
              new BufferedReader(new InputStreamReader(socket.getInputStream()));
          while (br.ready()) {
            String line = br.readLine();
            System.out.println(line);
          }

          // edit our local PAIRING_RAW to return the correct guid
          byte[] code = new byte[8];
          random.nextBytes(code);
          System.out.println("Device guid: " + toHex(code));
          System.arraycopy(code, 0, PAIRING_RAW, 16, 8);

          byte[] header =
              String.format(
                      "HTTP/1.1 200 OK\r\nContent-Length: %d\r\n\r\n",
                      new Integer(PAIRING_RAW.length))
                  .getBytes();
          byte[] reply = new byte[header.length + PAIRING_RAW.length];

          System.arraycopy(header, 0, reply, 0, header.length);
          System.arraycopy(PAIRING_RAW, 0, reply, header.length, PAIRING_RAW.length);

          System.out.println("Response: " + new String(reply));

          output.write(reply);
          output.flush();

          System.out.println("someone paired with me!");

          jmdns.unregisterService(pairservice);
        } finally {
          if (output != null) {
            output.close();
          }

          System.out.println("Closing Socket");
          if (!server.isClosed()) {
            server.close();
          }
          _running = false;
        }
      }
      Thread.sleep(6000);
      System.out.println("Closing JmDNS");
      jmdns.close();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }