@ -0,0 +1,10 @@
|
||||
*.iml |
||||
.gradle |
||||
/local.properties |
||||
/.idea/libraries |
||||
/.idea/modules.xml |
||||
/.idea/workspace.xml |
||||
.DS_Store |
||||
/build |
||||
/captures |
||||
.externalNativeBuild |
||||
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<projectDescription> |
||||
<name>android</name> |
||||
<comment>Project android created by Buildship.</comment> |
||||
<projects> |
||||
</projects> |
||||
<buildSpec> |
||||
<buildCommand> |
||||
<name>org.eclipse.buildship.core.gradleprojectbuilder</name> |
||||
<arguments> |
||||
</arguments> |
||||
</buildCommand> |
||||
</buildSpec> |
||||
<natures> |
||||
<nature>org.eclipse.buildship.core.gradleprojectnature</nature> |
||||
</natures> |
||||
</projectDescription> |
||||
@ -0,0 +1,2 @@
|
||||
connection.project.dir= |
||||
eclipse.preferences.version=1 |
||||
@ -0,0 +1,42 @@
|
||||
apply plugin: 'com.android.library' |
||||
|
||||
android { |
||||
compileSdkVersion 28 |
||||
defaultConfig { |
||||
minSdkVersion 14 |
||||
targetSdkVersion 23 |
||||
versionCode 1 |
||||
versionName "1.0" |
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" |
||||
externalNativeBuild { |
||||
cmake { |
||||
cppFlags "" |
||||
} |
||||
} |
||||
ndk { |
||||
// Tells Gradle to build outputs for the following ABIs and package |
||||
// them into your APK. |
||||
abiFilters 'armeabi-v7a' |
||||
} |
||||
} |
||||
buildTypes { |
||||
release { |
||||
minifyEnabled false |
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' |
||||
} |
||||
} |
||||
externalNativeBuild { |
||||
cmake { |
||||
path "../../../CMakeLists.txt" |
||||
} |
||||
} |
||||
} |
||||
|
||||
dependencies { |
||||
implementation fileTree(dir: 'libs', include: ['*.jar']) |
||||
implementation 'com.android.support:appcompat-v7:28.0.0-alpha3' |
||||
implementation 'com.android.support.constraint:constraint-layout:1.1.2' |
||||
testImplementation 'junit:junit:4.12' |
||||
androidTestImplementation 'com.android.support.test:runner:1.0.2' |
||||
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' |
||||
} |
||||
@ -0,0 +1,21 @@
|
||||
# Add project specific ProGuard rules here. |
||||
# You can control the set of applied configuration files using the |
||||
# proguardFiles setting in build.gradle. |
||||
# |
||||
# For more details, see |
||||
# http://developer.android.com/guide/developing/tools/proguard.html |
||||
|
||||
# If your project uses WebView with JS, uncomment the following |
||||
# and specify the fully qualified class name to the JavaScript interface |
||||
# class: |
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview { |
||||
# public *; |
||||
#} |
||||
|
||||
# Uncomment this to preserve the line number information for |
||||
# debugging stack traces. |
||||
#-keepattributes SourceFile,LineNumberTable |
||||
|
||||
# If you keep the line number information, uncomment this to |
||||
# hide the original source file name. |
||||
#-renamesourcefileattribute SourceFile |
||||
@ -0,0 +1,26 @@
|
||||
package com.example.zerotier; |
||||
|
||||
import android.content.Context; |
||||
import android.support.test.InstrumentationRegistry; |
||||
import android.support.test.runner.AndroidJUnit4; |
||||
|
||||
import org.junit.Test; |
||||
import org.junit.runner.RunWith; |
||||
|
||||
import static org.junit.Assert.*; |
||||
|
||||
/** |
||||
* Instrumented test, which will execute on an Android device. |
||||
* |
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a> |
||||
*/ |
||||
@RunWith(AndroidJUnit4.class) |
||||
public class ExampleInstrumentedTest { |
||||
@Test |
||||
public void useAppContext() { |
||||
// Context of the app under test.
|
||||
Context appContext = InstrumentationRegistry.getTargetContext(); |
||||
|
||||
assertEquals("com.example.zerotier", appContext.getPackageName()); |
||||
} |
||||
} |
||||
@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" |
||||
package="com.example.zerotier"> |
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" /> |
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> |
||||
|
||||
<application |
||||
android:allowBackup="true" |
||||
android:icon="@mipmap/ic_launcher" |
||||
android:label="@string/app_name" |
||||
android:roundIcon="@mipmap/ic_launcher_round" |
||||
android:supportsRtl="true" |
||||
android:theme="@style/AppTheme"> |
||||
<activity android:name=".MainActivity"> |
||||
<intent-filter> |
||||
<action android:name="android.intent.action.MAIN" /> |
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" /> |
||||
</intent-filter> |
||||
</activity> |
||||
</application> |
||||
|
||||
</manifest> |
||||
|
||||
@ -0,0 +1 @@
|
||||
|
||||
@ -0,0 +1,194 @@
|
||||
/* |
||||
* ZeroTier SDK - Network Virtualization Everywhere |
||||
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* |
||||
* 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/>.
|
||||
* |
||||
* -- |
||||
* |
||||
* You can be released from the requirements of the license by purchasing |
||||
* a commercial license. Buying such a license is mandatory as soon as you |
||||
* develop commercial closed-source software that incorporates or links |
||||
* directly against ZeroTier software without disclosing the source code |
||||
* of your own application. |
||||
*/ |
||||
|
||||
package com.zerotier.libzt; |
||||
|
||||
import java.net.*; |
||||
|
||||
public class ZeroTier |
||||
{ |
||||
static |
||||
{ |
||||
// loads libzt.so or libzt.dylib
|
||||
System.loadLibrary("zt"); |
||||
init(); |
||||
} |
||||
|
||||
public static int ZTS_ERR_OK = 0; // Everything is ok
|
||||
public static int ZTS_ERR_INVALID_ARG = -1; // A parameter provided by the user application is invalid (e.g. our of range, NULL, etc)
|
||||
public static int ZTS_ERR_SERVICE = -2; // The service isn't initialized or is for some other reason currently unavailable
|
||||
public static int ZTS_ERR_INVALID_OP = -3; // For some reason this API operation is not permitted (perhaps the service is still starting?)
|
||||
|
||||
// Events generated by ZeroTier service or by libzt
|
||||
// See ext/ZeroTierOne/include/ZeroTierOne.h
|
||||
public static int EVENT_NONE = -1; |
||||
// Node-specific events
|
||||
public static int EVENT_NODE_UP = 0; |
||||
public static int EVENT_NODE_OFFLINE = 1; |
||||
public static int EVENT_NODE_ONLINE = 2; |
||||
public static int EVENT_NODE_DOWN = 3; |
||||
public static int EVENT_NODE_IDENTITY_COLLISION = 4; |
||||
// libzt node events
|
||||
public static int EVENT_NODE_UNRECOVERABLE_ERROR = 16; |
||||
public static int EVENT_NODE_NORMAL_TERMINATION = 17; |
||||
// Network-specific events
|
||||
public static int EVENT_NETWORK_NOT_FOUND = 32; |
||||
public static int EVENT_NETWORK_CLIENT_TOO_OLD = 33; |
||||
public static int EVENT_NETWORK_REQUESTING_CONFIG = 34; |
||||
public static int EVENT_NETWORK_OK = 35; |
||||
public static int EVENT_NETWORK_ACCESS_DENIED = 36; |
||||
public static int EVENT_NETWORK_READY_IP4 = 37; |
||||
public static int EVENT_NETWORK_READY_IP6 = 38; |
||||
public static int EVENT_NETWORK_DOWN = 39; |
||||
// lwIP netif events
|
||||
public static int EVENT_NETIF_UP_IP4 = 64; |
||||
public static int EVENT_NETIF_UP_IP6 = 65; |
||||
public static int EVENT_NETIF_DOWN_IP4 = 66; |
||||
public static int EVENT_NETIF_DOWN_IP6 = 67; |
||||
public static int EVENT_NETIF_REMOVED = 68; |
||||
public static int EVENT_NETIF_LINK_UP = 69; |
||||
public static int EVENT_NETIF_LINK_DOWN = 70; |
||||
public static int EVENT_NETIF_NEW_ADDRESS = 71; |
||||
// Peer events
|
||||
public static int EVENT_PEER_P2P = 96; |
||||
public static int EVENT_PEER_RELAY = 97; |
||||
public static int EVENT_PEER_UNREACHABLE = 98; |
||||
|
||||
// Socket protocol types
|
||||
public static int SOCK_STREAM = 0x00000001; |
||||
public static int SOCK_DGRAM = 0x00000002; |
||||
public static int SOCK_RAW = 0x00000003; |
||||
// Socket family types
|
||||
public static int AF_INET = 0x00000002; |
||||
public static int AF_INET6 = 0x0000000a; |
||||
public static int PF_INET = AF_INET; |
||||
public static int PF_INET6 = AF_INET6; |
||||
// Used as level numbers for setsockopt() and getsockopt()
|
||||
public static int IPPROTO_IP = 0x00000000; |
||||
public static int IPPROTO_ICMP = 0x00000001; |
||||
public static int IPPROTO_TCP = 0x00000006; |
||||
public static int IPPROTO_UDP = 0x00000011; |
||||
public static int IPPROTO_IPV6 = 0x00000029; |
||||
public static int IPPROTO_ICMPV6 = 0x0000003a; |
||||
public static int IPPROTO_UDPLITE = 0x00000088; |
||||
public static int IPPROTO_RAW = 0x000000ff; |
||||
// send() and recv() flags
|
||||
public static int MSG_PEEK = 0x00000001; |
||||
public static int MSG_WAITALL = 0x00000002; |
||||
public static int MSG_OOB = 0x00000004; |
||||
public static int MSG_DONTWAIT = 0x00000008; |
||||
public static int MSG_MORE = 0x00000010; |
||||
// fnctl() commands
|
||||
public static int F_GETFL = 0x00000003; |
||||
public static int F_SETFL = 0x00000004; |
||||
// fnctl() flags
|
||||
public static int O_NONBLOCK = 0x00000001; |
||||
public static int O_NDELAY = 0x00000001; |
||||
// Shutdown commands
|
||||
public static int SHUT_RD = 0x00000000; |
||||
public static int SHUT_WR = 0x00000001; |
||||
public static int SHUT_RDWR = 0x00000002; |
||||
// ioctl() commands
|
||||
public static int FIONREAD = 0x4008667F; |
||||
public static int FIONBIO = 0x8008667E; |
||||
// Socket level option number
|
||||
public static int SOL_SOCKET = 0x00000FFF; |
||||
// Socket options
|
||||
public static int SO_REUSEADDR = 0x00000004; |
||||
public static int SO_KEEPALIVE = 0x00000008; |
||||
public static int SO_BROADCAST = 0x00000020; |
||||
// Socket options
|
||||
public static int SO_DEBUG = 0x00000001; // NOT YET SUPPORTED
|
||||
public static int SO_ACCEPTCONN = 0x00000002; |
||||
public static int SO_DONTROUTE = 0x00000010; // NOT YET SUPPORTED
|
||||
public static int SO_USELOOPBACK = 0x00000040; // NOT YET SUPPORTED
|
||||
public static int SO_LINGER = 0x00000080; |
||||
public static int SO_DONTLINGER = ((int)(~SO_LINGER)); |
||||
public static int SO_OOBINLINE = 0x00000100; // NOT YET SUPPORTED
|
||||
public static int SO_REUSEPORT = 0x00000200; // NOT YET SUPPORTED
|
||||
public static int SO_SNDBUF = 0x00001001; // NOT YET SUPPORTED
|
||||
public static int SO_RCVBUF = 0x00001002; |
||||
public static int SO_SNDLOWAT = 0x00001003; // NOT YET SUPPORTED
|
||||
public static int SO_RCVLOWAT = 0x00001004; // NOT YET SUPPORTED
|
||||
public static int SO_SNDTIMEO = 0x00001005; |
||||
public static int SO_RCVTIMEO = 0x00001006; |
||||
public static int SO_ERROR = 0x00001007; |
||||
public static int SO_TYPE = 0x00001008; |
||||
public static int SO_CONTIMEO = 0x00001009; // NOT YET SUPPORTED
|
||||
public static int SO_NO_CHECK = 0x0000100a; |
||||
// IPPROTO_IP options
|
||||
public static int IP_TOS = 0x00000001; |
||||
public static int IP_TTL = 0x00000002; |
||||
// IPPROTO_TCP options
|
||||
public static int TCP_NODELAY = 0x00000001; |
||||
public static int TCP_KEEPALIVE = 0x00000002; |
||||
public static int TCP_KEEPIDLE = 0x00000003; |
||||
public static int TCP_KEEPINTVL = 0x00000004; |
||||
public static int TCP_KEEPCNT = 0x00000005; |
||||
|
||||
public static native void start(String path, ZeroTierEventListener callbackClass, int port); |
||||
public static native void stop(); |
||||
public static native int join(long nwid); |
||||
public static native int leave(long nwid); |
||||
public static native long get_node_id(); |
||||
public static native int get_num_assigned_addresses(long nwid); |
||||
public static native void get_6plane_addr(long nwid, long nodeId, ZeroTierSocketAddress addr); |
||||
public static native void get_rfc4193_addr(long nwid, long nodeId, ZeroTierSocketAddress addr); |
||||
public static native int get_peer_status(long nodeId); |
||||
|
||||
public static native int socket(int family, int type, int protocol); |
||||
public static native int connect(int fd, ZeroTierSocketAddress addr); |
||||
public static native int bind(int fd, ZeroTierSocketAddress addr); |
||||
public static native int listen(int fd, int backlog); |
||||
public static native int accept(int fd, ZeroTierSocketAddress addr); |
||||
public static native int accept4(int fd, String addr, int port); |
||||
|
||||
public static native int setsockopt(int fd, int level, int optname, ZeroTierSocketOptionValue optval); |
||||
public static native int getsockopt(int fd, int level, int optname, ZeroTierSocketOptionValue optval); |
||||
|
||||
public static native int read(int fd, byte[] buf); |
||||
public static native int read_offset(int fd, byte[] buf, int offset, int len); |
||||
public static native int read_length(int fd, byte[] buf, int len); |
||||
public static native int recv(int fd, byte[] buf, int flags); |
||||
public static native int recvfrom(int fd, byte[] buf, int flags, ZeroTierSocketAddress addr); |
||||
|
||||
public static native int write(int fd, byte[] buf); |
||||
public static native int write_byte(int fd, byte b); |
||||
public static native int write_offset(int fd, byte[] buf, int offset, int len); |
||||
public static native int sendto(int fd, byte[] buf, int flags, ZeroTierSocketAddress addr); |
||||
public static native int send(int fd, byte[] buf, int flags); |
||||
|
||||
public static native int shutdown(int fd, int how); |
||||
public static native int close(int fd); |
||||
|
||||
public static native boolean getsockname(int fd, ZeroTierSocketAddress addr); |
||||
public static native int getpeername(int fd, ZeroTierSocketAddress addr); |
||||
public static native int fcntl(int sock, int cmd, int flag); |
||||
public static native int ioctl(int fd, long request, ZeroTierIoctlArg arg); |
||||
public static native int select(int nfds, ZeroTierFileDescriptorSet readfds, ZeroTierFileDescriptorSet writefds, ZeroTierFileDescriptorSet exceptfds, int timeout_sec, int timeout_usec); |
||||
|
||||
public static native void init(); // Only to be called by static initializer of this class
|
||||
} |
||||
@ -0,0 +1,9 @@
|
||||
package com.zerotier.libzt; |
||||
|
||||
public interface ZeroTierEventListener { |
||||
|
||||
/* |
||||
* Called when an even occurs in the native section of the ZeroTier library service |
||||
*/ |
||||
public void onZeroTierEvent(long nwid, int eventCode); |
||||
} |
||||
@ -0,0 +1,28 @@
|
||||
package com.zerotier.libzt; |
||||
|
||||
public class ZeroTierFileDescriptorSet |
||||
{ |
||||
byte[] fds_bits = new byte[1024]; |
||||
|
||||
public void CLR(int fd) |
||||
{ |
||||
fds_bits[fd] = 0x00; |
||||
} |
||||
|
||||
public boolean ISSET(int fd) |
||||
{ |
||||
return fds_bits[fd] == 0x01; |
||||
} |
||||
|
||||
public void SET(int fd) |
||||
{ |
||||
fds_bits[fd] = 0x01; |
||||
} |
||||
|
||||
public void ZERO() |
||||
{ |
||||
for (int i=0; i<1024; i++) { |
||||
fds_bits[i] = 0x00; |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,6 @@
|
||||
package com.zerotier.libzt; |
||||
|
||||
public class ZeroTierIoctlArg |
||||
{ |
||||
int integer; // General integer to be used or updated by the zts_ioctl() call
|
||||
} |
||||
@ -0,0 +1,81 @@
|
||||
package com.zerotier.libzt; |
||||
|
||||
import com.zerotier.libzt.ZeroTier; |
||||
|
||||
import java.io.*; |
||||
import java.util.Arrays; |
||||
import java.util.Objects; |
||||
|
||||
class ZeroTierOutputStream extends OutputStream |
||||
{ |
||||
/* |
||||
* File descriptor used by lower native layer |
||||
*/ |
||||
int zfd; |
||||
|
||||
/* |
||||
* |
||||
*/ |
||||
public void flush() |
||||
throws IOException |
||||
{ |
||||
// System.err.println("flush: ZeroTierOutputStream does not currently support this feature");
|
||||
// Not fully supported since we don't maintain a buffer
|
||||
} |
||||
|
||||
/* |
||||
* |
||||
*/ |
||||
public void close() |
||||
throws IOException |
||||
{ |
||||
/* Note: this operation currently only stops RX on a socket that is shared |
||||
between both I/OStreams. This means that closing this stream will only shutdown |
||||
that aspect of the socket but not actually close it and free resources. Resources |
||||
will be properly freed when the socket implementation's close() is called or if |
||||
both I/OStreams are closed separately */ |
||||
ZeroTier.shutdown(zfd, ZeroTier.SHUT_WR); |
||||
zfd = -1; |
||||
} |
||||
|
||||
/* |
||||
* |
||||
*/ |
||||
public void write(byte[] b) |
||||
throws IOException |
||||
{ |
||||
int err = ZeroTier.write(zfd, b); |
||||
if (err < 0) { |
||||
throw new IOException("write(b[]), errno="+err); |
||||
} |
||||
} |
||||
|
||||
/* |
||||
* |
||||
*/ |
||||
public void write(byte[] b, int off, int len) |
||||
throws IOException |
||||
{ |
||||
Objects.requireNonNull(b, "input byte array must not be null"); |
||||
if ((off < 0) | (len < 0) | (off+len > b.length)) { |
||||
throw new IndexOutOfBoundsException("write(b,off,len)"); |
||||
} |
||||
int err = ZeroTier.write_offset(zfd, b, off, len); |
||||
if (err < 0) { |
||||
throw new IOException("write(b[],off,len), errno="+err); |
||||
} |
||||
} |
||||
|
||||
/* |
||||
* |
||||
*/ |
||||
public void write(int b) |
||||
throws IOException |
||||
{ |
||||
byte lowByte = (byte)(b & 0xFF); |
||||
int err = ZeroTier.write_byte(zfd, lowByte); |
||||
if (err < 0) { |
||||
throw new IOException("write(b), errno="+err); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,101 @@
|
||||
package com.zerotier.libzt; |
||||
|
||||
import com.zerotier.libzt.ZeroTierSocket; |
||||
|
||||
import java.net.*; |
||||
import javax.net.SocketFactory; |
||||
import java.io.IOException; |
||||
import java.io.InputStream; |
||||
import java.security.*; |
||||
import java.util.Locale; |
||||
|
||||
import javax.net.ssl.SSLSocketFactory; |
||||
|
||||
public class ZeroTierSSLSocketFactory extends SSLSocketFactory |
||||
{ |
||||
private final SSLSocketFactory delegate; |
||||
|
||||
/* |
||||
* |
||||
*/ |
||||
public ZeroTierSSLSocketFactory(SSLSocketFactory delegate) |
||||
{ |
||||
this.delegate = delegate; |
||||
} |
||||
|
||||
/* |
||||
* |
||||
*/ |
||||
public Socket createSocket(Socket s, String host, int port, boolean autoClose) |
||||
throws IOException |
||||
{ |
||||
ZeroTierSocket zs = new ZeroTierSocket(); |
||||
zs.connect((SocketAddress)new InetSocketAddress(host, port), 10); |
||||
return delegate.createSocket(zs, host, port, autoClose); |
||||
} |
||||
|
||||
/* |
||||
* |
||||
*/ |
||||
public Socket createSocket(Socket s, InputStream consumed, boolean autoClose) |
||||
throws IOException |
||||
{ |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
/* |
||||
* |
||||
*/ |
||||
public Socket createSocket(InetAddress a,int b,InetAddress c,int d) |
||||
throws IOException |
||||
{ |
||||
ZeroTierSocket s = new ZeroTierSocket(); |
||||
return delegate.createSocket(a, b, c, d); |
||||
} |
||||
|
||||
/* |
||||
* |
||||
*/ |
||||
public Socket createSocket(InetAddress a,int b) |
||||
throws IOException |
||||
{ |
||||
ZeroTierSocket s = new ZeroTierSocket(); |
||||
return delegate.createSocket(a, b); |
||||
} |
||||
|
||||
/* |
||||
* |
||||
*/ |
||||
public Socket createSocket(String a,int b,InetAddress c,int d) |
||||
throws IOException |
||||
{ |
||||
ZeroTierSocket s = new ZeroTierSocket(); |
||||
return delegate.createSocket(a, b, c, d); |
||||
} |
||||
|
||||
/* |
||||
* |
||||
*/ |
||||
public Socket createSocket(String a,int b) |
||||
throws IOException |
||||
{ |
||||
ZeroTierSocket s = new ZeroTierSocket(); |
||||
return delegate.createSocket(a, b); |
||||
} |
||||
|
||||
/* |
||||
* |
||||
*/ |
||||
public String [] getSupportedCipherSuites() |
||||
{ |
||||
return new String[0]; |
||||
} |
||||
|
||||
/* |
||||
* |
||||
*/ |
||||
public String [] getDefaultCipherSuites() |
||||
{ |
||||
return new String[0]; |
||||
} |
||||
} |
||||
@ -0,0 +1,66 @@
|
||||
package com.zerotier.libzt; |
||||
|
||||
import com.zerotier.libzt.ZeroTier; |
||||
|
||||
import java.net.InetAddress; |
||||
|
||||
// Designed to transport address information across the JNI boundary
|
||||
public class ZeroTierSocketAddress |
||||
{ |
||||
public byte[] _ip6 = new byte[16]; |
||||
public byte[] _ip4 = new byte[4]; |
||||
|
||||
public int _family; |
||||
public int _port; // Also reused for netmask or prefix
|
||||
|
||||
public ZeroTierSocketAddress() {} |
||||
|
||||
public ZeroTierSocketAddress(String ipStr, int port) |
||||
{ |
||||
if(ipStr.contains(":")) { |
||||
_family = ZeroTier.AF_INET6; |
||||
try { |
||||
InetAddress ip = InetAddress.getByName(ipStr); |
||||
_ip6 = ip.getAddress(); |
||||
} |
||||
catch (Exception e) { } |
||||
} |
||||
else if(ipStr.contains(".")) { |
||||
_family = ZeroTier.AF_INET; |
||||
try { |
||||
InetAddress ip = InetAddress.getByName(ipStr); |
||||
_ip4 = ip.getAddress(); |
||||
} |
||||
catch (Exception e) { } |
||||
} |
||||
_port = port; |
||||
} |
||||
|
||||
public int getPort() { return _port; } |
||||
public int getNetmask() { return _port; } |
||||
public int getPrefix() { return _port; } |
||||
|
||||
public String ipString() |
||||
{ |
||||
if (_family == ZeroTier.AF_INET) { |
||||
try { |
||||
InetAddress inet = InetAddress.getByAddress(_ip4); |
||||
return "" + inet.getHostAddress(); |
||||
} catch (Exception e) { |
||||
System.out.println(e); |
||||
} |
||||
} |
||||
if (_family == ZeroTier.AF_INET6) { |
||||
try { |
||||
InetAddress inet = InetAddress.getByAddress(_ip6); |
||||
return "" + inet.getHostAddress(); |
||||
} catch (Exception e) { |
||||
System.out.println(e); |
||||
} |
||||
} |
||||
return ""; |
||||
} |
||||
|
||||
public String toString() { return ipString() + ":" + _port; } |
||||
public String toCIDR() { return ipString() + "/" + _port; } |
||||
} |
||||
@ -0,0 +1,51 @@
|
||||
package com.zerotier.libzt; |
||||
|
||||
import com.zerotier.libzt.ZeroTier; |
||||
import com.zerotier.libzt.ZeroTierSocket; |
||||
|
||||
import java.io.IOException; |
||||
import java.net.InetAddress; |
||||
import java.net.Socket; |
||||
import java.net.UnknownHostException; |
||||
import javax.net.SocketFactory; |
||||
import java.util.Objects; |
||||
|
||||
public class ZeroTierSocketFactory extends SocketFactory |
||||
{ |
||||
public ZeroTierSocketFactory() { } |
||||
|
||||
public static SocketFactory getDefault() |
||||
{ |
||||
return null; |
||||
} |
||||
|
||||
public Socket createSocket() |
||||
throws IOException, UnknownHostException |
||||
{ |
||||
return new ZeroTierSocket(); |
||||
} |
||||
|
||||
public Socket createSocket(String host, int port) |
||||
throws IOException, UnknownHostException |
||||
{ |
||||
return new ZeroTierSocket(host, port); |
||||
} |
||||
|
||||
public Socket createSocket(String host, int port, InetAddress localHost, int localPort) |
||||
throws IOException, UnknownHostException |
||||
{ |
||||
return new ZeroTierSocket(host, port, localHost, localPort); |
||||
} |
||||
|
||||
public Socket createSocket(InetAddress host, int port) |
||||
throws IOException |
||||
{ |
||||
return new ZeroTierSocket(host, port); |
||||
} |
||||
|
||||
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) |
||||
throws IOException |
||||
{ |
||||
return new ZeroTierSocket(address, port, localAddress, localPort); |
||||
} |
||||
} |
||||
@ -0,0 +1,772 @@
|
||||
package com.zerotier.libzt; |
||||
|
||||
import com.zerotier.libzt.ZeroTier; |
||||
import com.zerotier.libzt.ZeroTierSocketAddress; |
||||
import com.zerotier.libzt.ZeroTierInputStream; |
||||
import com.zerotier.libzt.ZeroTierOutputStream; |
||||
import com.zerotier.libzt.ZeroTierSocketOptionValue; |
||||
|
||||
import java.io.*; |
||||
import java.net.*; |
||||
import java.util.Objects; |
||||
import java.lang.Object; |
||||
import java.net.SocketImpl; |
||||
import java.net.InetSocketAddress; |
||||
import java.util.Set; |
||||
import java.lang.Boolean; |
||||
|
||||
import com.zerotier.libzt.ZeroTier; |
||||
|
||||
import android.os.ParcelFileDescriptor; |
||||
|
||||
public class ZeroTierSocketImpl extends SocketImpl |
||||
{ |
||||
private int defaultProtocol = 0; |
||||
|
||||
/* |
||||
* File descriptor from lower native layer |
||||
*/ |
||||
private int zfd = -1; |
||||
private int zfd4 = -1; |
||||
private int zfd6 = -1; |
||||
|
||||
/* |
||||
* Input and Output streams |
||||
*/ |
||||
private ZeroTierInputStream in = new ZeroTierInputStream(); |
||||
private ZeroTierOutputStream out = new ZeroTierOutputStream(); |
||||
|
||||
Socket socket = null; |
||||
ServerSocket serverSocket = null; |
||||
|
||||
/* |
||||
* The remote address the socket is connected to |
||||
*/ |
||||
protected InetAddress address; |
||||
|
||||
/* |
||||
* Sets the underlying file descriptor valud for the SocketImpl as well as the Input/OutputStream |
||||
*/ |
||||
private void setNativeFileDescriptor(int fd) |
||||
{ |
||||
zfd = fd; |
||||
in.zfd = fd; |
||||
out.zfd = fd; |
||||
} |
||||
|
||||
/* |
||||
* Various socket options that are cached from calls to setOption() before |
||||
* the socket exists. |
||||
*/ |
||||
private int _so_rcvtimeo; |
||||
private boolean _so_keepalive; |
||||
private int _so_sndbuf; |
||||
private int _so_rcvbuf; |
||||
private boolean _so_reuseaddr; |
||||
private int _so_linger; |
||||
private int _so_tos; |
||||
private boolean _so_nodelay; |
||||
|
||||
private void setCachedSocketOptions(int fd) |
||||
{ |
||||
if (fd < 0) { |
||||
return; |
||||
} |
||||
|
||||
// If we previously received a setSoTimeout() call but were unable to process it due
|
||||
// to the fact that the underlying socket didn't even exist yet, do so now.
|
||||
int err = 0; |
||||
ZeroTierSocketOptionValue optval = new ZeroTierSocketOptionValue(); |
||||
|
||||
try { |
||||
// SO_TIMEOUT
|
||||
if (_so_rcvtimeo > 0) { |
||||
optval.isInteger = true; |
||||
optval.isBoolean = false; |
||||
optval.integerValue = ((Integer)_so_rcvtimeo).intValue(); |
||||
if ((err = ZeroTier.setsockopt(fd, ZeroTier.SOL_SOCKET, ZeroTier.SO_RCVTIMEO, optval)) < 0) { |
||||
throw new IOException("socket("+fd+"), errno="+err+", unable to set previously cached SO_RCVTIMEO"); |
||||
} |
||||
} |
||||
// SO_KEEPALIVE
|
||||
if (_so_keepalive == true) { |
||||
optval.isInteger = false; |
||||
optval.isBoolean = true; |
||||
optval.booleanValue = ((Boolean)_so_keepalive).booleanValue() ? true : false; |
||||
if ((err = ZeroTier.setsockopt(fd, ZeroTier.SOL_SOCKET, ZeroTier.SO_KEEPALIVE, optval)) < 0) { |
||||
throw new IOException("socket("+fd+"), errno="+err+", unable to set previously cached SO_KEEPALIVE"); |
||||
} |
||||
} |
||||
// SO_SNDBUF
|
||||
if (_so_sndbuf > 0) { |
||||
optval.isInteger = true; |
||||
optval.isBoolean = false; |
||||
optval.integerValue = ((Integer)_so_sndbuf).intValue(); |
||||
if ((err = ZeroTier.setsockopt(fd, ZeroTier.SOL_SOCKET, ZeroTier.SO_SNDBUF, optval)) < 0) { |
||||
throw new IOException("socket("+fd+"), errno="+err+", unable to set previously cached SO_SNDBUF"); |
||||
} |
||||
} |
||||
// SO_RCVBUF
|
||||
if (_so_rcvbuf > 0) { |
||||
optval.isInteger = true; |
||||
optval.isBoolean = false; |
||||
optval.integerValue = ((Integer)_so_rcvbuf).intValue(); |
||||
if ((err = ZeroTier.setsockopt(fd, ZeroTier.SOL_SOCKET, ZeroTier.SO_RCVBUF, optval)) < 0) { |
||||
throw new IOException("socket("+fd+"), errno="+err+", unable to set previously cached SO_RCVBUF"); |
||||
} |
||||
} |
||||
// SO_REUSEADDR
|
||||
if (_so_reuseaddr == true) { |
||||
optval.isInteger = false; |
||||
optval.isBoolean = true; |
||||
optval.booleanValue = ((Boolean)_so_reuseaddr).booleanValue() ? true : false; |
||||
if ((err = ZeroTier.setsockopt(fd, ZeroTier.SOL_SOCKET, ZeroTier.SO_REUSEADDR, optval)) < 0) { |
||||
throw new IOException("socket("+fd+"), errno="+err+", unable to set previously cached SO_REUSEADDR"); |
||||
} |
||||
} |
||||
// SO_LINGER
|
||||
if (_so_linger > 0) { |
||||
optval.isInteger = true; |
||||
optval.isBoolean = false; |
||||
optval.integerValue = ((Integer)_so_linger).intValue(); |
||||
if ((err = ZeroTier.setsockopt(fd, ZeroTier.SOL_SOCKET, ZeroTier.SO_LINGER, optval)) < 0) { |
||||
throw new IOException("socket("+fd+"), errno="+err+", unable to set previously cached SO_LINGER"); |
||||
} |
||||
} |
||||
// IP_TOS
|
||||
if (_so_tos > 0) { |
||||
optval.isInteger = true; |
||||
optval.isBoolean = false; |
||||
optval.integerValue = ((Integer)_so_tos).intValue(); |
||||
if ((err = ZeroTier.setsockopt(fd, ZeroTier.SOL_SOCKET, ZeroTier.IP_TOS, optval)) < 0) { |
||||
throw new IOException("socket("+fd+"), errno="+err+", unable to set previously cached IP_TOS"); |
||||
} |
||||
} |
||||
// TCP_NODELAY
|
||||
if (_so_nodelay == true) { |
||||
optval.isInteger = false; |
||||
optval.isBoolean = true; |
||||
optval.booleanValue = ((Boolean)_so_nodelay).booleanValue() ? true : false; |
||||
if ((err = ZeroTier.setsockopt(fd, ZeroTier.SOL_SOCKET, ZeroTier.TCP_NODELAY, optval)) < 0) { |
||||
throw new IOException("socket("+fd+"), errno="+err+", unable to set previously cached TCP_NODELAY"); |
||||
} |
||||
} |
||||
} |
||||
catch (Exception e) { |
||||
System.err.println(e); |
||||
} |
||||
} |
||||
|
||||
/* |
||||
* Constructor which creates a new ZeroTierSocketImpl |
||||
*/ |
||||
public ZeroTierSocketImpl() |
||||
{ |
||||
if ((zfd > -1) | (zfd4 > -1) | (zfd6 > -1)) { return; } |
||||
try { |
||||
create(true); |
||||
} catch (Exception x) { |
||||
System.err.println("error creating ZeroTierSocketImpl instance: " + x); |
||||
} |
||||
in.zfd = zfd; |
||||
out.zfd = zfd; |
||||
} |
||||
|
||||
/* |
||||
* Constructor to be called when an underlying ZeroTier socket already exists (does not create a new ZeroTierSocketImpl) |
||||
*/ |
||||
public ZeroTierSocketImpl(int fd) { |
||||
setNativeFileDescriptor(fd); |
||||
} |
||||
|
||||
/* |
||||
* Creates a new ZeroTier socket in the native layer |
||||
*/ |
||||
protected void create(boolean stream) |
||||
throws IOException |
||||
{ |
||||
/* |
||||
* The native-layer socket is only created once a connect/bind call is made, this is due to the fact |
||||
* that beforehand we have no way to determine whether we should create an AF_INET or AF_INET6 socket, |
||||
* as a result, this method intentionally does nothing. |
||||
*/ |
||||
} |
||||
|
||||
/* |
||||
* Creates the underlying libzt socket. |
||||
* |
||||
* This does the real work that can't be done in the constructor. This is because the socket address type |
||||
* isn't known until a connect() or bind() request is given. Additionally we cache the value provided by any |
||||
* setSoTimeout() calls and implement it immediately after creation. |
||||
*/ |
||||
private void createAppropriateSocketImpl(InetAddress addr) |
||||
throws IOException |
||||
{ |
||||
if ((zfd > -1) | (zfd4 > -1) | (zfd6 > -1)) { |
||||
return; // Socket already created
|
||||
} |
||||
if(addr instanceof Inet4Address) { |
||||
if ((zfd4 = ZeroTier.socket(ZeroTier.AF_INET, ZeroTier.SOCK_STREAM, defaultProtocol)) < 0) { |
||||
throw new IOException("socket(), errno="+zfd4+", see: libzt/ext/lwip/src/include/errno.h"); |
||||
} |
||||
setCachedSocketOptions(zfd4); |
||||
} |
||||
/* |
||||
* Since Java creates sockets capable of handling IPV4 and IPV6, we must simulate this. We do this by |
||||
* creating two sockets (one of each type) |
||||
*/ |
||||
if(addr instanceof Inet6Address) { |
||||
if ((zfd4 = ZeroTier.socket(ZeroTier.AF_INET, ZeroTier.SOCK_STREAM, defaultProtocol)) < 0) { |
||||
throw new IOException("socket(), errno="+zfd4+", see: libzt/ext/lwip/src/include/errno.h"); |
||||
} |
||||
if ((zfd6 = ZeroTier.socket(ZeroTier.AF_INET6, ZeroTier.SOCK_STREAM, defaultProtocol)) < 0) { |
||||
throw new IOException("socket(), errno="+zfd6+", see: libzt/ext/lwip/src/include/errno.h"); |
||||
} |
||||
setCachedSocketOptions(zfd4); |
||||
setCachedSocketOptions(zfd6); |
||||
} |
||||
} |
||||
|
||||
/* |
||||
* Return the remote address the socket is connected to |
||||
*/ |
||||
protected InetAddress getInetAddress() |
||||
{ |
||||
return address; |
||||
} |
||||
|
||||
/* |
||||
* Connects the socket to a remote address |
||||
*/ |
||||
protected void connect(String host, int port) |
||||
throws IOException |
||||
{ |
||||
// TODO: Refactor and consolidate the connect() logic for all three methods
|
||||
createAppropriateSocketImpl(InetAddress.getByName(host)); |
||||
if ((zfd4 < 0) & (zfd6 < 0)) { |
||||
throw new IOException("invalid fd"); |
||||
} |
||||
int err; |
||||
InetAddress address = InetAddress.getByName(host); |
||||
ZeroTierSocketAddress zt_addr = new ZeroTierSocketAddress(host, port); |
||||
if (address instanceof Inet4Address) { |
||||
if ((err = ZeroTier.connect(zfd4, zt_addr)) < 0) { |
||||
throw new IOException("connect(), errno="+err+", see: libzt/ext/lwip/src/include/errno.h"); |
||||
} |
||||
setNativeFileDescriptor(zfd4); |
||||
} |
||||
if (address instanceof Inet6Address) { |
||||
if ((err = ZeroTier.connect(zfd6, zt_addr)) < 0) { |
||||
throw new IOException("connect(), errno="+err+", see: libzt/ext/lwip/src/include/errno.h"); |
||||
} |
||||
setNativeFileDescriptor(zfd6); |
||||
} |
||||
super.port = port; |
||||
} |
||||
|
||||
/* |
||||
* Connects the socket to a remote address |
||||
*/ |
||||
protected void connect(InetAddress address, int port) |
||||
throws IOException |
||||
{ |
||||
// TODO: Refactor and consolidate the connect() logic for all three methods
|
||||
createAppropriateSocketImpl(address); |
||||
if ((zfd4 < 0) & (zfd6 < 0)) { |
||||
throw new IOException("invalid fd"); |
||||
} |
||||
int err; |
||||
ZeroTierSocketAddress zt_addr = new ZeroTierSocketAddress(address.getHostAddress(), port); |
||||
if (address instanceof Inet4Address) { |
||||
if ((err = ZeroTier.connect(zfd4, zt_addr)) < 0) { |
||||
throw new IOException("connect(), errno="+err+", see: libzt/ext/lwip/src/include/errno.h"); |
||||
} |
||||
setNativeFileDescriptor(zfd4); |
||||
} |
||||
if (address instanceof Inet6Address) { |
||||
if ((err = ZeroTier.connect(zfd6, zt_addr)) < 0) { |
||||
throw new IOException("connect(), errno="+err+", see: libzt/ext/lwip/src/include/errno.h"); |
||||
} |
||||
setNativeFileDescriptor(zfd6); |
||||
} |
||||
super.port = port; |
||||
} |
||||
|
||||
/* |
||||
* Connects the socket to a remote address |
||||
*/ |
||||
protected void connect(SocketAddress address, int timeout) |
||||
throws IOException |
||||
{ |
||||
// TODO: Refactor and consolidate the connect() logic for all three methods
|
||||
//System.out.println("host="+((InetSocketAddress)address).getHostString()+", port="+((InetSocketAddress)address).getPort() + ", timeout="+timeout);
|
||||
createAppropriateSocketImpl(((InetSocketAddress)address).getAddress()); |
||||
if ((zfd4 < 0) & (zfd6 < 0)) { |
||||
throw new IOException("invalid fd"); |
||||
} |
||||
ZeroTierSocketAddress zt_addr = null; |
||||
int err; |
||||
int port = ((InetSocketAddress)address).getPort(); |
||||
if (((InetSocketAddress)address).getAddress() instanceof Inet4Address) { |
||||
zt_addr = new ZeroTierSocketAddress(((InetSocketAddress)address).getHostString(), ((InetSocketAddress)address).getPort()); |
||||
if ((err = ZeroTier.connect(zfd4, zt_addr)) < 0) { |
||||
throw new IOException("connect("+zfd4+"), errno="+err+", see: libzt/ext/lwip/src/include/errno.h"); |
||||
} |
||||
setNativeFileDescriptor(zfd4); |
||||
} |
||||
if (((InetSocketAddress)address).getAddress() instanceof Inet6Address) { |
||||
zt_addr = new ZeroTierSocketAddress(((InetSocketAddress)address).getHostString(), ((InetSocketAddress)address).getPort()); |
||||
if ((err = ZeroTier.connect(zfd6, zt_addr)) < 0) { |
||||
throw new IOException("connect("+zfd6+"), errno="+err+", see: libzt/ext/lwip/src/include/errno.h"); |
||||
} |
||||
setNativeFileDescriptor(zfd6); |
||||
} |
||||
super.port = port; |
||||
} |
||||
|
||||
/* |
||||
* Binds the socket to a local address. |
||||
* |
||||
* If this gets a bind() request on [::] it will create a both an IPv4 and an IPv6 |
||||
* socket. This is because we might receive a subsequent listen() and accept() request |
||||
* and want to accept an IPv6 connection. (or) we may get a connect() request with |
||||
* an IPv4 address. In the latter case we must abandon the IPv6 socket and use the IPv4 |
||||
* socket exclusively. |
||||
*/ |
||||
protected void bind(InetAddress host, int port) |
||||
throws IOException |
||||
{ |
||||
createAppropriateSocketImpl(host); |
||||
/* |
||||
After this point we may have either a) created a single IPv4 socket, or b) created |
||||
an IPv4 and IPv6 socket in anticipation of either verion being used |
||||
*/ |
||||
//System.out.println("host="+host.toString()+", port="+port);
|
||||
int err; |
||||
if ((zfd < 0) & (zfd4 < 0) & (zfd6 < 0)) { |
||||
throw new IOException("invalid fd"); |
||||
} |
||||
ZeroTierSocketAddress zt_addr = new ZeroTierSocketAddress(host.getHostAddress(), port); |
||||
|
||||
if (zfd6 > -1) { |
||||
// Since an IPv6 socket and accept IPv4 connections we will only bind to this address
|
||||
if ((err = ZeroTier.bind(zfd6, zt_addr)) < 0) { |
||||
throw new IOException("bind("+zfd6+"), errno="+err+", see: libzt/ext/lwip/src/include/errno.h"); |
||||
} |
||||
super.localport = port; |
||||
return; |
||||
} |
||||
if (zfd4 > -1) { |
||||
// Otherwise, just bind to the regular IPv4 address
|
||||
if ((err = ZeroTier.bind(zfd4, zt_addr)) < 0) { |
||||
throw new IOException("bind("+zfd4+"), errno="+err+", see: libzt/ext/lwip/src/include/errno.h"); |
||||
} |
||||
super.localport = port; |
||||
return; |
||||
} |
||||
|
||||
} |
||||
|
||||
/* |
||||
* Puts the socket into a listening state. |
||||
* |
||||
* We listen on the IPv6 socket since it can listen for IPv4 connections |
||||
*/ |
||||
protected void listen(int backlog) |
||||
throws IOException |
||||
{ |
||||
int err; |
||||
if ((zfd6 < 0) | (backlog < 0)) { |
||||
throw new IOException("invalid fd and/or backlog"); |
||||
} |
||||
if ((err = ZeroTier.listen(zfd6, backlog)) < 0) { |
||||
throw new IOException("listen("+zfd6+"), errno="+err+", see: libzt/ext/lwip/src/include/errno.h"); |
||||
} |
||||
} |
||||
|
||||
/* |
||||
* Accepts an incoming connection. |
||||
* |
||||
* We accept on the IPv6 socket since it can accept IPv4 connections |
||||
*/ |
||||
protected void accept(SocketImpl si) |
||||
throws IOException |
||||
{ |
||||
if (zfd6 < 0) { |
||||
throw new IOException("invalid fd"); |
||||
} |
||||
int accetpedFd = -1; |
||||
ZeroTierSocketAddress addr = new ZeroTierSocketAddress(); |
||||
if ((accetpedFd = ZeroTier.accept(zfd6, addr)) < 0) { |
||||
throw new IOException("accept("+zfd6+"), errno="+accetpedFd+", see: libzt/ext/lwip/src/include/errno.h"); |
||||
} |
||||
// Give the new socket fd from the native layer to the new unconnected ZeroTierSocketImpl
|
||||
((ZeroTierSocketImpl)si).setFileDescriptor(accetpedFd); |
||||
} |
||||
|
||||
/* |
||||
* Returns the input stream for this socket |
||||
*/ |
||||
protected ZeroTierInputStream getInputStream() |
||||
throws IOException |
||||
{ |
||||
if (in == null) { |
||||
throw new IOException(); |
||||
} |
||||
return in; |
||||
} |
||||
|
||||
/* |
||||
* Returns the output stream for this socket |
||||
*/ |
||||
protected ZeroTierOutputStream getOutputStream() |
||||
throws IOException |
||||
{ |
||||
if (out == null) { |
||||
throw new IOException(); |
||||
} |
||||
return out; |
||||
} |
||||
|
||||
/* |
||||
* Returns the remote port to which this socket is connected |
||||
*/ |
||||
protected int getPort() |
||||
{ |
||||
return super.port; |
||||
} |
||||
|
||||
/* |
||||
* Returns the local port to which this socket is bound |
||||
*/ |
||||
protected int getLocalPort() |
||||
{ |
||||
return super.localport; |
||||
} |
||||
|
||||
/* |
||||
* Returns whether this socket implementation supports urgent data (hint: it doesn't) |
||||
*/ |
||||
protected boolean supportsUrgentData() |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
/* |
||||
* |
||||
*/ |
||||
void setSocket(ZeroTierSocket soc) |
||||
{ |
||||
this.socket = soc; |
||||
} |
||||
|
||||
/* |
||||
* |
||||
*/ |
||||
Socket getSocket() |
||||
{ |
||||
return socket; |
||||
} |
||||
|
||||
/* |
||||
* |
||||
*/ |
||||
/* |
||||
void setServerSocket(ZeroTierServerSocket soc) |
||||
{ |
||||
this.serverSocket = soc; |
||||
} |
||||
*/ |
||||
|
||||
/* |
||||
* |
||||
*/ |
||||
ServerSocket getServerSocket() |
||||
{ |
||||
return serverSocket; |
||||
} |
||||
|
||||
/* |
||||
* Return the number of bytes that can be read from the socket without blocking |
||||
*/ |
||||
protected int available() |
||||
throws IOException |
||||
{ |
||||
// TODO
|
||||
return 0; |
||||
} |
||||
|
||||
/* |
||||
* Closes the socket |
||||
*/ |
||||
protected void close() |
||||
throws IOException |
||||
{ |
||||
if (zfd > -1) { |
||||
ZeroTier.close(zfd); |
||||
} |
||||
if (zfd4 > -1) { |
||||
ZeroTier.close(zfd4); |
||||
} |
||||
if (zfd6 > -1) { |
||||
ZeroTier.close(zfd6); |
||||
} |
||||
} |
||||
|
||||
/* |
||||
* Send one byte of urgent data on the socket |
||||
*/ |
||||
protected void sendUrgentData(int data) |
||||
throws IOException |
||||
{ |
||||
System.err.println("sendUrgentData: ZeroTierSocketImpl does not currently support this feature"); |
||||
} |
||||
|
||||
/* |
||||
* Gets some specified socket option |
||||
*/ |
||||
public Object getOption(int optID) |
||||
throws SocketException |
||||
{ |
||||
// Call native layer
|
||||
ZeroTierSocketOptionValue optval = new ZeroTierSocketOptionValue(); |
||||
int option = -1; |
||||
int level = -1; |
||||
|
||||
if (zfd < 0) { // If we haven't committed to a socket version yet, cache the value
|
||||
if (optID == SocketOptions.SO_TIMEOUT || optID == ZeroTier.SO_RCVTIMEO) { |
||||
return Integer.valueOf(_so_rcvtimeo); |
||||
} |
||||
if (optID == SocketOptions.SO_KEEPALIVE || optID == ZeroTier.SO_KEEPALIVE) { |
||||
return Boolean.valueOf(_so_keepalive); |
||||
} |
||||
if (optID == SocketOptions.SO_SNDBUF || optID == ZeroTier.SO_SNDBUF) { |
||||
return Integer.valueOf(_so_sndbuf); |
||||
} |
||||
if (optID == SocketOptions.SO_RCVBUF || optID == ZeroTier.SO_RCVBUF) { |
||||
return Integer.valueOf(_so_rcvbuf); |
||||
} |
||||
if (optID == SocketOptions.SO_REUSEADDR || optID == ZeroTier.SO_REUSEADDR) { |
||||
return Boolean.valueOf(_so_reuseaddr); |
||||
} |
||||
if (optID == SocketOptions.SO_LINGER || optID == ZeroTier.SO_LINGER) { |
||||
return Integer.valueOf(_so_linger); |
||||
} |
||||
if (optID == SocketOptions.IP_TOS || optID == ZeroTier.IP_TOS) { |
||||
return Integer.valueOf(_so_tos); |
||||
} |
||||
if (optID == SocketOptions.TCP_NODELAY || optID == ZeroTier.TCP_NODELAY) { |
||||
return Boolean.valueOf(_so_nodelay); |
||||
} |
||||
} |
||||
else { |
||||
if (optID == SocketOptions.SO_TIMEOUT || optID == ZeroTier.SO_RCVTIMEO) { |
||||
option = ZeroTier.SO_RCVTIMEO; |
||||
level = ZeroTier.SOL_SOCKET; |
||||
} |
||||
if (optID == SocketOptions.SO_KEEPALIVE || optID == ZeroTier.SO_KEEPALIVE) { |
||||
option = ZeroTier.SO_KEEPALIVE; |
||||
level = ZeroTier.SOL_SOCKET; |
||||
} |
||||
if (optID == SocketOptions.SO_SNDBUF || optID == ZeroTier.SO_SNDBUF) { |
||||
option = ZeroTier.SO_SNDBUF; |
||||
level = ZeroTier.SOL_SOCKET; |
||||
} |
||||
if (optID == SocketOptions.SO_RCVBUF || optID == ZeroTier.SO_RCVBUF) { |
||||
option = ZeroTier.SO_RCVBUF; |
||||
level = ZeroTier.SOL_SOCKET; |
||||
} |
||||
if (optID == SocketOptions.SO_REUSEADDR || optID == ZeroTier.SO_REUSEADDR) { |
||||
option = ZeroTier.SO_REUSEADDR; |
||||
level = ZeroTier.SOL_SOCKET; |
||||
} |
||||
if (optID == SocketOptions.SO_LINGER || optID == ZeroTier.SO_LINGER) { |
||||
option = ZeroTier.SO_LINGER; |
||||
level = ZeroTier.SOL_SOCKET; |
||||
} |
||||
// IP
|
||||
if (optID == SocketOptions.IP_TOS || optID == ZeroTier.IP_TOS) { |
||||
option = ZeroTier.IP_TOS; |
||||
level = ZeroTier.IPPROTO_IP; |
||||
} |
||||
// TCP
|
||||
if (optID == SocketOptions.TCP_NODELAY || optID == ZeroTier.TCP_NODELAY) { |
||||
option = ZeroTier.TCP_NODELAY; |
||||
level = ZeroTier.IPPROTO_TCP; |
||||
} |
||||
ZeroTier.getsockopt(zfd, level, option, optval); |
||||
// Convert native layer's response into Java object of some sort
|
||||
if (optval.isBoolean) { |
||||
return Boolean.valueOf(optval.booleanValue); |
||||
} |
||||
if (optval.isInteger) { |
||||
return Integer.valueOf(optval.integerValue); |
||||
} |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
/* |
||||
* Sets a socket option to a specified value. This method should be able to handle SocketOptions values |
||||
* as well as native ZeroTier.* options |
||||
*/ |
||||
public void setOption(int optID, Object value) |
||||
throws SocketException |
||||
{ |
||||
if (value == null) { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
int option = -1; |
||||
int level = -1; |
||||
|
||||
ZeroTierSocketOptionValue optval = new ZeroTierSocketOptionValue(); |
||||
|
||||
if (zfd < 0) { // If we haven't committed to a socket version yet, cache the value
|
||||
if (optID == SocketOptions.SO_TIMEOUT || optID == ZeroTier.SO_RCVTIMEO) { |
||||
_so_rcvtimeo = ((Integer)value).intValue(); return; |
||||
} |
||||
if (optID == SocketOptions.SO_KEEPALIVE || optID == ZeroTier.SO_KEEPALIVE) { |
||||
_so_keepalive = ((Boolean)value).booleanValue() ? true : false; return; |
||||
} |
||||
if (optID == SocketOptions.SO_SNDBUF || optID == ZeroTier.SO_SNDBUF) { |
||||
_so_sndbuf = ((Integer)value).intValue(); return; |
||||
} |
||||
if (optID == SocketOptions.SO_RCVBUF || optID == ZeroTier.SO_RCVBUF) { |
||||
_so_rcvbuf = ((Integer)value).intValue(); return; |
||||
} |
||||
if (optID == SocketOptions.SO_REUSEADDR || optID == ZeroTier.SO_REUSEADDR) { |
||||
_so_reuseaddr = ((Boolean)value).booleanValue() ? true : false; return; |
||||
} |
||||
if (optID == SocketOptions.SO_LINGER || optID == ZeroTier.SO_LINGER) { |
||||
_so_linger = ((Integer)value).intValue(); return; |
||||
} |
||||
if (optID == SocketOptions.IP_TOS || optID == ZeroTier.IP_TOS) { |
||||
_so_tos = ((Integer)value).intValue(); return; |
||||
} |
||||
if (optID == SocketOptions.TCP_NODELAY || optID == ZeroTier.TCP_NODELAY) { |
||||
_so_nodelay = ((Boolean)value).booleanValue() ? true : false; return; |
||||
} |
||||
} |
||||
else { |
||||
// SOL
|
||||
if (optID == SocketOptions.SO_TIMEOUT || optID == ZeroTier.SO_RCVTIMEO) { |
||||
option = ZeroTier.SO_RCVTIMEO; |
||||
level = ZeroTier.SOL_SOCKET; |
||||
if (value instanceof Integer) { |
||||
optval.isInteger = true; |
||||
optval.integerValue = ((Integer)value).intValue(); |
||||
} |
||||
} |
||||
|
||||
if (optID == SocketOptions.SO_KEEPALIVE || optID == ZeroTier.SO_KEEPALIVE) { |
||||
option = ZeroTier.SO_KEEPALIVE; |
||||
level = ZeroTier.SOL_SOCKET; |
||||
if (value instanceof Integer) { |
||||
optval.isBoolean = true; |
||||
optval.booleanValue = ((Boolean)value).booleanValue() ? true : false; |
||||
} |
||||
} |
||||
if (optID == SocketOptions.SO_SNDBUF || optID == ZeroTier.SO_SNDBUF) { |
||||
option = ZeroTier.SO_SNDBUF; |
||||
level = ZeroTier.SOL_SOCKET; |
||||
if (value instanceof Integer) { |
||||
optval.isInteger = true; |
||||
optval.integerValue = ((Integer)value).intValue(); |
||||
} |
||||
} |
||||
if (optID == SocketOptions.SO_RCVBUF || optID == ZeroTier.SO_RCVBUF) { |
||||
option = ZeroTier.SO_RCVBUF; |
||||
level = ZeroTier.SOL_SOCKET; |
||||
if (value instanceof Integer) { |
||||
optval.isInteger = true; |
||||
optval.integerValue = ((Integer)value).intValue(); |
||||
} |
||||
} |
||||
if (optID == SocketOptions.SO_REUSEADDR || optID == ZeroTier.SO_REUSEADDR) { |
||||
option = ZeroTier.SO_REUSEADDR; |
||||
level = ZeroTier.SOL_SOCKET; |
||||
if (value instanceof Integer) { |
||||
optval.isBoolean = true; |
||||
optval.booleanValue = ((Boolean)value).booleanValue() ? true : false; |
||||
} |
||||
} |
||||
if (optID == SocketOptions.SO_LINGER || optID == ZeroTier.SO_LINGER) { |
||||
option = ZeroTier.SO_LINGER; |
||||
level = ZeroTier.SOL_SOCKET; |
||||
if (value instanceof Integer) { |
||||
optval.isInteger = true; |
||||
optval.integerValue = ((Integer)value).intValue(); |
||||
} |
||||
} |
||||
// IP
|
||||
if (optID == SocketOptions.IP_TOS || optID == ZeroTier.IP_TOS) { |
||||
option = ZeroTier.IP_TOS; |
||||
level = ZeroTier.IPPROTO_IP; |
||||
if (value instanceof Integer) { |
||||
optval.isInteger = true; |
||||
optval.integerValue = ((Integer)value).intValue(); |
||||
} |
||||
} |
||||
// TCP
|
||||
if (optID == SocketOptions.TCP_NODELAY || optID == ZeroTier.TCP_NODELAY) { |
||||
option = ZeroTier.TCP_NODELAY; |
||||
level = ZeroTier.IPPROTO_TCP; |
||||
if (value instanceof Integer) { |
||||
optval.isBoolean = true; |
||||
optval.booleanValue = ((Boolean)value).booleanValue() ? true : false; |
||||
} |
||||
} |
||||
|
||||
if (option < 0) { // No option was properly set
|
||||
//throw new UnsupportedOperationException();
|
||||
} |
||||
ZeroTier.setsockopt(zfd, level, option, optval); |
||||
} |
||||
} |
||||
|
||||
/* |
||||
* Disables the input aspect of the socket |
||||
*/ |
||||
public void shutdownInput() |
||||
{ |
||||
ZeroTier.shutdown(zfd, ZeroTier.SHUT_RD); |
||||
// Alternatively: getInputStream().close();
|
||||
} |
||||
|
||||
/* |
||||
* Disables the output aspect of the socket |
||||
*/ |
||||
public void shutdownOutput() |
||||
{ |
||||
ZeroTier.shutdown(zfd, ZeroTier.SHUT_WR); |
||||
// Alternatively: getOutputStream().close();
|
||||
} |
||||
|
||||
/* |
||||
* Sets the file descriptor |
||||
*/ |
||||
public void setFileDescriptor(int fd) |
||||
{ |
||||
zfd = fd; |
||||
} |
||||
|
||||
/* |
||||
* Resets the socket |
||||
*/ |
||||
void reset() |
||||
throws IOException |
||||
{ |
||||
localport = 0; |
||||
address = null; |
||||
port = 0; |
||||
} |
||||
|
||||
public FileDescriptor getFileDescriptor() |
||||
{ |
||||
// TODO: Should probably remove this for production
|
||||
System.out.println("getFileDescriptor(), zfd="+zfd); |
||||
ParcelFileDescriptor pfd = ParcelFileDescriptor.adoptFd(zfd); |
||||
return pfd.getFileDescriptor(); |
||||
} |
||||
} |
||||
@ -0,0 +1,29 @@
|
||||
package com.zerotier.libzt; |
||||
|
||||
import com.zerotier.libzt.ZeroTier; |
||||
import com.zerotier.libzt.ZeroTierSocketImpl; |
||||
|
||||
import java.io.IOException; |
||||
import java.net.InetAddress; |
||||
import java.net.Socket; |
||||
import java.net.UnknownHostException; |
||||
import javax.net.SocketFactory; |
||||
import java.net.SocketImplFactory; |
||||
import java.util.Objects; |
||||
|
||||
|
||||
public class ZeroTierSocketImplFactory implements SocketImplFactory |
||||
{ |
||||
/* |
||||
* Does nothing |
||||
*/ |
||||
public ZeroTierSocketImplFactory() { } |
||||
|
||||
/* |
||||
* Produces a ZeroTierSocketImpl |
||||
*/ |
||||
public ZeroTierSocketImpl createSocketImpl() |
||||
{ |
||||
return new ZeroTierSocketImpl(); |
||||
} |
||||
} |
||||
@ -0,0 +1,14 @@
|
||||
package com.zerotier.libzt; |
||||
|
||||
public class ZeroTierSocketOptionValue |
||||
{ |
||||
public boolean isBoolean = false; |
||||
public boolean booleanValue; |
||||
|
||||
public boolean isInteger = false; |
||||
public int integerValue; |
||||
|
||||
public boolean isTimeval = false; |
||||
public int tv_sec; // seconds
|
||||
public int tv_usec; // microseconds
|
||||
} |
||||
@ -0,0 +1,34 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
||||
xmlns:aapt="http://schemas.android.com/aapt" |
||||
android:width="108dp" |
||||
android:height="108dp" |
||||
android:viewportHeight="108" |
||||
android:viewportWidth="108"> |
||||
<path |
||||
android:fillType="evenOdd" |
||||
android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z" |
||||
android:strokeColor="#00000000" |
||||
android:strokeWidth="1"> |
||||
<aapt:attr name="android:fillColor"> |
||||
<gradient |
||||
android:endX="78.5885" |
||||
android:endY="90.9159" |
||||
android:startX="48.7653" |
||||
android:startY="61.0927" |
||||
android:type="linear"> |
||||
<item |
||||
android:color="#44000000" |
||||
android:offset="0.0" /> |
||||
<item |
||||
android:color="#00000000" |
||||
android:offset="1.0" /> |
||||
</gradient> |
||||
</aapt:attr> |
||||
</path> |
||||
<path |
||||
android:fillColor="#FFFFFF" |
||||
android:fillType="nonZero" |
||||
android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z" |
||||
android:strokeColor="#00000000" |
||||
android:strokeWidth="1" /> |
||||
</vector> |
||||
@ -0,0 +1,170 @@
|
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
||||
android:width="108dp" |
||||
android:height="108dp" |
||||
android:viewportHeight="108" |
||||
android:viewportWidth="108"> |
||||
<path |
||||
android:fillColor="#26A69A" |
||||
android:pathData="M0,0h108v108h-108z" /> |
||||
<path |
||||
android:fillColor="#00000000" |
||||
android:pathData="M9,0L9,108" |
||||
android:strokeColor="#33FFFFFF" |
||||
android:strokeWidth="0.8" /> |
||||
<path |
||||
android:fillColor="#00000000" |
||||
android:pathData="M19,0L19,108" |
||||
android:strokeColor="#33FFFFFF" |
||||
android:strokeWidth="0.8" /> |
||||
<path |
||||
android:fillColor="#00000000" |
||||
android:pathData="M29,0L29,108" |
||||
android:strokeColor="#33FFFFFF" |
||||
android:strokeWidth="0.8" /> |
||||
<path |
||||
android:fillColor="#00000000" |
||||
android:pathData="M39,0L39,108" |
||||
android:strokeColor="#33FFFFFF" |
||||
android:strokeWidth="0.8" /> |
||||
<path |
||||
android:fillColor="#00000000" |
||||
android:pathData="M49,0L49,108" |
||||
android:strokeColor="#33FFFFFF" |
||||
android:strokeWidth="0.8" /> |
||||
<path |
||||
android:fillColor="#00000000" |
||||
android:pathData="M59,0L59,108" |
||||
android:strokeColor="#33FFFFFF" |
||||
android:strokeWidth="0.8" /> |
||||
<path |
||||
android:fillColor="#00000000" |
||||
android:pathData="M69,0L69,108" |
||||
android:strokeColor="#33FFFFFF" |
||||
android:strokeWidth="0.8" /> |
||||
<path |
||||
android:fillColor="#00000000" |
||||
android:pathData="M79,0L79,108" |
||||
android:strokeColor="#33FFFFFF" |
||||
android:strokeWidth="0.8" /> |
||||
<path |
||||
android:fillColor="#00000000" |
||||
android:pathData="M89,0L89,108" |
||||
android:strokeColor="#33FFFFFF" |
||||
android:strokeWidth="0.8" /> |
||||
<path |
||||
android:fillColor="#00000000" |
||||
android:pathData="M99,0L99,108" |
||||
android:strokeColor="#33FFFFFF" |
||||
android:strokeWidth="0.8" /> |
||||
<path |
||||
android:fillColor="#00000000" |
||||
android:pathData="M0,9L108,9" |
||||
android:strokeColor="#33FFFFFF" |
||||
android:strokeWidth="0.8" /> |
||||
<path |
||||
android:fillColor="#00000000" |
||||
android:pathData="M0,19L108,19" |
||||
android:strokeColor="#33FFFFFF" |
||||
android:strokeWidth="0.8" /> |
||||
<path |
||||
android:fillColor="#00000000" |
||||
android:pathData="M0,29L108,29" |
||||
android:strokeColor="#33FFFFFF" |
||||
android:strokeWidth="0.8" /> |
||||
<path |
||||
android:fillColor="#00000000" |
||||
android:pathData="M0,39L108,39" |
||||
android:strokeColor="#33FFFFFF" |
||||
android:strokeWidth="0.8" /> |
||||
<path |
||||
android:fillColor="#00000000" |
||||
android:pathData="M0,49L108,49" |
||||
android:strokeColor="#33FFFFFF" |
||||
android:strokeWidth="0.8" /> |
||||
<path |
||||
android:fillColor="#00000000" |
||||
android:pathData="M0,59L108,59" |
||||
android:strokeColor="#33FFFFFF" |
||||
android:strokeWidth="0.8" /> |
||||
<path |
||||
android:fillColor="#00000000" |
||||
android:pathData="M0,69L108,69" |
||||
android:strokeColor="#33FFFFFF" |
||||
android:strokeWidth="0.8" /> |
||||
<path |
||||
android:fillColor="#00000000" |
||||
android:pathData="M0,79L108,79" |
||||
android:strokeColor="#33FFFFFF" |
||||
android:strokeWidth="0.8" /> |
||||
<path |
||||
android:fillColor="#00000000" |
||||
android:pathData="M0,89L108,89" |
||||
android:strokeColor="#33FFFFFF" |
||||
android:strokeWidth="0.8" /> |
||||
<path |
||||
android:fillColor="#00000000" |
||||
android:pathData="M0,99L108,99" |
||||
android:strokeColor="#33FFFFFF" |
||||
android:strokeWidth="0.8" /> |
||||
<path |
||||
android:fillColor="#00000000" |
||||
android:pathData="M19,29L89,29" |
||||
android:strokeColor="#33FFFFFF" |
||||
android:strokeWidth="0.8" /> |
||||
<path |
||||
android:fillColor="#00000000" |
||||
android:pathData="M19,39L89,39" |
||||
android:strokeColor="#33FFFFFF" |
||||
android:strokeWidth="0.8" /> |
||||
<path |
||||
android:fillColor="#00000000" |
||||
android:pathData="M19,49L89,49" |
||||
android:strokeColor="#33FFFFFF" |
||||
android:strokeWidth="0.8" /> |
||||
<path |
||||
android:fillColor="#00000000" |
||||
android:pathData="M19,59L89,59" |
||||
android:strokeColor="#33FFFFFF" |
||||
android:strokeWidth="0.8" /> |
||||
<path |
||||
android:fillColor="#00000000" |
||||
android:pathData="M19,69L89,69" |
||||
android:strokeColor="#33FFFFFF" |
||||
android:strokeWidth="0.8" /> |
||||
<path |
||||
android:fillColor="#00000000" |
||||
android:pathData="M19,79L89,79" |
||||
android:strokeColor="#33FFFFFF" |
||||
android:strokeWidth="0.8" /> |
||||
<path |
||||
android:fillColor="#00000000" |
||||
android:pathData="M29,19L29,89" |
||||
android:strokeColor="#33FFFFFF" |
||||
android:strokeWidth="0.8" /> |
||||
<path |
||||
android:fillColor="#00000000" |
||||
android:pathData="M39,19L39,89" |
||||
android:strokeColor="#33FFFFFF" |
||||
android:strokeWidth="0.8" /> |
||||
<path |
||||
android:fillColor="#00000000" |
||||
android:pathData="M49,19L49,89" |
||||
android:strokeColor="#33FFFFFF" |
||||
android:strokeWidth="0.8" /> |
||||
<path |
||||
android:fillColor="#00000000" |
||||
android:pathData="M59,19L59,89" |
||||
android:strokeColor="#33FFFFFF" |
||||
android:strokeWidth="0.8" /> |
||||
<path |
||||
android:fillColor="#00000000" |
||||
android:pathData="M69,19L69,89" |
||||
android:strokeColor="#33FFFFFF" |
||||
android:strokeWidth="0.8" /> |
||||
<path |
||||
android:fillColor="#00000000" |
||||
android:pathData="M79,19L79,89" |
||||
android:strokeColor="#33FFFFFF" |
||||
android:strokeWidth="0.8" /> |
||||
</vector> |
||||
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||
xmlns:app="http://schemas.android.com/apk/res-auto" |
||||
xmlns:tools="http://schemas.android.com/tools" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="match_parent" |
||||
tools:context=".MainActivity"> |
||||
|
||||
<TextView |
||||
android:id="@+id/sample_text" |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:text="Hello World!" |
||||
app:layout_constraintBottom_toBottomOf="parent" |
||||
app:layout_constraintLeft_toLeftOf="parent" |
||||
app:layout_constraintRight_toRightOf="parent" |
||||
app:layout_constraintTop_toTopOf="parent" /> |
||||
|
||||
</android.support.constraint.ConstraintLayout> |
||||
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> |
||||
<background android:drawable="@drawable/ic_launcher_background" /> |
||||
<foreground android:drawable="@drawable/ic_launcher_foreground" /> |
||||
</adaptive-icon> |
||||
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> |
||||
<background android:drawable="@drawable/ic_launcher_background" /> |
||||
<foreground android:drawable="@drawable/ic_launcher_foreground" /> |
||||
</adaptive-icon> |
||||
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 4.9 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 6.9 KiB |
|
After Width: | Height: | Size: 6.3 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 9.0 KiB |
|
After Width: | Height: | Size: 15 KiB |
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<resources> |
||||
<color name="colorPrimary">#3F51B5</color> |
||||
<color name="colorPrimaryDark">#303F9F</color> |
||||
<color name="colorAccent">#FF4081</color> |
||||
</resources> |
||||
@ -0,0 +1,3 @@
|
||||
<resources> |
||||
<string name="app_name">ZeroTier</string> |
||||
</resources> |
||||
@ -0,0 +1,11 @@
|
||||
<resources> |
||||
|
||||
<!-- Base application theme. --> |
||||
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> |
||||
<!-- Customize your theme here. --> |
||||
<item name="colorPrimary">@color/colorPrimary</item> |
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item> |
||||
<item name="colorAccent">@color/colorAccent</item> |
||||
</style> |
||||
|
||||
</resources> |
||||
@ -0,0 +1,17 @@
|
||||
package com.example.zerotier; |
||||
|
||||
import org.junit.Test; |
||||
|
||||
import static org.junit.Assert.*; |
||||
|
||||
/** |
||||
* Example local unit test, which will execute on the development machine (host). |
||||
* |
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a> |
||||
*/ |
||||
public class ExampleUnitTest { |
||||
@Test |
||||
public void addition_isCorrect() { |
||||
assertEquals(4, 2 + 2); |
||||
} |
||||
} |
||||
@ -0,0 +1,27 @@
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules. |
||||
|
||||
buildscript { |
||||
|
||||
repositories { |
||||
google() |
||||
jcenter() |
||||
} |
||||
dependencies { |
||||
classpath 'com.android.tools.build:gradle:3.1.3' |
||||
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong |
||||
// in the individual module build.gradle files |
||||
} |
||||
} |
||||
|
||||
allprojects { |
||||
repositories { |
||||
google() |
||||
jcenter() |
||||
} |
||||
} |
||||
|
||||
task clean(type: Delete) { |
||||
delete rootProject.buildDir |
||||
} |
||||
@ -0,0 +1,13 @@
|
||||
# Project-wide Gradle settings. |
||||
# IDE (e.g. Android Studio) users: |
||||
# Gradle settings configured through the IDE *will override* |
||||
# any settings specified in this file. |
||||
# For more details on how to configure your build environment visit |
||||
# http://www.gradle.org/docs/current/userguide/build_environment.html |
||||
# Specifies the JVM arguments used for the daemon process. |
||||
# The setting is particularly useful for tweaking memory settings. |
||||
org.gradle.jvmargs=-Xmx1536m |
||||
# When configured, Gradle will run in incubating parallel mode. |
||||
# This option should only be used with decoupled projects. More details, visit |
||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects |
||||
# org.gradle.parallel=true |
||||
@ -0,0 +1,6 @@
|
||||
#Wed Jul 18 09:57:38 PDT 2018 |
||||
distributionBase=GRADLE_USER_HOME |
||||
distributionPath=wrapper/dists |
||||
zipStoreBase=GRADLE_USER_HOME |
||||
zipStorePath=wrapper/dists |
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip |
||||
@ -0,0 +1,172 @@
|
||||
#!/usr/bin/env sh |
||||
|
||||
############################################################################## |
||||
## |
||||
## Gradle start up script for UN*X |
||||
## |
||||
############################################################################## |
||||
|
||||
# Attempt to set APP_HOME |
||||
# Resolve links: $0 may be a link |
||||
PRG="$0" |
||||
# Need this for relative symlinks. |
||||
while [ -h "$PRG" ] ; do |
||||
ls=`ls -ld "$PRG"` |
||||
link=`expr "$ls" : '.*-> \(.*\)$'` |
||||
if expr "$link" : '/.*' > /dev/null; then |
||||
PRG="$link" |
||||
else |
||||
PRG=`dirname "$PRG"`"/$link" |
||||
fi |
||||
done |
||||
SAVED="`pwd`" |
||||
cd "`dirname \"$PRG\"`/" >/dev/null |
||||
APP_HOME="`pwd -P`" |
||||
cd "$SAVED" >/dev/null |
||||
|
||||
APP_NAME="Gradle" |
||||
APP_BASE_NAME=`basename "$0"` |
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. |
||||
DEFAULT_JVM_OPTS="" |
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value. |
||||
MAX_FD="maximum" |
||||
|
||||
warn () { |
||||
echo "$*" |
||||
} |
||||
|
||||
die () { |
||||
echo |
||||
echo "$*" |
||||
echo |
||||
exit 1 |
||||
} |
||||
|
||||
# OS specific support (must be 'true' or 'false'). |
||||
cygwin=false |
||||
msys=false |
||||
darwin=false |
||||
nonstop=false |
||||
case "`uname`" in |
||||
CYGWIN* ) |
||||
cygwin=true |
||||
;; |
||||
Darwin* ) |
||||
darwin=true |
||||
;; |
||||
MINGW* ) |
||||
msys=true |
||||
;; |
||||
NONSTOP* ) |
||||
nonstop=true |
||||
;; |
||||
esac |
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar |
||||
|
||||
# Determine the Java command to use to start the JVM. |
||||
if [ -n "$JAVA_HOME" ] ; then |
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then |
||||
# IBM's JDK on AIX uses strange locations for the executables |
||||
JAVACMD="$JAVA_HOME/jre/sh/java" |
||||
else |
||||
JAVACMD="$JAVA_HOME/bin/java" |
||||
fi |
||||
if [ ! -x "$JAVACMD" ] ; then |
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME |
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the |
||||
location of your Java installation." |
||||
fi |
||||
else |
||||
JAVACMD="java" |
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. |
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the |
||||
location of your Java installation." |
||||
fi |
||||
|
||||
# Increase the maximum file descriptors if we can. |
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then |
||||
MAX_FD_LIMIT=`ulimit -H -n` |
||||
if [ $? -eq 0 ] ; then |
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then |
||||
MAX_FD="$MAX_FD_LIMIT" |
||||
fi |
||||
ulimit -n $MAX_FD |
||||
if [ $? -ne 0 ] ; then |
||||
warn "Could not set maximum file descriptor limit: $MAX_FD" |
||||
fi |
||||
else |
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" |
||||
fi |
||||
fi |
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock |
||||
if $darwin; then |
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" |
||||
fi |
||||
|
||||
# For Cygwin, switch paths to Windows format before running java |
||||
if $cygwin ; then |
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"` |
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` |
||||
JAVACMD=`cygpath --unix "$JAVACMD"` |
||||
|
||||
# We build the pattern for arguments to be converted via cygpath |
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` |
||||
SEP="" |
||||
for dir in $ROOTDIRSRAW ; do |
||||
ROOTDIRS="$ROOTDIRS$SEP$dir" |
||||
SEP="|" |
||||
done |
||||
OURCYGPATTERN="(^($ROOTDIRS))" |
||||
# Add a user-defined pattern to the cygpath arguments |
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then |
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" |
||||
fi |
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh |
||||
i=0 |
||||
for arg in "$@" ; do |
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` |
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option |
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition |
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` |
||||
else |
||||
eval `echo args$i`="\"$arg\"" |
||||
fi |
||||
i=$((i+1)) |
||||
done |
||||
case $i in |
||||
(0) set -- ;; |
||||
(1) set -- "$args0" ;; |
||||
(2) set -- "$args0" "$args1" ;; |
||||
(3) set -- "$args0" "$args1" "$args2" ;; |
||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;; |
||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; |
||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; |
||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; |
||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; |
||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; |
||||
esac |
||||
fi |
||||
|
||||
# Escape application args |
||||
save () { |
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done |
||||
echo " " |
||||
} |
||||
APP_ARGS=$(save "$@") |
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules |
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" |
||||
|
||||
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong |
||||
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then |
||||
cd "$(dirname "$0")" |
||||
fi |
||||
|
||||
exec "$JAVACMD" "$@" |
||||
@ -0,0 +1,84 @@
|
||||
@if "%DEBUG%" == "" @echo off |
||||
@rem ########################################################################## |
||||
@rem |
||||
@rem Gradle startup script for Windows |
||||
@rem |
||||
@rem ########################################################################## |
||||
|
||||
@rem Set local scope for the variables with windows NT shell |
||||
if "%OS%"=="Windows_NT" setlocal |
||||
|
||||
set DIRNAME=%~dp0 |
||||
if "%DIRNAME%" == "" set DIRNAME=. |
||||
set APP_BASE_NAME=%~n0 |
||||
set APP_HOME=%DIRNAME% |
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. |
||||
set DEFAULT_JVM_OPTS= |
||||
|
||||
@rem Find java.exe |
||||
if defined JAVA_HOME goto findJavaFromJavaHome |
||||
|
||||
set JAVA_EXE=java.exe |
||||
%JAVA_EXE% -version >NUL 2>&1 |
||||
if "%ERRORLEVEL%" == "0" goto init |
||||
|
||||
echo. |
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. |
||||
echo. |
||||
echo Please set the JAVA_HOME variable in your environment to match the |
||||
echo location of your Java installation. |
||||
|
||||
goto fail |
||||
|
||||
:findJavaFromJavaHome |
||||
set JAVA_HOME=%JAVA_HOME:"=% |
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe |
||||
|
||||
if exist "%JAVA_EXE%" goto init |
||||
|
||||
echo. |
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% |
||||
echo. |
||||
echo Please set the JAVA_HOME variable in your environment to match the |
||||
echo location of your Java installation. |
||||
|
||||
goto fail |
||||
|
||||
:init |
||||
@rem Get command-line arguments, handling Windows variants |
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args |
||||
|
||||
:win9xME_args |
||||
@rem Slurp the command line arguments. |
||||
set CMD_LINE_ARGS= |
||||
set _SKIP=2 |
||||
|
||||
:win9xME_args_slurp |
||||
if "x%~1" == "x" goto execute |
||||
|
||||
set CMD_LINE_ARGS=%* |
||||
|
||||
:execute |
||||
@rem Setup the command line |
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar |
||||
|
||||
@rem Execute Gradle |
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% |
||||
|
||||
:end |
||||
@rem End local scope for the variables with windows NT shell |
||||
if "%ERRORLEVEL%"=="0" goto mainEnd |
||||
|
||||
:fail |
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of |
||||
rem the _cmd.exe /c_ return code! |
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 |
||||
exit /b 1 |
||||
|
||||
:mainEnd |
||||
if "%OS%"=="Windows_NT" endlocal |
||||
|
||||
:omega |
||||
@ -0,0 +1,4 @@
|
||||
rd /S /Q bin |
||||
rd /S /Q build |
||||
rd /S /Q WinBuild32 |
||||
rd /S /Q WinBuild64 |
||||
@ -0,0 +1,7 @@
|
||||
#!/bin/bash |
||||
|
||||
rm -rf bin build products tmp |
||||
rm -f *.o *.s *.exp *.lib .depend* *.core core |
||||
rm -rf .depend |
||||
find . -type f \( -name '*.o' -o -name '*.o.d' -o -name \ |
||||
'*.out' -o -name '*.log' -o -name '*.dSYM' -o -name '*.class' \) -delete |
||||
@ -0,0 +1,88 @@
|
||||
REM Build all target configurations and copy results into "prebuilt" |
||||
|
||||
set PrebuiltDebugWin32Dir=staging\debug\win32 |
||||
set PrebuiltDebugWin64Dir=staging\debug\win64 |
||||
set PrebuiltReleaseWin32Dir=staging\release\win32 |
||||
set PrebuiltReleaseWin64Dir=staging\release\win64 |
||||
|
||||
mkdir %PrebuiltDebugWin32Dir% |
||||
mkdir %PrebuiltDebugWin64Dir% |
||||
mkdir %PrebuiltReleaseWin32Dir% |
||||
mkdir %PrebuiltReleaseWin64Dir% |
||||
|
||||
set DebugWinBuildDir=bin\lib\Debug |
||||
set ReleaseWinBuildDir=bin\lib\Release |
||||
|
||||
mkdir WinBuild32 & pushd WinBuild32 |
||||
cmake -G "Visual Studio 15 2017" ../ |
||||
popd |
||||
mkdir WinBuild64 & pushd WinBuild64 |
||||
cmake -G "Visual Studio 15 2017 Win64" ../ |
||||
popd |
||||
|
||||
cmake --build WinBuild32 --config Release |
||||
cmake --build WinBuild32 --config Debug |
||||
|
||||
copy %DebugWinBuildDir%\zt-static.lib %PrebuiltDebugWin32Dir%\zt.lib |
||||
copy %DebugWinBuildDir%\zt-shared.dll %PrebuiltDebugWin32Dir%\zt.dll |
||||
copy %ReleaseWinBuildDir%\zt-static.lib %PrebuiltReleaseWin32Dir%\zt.lib |
||||
copy %ReleaseWinBuildDir%\zt-shared.dll %PrebuiltReleaseWin32Dir%\zt.dll |
||||
|
||||
cmake --build WinBuild64 --config Release |
||||
cmake --build WinBuild64 --config Debug |
||||
|
||||
copy %DebugWinBuildDir%\zt-static.lib %PrebuiltDebugWin64Dir%\zt.lib |
||||
copy %DebugWinBuildDir%\zt-shared.dll %PrebuiltDebugWin64Dir%\zt.dll |
||||
copy %ReleaseWinBuildDir%\zt-static.lib %PrebuiltReleaseWin64Dir%\zt.lib |
||||
copy %ReleaseWinBuildDir%\zt-shared.dll %PrebuiltReleaseWin64Dir%\zt.dll |
||||
|
||||
rd /S /Q bin |
||||
|
||||
# Build with JNI |
||||
|
||||
mkdir WinBuild32 & pushd WinBuild32 |
||||
cmake -D JNI:BOOL=ON -G "Visual Studio 15 2017" ../ |
||||
popd |
||||
mkdir WinBuild64 & pushd WinBuild64 |
||||
cmake -D JNI:BOOL=ON -G "Visual Studio 15 2017 Win64" ../ |
||||
popd |
||||
|
||||
cmake --build WinBuild32 --config Release |
||||
cmake --build WinBuild32 --config Debug |
||||
|
||||
REM Build JAR file |
||||
REM release variant |
||||
cd packages\java |
||||
del com/zerotier/libzt/*.class |
||||
move ..\..\%ReleaseWinBuildDir%\zt-shared.dll zt.dll |
||||
javac com/zerotier/libzt/*.java |
||||
jar cf zt.jar zt.dll com/zerotier/libzt/*.class |
||||
move zt.jar ..\..\%PrebuiltReleaseWin32Dir% |
||||
REM debug variant |
||||
del com/zerotier/libzt/*.class |
||||
move ..\..\%DebugWinBuildDir%\zt-shared.dll zt.dll |
||||
javac com/zerotier/libzt/*.java |
||||
jar cf zt.jar zt.dll com/zerotier/libzt/*.class |
||||
move zt.jar ..\..\%PrebuiltDebugWin32Dir% |
||||
popd |
||||
popd |
||||
|
||||
cmake --build WinBuild64 --config Release |
||||
cmake --build WinBuild64 --config Debug |
||||
|
||||
REM Build JAR file |
||||
REM release variant |
||||
cd packages\java |
||||
del com/zerotier/libzt/*.class |
||||
move ..\..\%ReleaseWinBuildDir%\zt-shared.dll zt.dll |
||||
javac com/zerotier/libzt/*.java |
||||
jar cf zt.jar zt.dll com/zerotier/libzt/*.class |
||||
move zt.jar ..\..\%PrebuiltReleaseWin64Dir% |
||||
REM debug variant |
||||
del com/zerotier/libzt/*.class |
||||
move ..\..\%DebugWinBuildDir%\zt-shared.dll zt.dll |
||||
javac com/zerotier/libzt/*.java |
||||
jar cf zt.jar zt.dll com/zerotier/libzt/*.class |
||||
move zt.jar ..\..\%PrebuiltDebugWin64Dir% |
||||
popd |
||||
popd |
||||
@ -0,0 +1,184 @@
|
||||
#!/bin/bash |
||||
|
||||
# Call this script from the root project directory via `make dist` |
||||
# - submodules will be recursively initialized and updated |
||||
# - patches will be applied to submodules if needed |
||||
# - this script will call CMake to generate library-building packages if necessary |
||||
# - once projects have been generated, this script will use their tooling to build the libraries/packages |
||||
# - when all products have been built and moved to `tmp`, they will be compressed and moved to `products` |
||||
|
||||
OSNAME=$(uname | tr '[A-Z]' '[a-z]') |
||||
BUILD_CONCURRENCY=4 |
||||
PROJROOT=$(pwd) |
||||
BUILD_PRODUCTS_DIR=$(pwd)/bin |
||||
LIB_PRODUCTS_DIR=$BUILD_PRODUCTS_DIR/lib |
||||
FINISHED_PRODUCTS_DIR=$(pwd)/products |
||||
STAGING_DIR=$(pwd)/staging |
||||
# Windows (previously built) |
||||
WIN_PREBUILT_DIR=$PROJROOT/staging/win |
||||
WIN_RELEASE_PRODUCTS_DIR=$WIN_PREBUILT_DIR/release |
||||
WIN_DEBUG_PRODUCTS_DIR=$WIN_PREBUILT_DIR/debug |
||||
WIN32_RELEASE_PRODUCTS_DIR=$WIN_RELEASE_PRODUCTS_DIR/win32 |
||||
WIN64_RELEASE_PRODUCTS_DIR=$WIN_RELEASE_PRODUCTS_DIR/win64 |
||||
WIN32_DEBUG_PRODUCTS_DIR=$WIN_DEBUG_PRODUCTS_DIR/win32 |
||||
WIN64_DEBUG_PRODUCTS_DIR=$WIN_DEBUG_PRODUCTS_DIR/win64 |
||||
# Linux |
||||
LINUX_PROD_DIR=$PROJROOT/staging/linux |
||||
# macOS |
||||
MACOS_PROD_DIR=$PROJROOT/staging/macos |
||||
MACOS_RELEASE_PROD_DIR=$MACOS_PROD_DIR/release |
||||
MACOS_DEBUG_PROD_DIR=$MACOS_PROD_DIR/debug |
||||
# iOS |
||||
IOS_PROD_DIR=$PROJROOT/staging/ios |
||||
# Android |
||||
ANDROID_PROJ_DIR=$(pwd)/"ports/android" |
||||
ANDROID_ARCHIVE_FILENAME="zt.aar" |
||||
# Xcode |
||||
XCODE_IOS_PROJ_DIR=$(pwd)/"ports/xcode_ios" |
||||
XCODE_MACOS_PROJ_DIR=$(pwd)/"ports/xcode_macos" |
||||
|
||||
mkdir $FINISHED_PRODUCTS_DIR |
||||
mkdir $STAGING_DIR |
||||
|
||||
# Check that projects exist, generate them and exit if they don't exist |
||||
generate_projects_if_necessary() |
||||
{ |
||||
if [[ $OSNAME = *"darwin"* ]]; then |
||||
# iOS |
||||
if [ ! -d "$XCODE_IOS_PROJ_DIR" ]; then |
||||
echo "BUILDING: iOS project" |
||||
should_exit=1 |
||||
mkdir -p $XCODE_IOS_PROJ_DIR |
||||
cd $XCODE_IOS_PROJ_DIR |
||||
cmake -G Xcode ../../ |
||||
# Bug in CMake requires us to manually replace architecture strings in project file |
||||
sed -i '' 's/x86_64/$(CURRENT_ARCH)/g' $PROJNAME.xcodeproj/project.pbxproj |
||||
cd - |
||||
fi |
||||
# macOS |
||||
if [ ! -d "$XCODE_MACOS_PROJ_DIR" ]; then |
||||
echo "BUILDING: macOS project" |
||||
should_exit=1 |
||||
mkdir -p $XCODE_MACOS_PROJ_DIR |
||||
cd $XCODE_MACOS_PROJ_DIR |
||||
cmake -G Xcode ../../ |
||||
cd - |
||||
fi |
||||
# android? |
||||
if [[ $should_exit = 1 ]]; then |
||||
echo "Generated projects. Perform necessary modifications and then re-run this script" |
||||
echo "Please place previously built windows binaries in $WIN_PREBUILT_DIR before running again." |
||||
exit 0 |
||||
else |
||||
echo "Projects detected, going to build stage next" |
||||
fi |
||||
fi |
||||
} |
||||
|
||||
build_all_products() |
||||
{ |
||||
CONFIG=$1 |
||||
UPPERCASE_CONFIG="$(tr '[:lower:]' '[:upper:]' <<< ${1:0:1})${1:1}" |
||||
|
||||
# Targets to build on and for darwin |
||||
if [[ $OSNAME = *"darwin"* ]]; then |
||||
# Xcode Frameworks --- Builds targets from a CMake-generated Xcode project |
||||
if false; then |
||||
if [[ $2 != *"JNI"* ]]; then |
||||
CURR_BUILD_PRODUCTS_DIR=$LIB_PRODUCTS_DIR/$UPPERCASE_CONFIG |
||||
# (iOS) |
||||
echo "BUILDING: iOS" |
||||
cd $XCODE_IOS_PROJ_DIR |
||||
xcodebuild -target zt -configuration "$UPPERCASE_CONFIG" -sdk "iphoneos" |
||||
xcodebuild -target zt-static -configuration "$UPPERCASE_CONFIG" -sdk "iphoneos" |
||||
cd - |
||||
CURR_ARCH="arm64" # spoof this architecture since HOSTTYPE is likely x86_64 |
||||
CURR_TMP_PRODUCT_DIR=$STAGING_DIR/$CONFIG/ios-$CURR_ARCH |
||||
mkdir -p $CURR_TMP_PRODUCT_DIR |
||||
mv $CURR_BUILD_PRODUCTS_DIR/*.framework $CURR_TMP_PRODUCT_DIR |
||||
mv $CURR_BUILD_PRODUCTS_DIR/libzt.* $CURR_TMP_PRODUCT_DIR |
||||
|
||||
# (macOS) |
||||
echo "BUILDING: macOS" |
||||
cd $XCODE_MACOS_PROJ_DIR |
||||
xcodebuild -target zt -configuration "$UPPERCASE_CONFIG" -sdk "macosx" |
||||
xcodebuild -target zt-static -configuration "$UPPERCASE_CONFIG" -sdk "macosx" |
||||
xcodebuild -target zt-shared -configuration "$UPPERCASE_CONFIG" -sdk "macosx" |
||||
cd - |
||||
CURR_TMP_PRODUCT_DIR=$STAGING_DIR/$CONFIG/macos-$(uname -m) |
||||
mkdir -p $CURR_TMP_PRODUCT_DIR |
||||
mv $CURR_BUILD_PRODUCTS_DIR/*.framework $CURR_TMP_PRODUCT_DIR |
||||
mv $CURR_BUILD_PRODUCTS_DIR/libzt.* $CURR_TMP_PRODUCT_DIR |
||||
fi |
||||
fi |
||||
# Android Archive (AAR) --- Executes a Gradle task |
||||
if true; then |
||||
CMAKE_FLAGS=$CMAKE_FLAGS" -DSDK_JNI=1" |
||||
CURR_ARCH="armeabi-v7a" # spoof this architecture since HOSTTYPE is likely x86_64 |
||||
CURR_TMP_PRODUCT_DIR=$STAGING_DIR/$CONFIG/android-$CURR_ARCH |
||||
mkdir -p $CURR_TMP_PRODUCT_DIR |
||||
echo "BUILDING: AAR" |
||||
cd $ANDROID_PROJ_DIR |
||||
./gradlew assemble$UPPERCASE_CONFIG # e.g. assembleRelease |
||||
mv $ANDROID_PROJ_DIR/app/build/outputs/aar/app-$CONFIG.aar $CURR_TMP_PRODUCT_DIR/$ANDROID_ARCHIVE_FILENAME |
||||
cd - |
||||
fi |
||||
# Java Archive (JAR) |
||||
if false; then |
||||
CURR_BUILD_PRODUCTS_DIR=$LIB_PRODUCTS_DIR |
||||
CMAKE_FLAGS=$CMAKE_FLAGS" -DJNI=1" |
||||
CURR_TMP_PRODUCT_DIR=$STAGING_DIR/$CONFIG/macos-$(uname -m) |
||||
mkdir -p $CURR_TMP_PRODUCT_DIR |
||||
echo "BUILDING: JAR" |
||||
rm -rf $LIB_PRODUCTS_DIR # clean-lite |
||||
cmake -H. -Bbuild -DCMAKE_BUILD_TYPE=$CONFIG "-DJNI=1 -DBUILD_TESTS=0" |
||||
cmake --build build |
||||
cd $PROJROOT/ports/java |
||||
cp $CURR_BUILD_PRODUCTS_DIR/libzt.dylib . |
||||
javac com/zerotier/libzt/*.java |
||||
jar cf zt.jar libzt.dylib com/zerotier/libzt/*.class |
||||
rm libzt.dylib |
||||
mv zt.jar $CURR_TMP_PRODUCT_DIR |
||||
cd - |
||||
fi |
||||
fi |
||||
# Linux targets |
||||
if [[ $OSNAME = *"linux"* ]]; then |
||||
CURR_BUILD_PRODUCTS_DIR=$LIB_PRODUCTS_DIR |
||||
# Ordinary libraries |
||||
if true; then |
||||
rm -rf $LIB_PRODUCTS_DIR |
||||
cmake -H. -Bbuild -DCMAKE_BUILD_TYPE=$CONFIG "-DBUILD_TESTS=0" |
||||
cmake --build build |
||||
# -j $BUILD_CONCURRENCY |
||||
CURR_TMP_PRODUCT_DIR=$STAGING_DIR/$CONFIG/linux-$(uname -m) |
||||
mkdir -p $CURR_TMP_PRODUCT_DIR |
||||
mv $CURR_BUILD_PRODUCTS_DIR/libzt.* $CURR_TMP_PRODUCT_DIR |
||||
fi |
||||
# Java JAR file |
||||
if true; then |
||||
rm -rf $LIB_PRODUCTS_DIR |
||||
cmake -H. -Bbuild -DCMAKE_BUILD_TYPE=$CONFIG "-DJNI=1 -DBUILD_TESTS=0" |
||||
cmake --build build |
||||
# -j $BUILD_CONCURRENCY |
||||
CURR_TMP_PRODUCT_DIR=$STAGING_DIR/$CONFIG/linux-$(uname -m) |
||||
mkdir -p $CURR_TMP_PRODUCT_DIR |
||||
cd $PROJROOT/ports/java |
||||
cp $CURR_BUILD_PRODUCTS_DIR/libzt.so . |
||||
javac com/zerotier/libzt/*.java |
||||
jar cf zt.jar libzt.dylib com/zerotier/libzt/*.class |
||||
rm libzt.dylib |
||||
mv zt.jar $CURR_TMP_PRODUCT_DIR |
||||
cd - |
||||
fi |
||||
fi |
||||
} |
||||
|
||||
main() |
||||
{ |
||||
#generate_projects_if_necessary |
||||
build_all_products "release" |
||||
build_all_products "debug" |
||||
} |
||||
|
||||
main "$@" |
||||
@ -0,0 +1,6 @@
|
||||
framework module zt { |
||||
umbrella header "Xcode-Bridging-Header.h" |
||||
|
||||
export * |
||||
module * { export * } |
||||
} |
||||
@ -0,0 +1,43 @@
|
||||
#!/bin/bash |
||||
|
||||
PROJNAME="zt" |
||||
LIBNAME="lib"$PROJNAME |
||||
LIBZT_VERSION="1.2.0" |
||||
LIBZT_REVISION="1" |
||||
ZT_CORE_VERSION="1.2.12" |
||||
FILENAME_PREFIX=${LIBNAME} |
||||
|
||||
STAGING_DIR=$(pwd)/staging |
||||
STAGING_DEBUG_DIR=$(pwd)/staging/debug |
||||
STAGING_RELEASE_DIR=$(pwd)/staging/release |
||||
FINISHED_PRODUCTS_DIR=$(pwd)/products |
||||
|
||||
# Clean before zipping |
||||
find . -type f \( -name '*.DS_Store' -o -name 'thumbs.db' \) -delete |
||||
|
||||
# Emit a README file |
||||
echo $'* libzt version: '${LIBZT_VERSION}$'r'${LIBZT_REVISION}$'\n* Core ZeroTier version: '${ZT_CORE_VERSION}$'\n* Date: '$(date)$'\n\nZeroTier Manual: https://www.zerotier.com/manual.shtml\n |
||||
Other Downloads: https://www.zerotier.com/download.shtml |
||||
\nlibzt Repo: https://github.com/zerotier/libzt\n\nFor more assistance, visit https://my.zerotier.com and ask your question in our Community section' > ${STAGING_DIR}/README.md |
||||
|
||||
cp ${STAGING_DIR}/README.md ${STAGING_DIR}/debug/README.md |
||||
cp ${STAGING_DIR}/README.md ${STAGING_DIR}/release/README.md |
||||
|
||||
# Package everything together |
||||
# (debug) |
||||
PRODUCT_FILENAME=${FILENAME_PREFIX}-debug.tar.gz |
||||
echo "Making: " ${FINISHED_PRODUCTS_DIR}/${PRODUCT_FILENAME} |
||||
cd ${STAGING_DEBUG_DIR} |
||||
tar --exclude=${PRODUCT_FILENAME} -zcvf ${PRODUCT_FILENAME} . |
||||
md5 $PRODUCT_FILENAME |
||||
mv *.tar.gz ${FINISHED_PRODUCTS_DIR} |
||||
cd - |
||||
|
||||
# (release) |
||||
PRODUCT_FILENAME=${FILENAME_PREFIX}-release.tar.gz |
||||
echo "Making: " ${FINISHED_PRODUCTS_DIR}/${PRODUCT_FILENAME} |
||||
cd ${STAGING_RELEASE_DIR} |
||||
tar --exclude=${PRODUCT_FILENAME} -zcvf ${PRODUCT_FILENAME} . |
||||
md5 $PRODUCT_FILENAME |
||||
mv *.tar.gz ${FINISHED_PRODUCTS_DIR} |
||||
cd - |
||||