summaryrefslogtreecommitdiff
path: root/java/src/com/zerotier/sdk/Node.java
blob: 8e7d44e7b12502e763b711bbdab5e9787e1dca94 (plain)
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
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
/*
 * ZeroTier One - Network Virtualization Everywhere
 * Copyright (C) 2011-2015  ZeroTier, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * --
 *
 * ZeroTier may be used and distributed under the terms of the GPLv3, which
 * are available at: http://www.gnu.org/licenses/gpl-3.0.html
 *
 * If you would like to embed ZeroTier into a commercial application or
 * redistribute it in a modified binary form, please contact ZeroTier Networks
 * LLC. Start here: http://www.zerotier.com/
 */

package com.zerotier.sdk;

import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.io.IOException;

/**
 * A ZeroTier One node
 */
public class Node {
	static {
        try {
    		System.loadLibrary("ZeroTierOneJNI");
        } catch (UnsatisfiedLinkError e) {
            try { 
                if(System.getProperty("os.name").startsWith("Windows")) {
                    System.out.println("Arch: " + System.getProperty("sun.arch.data.model"));
                    if(System.getProperty("sun.arch.data.model").equals("64")) {
                        NativeUtils.loadLibraryFromJar("/lib/ZeroTierOneJNI_win64.dll");
                    } else {
                        NativeUtils.loadLibraryFromJar("/lib/ZeroTierOneJNI_win32.dll");
                    }
                } else if(System.getProperty("os.name").startsWith("Mac")) {
                    NativeUtils.loadLibraryFromJar("/lib/libZeroTierOneJNI.jnilib");
                } else {
                    // TODO: Linux
                }
            } catch (IOException ioe) {
                ioe.printStackTrace();
            }
        }
	}

    private static final String TAG = "NODE";

    /**
     * Node ID for JNI purposes.
     * Currently set to the now value passed in at the constructor
     * 
     * -1 if the node has already been closed
     */
    private long nodeId;

    private final DataStoreGetListener getListener;
    private final DataStorePutListener putListener;
    private final PacketSender sender;
    private final EventListener eventListener;
    private final VirtualNetworkFrameListener frameListener;
    private final VirtualNetworkConfigListener configListener;
    private final PathChecker pathChecker;
    
    /**
     * Create a new ZeroTier One node
     *
     * <p>Note that this can take a few seconds the first time it's called, as it
     * will generate an identity.</p>
     *
     * @param now Current clock in milliseconds
     * @param getListener User written instance of the {@link DataStoreGetListener} interface called to get objects from persistent storage.  This instance must be unique per Node object.
     * @param putListener User written intstance of the {@link DataStorePutListener} interface called to put objects in persistent storage.  This instance must be unique per Node object.
     * @param sender
     * @param eventListener User written instance of the {@link EventListener} interface to receive status updates and non-fatal error notices.  This instance must be unique per Node object.
     * @param frameListener 
     * @param configListener User written instance of the {@link VirtualNetworkConfigListener} interface to be called when virtual LANs are created, deleted, or their config parameters change.  This instance must be unique per Node object.
     * @param pathChecker User written instance of the {@link PathChecker} interface. Not required and can be null.
     */
	public Node(long now,
                DataStoreGetListener getListener,
                DataStorePutListener putListener,
                PacketSender sender,
                EventListener eventListener,
                VirtualNetworkFrameListener frameListener,
                VirtualNetworkConfigListener configListener,
                PathChecker pathChecker) throws NodeException
	{
        this.nodeId = now;

        this.getListener = getListener;
        this.putListener = putListener;
        this.sender = sender;
        this.eventListener = eventListener;
        this.frameListener = frameListener;
        this.configListener = configListener;
        this.pathChecker = pathChecker;

        ResultCode rc = node_init(now);
        if(rc != ResultCode.RESULT_OK)
        {
            // TODO: Throw Exception
            throw new NodeException(rc.toString());
        }
	}

    /**
      * Close this Node.
      * 
      * <p>The Node object can no longer be used once this method is called.</p>
      */
    public void close() {
        if(nodeId != -1) {
            node_delete(nodeId);
            nodeId = -1;
        }
    }

    @Override
    protected void finalize() {
        close();
    }

    /**
     * Process a frame from a virtual network port
     *
     * @param now Current clock in milliseconds
     * @param nwid ZeroTier 64-bit virtual network ID
     * @param sourceMac Source MAC address (least significant 48 bits)
     * @param destMac Destination MAC address (least significant 48 bits)
     * @param etherType 16-bit Ethernet frame type
     * @param vlanId 10-bit VLAN ID or 0 if none
     * @param frameData Frame payload data
     * @param nextBackgroundTaskDeadline Value/result: set to deadline for next call to processBackgroundTasks()
     * @return OK (0) or error code if a fatal error condition has occurred
     */
    public ResultCode processVirtualNetworkFrame(
        long now,
        long nwid,
        long sourceMac,
        long destMac,
        int etherType,
        int vlanId,
        byte[] frameData,
        long[] nextBackgroundTaskDeadline) {
        return processVirtualNetworkFrame(
            nodeId, now, nwid, sourceMac, destMac, etherType, vlanId, 
            frameData, nextBackgroundTaskDeadline);
    }

