package com.beowulfe.hap; import java.io.IOException; import java.math.BigInteger; import java.net.InetAddress; import java.security.InvalidAlgorithmParameterException; import com.beowulfe.hap.impl.HomekitBridge; import com.beowulfe.hap.impl.HomekitUtils; import com.beowulfe.hap.impl.http.impl.HomekitHttpServer; /** * The main entry point for hap-java. Creating an instance of this class will listen for Homekit connections * on the supplied port. Only a single root accessory can be added for each unique instance and port, however, * that accessory may be a {@link #createBridge(HomekitAuthInfo, String, String, String, String) bridge accessory} * containing child accessories. * * The {@link HomekitAuthInfo HomekitAuthInfo} argument when creating accessories should be an implementation supplied * by your application. Several of the values needed for your implementation are provided by this class, specifically * {@link #generateKey() generateKey}, {@link #generateMac() generateMac}, and {@link #generateSalt()}. It is important * that you provide these same values on each start of your application or Homekit will fail to recognize your device as * being the same. * * @author Andy Lintner */ public class HomekitServer { private final HomekitHttpServer http; private final InetAddress localAddress; /** * Constructor. Contains an argument indicating the number of threads to use in the http server. The other constructors * default this to the number of available processors, however you may increase this in an environment with many users * and/or blocking accessory implementations. * * @param localAddress local address to bind to. * @param port local port to bind to. * @param nThreads number of threads to use in the http server * @throws IOException when the server cannot bind to the supplied port */ public HomekitServer(InetAddress localAddress, int port, int nThreads) throws IOException { this.localAddress = localAddress; http = new HomekitHttpServer(port, nThreads); } /** * Constructor * * @param localAddress local address to bind to * @param port local port to bind to * @throws IOException when the server cannot bind to the supplied port */ public HomekitServer(InetAddress localAddress, int port) throws IOException { this(localAddress, port, Runtime.getRuntime().availableProcessors()); } /** * Constructor * * @param port local port to bind to. * @throws IOException when the server cannot bind to the supplied port */ public HomekitServer(int port) throws IOException { this(InetAddress.getLocalHost(), port); } /** * Stops the service, closing down existing connections and preventing new ones. */ public void stop() { http.stop(); } /** * Creates a single (non-bridge) accessory * * @param authInfo authentication information for this accessory. These values should be persisted and re-supplied on re-start * of your application. * @param accessory accessory implementation. This will usually be an implementation of an interface in * {#link com.beowulfe.hap.accessories com.beowulfe.hap.accessories}. * @return the newly created server. Call {@link HomekitStandaloneAccessoryServer#start start} on this to begin. * @throws IOException when mDNS cannot connect to the network */ public HomekitStandaloneAccessoryServer createStandaloneAccessory(HomekitAuthInfo authInfo, HomekitAccessory accessory) throws IOException { return new HomekitStandaloneAccessoryServer(accessory, http, localAddress, authInfo); } /** * Creates a bridge accessory, capable of holding multiple child accessories. This has the advantage over multiple standalone * accessories of only requiring a single pairing from iOS for the bridge. * * @param authInfo authentication information for this accessory. These values should be persisted and re-supplied on re-start * of your application. * @param label label for the bridge. This will show in iOS during pairing. * @param manufacturer manufacturer of the bridge. This information is exposed to iOS for unknown purposes. * @param model model of the bridge. This is also exposed to iOS for unknown purposes. * @param serialNumber serial number of the bridge. Also exposed. Purposes also unknown. * @return the bridge, from which you can {@link HomekitRoot#addAccessory add accessories} and then {@link HomekitRoot#start start} handling requests. * @throws IOException when mDNS cannot connect to the network */ public HomekitRoot createBridge(HomekitAuthInfo authInfo, String label, String manufacturer, String model, String serialNumber) throws IOException { HomekitRoot root = new HomekitRoot(label, http, localAddress, authInfo); root.addAccessory(new HomekitBridge(label, serialNumber, model, manufacturer)); return root; } /** * Generates a value to supply in {@link HomekitAuthInfo#getSalt() HomekitAuthInfo.getSalt()}. This is used to salt * the pin-code. You don't need to worry about that though - the salting is done on the plaintext pin. (Yes, plaintext * passwords are bad. Please don't secure your nuclear storage facility with this implementation) * * @return the generated salt */ static public BigInteger generateSalt() { return HomekitUtils.generateSalt(); } /** * Generates a value to supply in {@link HomekitAuthInfo#getPrivateKey() HomekitAuthInfo.getPrivKey()}. This is used as the * private key during pairing and connection setup. * * @return the generated key * @throws InvalidAlgorithmParameterException if the JVM does not contain the necessary encryption algorithms. */ static public byte[] generateKey() throws InvalidAlgorithmParameterException { return HomekitUtils.generateKey(); } /** * Generates a value to supply in {@link HomekitAuthInfo#getMac() HomekitAuthInfo.getMac()}. This is used as the unique * identifier of the accessory during mDNS advertising. It is a valid MAC address generated in the locally administered * range so as not to conflict with any commercial devices. * * @return the generated MAC */ static public String generateMac() { return HomekitUtils.generateMac(); } }