summaryrefslogtreecommitdiff
path: root/src/SDK_Service.cpp
diff options
context:
space:
mode:
authorJoseph Henry <[email protected]>2016-08-15 17:29:02 -0700
committerJoseph Henry <[email protected]>2016-08-15 17:29:02 -0700
commit6090138428a81be67eeccd11cd4e19f2e17be012 (patch)
tree9974607e8c759e2e48a87e47d7cb5fec09d2ee3f /src/SDK_Service.cpp
parent74c5245aa8613e79fec8ff49038ba17924914519 (diff)
ZT/ZTS api layer updates, combined contents of SDK_ServiceSetup.h with SDK.h0.3.1
Diffstat (limited to 'src/SDK_Service.cpp')
-rw-r--r--src/SDK_Service.cpp414
1 files changed, 414 insertions, 0 deletions
diff --git a/src/SDK_Service.cpp b/src/SDK_Service.cpp
new file mode 100644
index 0000000..dc50034
--- /dev/null
+++ b/src/SDK_Service.cpp
@@ -0,0 +1,414 @@
+/*
+ * 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/
+ */
+
+#if defined(__ANDROID__)
+ #include <jni.h>
+#endif
+
+#include <dlfcn.h>
+#include <sys/socket.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <pthread.h>
+
+#include "OneService.hpp"
+#include "Utils.hpp"
+#include "OSUtils.hpp"
+
+#include "SDK_EthernetTap.hpp"
+#include "SDK.h"
+#include "SDK_Debug.h"
+
+std::string service_path;
+pthread_t intercept_thread;
+int * intercept_thread_id;
+pthread_key_t thr_id_key;
+static ZeroTier::OneService *volatile zt1Service;
+
+std::string localHomeDir; // Local shortened path
+std::string givenHomeDir; // What the user/application provides as a suggestion
+std::string homeDir; // The resultant platform-specific dir we *must* use internally
+std::string netDir;
+std::string rpcNWID;
+
+bool rpcEnabled;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void zt_init_rpc(const char * path, const char * nwid);
+void dwr(int level, const char *fmt, ... );
+
+#if defined(__UNITY_3D__)
+ // .NET Interop-friendly debug mechanism
+ typedef void (*FuncPtr)( const char * );
+ FuncPtr Debug;
+ void SetDebugFunction( FuncPtr fp ) { Debug = fp; }
+
+ // Starts a ZeroTier service at the given path
+ void unity_start_service(char * path, int len) {
+ std::string dstr = std::string(path);
+ dstr = "unity_start_service(): path = " + dstr;
+ Debug(dstr.c_str());
+ init_service(INTERCEPT_DISABLED, path);
+ }
+ // Starts a ZeroTier service and RPC
+ void unity_start_service_and_rpc(char * path, char *nwid, int len) {
+ std::string dstr = std::string(path);
+ dstr = "unity_start_service_and_rpc(): path = " + dstr;
+ Debug(dstr.c_str());
+ init_service_and_rpc(INTERCEPT_DISABLED, path, nwid);
+ }
+#endif
+
+
+// Basic ZT service controls
+void zts_join_network(const char * nwid) {
+ std::string confFile = zt1Service->givenHomePath() + "/networks.d/" + nwid + ".conf";
+ dwr(MSG_ERROR, "writing conf file = %s\n", confFile.c_str());
+ if(!ZeroTier::OSUtils::mkdir(netDir)) {
+ dwr(MSG_ERROR, "unable to create %s\n", netDir.c_str());
+ }
+ if(!ZeroTier::OSUtils::writeFile(confFile.c_str(), "")) {
+ dwr(MSG_ERROR, "unable to write network conf file: %s\n", confFile.c_str());
+ }
+ // Provide the API with the RPC information
+ zt_init_rpc(homeDir.c_str(), nwid);
+}
+void zts_leave_network(const char * nwid) { zt1Service->leave(nwid); }
+bool zts_is_running() { return zt1Service->isRunning(); }
+void zts_terminate() { zt1Service->terminate(); }
+
+// FIXME: Re-implemented to make it play nicer with the C-linkage required for Xcode integrations
+// Now only returns first assigned address per network. Shouldn't normally be a problem
+void zts_get_addresses(const char * nwid, char *addrstr)
+{
+ uint64_t nwid_int = strtoull(nwid, NULL, 16);
+ ZeroTier::NetconEthernetTap * tap = zt1Service->getTaps()[nwid_int];
+ if(tap && tap->_ips.size()){
+ std::string addr = tap->_ips[0].toString();
+ memcpy(addrstr, addr.c_str(), addr.length());
+ }
+ else {
+ memcpy(addrstr, "-1.-1.-1.-1/-1", 14);
+ }
+ /*
+ uint64_t nwid_int = strtoull(nwid.c_str(), NULL, 16);
+ ZeroTier::NetconEthernetTap * tap = zt1Service->getTaps()[nwid_int];
+ std::vector<std::string> ip_strings;
+ if(tap) {
+ for(int i=0; i<tap->_ips.size(); i++) {
+ ip_strings.push_back(tap->_ips[i].toString());
+ }
+ return ip_strings;
+ }
+ return ip_strings;
+ */
+}
+int zts_get_device_id() { /* TODO */ return 0; }
+
+bool zts_is_relayed() {
+ // TODO
+ // zt1Service->getNode()->peers()
+ return false;
+}
+
+int zts_start_proxy_server(const char * nwid, struct sockaddr_storage * addr) {
+ //uint64_t nwid_int = strtoull(nwid, NULL, 16);
+ //return zt1Service->getTaps()[nwid_int]->proxyListenPort;
+ return 0;
+}
+int zts_stop_proxy_server(const char * nwid) {
+ //uint64_t nwid_int = strtoull(nwid, NULL, 16);
+ //return zt1Service->getTaps()[nwid_int]->proxyListenPort;
+ return 0;
+}
+int zts_get_proxy_server_address(const char * nwid, struct sockaddr_storage * addr) {
+ //uint64_t nwid_int = strtoull(nwid, NULL, 16);
+ //zt1Service->getTaps()[nwid_int]->proxyListenPort;
+ return 0;
+}
+
+// Android JNI wrapper
+// JNI naming convention: Java_PACKAGENAME_CLASSNAME_METHODNAME
+#if defined(__ANDROID__)
+ // Join a network
+ JNIEXPORT void JNICALL Java_ZeroTier_SDK_zt_1join_1network(JNIEnv *env, jobject thisObj, jstring nwid) {
+ const char *nwidstr;
+ if(nwid) {
+ nwidstr = env->GetStringUTFChars(nwid, NULL);
+ zts_join_network(nwidstr);
+ }
+ }
+ // Leave a network
+ JNIEXPORT void JNICALL Java_ZeroTier_SDK_zt_1leave_1network(JNIEnv *env, jobject thisObj, jstring nwid) {
+ const char *nwidstr;
+ if(nwid) {
+ nwidstr = env->GetStringUTFChars(nwid, NULL);
+ zts_leave_network(nwidstr);
+ }
+ }
+ // Returns whether the ZeroTier service is running
+ JNIEXPORT jboolean JNICALL Java_ZeroTier_SDK_zt_1running(JNIEnv *env, jobject thisObj) {
+ if(zt1Service)
+ return zts_is_running();
+ return false;
+ }
+ // Shuts down ZeroTier service and SOCKS5 Proxy server
+ JNIEXPORT void JNICALL Java_ZeroTier_SDK_zt_1terminate_1service(JNIEnv *env, jobject thisObj) {
+ if(zt1Service)
+ zts_terminate();
+ // TODO: Also terminate SOCKS5 Proxy
+ // zts_stop_proxy_server();
+ }
+ // FIXME: Re-implemented to make it play nicer with the C-linkage required for Xcode integrations
+ // Now only returns first assigned address per network. Shouldn't normally be a problem
+ JNIEXPORT jobject JNICALL Java_ZeroTier_SDK_zt_1get_1addresses(JNIEnv *env, jobject thisObj, jstring nwid) {
+ const char *nwid_str = env->GetStringUTFChars(nwid, NULL);
+ char address_string[32];
+ memset(address_string, 0, 32);
+ zts_get_addresses(nwid_str, address_string);
+ jclass clazz = (*env).FindClass("java/util/ArrayList");
+ jobject addresses = (*env).NewObject(clazz, (*env).GetMethodID(clazz, "<init>", "()V"));
+ jstring _str = (*env).NewStringUTF(address_string);
+ env->CallBooleanMethod(addresses, env->GetMethodID(clazz, "add", "(Ljava/lang/Object;)Z"), _str);
+ return addresses;
+ /*
+ const char *nwid_str = env->GetStringUTFChars(nwid, NULL);
+ std::vector<std::string> address_strings = zts_get_addresses(nwid_str);
+ jclass clazz = (*env).FindClass("java/util/ArrayList");
+ jobject addresses = (*env).NewObject(clazz, (*env).GetMethodID(clazz, "<init>", "()V"));
+ if(address_strings.size()) {
+ for (int n=0;n<address_strings.size();n++) {
+ jstring _str = (*env).NewStringUTF(address_strings[n].c_str());
+ env->CallBooleanMethod(addresses, env->GetMethodID(clazz, "add", "(Ljava/lang/Object;)Z"), _str);
+ }
+ }
+ else { // Add dummy value
+ jstring _str = (*env).NewStringUTF("-1.-1.-1.-1/-1");
+ env->CallBooleanMethod(addresses, env->GetMethodID(clazz, "add", "(Ljava/lang/Object;)Z"), _str);
+ }
+ return addresses;
+ */
+ }
+ // Returns the device is in integer form
+ JNIEXPORT jint Java_ZeroTier_SDK_zt_1get_1device_1id() {
+ return zts_get_device_id();
+ }
+ // Returns whether the path to an endpoint is currently relayed by a root server
+ JNIEXPORT jboolean JNICALL Java_ZeroTier_SDK_zt_1is_1relayed() {
+ return zts_is_relayed();
+ }
+ // Returns the local address of the SOCKS5 Proxy server
+ JNIEXPORT jint JNICALL Java_ZeroTier_SDK_zt_1get_1proxy_1server_1address(JNIEnv *env, jobject thisObj, jstring nwid, jobject ztaddr) {
+ // TODO
+ //const char *nwid_str = env->GetStringUTFChars(nwid, NULL);
+ //return zts_get_proxy_server_address(nwid_str, addr);
+ return 0;
+ }
+ // Starts a SOCKS5 proxy server for a given ZeroTier network
+ JNIEXPORT jint JNICALL Java_ZeroTier_SDK_zt_1start_1proxy_1server(JNIEnv *env, jobject thisObj, jstring nwid, jobject ztaddr) {
+ // TODO
+ return 0;
+ }
+ // Stops the SOCKS5 proxy server for a given ZeroTier network
+ JNIEXPORT jint JNICALL Java_ZeroTier_SDK_zt_1stop_1proxy_1server(JNIEnv *env, jobject thisObj, jstring nwid) {
+ // TODO
+ return 0;
+ }
+#endif
+
+
+// Typically used on iOS/OSX
+#if !defined(__ANDROID__)
+ /*
+ * Starts a service thread and performs basic setup tasks
+ */
+ void init_service(int key, const char * path) {
+ givenHomeDir = path;
+ pthread_key_create(&thr_id_key, NULL);
+ intercept_thread_id = (int*)malloc(sizeof(int));
+ *intercept_thread_id = key;
+ pthread_create(&intercept_thread, NULL, zt_start_service, (void *)(intercept_thread_id));
+ }
+ void init_service_and_rpc(int key, const char * path, const char * nwid) {
+ rpcEnabled = true;
+ rpcNWID = nwid;
+ init_service(key, path);
+ }
+ /*
+ * Enables or disables intercept for current thread using key in thread-local storage
+ */
+ void set_intercept_status(int mode) {
+ fprintf(stderr, "set_intercept_status(mode=%d): tid = %d\n", mode, pthread_mach_thread_np(pthread_self()));
+ pthread_key_create(&thr_id_key, NULL);
+ intercept_thread_id = (int*)malloc(sizeof(int));
+ *intercept_thread_id = mode;
+ pthread_setspecific(thr_id_key, intercept_thread_id);
+ }
+#endif
+
+/*
+ * Starts a new service instance
+ */
+#if defined(__ANDROID__)
+ JNIEXPORT int JNICALL Java_ZeroTier_SDK_zt_1start_1service(JNIEnv *env, jobject thisObj, jstring path) {
+ if(path)
+ homeDir = env->GetStringUTFChars(path, NULL);
+#else
+ void *zt_start_service(void *thread_id) {
+#endif
+
+ #if defined(SDK_BUNDLED) && !defined(__ANDROID__)
+ set_intercept_status(INTERCEPT_DISABLED); // Ignore network calls from ZT service
+ #endif
+
+ #if defined(__UNITY_3D__)
+ int MAX_DIR_SZ = 256;
+ char current_dir[MAX_DIR_SZ];
+ getcwd(current_dir, MAX_DIR_SZ);
+ chdir(service_path.c_str());
+ homeDir = current_dir; // homeDir shall be current_dir
+ #endif
+
+ #if defined(__APPLE__)
+ #include "TargetConditionals.h"
+ #if TARGET_IPHONE_SIMULATOR
+ // homeDir = "dont/run/this/in/the/simulator/it/wont/work";
+ #elif TARGET_OS_IPHONE
+ localHomeDir = "ZeroTier/One";
+ std::string del = givenHomeDir.length() && givenHomeDir[givenHomeDir.length()-1]!='/' ? "/" : "";
+ homeDir = givenHomeDir + del + localHomeDir;
+ #endif
+ #endif
+
+ #if defined(__ANDROID__)
+ /* NOTE: Since on Android devices the sdcard is formatted as fat32, we can't use this
+ location to set up the RPC unix domain socket. Rather we must use the application's
+ specific data directory given by getApplicationContext().getFilesDir() */
+ //rpcDir = homeDir; // Take given homeDir as rpcDir
+ //homeDir = "/sdcard/zerotier"; // Use fat32-formatted sdcard for writing network conf & supporting files
+ #endif
+
+ #if defined(__APPLE__) && !defined(__IOS__)
+ homeDir = givenHomeDir;
+ localHomeDir = givenHomeDir; // Used for RPC and *can* differ from homeDir on some platforms
+ #endif
+
+ dwr(MSG_DEBUG, "homeDir = %s", givenHomeDir.c_str());
+ // Where network .conf files will be stored
+ netDir = homeDir + "/networks.d";
+ zt1Service = (ZeroTier::OneService *)0;
+
+ // Construct path for network config and supporting service files
+ if (homeDir.length()) {
+ dwr(MSG_DEBUG, "start_service(): constructing path...\n");
+ std::vector<std::string> hpsp(ZeroTier::Utils::split(homeDir.c_str(),ZT_PATH_SEPARATOR_S,"",""));
+ std::string ptmp;
+ if (homeDir[0] == ZT_PATH_SEPARATOR)
+ ptmp.push_back(ZT_PATH_SEPARATOR);
+ for(std::vector<std::string>::iterator pi(hpsp.begin());pi!=hpsp.end();++pi) {
+ if (ptmp.length() > 0)
+ ptmp.push_back(ZT_PATH_SEPARATOR);
+ ptmp.append(*pi);
+ if ((*pi != ".")&&(*pi != "..")) {
+ if (!ZeroTier::OSUtils::mkdir(ptmp)) {
+ dwr(MSG_ERROR, "startOneService(): home path does not exist, and could not create\n");
+ }
+ }
+ }
+ }
+ else {
+ fprintf(stderr, "start_service(): homeDir is empty, could not construct path\n");
+ return NULL;
+ }
+
+ #if defined(__IOS__)
+ // Go to the app's data directory so we can shorten the sun_path we bind to
+ int MAX_DIR_SZ = 256;
+ char current_dir[MAX_DIR_SZ];
+ getcwd(current_dir, MAX_DIR_SZ);
+ std::string targetDir = homeDir + "/../../";
+ chdir(targetDir.c_str());
+ homeDir = localHomeDir;
+ #endif
+
+ //chdir(current_dir); // Return to previous current working directory (at the request of Unity3D)
+ #if defined(__UNITY_3D__)
+ Debug("Starting service...\n");
+ #endif
+
+ // Initialize RPC
+ if(rpcEnabled) {
+ zt_init_rpc(localHomeDir.c_str(), rpcNWID.c_str());
+ }
+
+ // Generate random port for new service instance
+ unsigned int randp = 0;
+ ZeroTier::Utils::getSecureRandom(&randp,sizeof(randp));
+ int servicePort = 9000 + (randp % 1000);
+
+ for(;;) {
+ zt1Service = ZeroTier::OneService::newInstance(homeDir.c_str(),servicePort);
+ switch(zt1Service->run()) {
+ case ZeroTier::OneService::ONE_STILL_RUNNING: // shouldn't happen, run() won't return until done
+ case ZeroTier::OneService::ONE_NORMAL_TERMINATION:
+ break;
+ case ZeroTier::OneService::ONE_UNRECOVERABLE_ERROR:
+ fprintf(stderr,"start_service(): fatal error: %s",zt1Service->fatalErrorMessage().c_str());
+ break;
+ case ZeroTier::OneService::ONE_IDENTITY_COLLISION: {
+ delete zt1Service;
+ zt1Service = (ZeroTier::OneService *)0;
+ std::string oldid;
+ ZeroTier::OSUtils::readFile((homeDir + ZT_PATH_SEPARATOR_S + "identity.secret").c_str(),oldid);
+ if (oldid.length()) {
+ ZeroTier::OSUtils::writeFile((homeDir + ZT_PATH_SEPARATOR_S + "identity.secret.saved_after_collision").c_str(),oldid);
+ ZeroTier::OSUtils::rm((homeDir + ZT_PATH_SEPARATOR_S + "identity.secret").c_str());
+ ZeroTier::OSUtils::rm((homeDir + ZT_PATH_SEPARATOR_S + "identity.public").c_str());
+ }
+ }
+ continue; // restart!
+ }
+ break; // terminate loop -- normally we don't keep restarting
+ }
+ delete zt1Service;
+ zt1Service = (ZeroTier::OneService *)0;
+ return NULL;
+ }
+
+#ifdef __cplusplus
+}
+#endif