    /**
     * Process a packet received from the physical wire
     *
     * @param now Current clock in milliseconds
     * @param remoteAddress Origin of packet
     * @param packetData Packet data
     * @param nextBackgroundTaskDeadline Value/result: set to deadline for next call to processBackgroundTasks()
     * @return OK (0) or error code if a fatal error condition has occurred
     */
    public ResultCode processWirePacket(
        long now,
        InetSocketAddress localAddress,
        InetSocketAddress remoteAddress,
        byte[] packetData,
        long[] nextBackgroundTaskDeadline) {
        return processWirePacket(
            nodeId, now, localAddress, remoteAddress, packetData, 
            nextBackgroundTaskDeadline);
    }

    /**
     * Perform periodic background operations
     *
     * @param now Current clock in milliseconds
     * @param nextBackgroundTaskDeadline Value/result: set to deadline for next call to processBackgroundTasks()
     * @return OK (0) or error code if a fatal error condition has occurred
     */
    public ResultCode processBackgroundTasks(long now, long[] nextBackgroundTaskDeadline) {
        return processBackgroundTasks(nodeId, now, nextBackgroundTaskDeadline);
    }

    /**
     * Join a network
     *
     * <p>This may generate calls to the port config callback before it returns,
     * or these may be deffered if a netconf is not available yet.</p>
     *
     * <p>If we are already a member of the network, nothing is done and OK is
     * returned.</p>
     *
     * @param nwid 64-bit ZeroTier network ID
     * @return OK (0) or error code if a fatal error condition has occurred
     */
    public ResultCode join(long nwid) {
        return join(nodeId, nwid);
    }

    /**
     * Leave a network
     *
     * <p>If a port has been configured for this network this will generate a call
     * to the port config callback with a NULL second parameter to indicate that
     * the port is now deleted.</p>
     *
     * @param nwid 64-bit network ID
     * @return OK (0) or error code if a fatal error condition has occurred
     */
    public ResultCode leave(long nwid) {
        return leave(nodeId, nwid);
    }

    /**
     * Subscribe to an Ethernet multicast group
     *
     * <p>For IPv4 ARP, the implementation must subscribe to 0xffffffffffff (the
     * broadcast address) but with an ADI equal to each IPv4 address in host
     * byte order. This converts ARP from a non-scalable broadcast protocol to
     * a scalable multicast protocol with perfect address specificity.</p>
     *
     * <p>If this is not done, ARP will not work reliably.</p>
     *
     * <p>Multiple calls to subscribe to the same multicast address will have no
     * effect. It is perfectly safe to do this.</p>
     *
     * <p>This does not generate an update call to the {@link VirtualNetworkConfigListener#onNetworkConfigurationUpdated} method.</p>
     *
     * @param nwid 64-bit network ID
     * @param multicastGroup Ethernet multicast or broadcast MAC (least significant 48 bits)
     * @return OK (0) or error code if a fatal error condition has occurred
     */
    public ResultCode multicastSubscribe(
		long nwid,
		long multicastGroup) {
		return multicastSubscribe(nodeId, nwid, multicastGroup, 0);
	}

    /**
     * Subscribe to an Ethernet multicast group
     *
     * <p>ADI stands for additional distinguishing information. This defaults to zero
     * and is rarely used. Right now its only use is to enable IPv4 ARP to scale,
     * and this must be done.</p>
     *
     * <p>For IPv4 ARP, the implementation must subscribe to 0xffffffffffff (the
     * broadcast address) but with an ADI equal to each IPv4 address in host
     * byte order. This converts ARP from a non-scalable broadcast protocol to
     * a scalable multicast protocol with perfect address specificity.</p>
     *
     * <p>If this is not done, ARP will not work reliably.</p>
     *
     * <p>Multiple calls to subscribe to the same multicast address will have no
     * effect. It is perfectly safe to do this.</p>
     *
     * <p>This does not generate an update call to the {@link VirtualNetworkConfigListener#onNetworkConfigurationUpdated} method.</p>
     *
     * @param nwid 64-bit network ID
     * @param multicastGroup Ethernet multicast or broadcast MAC (least significant 48 bits)
     * @param multicastAdi Multicast ADI (least significant 32 bits only, default: 0)
     * @return OK (0) or error code if a fatal error condition has occurred
     */
    public ResultCode multicastSubscribe(
        long nwid,
        long multicastGroup,
        long multicastAdi) {
        return multicastSubscribe(nodeId, nwid, multicastGroup, multicastAdi);
    }


    /**
     * Unsubscribe from an Ethernet multicast group (or all groups)
     *
     * <p>If multicastGroup is zero (0), this will unsubscribe from all groups. If
     * you are not subscribed to a group this has no effect.</p>
     *
     * <p>This does not generate an update call to the {@link VirtualNetworkConfigListener#onNetworkConfigurationUpdated} method.</p>
     *
     * @param nwid 64-bit network ID
     * @param multicastGroup Ethernet multicast or broadcast MAC (least significant 48 bits)
     * @return OK (0) or error code if a fatal error condition has occurred
     */
	public ResultCode multicastUnsubscribe(
		long nwid,
		long multicastGroup) {
		return multicastUnsubscribe(nodeId, nwid, multicastGroup, 0);
	}

