forked from hap-java/HAP-Java
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathHomekitServer.java
More file actions
218 lines (203 loc) · 8.57 KB
/
HomekitServer.java
File metadata and controls
218 lines (203 loc) · 8.57 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
package io.github.hapjava.server.impl;
import io.github.hapjava.accessories.HomekitAccessory;
import io.github.hapjava.server.HomekitAuthInfo;
import io.github.hapjava.server.impl.http.impl.HomekitHttpServer;
import java.io.IOException;
import java.math.BigInteger;
import java.net.InetAddress;
import java.security.InvalidAlgorithmParameterException;
import java.util.concurrent.ExecutionException;
import javax.jmdns.JmDNS;
/**
* 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, String, String) bridge accessory} containing child accessories.
*
* <p>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;
private final JmDNS jmdns;
/**
* 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;
this.jmdns = null;
http = new HomekitHttpServer(localAddress, port, nThreads);
}
/**
* Constructor
*
* @param jmdns mdns service to register with
* @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(JmDNS jmdns, int port, int nThreads) throws IOException {
this.jmdns = jmdns;
this.localAddress = null;
http = new HomekitHttpServer(jmdns.getInetAddress(), 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 jmdns mdns service to register with
* @param port local port to bind to
* @throws IOException when the server cannot bind to the supplied port
*/
public HomekitServer(JmDNS jmdns, int port) throws IOException {
this(jmdns, 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 io.github.hapjava.accessories io.github.hapjava.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, ExecutionException, InterruptedException {
if (jmdns != null) {
return new HomekitStandaloneAccessoryServer(accessory, http, jmdns, authInfo);
} else {
return new HomekitStandaloneAccessoryServer(accessory, http, localAddress, authInfo);
}
}
public HomekitStandaloneAccessoryServer createStandaloneAccessory(
HomekitAuthInfo authInfo, HomekitAccessory accessory, int category)
throws IOException, ExecutionException, InterruptedException {
if (jmdns != null) {
return new HomekitStandaloneAccessoryServer(accessory, http, jmdns, authInfo, category);
} else {
return new HomekitStandaloneAccessoryServer(
accessory, http, localAddress, authInfo, category);
}
}
/**
* 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.
* @param firmwareRevision firmware revision of the bridge.
* @param hardwareRevision hardware revision of the brigde.
* @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,
int category,
String manufacturer,
String model,
String serialNumber,
String firmwareRevision,
String hardwareRevision)
throws IOException {
HomekitRoot root;
if (jmdns != null) {
root = new HomekitRoot(label, category, http, jmdns, authInfo);
} else {
root = new HomekitRoot(label, category, http, localAddress, authInfo);
}
root.addAccessory(
new HomekitBridge(
label, serialNumber, model, manufacturer, firmwareRevision, hardwareRevision));
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
*/
public static 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.
*/
public static 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
*/
public static String generateMac() {
return HomekitUtils.generateMac();
}
/**
* Generates a value to supply in {@link HomekitAuthInfo#getPin() HomekitAuthInfo.getPin()}. This
* is used as the Pin a user enters into their HomeKit device in order to confirm pairing.
*
* @return the generated Pin
*/
public static String generatePin() {
return HomekitUtils.generatePin();
}
}