    /**
     * Unsubscribe from an Ethernet multicast group (or all groups)
     *
     * <p>If multicastGroup is zero (0), this will unsubscribe from all groups. If
     * you are not subscribed to a group this has no effect.</p>
     *
     * <p>This does not generate an update call to the {@link VirtualNetworkConfigListener#onNetworkConfigurationUpdated} method.</p>
     *
     * <p>ADI stands for additional distinguishing information. This defaults to zero
     * and is rarely used. Right now its only use is to enable IPv4 ARP to scale,
     * and this must be done.</p>
     *
     * @param nwid 64-bit network ID
     * @param multicastGroup Ethernet multicast or broadcast MAC (least significant 48 bits)
     * @param multicastAdi Multicast ADI (least significant 32 bits only, default: 0)
     * @return OK (0) or error code if a fatal error condition has occurred
     */
    public ResultCode multicastUnsubscribe(
        long nwid,
        long multicastGroup,
        long multicastAdi) {
        return multicastUnsubscribe(nodeId, nwid, multicastGroup, multicastAdi);
    }

    /**
     * Add or update a moon
     *
     * Moons are persisted in the data store in moons.d/, so this can persist
     * across invocations if the contents of moon.d are scanned and orbit is
     * called for each on startup.
     *
     * @param moonWorldId Moon's world ID
     * @param moonSeed If non-zero, the ZeroTier address of any member of the moon to query for moon definition
     * @return Error if moon was invalid or failed to be added
     */
    public ResultCode orbit(
            long moonWorldId,
            long moonSeed) {
        return orbit(nodeId, moonWorldId, moonSeed);
    }

    /**
     * Remove a moon (does nothing if not present)
     *
     * @param moonWorldId World ID of moon to remove
     * @return Error if anything bad happened
     */
    public ResultCode deorbit(
            long moonWorldId) {
        return deorbit(nodeId, moonWorldId);
    }

    /**
     * Get this node's 40-bit ZeroTier address
     *
     * @return ZeroTier address (least significant 40 bits of 64-bit int)
     */
    public long address() {
        return address(nodeId);
    }

    /**
     * Get the status of this node
     *
     * @return @{link NodeStatus} struct with the current node status.
     */
    public NodeStatus status() {
        return status(nodeId);
    }

    /**
     * Get a list of known peer nodes
     *
     * @return List of known peers or NULL on failure
     */
    public Peer[] peers() {
        return peers(nodeId);
    }

    /**
     * Get the status of a virtual network
     *
     * @param nwid 64-bit network ID
     * @return {@link VirtualNetworkConfig} or NULL if we are not a member of this network
     */
    public VirtualNetworkConfig networkConfig(long nwid) {
        return networkConfig(nodeId, nwid);
    }

    /**
     * Enumerate and get status of all networks
     *
     * @return List of networks or NULL on failure
     */
    public VirtualNetworkConfig[] networks() {
        return networks(nodeId);
    }

    /**
     * Get ZeroTier One version
     *
     * @return {@link Version} object with ZeroTierOne version information.
     */
    public Version getVersion() {
        return version();
    }

    //
    // function declarations for JNI
    //
    private native ResultCode node_init(long now);

    private native void node_delete(long nodeId);

    private native ResultCode processVirtualNetworkFrame(
        long nodeId,
        long now,
        long nwid,
        long sourceMac,
        long destMac,
        int etherType,
        int vlanId,
        byte[] frameData,
        long[] nextBackgroundTaskDeadline);

    private native ResultCode processWirePacket(
        long nodeId,
        long now,
        InetSocketAddress localAddress,
        InetSocketAddress remoteAddress,
        byte[] packetData,
        long[] nextBackgroundTaskDeadline);

    private native ResultCode processBackgroundTasks(
        long nodeId,
        long now,
        long[] nextBackgroundTaskDeadline);

    private native ResultCode join(long nodeId, long nwid);

    private native ResultCode leave(long nodeId, long nwid);

    private native ResultCode multicastSubscribe(
        long nodeId,
        long nwid,
        long multicastGroup,
        long multicastAdi);

    private native ResultCode multicastUnsubscribe(
        long nodeId,
        long nwid,
        long multicastGroup,
        long multicastAdi);

    private native ResultCode orbit(
            long nodeId,
            long moonWorldId,
            long moonSeed);

    private native ResultCode deorbit(
            long nodeId,
            long moonWorldId);

    private native long address(long nodeId);

    private native NodeStatus status(long nodeId);

    private native VirtualNetworkConfig networkConfig(long nodeId, long nwid);

    private native Version version();

    private native Peer[] peers(long nodeId);

    private native VirtualNetworkConfig[] networks(long nodeId);
}