diff --git a/CMakeLists.txt b/CMakeLists.txt index 1023750..2621b87 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -720,11 +720,11 @@ endif() # ----------------------------------------------------------------------------- if(BUILD_HOST_SELFTEST) - add_executable(selftest ${PROJ_DIR}/test/selftest.c) - target_link_libraries(selftest ${STATIC_LIB_NAME}) + add_executable(selftest-c-api ${PROJ_DIR}/test/selftest-c-api.c) + target_link_libraries(selftest-c-api ${STATIC_LIB_NAME}) project(TEST) enable_testing() - add_test(NAME selftest COMMAND selftest) + add_test(NAME selftest-c-api COMMAND selftest-c-api) endif() # ----------------------------------------------------------------------------- diff --git a/README.md b/README.md index 54fdae6..70e0cfd 100644 --- a/README.md +++ b/README.md @@ -93,7 +93,7 @@ Important directories: # Self-hosting (Optional) -We provide ways for your app or enterprise to function indepenently from any of our services if desired. +We provide ways for your app or enterprise to function independently from any of our services if desired. While we do operate a global network of redundant root servers, network controllers and an admin API/UI called [Central](https://my.zerotier.com), some use-cases require full control over the infrastructure and we try to make it as easy as possible to set up your own controllers and root servers: See [here](https://github.com/zerotier/ZeroTierOne/tree/master/controller) to learn more about how to set up your own network controller, and [here](https://www.zerotier.com/manual/#4_4) to learn more about setting up your own roots. diff --git a/build.sh b/build.sh index 0d0376b..8f08420 100755 --- a/build.sh +++ b/build.sh @@ -71,7 +71,7 @@ DEFAULT_HOST_LIB_OUTPUT_DIR=$BUILD_OUTPUT_DIR/$HOST_PLATFORM-$HOST_MACHINE_TYPE DEFAULT_HOST_BIN_OUTPUT_DIR=$BUILD_OUTPUT_DIR/$HOST_PLATFORM-$HOST_MACHINE_TYPE # Default location for (host) packages DEFAULT_HOST_PKG_OUTPUT_DIR=$BUILD_OUTPUT_DIR/$HOST_PLATFORM-$HOST_MACHINE_TYPE -# Defaultlocation for CMake's caches (when building for host) +# Default location for CMake's caches (when building for host) DEFAULT_HOST_BUILD_CACHE_DIR=$BUILD_CACHE_DIR/$HOST_PLATFORM-$HOST_MACHINE_TYPE gethosttype() @@ -89,8 +89,8 @@ gethosttype() # # Example output: # -# - Cache : /Volumes/$USER/zt/libzt/libzt-dev/cache/apple-xcframework-debug -# - Build output : /Volumes/$USER/zt/libzt/libzt-dev/dist +# - Cache : libzt/cache/apple-xcframework-debug +# - Build output : libzt/dist # # apple-xcframework-debug # └── pkg @@ -146,10 +146,10 @@ xcframework() # # Example output: # -# - Cache : /Volumes/$USER/zt/libzt/libzt-dev/cache/iphonesimulator-x64-framework-debug -# - Build output : /Volumes/$USER/zt/libzt/libzt-dev/dist +# - Cache : libzt/cache/iphonesimulator-x64-framework-debug +# - Build output : libzt/dist # -# /Volumes/$USER/zt/libzt/libzt-dev/dist/iphonesimulator-x64-framework-debug +# libzt/dist/iphonesimulator-x64-framework-debug # └── pkg # └── zt.framework # ├── Headers @@ -195,10 +195,10 @@ iphonesimulator-framework() # # Example output: # -# - Cache : /Volumes/$USER/zt/libzt/libzt-dev/cache/macos-x64-framework-debug -# - Build output : /Volumes/$USER/zt/libzt/libzt-dev/dist +# - Cache : libzt/cache/macos-x64-framework-debug +# - Build output : libzt/dist # -# /Volumes/$USER/zt/libzt/libzt-dev/dist/macos-x64-framework-debug +# libzt/dist/macos-x64-framework-debug # └── pkg # └── zt.framework # ├── Headers @@ -241,10 +241,10 @@ macos-framework() # # Example output: # -# - Cache : /Volumes/$USER/zt/libzt/libzt-dev/cache/iphoneos-arm64-framework-debug -# - Build output : /Volumes/$USER/zt/libzt/libzt-dev/dist +# - Cache : libzt/cache/iphoneos-arm64-framework-debug +# - Build output : libzt/dist # -# /Volumes/$USER/zt/libzt/libzt-dev/dist/iphoneos-arm64-framework-debug +# libzt/dist/iphoneos-arm64-framework-debug # └── pkg # └── zt.framework # ├── Headers @@ -291,8 +291,8 @@ iphoneos-framework() # # Example output: # -# - Cache : /Volumes/$USER/zt/libzt/libzt-dev/cache/linux-x64-host-release -# - Build output : /Volumes/$USER/zt/libzt/libzt-dev/dist +# - Cache : libzt/cache/linux-x64-host-release +# - Build output : libzt/dist # # linux-x64-host-release # ├── bin @@ -307,6 +307,11 @@ host() ARTIFACT="host" # Default to release BUILD_TYPE=${1:-release} + if [[ $1 = *"docs"* ]]; then + # Generate documentation + cd docs/c && doxygen + exit 0 + fi # -DZTS_ENABLE_CENTRAL_API=0 VARIANT="-DBUILD_HOST=True" CACHE_DIR=$DEFAULT_HOST_BUILD_CACHE_DIR-$ARTIFACT-$BUILD_TYPE @@ -336,6 +341,29 @@ host-uninstall() cd - } +# Build C extension module (*.so), python module, package both into wheel +# +# ./build.sh host-python-wheel "release" +# +# Example output: +# +# libzt/dist/macos-x64-python-debug +# └── pkg +# └── libzt-1.3.4b1-cp39-cp39-macosx_11_0_x86_64.whl +# +host-python-wheel() +{ + ARTIFACT="python" + # Default to release + BUILD_TYPE=${1:-release} + CACHE_DIR=$DEFAULT_HOST_BUILD_CACHE_DIR-$ARTIFACT-$BUILD_TYPE + TARGET_BUILD_DIR=$DEFAULT_HOST_BIN_OUTPUT_DIR-$ARTIFACT-$BUILD_TYPE + PKG_OUTPUT_DIR=$TARGET_BUILD_DIR/pkg + mkdir -p $PKG_OUTPUT_DIR + # Requires setuptools, etc + cd pkg/pypi && ./build.sh wheel && cp -f dist/*.whl $PKG_OUTPUT_DIR +} + # Build shared library with python wrapper symbols exported host-python() { @@ -345,9 +373,8 @@ host-python() VARIANT="-DZTS_ENABLE_PYTHON=True" CACHE_DIR=$DEFAULT_HOST_BUILD_CACHE_DIR-$ARTIFACT-$BUILD_TYPE TARGET_BUILD_DIR=$DEFAULT_HOST_BIN_OUTPUT_DIR-$ARTIFACT-$BUILD_TYPE - rm -rf $TARGET_BUILD_DIR LIB_OUTPUT_DIR=$TARGET_BUILD_DIR/lib - BIN_OUTPUT_DIR=$TARGET_BUILD_DIR/bin + rm -rf $LIB_OUTPUT_DIR mkdir -p $LIB_OUTPUT_DIR # Optional step to generate new SWIG wrapper swig -c++ -python -o src/bindings/python/zt_wrap.cpp -Iinclude src/bindings/python/zt.i @@ -384,6 +411,11 @@ host-jar() ARTIFACT="jar" # Default to release BUILD_TYPE=${1:-release} + if [[ $1 = *"docs"* ]]; then + # Generate documentation + javadoc src/bindings/java/*.java -d docs/java + exit 0 + fi VARIANT="-DZTS_ENABLE_JAVA=True" CACHE_DIR=$DEFAULT_HOST_BUILD_CACHE_DIR-$ARTIFACT-$BUILD_TYPE TARGET_BUILD_DIR=$DEFAULT_HOST_BIN_OUTPUT_DIR-$ARTIFACT-$BUILD_TYPE @@ -402,7 +434,7 @@ host-jar() cp -f $CACHE_DIR/lib/libzt.* $JAVA_JAR_DIR cd $JAVA_JAR_DIR export JAVA_TOOL_OPTIONS=-Dfile.encoding=UTF8 - javac com/zerotier/libzt/*.java + javac -Xlint:deprecation com/zerotier/libzt/*.java jar cf libzt-"$(git describe --abbrev=0)".jar $SHARED_LIB_NAME com/zerotier/libzt/*.class rm -rf com $SHARED_LIB_NAME cd - @@ -441,8 +473,8 @@ fi # # Example output: # -# - Cache : /Volumes/$USER/zt/libzt/libzt-dev/cache/android-any-android-release -# - Build output : /Volumes/$USER/zt/libzt/libzt-dev/dist +# - Cache : libzt/cache/android-any-android-release +# - Build output : libzt/dist # # android-any-android-release # └── libzt-release.aar @@ -496,10 +528,34 @@ test() $TREE $TARGET_BUILD_DIR # Test cd $CACHE_DIR - ctest -C release + #ctest -C release cd - } +# Test C API +test-c() +{ + if [[ -z "${alice_path}" ]]; then + echo "Please set necessary environment variables for test" + exit 0 + fi + ARTIFACT="test" + # Default to debug so asserts aren't optimized out + BUILD_TYPE=${1:-debug} + TARGET_BUILD_DIR=$DEFAULT_HOST_BIN_OUTPUT_DIR-$ARTIFACT-$BUILD_TYPE + BIN_OUTPUT_DIR=$TARGET_BUILD_DIR/bin + rm -rf $TARGET_BUILD_DIR + # Build selftest + test $1 + # Ports can be anything we want since they aren't system ports + port4=8080 + port6=8081 + # Start Alice as server + "$BIN_OUTPUT_DIR/selftest-c-api" $alice_path $testnet $port4 $port6 & + # Start Bob as client + "$BIN_OUTPUT_DIR/selftest-c-api" $bob_path $testnet $port4 $alice_ip4 $port6 $alice_ip6 & +} + # Recursive deep clean clean() { diff --git a/include/ZeroTierSockets.h b/include/ZeroTierSockets.h index 68247e2..0abe99c 100644 --- a/include/ZeroTierSockets.h +++ b/include/ZeroTierSockets.h @@ -20,101 +20,135 @@ #ifndef ZT_SOCKETS_H #define ZT_SOCKETS_H -////////////////////////////////////////////////////////////////////////////// -// Configuration Options // -////////////////////////////////////////////////////////////////////////////// - -#if !defined(ZTS_ENABLE_PYTHON) && !defined(ZTS_ENABLE_PINVOKE) -#define ZTS_C_API_ONLY 1 -#endif - -#if !ZTS_NO_STDINT_H -#include -#endif - -#if defined(_MSC_VER) - #ifndef ssize_t - // TODO: Should be SSIZE_T, would require lwIP patch - // #include - // typedef SSIZE_T ssize_t; - typedef int ssize_t; - #endif -#else - #include -#endif - #ifdef __cplusplus extern "C" { #endif -#ifdef ZTS_ENABLE_PINVOKE - // Used by P/INVOKE wrappers - typedef void (*CppCallback)(void *msg); -#endif +//----------------------------------------------------------------------------// +// Error codes // +//----------------------------------------------------------------------------// -////////////////////////////////////////////////////////////////////////////// -// Event codes // -////////////////////////////////////////////////////////////////////////////// +/** Common error return values */ +enum zts_error +{ + /** No error */ + ZTS_ERR_OK = 0, + /** Socket error, see `zts_errno` */ + ZTS_ERR_SOCKET = -1, + /** The node service experienced a problem. Did you start the service? */ + ZTS_ERR_SERVICE = -2, + /** Invalid argument */ + ZTS_ERR_ARG = -3, + /** No result (not necessarily an error) */ + ZTS_ERR_NO_RESULT = -4, + /** Consider filing a bug report */ + ZTS_ERR_GENERAL = -5 +}; -// Node events -#define ZTS_EVENT_NODE_UP 200 -#define ZTS_EVENT_NODE_ONLINE 201 -#define ZTS_EVENT_NODE_OFFLINE 202 -#define ZTS_EVENT_NODE_DOWN 203 -#define ZTS_EVENT_NODE_IDENTITY_COLLISION 204 -#define ZTS_EVENT_NODE_UNRECOVERABLE_ERROR 205 -#define ZTS_EVENT_NODE_NORMAL_TERMINATION 206 -// Network events -#define ZTS_EVENT_NETWORK_NOT_FOUND 210 -#define ZTS_EVENT_NETWORK_CLIENT_TOO_OLD 211 -#define ZTS_EVENT_NETWORK_REQ_CONFIG 212 -#define ZTS_EVENT_NETWORK_OK 213 -#define ZTS_EVENT_NETWORK_ACCESS_DENIED 214 -#define ZTS_EVENT_NETWORK_READY_IP4 215 -#define ZTS_EVENT_NETWORK_READY_IP6 216 -#define ZTS_EVENT_NETWORK_READY_IP4_IP6 217 -#define ZTS_EVENT_NETWORK_DOWN 218 -#define ZTS_EVENT_NETWORK_UPDATE 219 -// Network Stack events -#define ZTS_EVENT_STACK_UP 220 -#define ZTS_EVENT_STACK_DOWN 221 -// lwIP netif events -#define ZTS_EVENT_NETIF_UP 230 -#define ZTS_EVENT_NETIF_DOWN 231 -#define ZTS_EVENT_NETIF_REMOVED 232 -#define ZTS_EVENT_NETIF_LINK_UP 233 -#define ZTS_EVENT_NETIF_LINK_DOWN 234 -// Peer events -#define ZTS_EVENT_PEER_DIRECT 240 -#define ZTS_EVENT_PEER_RELAY 241 -#define ZTS_EVENT_PEER_UNREACHABLE 242 -#define ZTS_EVENT_PEER_PATH_DISCOVERED 243 -#define ZTS_EVENT_PEER_PATH_DEAD 244 -// Route events -#define ZTS_EVENT_ROUTE_ADDED 250 -#define ZTS_EVENT_ROUTE_REMOVED 251 -// Address events -#define ZTS_EVENT_ADDR_ADDED_IP4 260 -#define ZTS_EVENT_ADDR_REMOVED_IP4 261 -#define ZTS_EVENT_ADDR_ADDED_IP6 262 -#define ZTS_EVENT_ADDR_REMOVED_IP6 263 +//----------------------------------------------------------------------------// +// Event codes // +//----------------------------------------------------------------------------// -////////////////////////////////////////////////////////////////////////////// -// Return Error codes // -////////////////////////////////////////////////////////////////////////////// +/** Event codes used by the callback API */ +enum zts_event +{ + /** The node service started successfully (no action needed) */ + ZTS_EVENT_NODE_UP = 200, + /** The node can reach the Internet */ + ZTS_EVENT_NODE_ONLINE = 201, + /** The node cannot reach the Internet */ + ZTS_EVENT_NODE_OFFLINE = 202, + /** The node service has stopped */ + ZTS_EVENT_NODE_DOWN = 203, + /** Multiple identities in use (undefined behavior) */ + ZTS_EVENT_NODE_IDENTITY_COLLISION = 204, + /** Something went horribly wrong */ + ZTS_EVENT_NODE_UNRECOVERABLE_ERROR = 205, + /** The node has been terminated */ + ZTS_EVENT_NODE_NORMAL_TERMINATION = 206, -#define ZTS_ERR_OK 0 // No error -#define ZTS_ERR_SOCKET -1 // Socket error, see zts_errno -#define ZTS_ERR_SERVICE -2 // You probably did something at the wrong time -#define ZTS_ERR_ARG -3 // Invalid argument -#define ZTS_ERR_NO_RESULT -4 // No result (not necessarily an error) -#define ZTS_ERR_GENERAL -5 // Consider filing a bug report + ZTS_EVENT_NODE_WHAT = 207, -////////////////////////////////////////////////////////////////////////////// -// zts_errno Error codes // -////////////////////////////////////////////////////////////////////////////// + // Network events -// Error variable set after each zts_* call to provide additional information. + /** The network ID does not correspond to a known network */ + ZTS_EVENT_NETWORK_NOT_FOUND = 210, + /** The version of ZeroTier inside libzt is too old */ + ZTS_EVENT_NETWORK_CLIENT_TOO_OLD = 211, + /** The configuration for a network has been requested (no action needed) */ + ZTS_EVENT_NETWORK_REQ_CONFIG = 212, + /** The node joined the network successfully (no action needed) */ + ZTS_EVENT_NETWORK_OK = 213, + /** The node is not allowed to join the network (you must authorize node) */ + ZTS_EVENT_NETWORK_ACCESS_DENIED = 214, + /** The node has received an IPv4 address from the network controller */ + ZTS_EVENT_NETWORK_READY_IP4 = 215, + /** The node has received an IPv6 address from the network controller */ + ZTS_EVENT_NETWORK_READY_IP6 = 216, + /** Deprecated */ + ZTS_EVENT_NETWORK_READY_IP4_IP6 = 217, + /** Network controller is unreachable */ + ZTS_EVENT_NETWORK_DOWN = 218, + /** Network change received from controller */ + ZTS_EVENT_NETWORK_UPDATE = 219, + + // Network Stack events + + /** TCP/IP stack (lwIP) is up */ + ZTS_EVENT_STACK_UP = 220, + /** TCP/IP stack (lwIP) id down */ + ZTS_EVENT_STACK_DOWN = 221, + + // lwIP netif events + + /** lwIP netif up (for debug purposes) */ + ZTS_EVENT_NETIF_UP = 230, + /** lwIP netif down (for debug purposes) */ + ZTS_EVENT_NETIF_DOWN = 231, + /** lwIP netif removed (for debug purposes) */ + ZTS_EVENT_NETIF_REMOVED = 232, + /** lwIP netif link up (for debug purposes) */ + ZTS_EVENT_NETIF_LINK_UP = 233, + /** lwIP netif link down (for debug purposes) */ + ZTS_EVENT_NETIF_LINK_DOWN = 234, + + // Peer events + + /** A direct P2P path to peer is known */ + ZTS_EVENT_PEER_DIRECT = 240, + /** A direct P2P path to peer is NOT known. Traffic is now relayed */ + ZTS_EVENT_PEER_RELAY = 241, + /** A peer is unreachable. Check NAT/Firewall settings */ + ZTS_EVENT_PEER_UNREACHABLE = 242, + /** A new path to a peer was discovered */ + ZTS_EVENT_PEER_PATH_DISCOVERED = 243, + /** A known path to a peer is now considered dead */ + ZTS_EVENT_PEER_PATH_DEAD = 244, + + // Route events + + /** A new managed network route was added */ + ZTS_EVENT_ROUTE_ADDED = 250, + /** A managed network route was removed */ + ZTS_EVENT_ROUTE_REMOVED = 251, + + // Address events + + /** A new managed IPv4 address was assigned to this peer */ + ZTS_EVENT_ADDR_ADDED_IP4 = 260, + /** A managed IPv4 address assignment was removed from this peer */ + ZTS_EVENT_ADDR_REMOVED_IP4 = 261, + /** A new managed IPv4 address was assigned to this peer */ + ZTS_EVENT_ADDR_ADDED_IP6 = 262, + /** A managed IPv6 address assignment was removed from this peer */ + ZTS_EVENT_ADDR_REMOVED_IP6 = 263 +}; + +//----------------------------------------------------------------------------// +// zts_errno Error codes // +//----------------------------------------------------------------------------// + +/** Error variable set after each `zts_*` call. Provides additional information. */ extern int zts_errno; #define ZTS_EPERM 1 /* Operation not permitted */ @@ -174,9 +208,7 @@ extern int zts_errno; #define ZTS_ENOANO 55 /* No anode */ #define ZTS_EBADRQC 56 /* Invalid request code */ #define ZTS_EBADSLT 57 /* Invalid slot */ - #define ZTS_EDEADLOCK ZTS_EDEADLK - #define ZTS_EBFONT 59 /* Bad font file format */ #define ZTS_ENOSTR 60 /* Device not a stream */ #define ZTS_ENODATA 61 /* No data available */ @@ -241,20 +273,47 @@ extern int zts_errno; #define ZTS_EISNAM 120 /* Is a named type file */ #define ZTS_EREMOTEIO 121 /* Remote I/O error */ #define ZTS_EDQUOT 122 /* Quota exceeded */ - #define ZTS_ENOMEDIUM 123 /* No medium found */ #define ZTS_EMEDIUMTYPE 124 /* Wrong medium type */ -////////////////////////////////////////////////////////////////////////////// -// Common definitions and structures for interoperability between zts_* and // -// lwIP functions. Some of the code in the following section is a borrowed // -// from the lwIP codebase so that the user doesn't need to include headers // -// from that project in addition to the ZeroTier SDK headers. The license // -// applying to this code borrowed from lwIP is produced below and only // -// applies to the portions of code which are merely renamed versions of // -// their lwIP counterparts. The rest of the code in this C API file is // -// governed by the license text provided at the beginning of this file. // -////////////////////////////////////////////////////////////////////////////// +//----------------------------------------------------------------------------// +// Misc // +//----------------------------------------------------------------------------// + +#if !defined(ZTS_ENABLE_PYTHON) && !defined(ZTS_ENABLE_PINVOKE) +#define ZTS_C_API_ONLY 1 +#endif + +#if !ZTS_NO_STDINT_H +#include +#endif + +#if defined(_MSC_VER) + #ifndef ssize_t + // TODO: Should be SSIZE_T, would require lwIP patch + // #include + // typedef SSIZE_T ssize_t; + typedef int ssize_t; + #endif +#else + #include +#endif + +#ifdef ZTS_ENABLE_PINVOKE + // Used by P/INVOKE wrappers + typedef void (*CppCallback)(void *msg); +#endif + +//----------------------------------------------------------------------------// +// Common definitions and structures for interoperability between zts_* and // +// lwIP functions. Some of the code in the following section is a borrowed // +// from the lwIP codebase so that the user doesn't need to include headers // +// from that project in addition to the ZeroTier SDK headers. The license // +// applying to this code borrowed from lwIP is produced below and only // +// applies to the portions of code which are merely renamed versions of // +// their lwIP counterparts. The rest of the code in this C API file is // +// governed by the license text provided at the beginning of this file. // +//----------------------------------------------------------------------------// /* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. @@ -354,9 +413,9 @@ extern int zts_errno; #define ZTS_FIONREAD ZTS_IOR('f', 127, unsigned long) #define ZTS_FIONBIO ZTS_IOW('f', 126, unsigned long) -////////////////////////////////////////////////////////////////////////////// -// Custom but still mostly standard socket interface structures // -////////////////////////////////////////////////////////////////////////////// +//----------------------------------------------------------------------------// +// Custom but still mostly standard socket interface structures // +//----------------------------------------------------------------------------// typedef uint32_t zts_socklen_t; typedef uint32_t zts_in_addr_t; @@ -412,9 +471,9 @@ struct zts_sockaddr_storage { uint32_t s2_data3[3]; }; -////////////////////////////////////////////////////////////////////////////// -// Structures used to convey details during various callback events // -////////////////////////////////////////////////////////////////////////////// +//----------------------------------------------------------------------------// +// Structures used to convey details during various callback events // +//----------------------------------------------------------------------------// /** * Maximum address assignments per network @@ -839,9 +898,9 @@ struct zts_peer_list unsigned long peerCount; }; -////////////////////////////////////////////////////////////////////////////// -// Python Bindings (Subset of regular socket API) // -////////////////////////////////////////////////////////////////////////////// +//----------------------------------------------------------------------------// +// Python Bindings (Subset of regular socket API) // +//----------------------------------------------------------------------------// #ifdef ZTS_ENABLE_PYTHON @@ -850,8 +909,6 @@ struct zts_peer_list /** * Abstract class used as a director. Pointer to an instance of this class * is provided to the Python layer. - * - * See: https://rawgit.com/swig/swig/master/Doc/Manual/SWIGPlus.html#SWIGPlus_target_language_callbacks */ class PythonDirectorCallbackClass { @@ -877,9 +934,9 @@ int zts_py_getblocking(int fd); #endif // ZTS_ENABLE_PYTHON -////////////////////////////////////////////////////////////////////////////// -// ZeroTier Service Controls // -////////////////////////////////////////////////////////////////////////////// +//----------------------------------------------------------------------------// +// ZeroTier Service and Network Controls // +//----------------------------------------------------------------------------// #if defined(_WIN32) #ifdef ADD_EXPORTS @@ -893,9 +950,9 @@ int zts_py_getblocking(int fd); #define ZTCALL #endif -////////////////////////////////////////////////////////////////////////////// -// Central API // -////////////////////////////////////////////////////////////////////////////// +//----------------------------------------------------------------------------// +// Central API // +//----------------------------------------------------------------------------// #ifdef ZTS_ENABLE_CENTRAL_API @@ -916,7 +973,7 @@ int zts_py_getblocking(int fd); /** * @brief Enables read/write capability. Default before calling this is - * read-only (ZTS_CENTRAL_READ.) + * read-only: `ZTS_CENTRAL_READ` * * @param modes Whether the API allows read, write, or both */ @@ -937,8 +994,8 @@ ZTS_API void ZTCALL zts_central_clear_resp_buf(); * @param url_str The URL to the Central API server * @param token_str User API token * @param resp_buf Destination buffer for raw JSON output - * @param buf_len Size of buffer for server response (specify 0 for default size) - * @return ZTS_ERR_OK on success. ZTS_ERR_ARG if invalid arguments provided. + * @param buf_len Size of buffer for server response (specify `0` for default size) + * @return `ZTS_ERR_OK` if successful, `ZTS_ERR_ARG` if invalid arg. */ ZTS_API int ZTCALL zts_central_init( const char *url_str, const char *token_str, char *resp_buf, uint32_t buf_len); @@ -951,8 +1008,8 @@ ZTS_API void ZTCALL zts_central_cleanup(); * * @param dest_buffer User-provided destination buffer * @param dest_buf_len Length of aforementioned buffer - * @return ZTS_ERR_OK if all contents were copied successfully. - * ZTS_ERR_ARG if provided buffer was too small. + * @return `ZTS_ERR_OK` if all contents were copied successfully. + * `ZTS_ERR_ARG` if provided buffer was too small. */ ZTS_API int ZTCALL zts_central_get_last_response_buf( char *dest_buffer, int dest_buf_len); @@ -1036,7 +1093,7 @@ ZTS_API int ZTCALL zts_central_update_member( * @param nwid The network ID * @param nodeid The node ID * @param is_authed Boolean value for whether this node should be authorized - * @return Standard HTTP response codes. ZTS_ERR_ARG invalid argument specified. + * @return `ZTS_ERR_OK` if successful, `ZTS_ERR_ARG` if invalid arg. */ ZTS_API int ZTCALL zts_central_set_node_auth( int *http_response_code, uint64_t nwid, uint64_t nodeid, uint8_t is_authed); @@ -1053,24 +1110,25 @@ ZTS_API int ZTCALL zts_central_get_members_of_network( #endif // NO_CENTRAL_API -////////////////////////////////////////////////////////////////////////////// -// Identity Management // -////////////////////////////////////////////////////////////////////////////// +//----------------------------------------------------------------------------// +// Identity Management // +//----------------------------------------------------------------------------// /** - * @brief Generates a node identity (public/secret keypair) and stores it in a user-provided buffer. + * @brief Generates a node identity (public/secret key-pair) and stores it in a user-provided buffer. * * @param key_pair_str User-provided destination buffer * @param key_buf_len Length of user-provided destination buffer. Will be set to number of bytes copied. - * @return ZTS_ERR_OK on success. ZTS_ERR_SERVICE on failure. + * @return `ZTS_ERR_OK` if successful, `ZTS_ERR_ARG` if invalid arg. */ -ZTS_API int ZTCALL zts_generate_orphan_identity(char *key_pair_str, uint16_t *key_buf_len); +ZTS_API int ZTCALL zts_generate_orphan_identity( + char *key_pair_str, uint16_t *key_buf_len); /** - * @brief Verifies that a keypair is valid for use. + * @brief Verifies that a key-pair is valid for use. * - * @param key_pair_str Buffer containing keypair - * @return ZTS_ERR_OK on success. ZTS_ERR_SERVICE on failure. + * @param key_pair_str Buffer containing key-pair + * @return `ZTS_ERR_OK` if successful, `ZTS_ERR_ARG` if invalid arg. */ ZTS_API int ZTCALL zts_verify_identity(const char *key_pair_str); @@ -1079,18 +1137,21 @@ ZTS_API int ZTCALL zts_verify_identity(const char *key_pair_str); * * @param key_pair_str User-provided destination buffer * @param key_buf_len Length of user-provided destination buffer. Will be set to number of bytes copied. - * @return ZTS_ERR_OK on success. ZTS_ERR_SERVICE on failure. + * @return `ZTS_ERR_OK` if successful, `ZTS_ERR_SERVICE` if the node + * experiences a problem, `ZTS_ERR_ARG` if invalid arg. */ -ZTS_API int ZTCALL zts_get_node_identity(char *key_pair_str, uint16_t *key_buf_len); +ZTS_API int ZTCALL zts_get_node_identity( + char *key_pair_str, uint16_t *key_buf_len); /** * @brief Starts the ZeroTier service and notifies user application of events via callback. This * variant will assign a user-provided identity to the node. * * @param path path directory where configuration files are stored - * @param callback User-specified callback for ZTS_EVENT_* events + * @param callback User-specified callback for `ZTS_EVENT_*` events * @param port Port that the library should use for talking to other ZeroTier nodes - * @return ZTS_ERR_OK on success. ZTS_ERR_SERVICE or ZTS_ERR_ARG on failure + * @return `ZTS_ERR_OK` if successful, `ZTS_ERR_SERVICE` if the node + * experiences a problem, `ZTS_ERR_ARG` if invalid arg. */ #ifdef ZTS_ENABLE_PYTHON int zts_start_with_identity(const char *key_pair_str, uint16_t key_buf_len, @@ -1114,10 +1175,11 @@ int zts_start_with_identity(const char *key_pair_str, uint16_t key_buf_len, * config details to be written to storage. This is especially useful for situations where * address assignments do not change often. * - * @usage Should be called before zts_start() if you intend on changing its state. + * Should be called before `zts_start()` if you intend on changing its state. * * @param enabled Whether or not this feature is enabled - * @return ZTS_ERR_OK on success. ZTS_ERR_SERVICE on failure. + * @return `ZTS_ERR_OK` if successful, `ZTS_ERR_SERVICE` if the node + * experiences a problem, `ZTS_ERR_ARG` if invalid arg. */ ZTS_API int ZTCALL zts_allow_network_caching(uint8_t allowed); @@ -1130,27 +1192,29 @@ ZTS_API int ZTCALL zts_allow_network_caching(uint8_t allowed); * useful for situations where paths to peers do not change often. This is enabled by default * and can be disabled for cases where one may not want peer details to be written to storage. * - * @usage Should be called before zts_start() if you intend on changing its state. + * Should be called before `zts_start()` if you intend on changing its state. * * @param enabled Whether or not this feature is enabled - * @return ZTS_ERR_OK on success. ZTS_ERR_SERVICE on failure. + * @return `ZTS_ERR_OK` if successful, `ZTS_ERR_SERVICE` if the node + * experiences a problem, `ZTS_ERR_ARG` if invalid arg. */ ZTS_API int ZTCALL zts_allow_peer_caching(uint8_t allowed); /** * @brief Enable or disable whether the service will read node configuration settings from a local.conf * - * @usage Should be called before zts_start() if you intend on changing its state. + * Should be called before `zts_start()` if you intend on changing its state. * * @param enabled Whether or not this feature is enabled - * @return ZTS_ERR_OK on success. ZTS_ERR_SERVICE on failure. + * @return `ZTS_ERR_OK` if successful, `ZTS_ERR_SERVICE` if the node + * experiences a problem, `ZTS_ERR_ARG` if invalid arg. */ ZTS_API int ZTCALL zts_allow_local_conf(uint8_t allowed); /** * @brief Enable or disable whether the service will read or write config data to local storage * - * @usage Should be called before zts_start() if you intend on changing its state. + * Should be called before zts_start() if you intend on changing its state. * * @param enabled Whether or not this feature is enabled * @return ZTS_ERR_OK on success. ZTS_ERR_SERVICE on failure. @@ -1163,7 +1227,8 @@ ZTS_API int ZTCALL zts_disable_local_storage(uint8_t disabled); * @param path path directory where configuration files are stored * @param callback User-specified callback for ZTS_EVENT_* events * @param port Port that the library should use for talking to other ZeroTier nodes - * @return ZTS_ERR_OK on success. ZTS_ERR_SERVICE or ZTS_ERR_ARG on failure + * @return `ZTS_ERR_OK` if successful, `ZTS_ERR_SERVICE` if the node + * experiences a problem, `ZTS_ERR_ARG` if invalid arg. */ #ifdef ZTS_ENABLE_PYTHON ZTS_API int ZTCALL zts_start(const char *path, PythonDirectorCallbackClass *callback, uint16_t port); @@ -1178,20 +1243,22 @@ ZTS_API int ZTCALL zts_disable_local_storage(uint8_t disabled); /** * @brief Stops the ZeroTier service and brings down all virtual network interfaces * - * @usage While the ZeroTier service will stop, the stack driver (with associated timers) + * While the ZeroTier service will stop, the stack driver (with associated timers) * will remain active in case future traffic processing is required. To stop all activity - * and free all resources use zts_free() instead. - * @return ZTS_ERR_OK on success. ZTS_ERR_SERVICE on failure. + * and free all resources use `zts_free()` instead. + * @return `ZTS_ERR_OK` if successful, `ZTS_ERR_SERVICE` if the node + * experiences a problem. Sets `zts_errno` */ ZTS_API int ZTCALL zts_stop(); /** * @brief Restart the ZeroTier service. * - * @usage This call will block until the service has been brought offline. Then + * This call will block until the service has been brought offline. Then * it will return and the user application can then watch for the appropriate * startup callback events. - * @return ZTS_ERR_OK on success. ZTS_ERR_SERVICE on failure. + * @return `ZTS_ERR_OK` if successful, `ZTS_ERR_SERVICE` if the node + * experiences a problem. Sets `zts_errno` */ ZTS_API int ZTCALL zts_restart(); @@ -1200,85 +1267,90 @@ ZTS_API int ZTCALL zts_restart(); * calling this function an application restart will be required before the library can be * used again. * - * @usage This should be called at the end of your program or when you do not anticipate + * This should be called at the end of your program or when you do not anticipate * communicating over ZeroTier - * @return ZTS_ERR_OK on success. ZTS_ERR_SERVICE on failure. + * @return `ZTS_ERR_OK` if successful, `ZTS_ERR_SERVICE` if the node + * experiences a problem. Sets `zts_errno` */ ZTS_API int ZTCALL zts_free(); /** * @brief Join a network * - * @param networkId A 16-digit hexadecimal virtual network ID - * @return ZTS_ERR_OK on success. ZTS_ERR_SERVICE or ZTS_ERR_ARG on failure. + * @param networkId A `16-digit hexadecimal` virtual network ID + * @return `ZTS_ERR_OK` if successful, `ZTS_ERR_SERVICE` if the node + * experiences a problem, `ZTS_ERR_ARG` if invalid arg. */ ZTS_API int ZTCALL zts_join(const uint64_t networkId); /** * @brief Leave a network * - * @param networkId A 16-digit hexadecimal virtual network ID - * @return ZTS_ERR_OK on success. ZTS_ERR_SERVICE or ZTS_ERR_ARG on failure. + * @param networkId A `16-digit hexadecimal` virtual network ID + * @return `ZTS_ERR_OK` if successful, `ZTS_ERR_SERVICE` if the node + * experiences a problem, `ZTS_ERR_ARG` if invalid arg. */ ZTS_API int ZTCALL zts_leave(const uint64_t networkId); /** * @brief Orbit a given moon (user-defined root server) * - * @param moonWorldId A 16-digit hexadecimal world ID - * @param moonSeed A 16-digit hexadecimal seed ID - * @return ZTS_ERR_OK on success. ZTS_ERR_SERVICE or ZTS_ERR_ARG on failure. + * @param moonWorldId A `16-digit hexadecimal` world ID + * @param moonSeed A `16-digit hexadecimal` seed ID + * @return `ZTS_ERR_OK` if successful, `ZTS_ERR_SERVICE` if the node + * experiences a problem, `ZTS_ERR_ARG` if invalid arg. */ ZTS_API int ZTCALL zts_orbit(uint64_t moonWorldId, uint64_t moonSeed); /** * @brief De-orbit a given moon (user-defined root server) * - * @param moonWorldId A 16-digit world ID - * @return ZTS_ERR_OK on success. ZTS_ERR_SERVICE or ZTS_ERR_ARG on failure. + * @param moonWorldId A `16-digit` world ID + * @return `ZTS_ERR_OK` if successful, `ZTS_ERR_SERVICE` if the node + * experiences a problem, `ZTS_ERR_ARG` if invalid arg. */ ZTS_API int ZTCALL zts_deorbit(uint64_t moonWorldId); /** - * @brief Compute a 6PLANE IPv6 address for the given Network ID and Node ID + * @brief Compute a `6PLANE` IPv6 address for the given Network ID and Node ID * * @param addr Destination structure for address * @param networkId Network ID * @param nodeId Node ID - * @return ZTS_ERR_OK on success. ZTS_ERR_ARG on failure. + * @return `ZTS_ERR_OK` if successful, `ZTS_ERR_ARG` if invalid arg. */ ZTS_API int ZTCALL zts_get_6plane_addr(struct zts_sockaddr_storage *addr, const uint64_t networkId, const uint64_t nodeId); /** - * @brief Compute a RFC4193 IPv6 address for the given Network ID and Node ID + * @brief Compute a `RFC4193` IPv6 address for the given Network ID and Node ID * * @param addr Destination structure for address * @param networkId Network ID * @param nodeId Node ID - * @return ZTS_ERR_OK on success. ZTS_ERR_ARG on failure. + * @return `ZTS_ERR_OK` if successful, `ZTS_ERR_ARG` if invalid arg. */ ZTS_API int ZTCALL zts_get_rfc4193_addr( struct zts_sockaddr_storage *addr, const uint64_t networkId, const uint64_t nodeId); /** - * @brief Compute a RFC4193 IPv6 address for the given Network ID and Node ID + * @brief Compute a `RFC4193` IPv6 address for the given Network ID and Node ID * * Ad-hoc Network: - * + * ``` * ffSSSSEEEE000000 * | | | | * | | | Reserved for future use, must be 0 * | | End of port range (hex) * | Start of port range (hex) * Reserved ZeroTier address prefix indicating a controller-less network. - * + * ``` * Ad-hoc networks are public (no access control) networks that have no network controller. Instead * their configuration and other credentials are generated locally. Ad-hoc networks permit only IPv6 * UDP and TCP unicast traffic (no multicast or broadcast) using 6plane format NDP-emulated IPv6 * addresses. In addition an ad-hoc network ID encodes an IP port range. UDP packets and TCP SYN * (connection open) packets are only allowed to destination ports within the encoded range. * - * For example ff00160016000000 is an ad-hoc network allowing only SSH, while ff0000ffff000000 is an + * For example `ff00160016000000` is an ad-hoc network allowing only SSH, while `ff0000ffff000000` is an * ad-hoc network allowing any UDP or TCP port. * * Keep in mind that these networks are public and anyone in the entire world can join them. Care must @@ -1299,9 +1371,9 @@ ZTS_API uint64_t ZTCALL zts_generate_adhoc_nwid_from_range( */ ZTS_API void ZTCALL zts_delay_ms(long interval_ms); -////////////////////////////////////////////////////////////////////////////// -// Statistics // -////////////////////////////////////////////////////////////////////////////// +//----------------------------------------------------------------------------// +// Statistics // +//----------------------------------------------------------------------------// #ifdef ZTS_ENABLE_STATS @@ -1399,7 +1471,7 @@ struct zts_stats { /** * @brief Return all statistical counters for all protocols (inefficient) * - * @usage This function can only be used in debug builds. + * This function can only be used in debug builds. * @return ZTS_ERR_OK on success. ZTS_ERR_ARG or ZTS_ERR_NO_RESULT on failure. */ ZTS_API int ZTCALL zts_get_all_stats(struct zts_stats *statsDest); @@ -1408,68 +1480,99 @@ ZTS_API int ZTCALL zts_get_all_stats(struct zts_stats *statsDest); * @brief Populate the given structure with the requested protocol's * statistical counters (from network stack) * - * @usage This function can only be used in debug builds. + * This function can only be used in debug builds. * @return ZTS_ERR_OK on success. ZTS_ERR_ARG or ZTS_ERR_NO_RESULT on failure. */ -ZTS_API int ZTCALL zts_get_protocol_stats(int protocolType, void *protoStatsDest); +ZTS_API int ZTCALL zts_get_protocol_stats( + int protocolType, void *protoStatsDest); #endif // ZTS_ENABLE_STATS -////////////////////////////////////////////////////////////////////////////// -// Socket API // -////////////////////////////////////////////////////////////////////////////// +//----------------------------------------------------------------------------// +// Socket API // +//----------------------------------------------------------------------------// /** - * @brief Create a socket (sets zts_errno) + * @brief Create a socket * * @param socket_family Address family (ZTS_AF_INET, ZTS_AF_INET6) * @param socket_type Type of socket (ZTS_SOCK_STREAM, ZTS_SOCK_DGRAM, ZTS_SOCK_RAW) * @param protocol Protocols supported on this socket - * @return Numbered file descriptor on success. ZTS_ERR_SERVICE or ZTS_ERR_SOCKET on failure. + * @return Numbered file descriptor on success, `ZTS_ERR_SERVICE` if the node + * experiences a problem, `ZTS_ERR_ARG` if invalid arg. Sets `zts_errno` */ ZTS_API int ZTCALL zts_socket( const int socket_family, const int socket_type, const int protocol); /** - * @brief Connect a socket to a remote host (sets zts_errno) + * @brief Connect a socket to a remote host * * @param fd Socket file descriptor * @param addr Remote host address to connect to * @param addrlen Length of address - * @return ZTS_ERR_OK on success. ZTS_ERR_SOCKET, ZTS_ERR_SERVICE, ZTS_ERR_ARG on failure. + * @return `ZTS_ERR_OK` if successful, `ZTS_ERR_SERVICE` if the node + * experiences a problem, `ZTS_ERR_ARG` if invalid arg. Sets `zts_errno` */ ZTS_API int ZTCALL zts_connect( int fd, const struct zts_sockaddr *addr, zts_socklen_t addrlen); /** - * @brief Bind a socket to a virtual interface (sets zts_errno) + * @brief Connect a socket to a remote host + * + * @param fd Socket file descriptor + * @param family Address family: `ZTS_AF_INET` or `ZTS_AF_INET6` + * @param ipstr Human-readable IP string + * @param port Port + * @return `ZTS_ERR_OK` if successful, `ZTS_ERR_SERVICE` if the node + * experiences a problem, `ZTS_ERR_ARG` if invalid arg. Sets `zts_errno` + */ +ZTS_API int ZTCALL zts_connect_easy(int fd, int family, char *ipstr, int port); + +/** + * @brief Bind a socket to a local address * * @param fd Socket file descriptor * @param addr Local interface address to bind to * @param addrlen Length of address - * @return ZTS_ERR_OK on success. ZTS_ERR_SOCKET, ZTS_ERR_SERVICE, ZTS_ERR_ARG on failure. + * @return `ZTS_ERR_OK` if successful, `ZTS_ERR_SERVICE` if the node + * experiences a problem, `ZTS_ERR_ARG` if invalid arg. Sets `zts_errno` */ ZTS_API int ZTCALL zts_bind( int fd, const struct zts_sockaddr *addr, zts_socklen_t addrlen); /** - * @brief Listen for incoming connections on socket (sets zts_errno) + * @brief Bind a socket to a local address + * + * @param fd Socket file descriptor + * @param family Address family: `ZTS_AF_INET` or `ZTS_AF_INET6` + * @param ipstr Human-readable IP string + * @param port Port + * @return `ZTS_ERR_OK` if successful, `ZTS_ERR_SERVICE` if the node + * experiences a problem, `ZTS_ERR_ARG` if invalid arg. Sets `zts_errno` + */ +ZTS_API int ZTCALL zts_bind_easy(int fd, int family, char *ipstr, int port); + +/** + * @brief Listen for incoming connections on socket * * @param fd Socket file descriptor * @param backlog Number of backlogged connections allowed - * @return ZTS_ERR_OK on success. ZTS_ERR_SOCKET, ZTS_ERR_SERVICE, ZTS_ERR_ARG on failure. + * @return `ZTS_ERR_OK` if successful, `ZTS_ERR_SERVICE` if the node + * experiences a problem, `ZTS_ERR_ARG` if invalid arg. Sets `zts_errno` */ ZTS_API int ZTCALL zts_listen(int fd, int backlog); /** - * @brief Accept an incoming connection (sets zts_errno) + * @brief Accept an incoming connection * * @param fd Socket file descriptor * @param addr Address of remote host for accepted connection * @param addrlen Length of address - * @return New socket file descriptor on success. ZTS_ERR_SOCKET, ZTS_ERR_SERVICE, ZTS_ERR_ARG on failure. + * @return New file descriptor if successful, `ZTS_ERR_SERVICE` if the node + * experiences a problem, `ZTS_ERR_ARG` if invalid arg. Sets `zts_errno` */ -ZTS_API int ZTCALL zts_accept(int fd, struct zts_sockaddr *addr, zts_socklen_t *addrlen); +ZTS_API int ZTCALL zts_accept( + int fd, struct zts_sockaddr *addr, zts_socklen_t *addrlen); // Socket level option number #define ZTS_SOL_SOCKET 0x0fff @@ -1595,38 +1698,41 @@ typedef struct zts_ipv6_mreq { #define ZTS_IPTOS_PREC_ROUTINE 0x00 /** - * @brief Set socket options (sets zts_errno) + * @brief Set socket options * * @param fd Socket file descriptor * @param level Protocol level to which option name should apply * @param optname Option name to set * @param optval Source of option value to set * @param optlen Length of option value - * @return ZTS_ERR_OK on success. ZTS_ERR_SOCKET, ZTS_ERR_SERVICE, ZTS_ERR_ARG on failure. + * @return `ZTS_ERR_OK` if successful, `ZTS_ERR_SERVICE` if the node + * experiences a problem, `ZTS_ERR_ARG` if invalid arg. Sets `zts_errno` */ ZTS_API int ZTCALL zts_setsockopt( int fd, int level, int optname, const void *optval, zts_socklen_t optlen); /** - * @brief Get socket options (sets zts_errno) + * @brief Get socket options * * @param fd Socket file descriptor * @param level Protocol level to which option name should apply * @param optname Option name to get * @param optval Where option value will be stored * @param optlen Length of value - * @return ZTS_ERR_OK on success. ZTS_ERR_SOCKET, ZTS_ERR_SERVICE, ZTS_ERR_ARG on failure. + * @return `ZTS_ERR_OK` if successful, `ZTS_ERR_SERVICE` if the node + * experiences a problem, `ZTS_ERR_ARG` if invalid arg. Sets `zts_errno` */ ZTS_API int ZTCALL zts_getsockopt( int fd, int level, int optname, void *optval, zts_socklen_t *optlen); /** - * @brief Get socket name (sets zts_errno) + * @brief Get socket name * * @param fd Socket file descriptor * @param addr Name associated with this socket * @param addrlen Length of name - * @return ZTS_ERR_OK on success. ZTS_ERR_SOCKET, ZTS_ERR_SERVICE, ZTS_ERR_ARG on failure. + * @return `ZTS_ERR_OK` if successful, `ZTS_ERR_SERVICE` if the node + * experiences a problem, `ZTS_ERR_ARG` if invalid arg. Sets `zts_errno` */ ZTS_API int ZTCALL zts_getsockname(int fd, struct zts_sockaddr *addr, zts_socklen_t *addrlen); @@ -1636,15 +1742,17 @@ ZTS_API int ZTCALL zts_getsockname(int fd, struct zts_sockaddr *addr, zts_sockle * @param fd Socket file descriptor * @param addr Name associated with remote end of this socket * @param addrlen Length of name - * @return ZTS_ERR_OK on success. ZTS_ERR_SOCKET, ZTS_ERR_SERVICE, ZTS_ERR_ARG on failure. + * @return `ZTS_ERR_OK` if successful, `ZTS_ERR_SERVICE` if the node + * experiences a problem, `ZTS_ERR_ARG` if invalid arg. Sets `zts_errno` */ ZTS_API int ZTCALL zts_getpeername(int fd, struct zts_sockaddr *addr, zts_socklen_t *addrlen); /** - * @brief Close a socket (sets zts_errno) + * @brief Close a socket * * @param fd Socket file descriptor - * @return ZTS_ERR_OK on success. ZTS_ERR_SOCKET, ZTS_ERR_SERVICE on failure. + * @return `ZTS_ERR_OK` if successful, `ZTS_ERR_SERVICE` if the node + * experiences a problem, `ZTS_ERR_ARG` if invalid arg. Sets `zts_errno` */ ZTS_API int ZTCALL zts_close(int fd); @@ -1688,7 +1796,7 @@ struct zts_timeval { }; /** - * @brief Monitor multiple file descriptors for "readiness" (sets zts_errno) + * @brief Monitor multiple file descriptors for "readiness" * * @param nfds Set to the highest numbered file descriptor in any of the given sets * @param readfds Set of file descriptors to monitor for READ readiness @@ -1743,38 +1851,41 @@ struct zts_pollfd }; /** - * @brief Wait for some event on a file descriptor. (sets zts_errno) + * @brief Wait for some event on a file descriptor. * * @param fds Set of file descriptors to monitor * @param nfds Number of elements in the fds array * @param timeout How long this call should block - * @return Number of ready file descriptors on success. ZTS_ERR_SOCKET, ZTS_ERR_SERVICE on failure. + * @return Number of ready file descriptors if successful, `ZTS_ERR_SERVICE` if the node + * experiences a problem, `ZTS_ERR_ARG` if invalid arg. Sets `zts_errno` */ ZTS_API int ZTCALL zts_poll(struct zts_pollfd *fds, zts_nfds_t nfds, int timeout); /** - * @brief Control a device (sets zts_errno) + * @brief Control a device * * @param fd Socket file descriptor * @param request * @param argp - * @return ZTS_ERR_OK on success, ZTS_ERR_SERVICE on failure. + * @return `ZTS_ERR_OK` if successful, `ZTS_ERR_SERVICE` if the node + * experiences a problem, `ZTS_ERR_ARG` if invalid arg. Sets `zts_errno` */ ZTS_API int ZTCALL zts_ioctl(int fd, unsigned long request, void *argp); /** - * @brief Send data to remote host (sets zts_errno) + * @brief Send data to remote host * * @param fd Socket file descriptor * @param buf Pointer to data buffer * @param len Length of data to write - * @param flags (e.g. ZTS_MSG_DONTWAIT, ZTS_MSG_MORE) - * @return Byte count sent on success. ZTS_ERR_SOCKET, ZTS_ERR_SERVICE, ZTS_ERR_ARG on failure. + * @param flags (e.g. `ZTS_MSG_DONTWAIT`, `ZTS_MSG_MORE`) + * @return Number of bytes sent if successful, `ZTS_ERR_SERVICE` if the node + * experiences a problem, `ZTS_ERR_ARG` if invalid arg. Sets `zts_errno` */ ZTS_API ssize_t ZTCALL zts_send(int fd, const void *buf, size_t len, int flags); /** - * @brief Send data to remote host (sets zts_errno) + * @brief Send data to remote host * * @param fd Socket file descriptor * @param buf Pointer to data buffer @@ -1782,7 +1893,8 @@ ZTS_API ssize_t ZTCALL zts_send(int fd, const void *buf, size_t len, int flags); * @param flags * @param addr Destination address * @param addrlen Length of destination address - * @return Byte count sent on success. ZTS_ERR_SOCKET, ZTS_ERR_SERVICE, ZTS_ERR_ARG on failure. + * @return Number of bytes sent if successful, `ZTS_ERR_SERVICE` if the node + * experiences a problem, `ZTS_ERR_ARG` if invalid arg. Sets `zts_errno` */ ZTS_API ssize_t ZTCALL zts_sendto( int fd, const void *buf, size_t len, int flags, const struct zts_sockaddr *addr, zts_socklen_t addrlen); @@ -1808,28 +1920,30 @@ struct zts_msghdr { #define ZTS_MSG_CTRUNC 0x08 /** - * @brief Send message to remote host (sets zts_errno) + * @brief Send message to remote host * * @param fd Socket file descriptor * @param msg * @param flags - * @return Byte count sent on success. ZTS_ERR_SOCKET, ZTS_ERR_SERVICE, ZTS_ERR_ARG on failure. + * @return Number of bytes sent if successful, `ZTS_ERR_SERVICE` if the node + * experiences a problem, `ZTS_ERR_ARG` if invalid arg. Sets `zts_errno` */ ZTS_API ssize_t ZTCALL zts_sendmsg(int fd, const struct zts_msghdr *msg, int flags); /** - * @brief Receive data from remote host (sets zts_errno) + * @brief Receive data from remote host * * @param fd Socket file descriptor * @param buf Pointer to data buffer * @param len Length of data buffer * @param flags - * @return Byte count received on success. ZTS_ERR_SOCKET, ZTS_ERR_SERVICE, ZTS_ERR_ARG on failure. + * @return Number of bytes received if successful, `ZTS_ERR_SERVICE` if the node + * experiences a problem, `ZTS_ERR_ARG` if invalid arg. Sets `zts_errno` */ ZTS_API ssize_t ZTCALL zts_recv(int fd, void *buf, size_t len, int flags); /** - * @brief Receive data from remote host (sets zts_errno) + * @brief Receive data from remote host * * @param fd Socket file descriptor * @param buf Pointer to data buffer @@ -1837,58 +1951,64 @@ ZTS_API ssize_t ZTCALL zts_recv(int fd, void *buf, size_t len, int flags); * @param flags * @param addr * @param addrlen - * @return Byte count received on success. ZTS_ERR_SOCKET, ZTS_ERR_SERVICE, ZTS_ERR_ARG on failure. + * @return Number of bytes received if successful, `ZTS_ERR_SERVICE` if the node + * experiences a problem, `ZTS_ERR_ARG` if invalid arg. Sets `zts_errno` */ ZTS_API ssize_t ZTCALL zts_recvfrom( int fd, void *buf, size_t len, int flags, struct zts_sockaddr *addr, zts_socklen_t *addrlen); /** - * @brief Receive a message from remote host (sets zts_errno) + * @brief Receive a message from remote host * * @param fd Socket file descriptor * @param msg * @param flags - * @return Byte count received on success. ZTS_ERR_SOCKET, ZTS_ERR_SERVICE, ZTS_ERR_ARG on failure. + * @return Number of bytes received if successful, `ZTS_ERR_SERVICE` if the node + * experiences a problem, `ZTS_ERR_ARG` if invalid arg. Sets `zts_errno` */ ZTS_API ssize_t ZTCALL zts_recvmsg(int fd, struct zts_msghdr *msg,int flags); /** - * @brief Read bytes from socket onto buffer (sets zts_errno) + * @brief Read bytes from socket onto buffer * * @param fd Socket file descriptor * @param buf Pointer to data buffer * @param len Length of data buffer to receive data - * @return Byte count received on success. ZTS_ERR_SOCKET, ZTS_ERR_SERVICE, ZTS_ERR_ARG on failure. + * @return Number of bytes read if successful, `ZTS_ERR_SERVICE` if the node + * experiences a problem, `ZTS_ERR_ARG` if invalid arg. Sets `zts_errno` */ ZTS_API ssize_t ZTCALL zts_read(int fd, void *buf, size_t len); /** - * @brief Read bytes from socket into multiple buffers (sets zts_errno) + * @brief Read bytes from socket into multiple buffers * * @param fd Socket file descriptor * @param iov Array of destination buffers * @param iovcnt Number of buffers to read into - * @return Byte count received on success. ZTS_ERR_SOCKET, ZTS_ERR_SERVICE, ZTS_ERR_ARG on failure. + * @return Number of bytes read if successful, `ZTS_ERR_SERVICE` if the node + * experiences a problem, `ZTS_ERR_ARG` if invalid arg. Sets `zts_errno` */ ZTS_API ssize_t ZTCALL zts_readv(int fd, const struct zts_iovec *iov, int iovcnt); /** - * @brief Write bytes from buffer to socket (sets zts_errno) + * @brief Write bytes from buffer to socket * * @param fd Socket file descriptor * @param buf Pointer to data buffer * @param len Length of buffer to write - * @return Byte count sent on success. ZTS_ERR_SOCKET, ZTS_ERR_SERVICE, ZTS_ERR_ARG on failure. + * @return Number of bytes written if successful, `ZTS_ERR_SERVICE` if the node + * experiences a problem, `ZTS_ERR_ARG` if invalid arg. Sets `zts_errno` */ ZTS_API ssize_t ZTCALL zts_write(int fd, const void *buf, size_t len); /** - * @brief Write data from multiple buffers to socket. (sets zts_errno) + * @brief Write data from multiple buffers to socket. * * @param fd Socket file descriptor * @param iov Array of source buffers * @param iovcnt Number of buffers to read from - * @return Byte count sent on success. ZTS_ERR_SOCKET, ZTS_ERR_SERVICE, ZTS_ERR_ARG on failure. + * @return Number of bytes written if successful, `ZTS_ERR_SERVICE` if the node + * experiences a problem, `ZTS_ERR_ARG` if invalid arg. Sets `zts_errno` */ ZTS_API ssize_t ZTCALL zts_writev(int fd, const struct zts_iovec *iov, int iovcnt); @@ -1897,17 +2017,231 @@ ZTS_API ssize_t ZTCALL zts_writev(int fd, const struct zts_iovec *iov, int iovcn #define ZTS_SHUT_RDWR 0x2 /** - * @brief Shut down some aspect of a socket (sets zts_errno) + * @brief Shut down some aspect of a socket * * @param fd Socket file descriptor * @param how Which aspects of the socket should be shut down - * @return ZTS_ERR_OK on success. ZTS_ERR_SOCKET, ZTS_ERR_SERVICE, ZTS_ERR_ARG on failure. + * @return `ZTS_ERR_OK` if successful, `ZTS_ERR_SERVICE` if the node + * experiences a problem, `ZTS_ERR_ARG` if invalid arg. Sets `zts_errno` */ ZTS_API int ZTCALL zts_shutdown(int fd, int how); -////////////////////////////////////////////////////////////////////////////// -// DNS // -////////////////////////////////////////////////////////////////////////////// +//----------------------------------------------------------------------------// +// Convenience functions // +//----------------------------------------------------------------------------// + +/** +* Helper functions that simplify API wrapper generation and usage in other +* non-C-like languages. Use simple integer types instead of bit flags, limit +* the number of operations each function performs, prevent the user from +* needing to manipulate the content of structures in a non-native language. +*/ + +/** + * @brief Enable or disable `TCP_NODELAY`. Enabling this is equivalent to + * turning off Nagle's algorithm + * + * @param fd Socket file descriptor + * @param enabled `[0, 1]` integer value + * @return `ZTS_ERR_OK` if successful, `ZTS_ERR_SERVICE` if the node + * experiences a problem, `ZTS_ERR_ARG` if invalid arg. Sets `zts_errno` + */ +ZTS_API int ZTCALL zts_set_no_delay(int fd, int enabled); + +/** + * @brief Return whether `TCP_NODELAY` is enabled + * + * @param fd Socket file descriptor + * @return `1` if enabled, `0` if disabled, `ZTS_ERR_SERVICE` if the node + * experiences a problem, `ZTS_ERR_ARG` if invalid arg. Sets `zts_errno` + */ +ZTS_API int ZTCALL zts_get_no_delay(int fd); + +/** + * @brief Enable or disable `SO_LINGER` while also setting its value + * + * @param fd Socket file descriptor + * @param enabled `[0, 1]` integer value + * @param value How long socket should linger + * @return `ZTS_ERR_OK` if successful, `ZTS_ERR_SERVICE` if the node + * experiences a problem, `ZTS_ERR_ARG` if invalid arg. Sets `zts_errno` + */ +ZTS_API int ZTCALL zts_set_linger(int fd, int enabled, int value); + +/** + * @brief Return whether `SO_LINGER` is enabled + * + * @param fd Socket file descriptor + * @return `1` if enabled, `0` if disabled, `ZTS_ERR_SERVICE` if the node + * experiences a problem, `ZTS_ERR_ARG` if invalid arg. Sets `zts_errno` + */ +ZTS_API int ZTCALL zts_get_linger_enabled(int fd); + +/** + * @brief Return the value of `SO_LINGER` + * + * @param fd Socket file descriptor + * @return Value of `SO_LINGER` if successful, `ZTS_ERR_SERVICE` if the node + * experiences a problem, `ZTS_ERR_ARG` if invalid arg. Sets `zts_errno` + */ +ZTS_API int ZTCALL zts_get_linger_value(int fd); + +/** + * @brief Enable or disable `SO_REUSEADDR` + * + * @param fd Socket file descriptor + * @param enabled `[0, 1]` integer value + * @return `ZTS_ERR_OK` if successful, `ZTS_ERR_SERVICE` if the node + * experiences a problem, `ZTS_ERR_ARG` if invalid arg. Sets `zts_errno` + */ +ZTS_API int ZTCALL zts_set_reuse_addr(int fd, int enabled); + +/** + * @brief Return whether `SO_REUSEADDR` is enabled + * + * @param fd Socket file descriptor + * @return `1` if enabled, `0` if disabled, `ZTS_ERR_SERVICE` if the node + * experiences a problem, `ZTS_ERR_ARG` if invalid arg. Sets `zts_errno` + */ +ZTS_API int ZTCALL zts_get_reuse_addr(int fd); + +/** + * @brief Set the value of `SO_RCVTIMEO` + * + * @param fd Socket file descriptor + * @param something + * @return `ZTS_ERR_OK` if successful, `ZTS_ERR_SERVICE` if the node + * experiences a problem, `ZTS_ERR_ARG` if invalid arg. Sets `zts_errno` + */ +ZTS_API int ZTCALL zts_set_recv_timeout(int fd, int seconds, int microseconds); + +/** + * @brief Return the value of `SO_RCVTIMEO` + * + * @param fd Socket file descriptor + * @return Value of `SO_RCVTIMEO` if successful, `ZTS_ERR_SERVICE` if the node + * experiences a problem, `ZTS_ERR_ARG` if invalid arg. Sets `zts_errno` + */ +ZTS_API int ZTCALL zts_get_recv_timeout(int fd); + +/** + * @brief Set the value of `SO_SNDTIMEO` + * + * @param fd Socket file descriptor + * @param something + * @return `ZTS_ERR_OK` if successful, `ZTS_ERR_SERVICE` if the node + * experiences a problem, `ZTS_ERR_ARG` if invalid arg. Sets `zts_errno` + */ +ZTS_API int ZTCALL zts_set_send_timeout(int fd, int seconds, int microseconds); + +/** + * @brief Return the value of `SO_SNDTIMEO` + * + * @param fd Socket file descriptor + * @return Value of `SO_SNDTIMEO` if successful, `ZTS_ERR_SERVICE` if the node + * experiences a problem, `ZTS_ERR_ARG` if invalid arg. Sets `zts_errno` + */ +ZTS_API int ZTCALL zts_get_send_timeout(int fd); + +/** + * @brief Set the value of `SO_SNDBUF` + * + * @param fd Socket file descriptor + * @param size Size of buffer + * @return `ZTS_ERR_OK` if successful, `ZTS_ERR_SERVICE` if the node + * experiences a problem, `ZTS_ERR_ARG` if invalid arg. Sets `zts_errno` + */ +ZTS_API int ZTCALL zts_set_send_buf_size(int fd, int size); + +/** + * @brief Return the value of `SO_SNDBUF` + * + * @param fd Socket file descriptor + * @return Value of `SO_SNDBUF` if successful, `ZTS_ERR_SERVICE` if the node + * experiences a problem, `ZTS_ERR_ARG` if invalid arg. Sets `zts_errno` + */ +ZTS_API int ZTCALL zts_get_send_buf_size(int fd); + +/** + * @brief Set the value of `SO_RCVBUF` + * + * @param fd Socket file descriptor + * @param size Size of buffer + * @return `ZTS_ERR_OK` if successful, `ZTS_ERR_SERVICE` if the node + * experiences a problem, `ZTS_ERR_ARG` if invalid arg. Sets `zts_errno` + */ +ZTS_API int ZTCALL zts_set_recv_buf_size(int fd, int size); + +/** + * @brief Return the value of `SO_RCVBUF` + * + * @param fd Socket file descriptor + * @return Value of `SO_RCVBUF` if successful, `ZTS_ERR_SERVICE` if the node + * experiences a problem, `ZTS_ERR_ARG` if invalid arg. Sets `zts_errno` + */ +ZTS_API int ZTCALL zts_get_recv_buf_size(int fd); + +/** + * @brief Set the value of `IP_TTL` + * + * @param fd Socket file descriptor + * @param ttl Value of `IP_TTL` + * @return `ZTS_ERR_OK` if successful, `ZTS_ERR_SERVICE` if the node + * experiences a problem, `ZTS_ERR_ARG` if invalid arg. Sets `zts_errno` + */ +ZTS_API int ZTCALL zts_set_ttl(int fd, int ttl); + +/** + * @brief Return the value of `IP_TTL` + * + * @param fd Socket file descriptor + * @return Value of `IP_TTL` `[0,255]` if successful, `ZTS_ERR_SERVICE` if the node + * experiences a problem, `ZTS_ERR_ARG` if invalid arg. Sets `zts_errno` + */ +ZTS_API int ZTCALL zts_get_ttl(int fd); + +/** + * @brief Change blocking behavior `O_NONBLOCK` + * + * @param fd Socket file descriptor + * @param enabled `[0, 1]` integer value, `1` maintains default behavior, + * `0` sets to non-blocking mode + * @return `ZTS_ERR_OK` if successful, `ZTS_ERR_SERVICE` if the node + * experiences a problem, `ZTS_ERR_ARG` if invalid arg. Sets `zts_errno` + */ +ZTS_API int ZTCALL zts_set_blocking(int fd, int enabled); + +/** + * @brief Return whether blocking mode `O_NONBLOCK` is enabled + * + * @param fd Socket file descriptor + * @return `1` if enabled, `0` if disabled, `ZTS_ERR_SERVICE` if the node + * experiences a problem, `ZTS_ERR_ARG` if invalid arg. Sets `zts_errno` + */ +ZTS_API int ZTCALL zts_get_blocking(int fd); + +/** + * @brief Enable or disable `SO_KEEPALIVE` + * + * @param fd Socket file descriptor + * @param enabled `[0, 1]` integer value + * @return `ZTS_ERR_OK` if successful, `ZTS_ERR_SERVICE` if the node + * experiences a problem, `ZTS_ERR_ARG` if invalid arg. Sets `zts_errno` + */ +ZTS_API int ZTCALL zts_set_keepalive(int fd, int enabled); + +/** + * @brief Return whether `SO_KEEPALIVE` is enabled + * + * @param fd Socket file descriptor + * @return `1` if enabled, `0` if disabled, `ZTS_ERR_SERVICE` if the node + * experiences a problem, `ZTS_ERR_ARG` if invalid arg. Sets `zts_errno` + */ +ZTS_API int ZTCALL zts_get_keepalive(int fd); + +//----------------------------------------------------------------------------// +// DNS // +//----------------------------------------------------------------------------// struct zts_hostent { char *h_name; /* Official name of the host. */ @@ -1921,9 +2255,9 @@ struct zts_hostent { }; /** - * @brief Resolve a hostname + * @brief Resolve a host-name * - * @param name A null-terminated string representating the name of the host + * @param name A null-terminated string representing the name of the host * @return Pointer to struct zts_hostent if successful, NULL otherwise */ struct zts_hostent *zts_gethostbyname(const char *name); @@ -1976,15 +2310,14 @@ ZTS_API int ZTCALL zts_dns_set_server(uint8_t index, const zts_ip_addr *addr); */ ZTS_API const zts_ip_addr * ZTCALL zts_dns_get_server(uint8_t index); -////////////////////////////////////////////////////////////////////////////// -// Convenience functions pulled from lwIP // -////////////////////////////////////////////////////////////////////////////// - +//----------------------------------------------------------------------------// +// Convenience functions pulled from lwIP // +//----------------------------------------------------------------------------// /** * Convert numeric IP address (both versions) into ASCII representation. * returns ptr to static buffer; not reentrant! * - * @param addr ip address in network order to convert + * @param addr IP address in network order to convert * @return pointer to a global static (!) buffer that holds the ASCII * representation of addr */ @@ -1996,31 +2329,44 @@ char *zts_ipaddr_ntoa(const zts_ip_addr *addr); * * @param cp IP address string to convert * @param addr conversion result is stored here - * @return 1 on success, 0 on error + * @return `1` on success, `0` on error */ int zts_ipaddr_aton(const char *cp, zts_ip_addr *addr); /** * Convert IPv4 and IPv6 address structures to human-readable text form. * - * @param af Address family (ZTS_AF_INET, ZTS_AF_INET6) + * @param family Address family: `ZTS_AF_INET` or `ZTS_AF_INET6` * @param src Pointer to source address structure * @param dst Pointer to destination character array * @param size Size of the destination buffer * @return On success, returns a non-null pointer to the destination character array */ ZTS_API const char * ZTCALL zts_inet_ntop( - int af, const void *src, char *dst, zts_socklen_t size); + int family, const void *src, char *dst, zts_socklen_t size); /** * Convert C-string IPv4 and IPv6 addresses to binary form. * - * @param af Address family (ZTS_AF_INET, ZTS_AF_INET6) + * @param family Address family: `ZTS_AF_INET` or `ZTS_AF_INET6` * @param src Pointer to source character array * @param dst Pointer to destination address structure - * @return return 1 on success. 0 or -1 on failure. (Does not follow zts_* conventions) + * @return return `1` on success. `0` or `-1` on failure. (Does not follow `zts_*` conventions) */ -ZTS_API int ZTCALL zts_inet_pton(int af, const char *src, void *dst); +ZTS_API int ZTCALL zts_inet_pton(int family, const char *src, void *dst); + +/** + * Convert human-friendly IP string to `zts_sockaddr_in` or `zts_sockaddr_in6`. + * + * @param family Address family: `ZTS_AF_INET` or `ZTS_AF_INET6` + * @param src_ipstr Source IP string + * @param port Port + * @param dest_addr Pointer to destination structure `zts_sockaddr_in` or `zts_sockaddr_in6` + * @param addrlen Size of destination structure. Value-result: Will be set to actual size of data available + * @return return `ZTS_ERR_OK` on success, `ZTS_ERR_ARG` if invalid argument + */ +int ipstr2sockaddr( + int family, char *src_ipstr, int port, struct zts_sockaddr *dest_addr, zts_socklen_t *addrlen); #ifdef __cplusplus } // extern "C" diff --git a/src/Controls.cpp b/src/Controls.cpp index 082fdcb..7ea6339 100644 --- a/src/Controls.cpp +++ b/src/Controls.cpp @@ -70,6 +70,7 @@ namespace ZeroTier jobject objRef = NULL; jmethodID _userCallbackMethodRef = NULL; #endif + extern uint8_t _serviceStateFlags; } #ifdef __cplusplus @@ -421,6 +422,9 @@ JNIEXPORT void JNICALL Java_com_zerotier_libzt_ZeroTier_restart( int zts_free() { + if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) { + return ZTS_ERR_SERVICE; + } if (_getState(ZTS_STATE_FREE_CALLED)) { return ZTS_ERR_SERVICE; } diff --git a/src/Sockets.cpp b/src/Sockets.cpp index 9b9cf8e..6254406 100644 --- a/src/Sockets.cpp +++ b/src/Sockets.cpp @@ -59,12 +59,33 @@ int zts_connect(int fd, const struct zts_sockaddr *addr, zts_socklen_t addrlen) if (!addr) { return ZTS_ERR_ARG; } - if (addrlen > (int)sizeof(struct zts_sockaddr_storage) || addrlen < (int)sizeof(struct zts_sockaddr_in)) { + if (addrlen > (int)sizeof(struct zts_sockaddr_storage) + || addrlen < (int)sizeof(struct zts_sockaddr_in)) { return ZTS_ERR_ARG; } return lwip_connect(fd, (sockaddr*)addr, addrlen); } +int zts_connect_easy(int fd, int family, char *ipstr, int port) { + if (family == ZTS_AF_INET) { + struct zts_sockaddr_in in4; + zts_socklen_t addrlen = sizeof(in4); + ipstr2sockaddr( + family, ipstr, port, (struct zts_sockaddr *)&in4, &addrlen); + struct zts_sockaddr *sa = (struct zts_sockaddr *)&in4; + return zts_connect(fd, sa, addrlen); + } + if (family == ZTS_AF_INET6) { + struct zts_sockaddr_in6 in6; + zts_socklen_t addrlen = sizeof(in6); + ipstr2sockaddr( + family, ipstr, port, (struct zts_sockaddr *)&in6, &addrlen); + struct zts_sockaddr *sa = (struct zts_sockaddr *)&in6; + return zts_connect(fd, sa, addrlen); + } + return ZTS_ERR_ARG; +} + int zts_bind(int fd, const struct zts_sockaddr *addr, zts_socklen_t addrlen) { if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) { @@ -73,12 +94,33 @@ int zts_bind(int fd, const struct zts_sockaddr *addr, zts_socklen_t addrlen) if (!addr) { return ZTS_ERR_ARG; } - if (addrlen > (int)sizeof(struct zts_sockaddr_storage) || addrlen < (int)sizeof(struct zts_sockaddr_in)) { + if (addrlen > (int)sizeof(struct zts_sockaddr_storage) + || addrlen < (int)sizeof(struct zts_sockaddr_in)) { return ZTS_ERR_ARG; } return lwip_bind(fd, (sockaddr*)addr, addrlen); } +int zts_bind_easy(int fd, int family, char *ipstr, int port) { + if (family == ZTS_AF_INET) { + struct zts_sockaddr_in in4; + zts_socklen_t addrlen = sizeof(in4); + ipstr2sockaddr( + family, ipstr, port, (struct zts_sockaddr *)&in4, &addrlen); + struct zts_sockaddr *sa = (struct zts_sockaddr *)&in4; + return zts_bind(fd, sa, addrlen); + } + if (family == ZTS_AF_INET6) { + struct zts_sockaddr_in6 in6; + zts_socklen_t addrlen = sizeof(in6); + ipstr2sockaddr( + family, ipstr, port, (struct zts_sockaddr *)&in6, &addrlen); + struct zts_sockaddr *sa = (struct zts_sockaddr *)&in6; + return zts_bind(fd, sa, addrlen); + } + return ZTS_ERR_ARG; +} + int zts_listen(int fd, int backlog) { if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) { @@ -95,7 +137,8 @@ int zts_accept(int fd, struct zts_sockaddr *addr, zts_socklen_t *addrlen) return lwip_accept(fd, (sockaddr*)addr, (socklen_t*)addrlen); } -int zts_setsockopt(int fd, int level, int optname, const void *optval,zts_socklen_t optlen) +int zts_setsockopt( + int fd, int level, int optname, const void *optval,zts_socklen_t optlen) { if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) { return ZTS_ERR_SERVICE; @@ -103,7 +146,8 @@ int zts_setsockopt(int fd, int level, int optname, const void *optval,zts_sockle return lwip_setsockopt(fd, level, optname, optval, optlen); } -int zts_getsockopt(int fd, int level, int optname, void *optval, zts_socklen_t *optlen) +int zts_getsockopt( + int fd, int level, int optname, void *optval, zts_socklen_t *optlen) { if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) { return ZTS_ERR_SERVICE; @@ -119,7 +163,8 @@ int zts_getsockname(int fd, struct zts_sockaddr *addr, zts_socklen_t *addrlen) if (!addr) { return ZTS_ERR_ARG; } - if (*addrlen > (int)sizeof(struct zts_sockaddr_storage) || *addrlen < (int)sizeof(struct zts_sockaddr_in)) { + if (*addrlen > (int)sizeof(struct zts_sockaddr_storage) + || *addrlen < (int)sizeof(struct zts_sockaddr_in)) { return ZTS_ERR_ARG; } return lwip_getsockname(fd, (sockaddr*)addr, (socklen_t*)addrlen); @@ -133,7 +178,8 @@ int zts_getpeername(int fd, struct zts_sockaddr *addr, zts_socklen_t *addrlen) if (!addr) { return ZTS_ERR_ARG; } - if (*addrlen > (int)sizeof(struct zts_sockaddr_storage) || *addrlen < (int)sizeof(struct zts_sockaddr_in)) { + if (*addrlen > (int)sizeof(struct zts_sockaddr_storage) + || *addrlen < (int)sizeof(struct zts_sockaddr_in)) { return ZTS_ERR_ARG; } return lwip_getpeername(fd, (sockaddr*)addr, (socklen_t*)addrlen); @@ -147,13 +193,15 @@ int zts_close(int fd) return lwip_close(fd); } -int zts_select(int nfds, zts_fd_set *readfds, zts_fd_set *writefds, zts_fd_set *exceptfds, +int zts_select( + int nfds, zts_fd_set *readfds, zts_fd_set *writefds, zts_fd_set *exceptfds, struct zts_timeval *timeout) { if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) { return ZTS_ERR_SERVICE; } - return lwip_select(nfds, (fd_set*)readfds, (fd_set*)writefds, (fd_set*)exceptfds, (timeval*)timeout); + return lwip_select( + nfds, (fd_set*)readfds, (fd_set*)writefds, (fd_set*)exceptfds, (timeval*)timeout); } int zts_fcntl(int fd, int cmd, int flags) @@ -203,7 +251,8 @@ ssize_t zts_sendto(int fd, const void *buf, size_t len, int flags, if (!addr || !buf) { return ZTS_ERR_ARG; } - if (addrlen > (int)sizeof(struct zts_sockaddr_storage) || addrlen < (int)sizeof(struct zts_sockaddr_in)) { + if (addrlen > (int)sizeof(struct zts_sockaddr_storage) + || addrlen < (int)sizeof(struct zts_sockaddr_in)) { return ZTS_ERR_ARG; } return lwip_sendto(fd, buf, len, flags, (sockaddr*)addr, addrlen); @@ -214,6 +263,7 @@ ssize_t zts_sendmsg(int fd, const struct zts_msghdr *msg, int flags) if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) { return ZTS_ERR_SERVICE; } + return lwip_sendmsg(fd, (const struct msghdr *)msg, flags); } @@ -237,7 +287,8 @@ ssize_t zts_recvfrom(int fd, void *buf, size_t len, int flags, if (!buf) { return ZTS_ERR_ARG; } - return lwip_recvfrom(fd, buf, len, flags, (sockaddr*)addr, (socklen_t*)addrlen); + return lwip_recvfrom( + fd, buf, len, flags, (sockaddr*)addr, (socklen_t*)addrlen); } ssize_t zts_recvmsg(int fd, struct zts_msghdr *msg, int flags) @@ -262,12 +313,13 @@ ssize_t zts_read(int fd, void *buf, size_t len) return lwip_read(fd, buf, len); } -ssize_t zts_readv(int s, const struct zts_iovec *iov, int iovcnt) +ssize_t zts_readv(int fd, const struct zts_iovec *iov, int iovcnt) { if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) { return ZTS_ERR_SERVICE; } - return lwip_readv(s, (iovec*)iov, iovcnt); + + return lwip_readv(fd, (iovec*)iov, iovcnt); } ssize_t zts_write(int fd, const void *buf, size_t len) @@ -275,6 +327,7 @@ ssize_t zts_write(int fd, const void *buf, size_t len) if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) { return ZTS_ERR_SERVICE; } + if (!buf) { return ZTS_ERR_ARG; } @@ -286,6 +339,7 @@ ssize_t zts_writev(int fd, const struct zts_iovec *iov, int iovcnt) if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) { return ZTS_ERR_SERVICE; } + return lwip_writev(fd, (iovec*)iov, iovcnt); } @@ -344,19 +398,356 @@ int zts_ipaddr_aton(const char *cp, zts_ip_addr *addr) return ipaddr_aton(cp, (ip_addr_t *)addr); } -const char *zts_inet_ntop(int af, const void *src, char *dst, zts_socklen_t size) +const char *zts_inet_ntop( + int family, const void *src, char *dst, zts_socklen_t size) { - return lwip_inet_ntop(af,src,dst,size); + return lwip_inet_ntop(family,src,dst,size); } -int zts_inet_pton(int af, const char *src, void *dst) +int zts_inet_pton(int family, const char *src, void *dst) { - return lwip_inet_pton(af,src,dst); + return lwip_inet_pton(family,src,dst); } -////////////////////////////////////////////////////////////////////////////// -// Statistics // -////////////////////////////////////////////////////////////////////////////// +int ipstr2sockaddr( + int family, char *src_ipstr, int port, struct zts_sockaddr *dest_addr, zts_socklen_t *addrlen) { + if (family == ZTS_AF_INET) { + struct zts_sockaddr_in in4; + in4.sin_port = htons(port); + in4.sin_family = family; +#if defined(_WIN32) + zts_inet_pton(family, src_ipstr, &(in4.sin_addr.S_addr)); +#else + zts_inet_pton(family, src_ipstr, &(in4.sin_addr.s_addr)); +#endif + dest_addr = (struct zts_sockaddr *)&in4; + *addrlen = sizeof(in4); + return ZTS_ERR_OK; + } + if (family == ZTS_AF_INET6) { + struct zts_sockaddr_in6 in6; + in6.sin6_port = htons(port); + in6.sin6_family = family; +#if defined(_WIN32) + zts_inet_pton(family, src_ipstr, &(in6.sin6_addr)); +#else + zts_inet_pton(family, src_ipstr, &(in6.sin6_addr)); +#endif + dest_addr = (struct zts_sockaddr *)&in6; + *addrlen = sizeof(in6); + return ZTS_ERR_OK; + } + return ZTS_ERR_ARG; +} + +//----------------------------------------------------------------------------// +// Convenience functions // +//----------------------------------------------------------------------------// + +/** +* Helper functions that simplify API wrapper generation and usage in other +* non-C-like languages. Use simple integer types instead of bit flags, limit +* the number of operations each function performs, prevent the user from +* needing to manipulate the content of structures in a non-native language. +*/ + +int zts_set_no_delay(int fd, int enabled) { + if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) { + return ZTS_ERR_SERVICE; + } + if (enabled != 0 && enabled != 1) { + return ZTS_ERR_ARG; + } + return zts_setsockopt( + fd, ZTS_IPPROTO_TCP, ZTS_TCP_NODELAY, (void *)&enabled, sizeof(int)); +} + +int zts_get_no_delay(int fd) +{ + if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) { + return ZTS_ERR_SERVICE; + } + int err, optval = 0; + zts_socklen_t len = sizeof(optval); + if ((err = zts_getsockopt( + fd, ZTS_IPPROTO_TCP, ZTS_TCP_NODELAY, (void *)&optval, &len)) < 0) { + return err; + } + return optval != 0; +} + +int zts_set_linger(int fd, int enabled, int value) { + if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) { + return ZTS_ERR_SERVICE; + } + if (enabled != 0 && enabled != 1) { + return ZTS_ERR_ARG; + } + if (value < 0) { + return ZTS_ERR_ARG; + } + struct zts_linger linger; + linger.l_onoff = enabled; + linger.l_linger = value; + return zts_setsockopt( + fd, ZTS_SOL_SOCKET, ZTS_SO_LINGER, (void *)&linger, sizeof(linger)); +} + +int zts_get_linger_enabled(int fd) +{ + if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) { + return ZTS_ERR_SERVICE; + } + int err; + struct zts_linger linger; + zts_socklen_t len = sizeof(linger); + if ((err = zts_getsockopt( + fd, ZTS_SOL_SOCKET, ZTS_SO_LINGER, (void *)&linger, &len)) < 0) { + return err; + } + return linger.l_onoff; +} + +int zts_get_linger_value(int fd) +{ + if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) { + return ZTS_ERR_SERVICE; + } + int err; + struct zts_linger linger; + zts_socklen_t len = sizeof(linger); + if ((err = zts_getsockopt( + fd, ZTS_SOL_SOCKET, ZTS_SO_LINGER, (void *)&linger, &len)) < 0) { + return err; + } + return linger.l_linger; +} + +int zts_set_reuse_addr(int fd, int enabled) +{ + if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) { + return ZTS_ERR_SERVICE; + } + if (enabled != 0 && enabled != 1) { + return ZTS_ERR_ARG; + } + return zts_setsockopt( + fd, ZTS_SOL_SOCKET, ZTS_SO_REUSEADDR, (void *)&enabled, sizeof(enabled)); +} + +int zts_get_reuse_addr(int fd) +{ + if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) { + return ZTS_ERR_SERVICE; + } + int err; + int optval = 0; + zts_socklen_t optlen = sizeof(optval); + if ((err = zts_getsockopt( + fd, ZTS_SOL_SOCKET, ZTS_SO_REUSEADDR, (void *)&optval, &optlen)) < 0) { + return err; + } + return optval != 0; +} + +int zts_set_recv_timeout(int fd, int seconds, int microseconds) +{ + if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) { + return ZTS_ERR_SERVICE; + } + if (seconds < 0 || microseconds < 0) { + return ZTS_ERR_ARG; + } + struct timeval tv; + tv.tv_sec = seconds; + tv.tv_usec = microseconds; + return zts_setsockopt( + fd, SOL_SOCKET, SO_RCVTIMEO, (void *)&tv, sizeof(tv)); +} + +int zts_get_recv_timeout(int fd) +{ + if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) { + return ZTS_ERR_SERVICE; + } + struct timeval tv; + zts_socklen_t optlen = sizeof(tv); + int err; + if ((err = zts_getsockopt( + fd, SOL_SOCKET, SO_RCVTIMEO, (void *)&tv, &optlen)) < 0) { + return err; + } + return tv.tv_sec; // TODO microseconds +} + +int zts_set_send_timeout(int fd, int seconds, int microseconds) +{ + if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) { + return ZTS_ERR_SERVICE; + } + if (seconds < 0 || microseconds < 0) { + return ZTS_ERR_ARG; + } + struct timeval tv; + tv.tv_sec = seconds; + tv.tv_usec = microseconds; + return zts_setsockopt( + fd, SOL_SOCKET, SO_SNDTIMEO, (void *)&tv, sizeof(tv)); +} + +int zts_get_send_timeout(int fd) +{ + if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) { + return ZTS_ERR_SERVICE; + } + struct zts_timeval tv; + zts_socklen_t optlen = sizeof(tv); + int err; + if ((err = zts_getsockopt( + fd, SOL_SOCKET, SO_SNDTIMEO, (void *)&tv, &optlen)) < 0) { + return err; + } + return tv.tv_sec; // TODO microseconds +} + +int zts_set_send_buf_size(int fd, int size) +{ + if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) { + return ZTS_ERR_SERVICE; + } + if (size < 0) { + return ZTS_ERR_ARG; + } + return zts_setsockopt( + fd, SOL_SOCKET, SO_SNDBUF, (void *)&size, sizeof(int)); +} + +int zts_get_send_buf_size(int fd) +{ + if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) { + return ZTS_ERR_SERVICE; + } + int err, optval = 0; + zts_socklen_t optlen = sizeof(optval); + if ((err = zts_getsockopt( + fd, SOL_SOCKET, SO_SNDBUF, (char *)&optval, &optlen)) < 0) { + return err; + } + return optval; +} + +int zts_set_recv_buf_size(int fd, int size) +{ + if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) { + return ZTS_ERR_SERVICE; + } + if (size < 0) { + return ZTS_ERR_ARG; + } + return zts_setsockopt( + fd, SOL_SOCKET, SO_RCVBUF, (void *)&size, sizeof(int)); +} + +int zts_get_recv_buf_size(int fd) +{ + if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) { + return ZTS_ERR_SERVICE; + } + int err, optval = 0; + zts_socklen_t optlen = sizeof(optval); + if ((err = zts_getsockopt( + fd, SOL_SOCKET, SO_RCVBUF, (char *)&optval, &optlen)) < 0) { + return err; + } + return optval; +} + +int zts_set_ttl(int fd, int ttl) +{ + if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) { + return ZTS_ERR_SERVICE; + } + if (ttl < 0 || ttl > 255) { + return ZTS_ERR_ARG; + } + return zts_setsockopt(fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)); +} + +int zts_get_ttl(int fd) +{ + if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) { + return ZTS_ERR_SERVICE; + } + int err, ttl = 0; + zts_socklen_t optlen = sizeof(ttl); + if ((err = zts_getsockopt(fd, IPPROTO_IP, IP_TTL, &ttl, &optlen)) < 0) { + return err; + } + return ttl; +} + +int zts_set_blocking(int fd, int enabled) +{ + if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) { + return ZTS_ERR_SERVICE; + } + if (enabled != 0 && enabled != 1) { + return ZTS_ERR_ARG; + } + int flags = zts_fcntl(fd, ZTS_F_GETFL, 0); + if (!enabled) { + return zts_fcntl(fd, ZTS_F_SETFL, flags | ZTS_O_NONBLOCK); + } + else { + // Default + return zts_fcntl(fd, ZTS_F_SETFL, flags & (~ZTS_O_NONBLOCK)); + } +} + +int zts_get_blocking(int fd) +{ + if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) { + return ZTS_ERR_SERVICE; + } + int flags = zts_fcntl(fd, ZTS_F_GETFL, 0); + if (flags < 0) { + return flags; + } + return !(flags & ZTS_O_NONBLOCK); +} + +int zts_set_keepalive(int fd, int enabled) +{ + // + if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) { + return ZTS_ERR_SERVICE; + } + if (enabled != 0 && enabled != 1) { + return ZTS_ERR_ARG; + } + int keepalive = enabled; + return zts_setsockopt( + fd, ZTS_SOL_SOCKET, ZTS_SO_KEEPALIVE, &keepalive , sizeof(keepalive)); +} + +int zts_get_keepalive(int fd) +{ + if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) { + return ZTS_ERR_SERVICE; + } + int err; + int optval = 0; + zts_socklen_t optlen = sizeof(optval); + if ((err = zts_getsockopt( + fd, ZTS_SOL_SOCKET, ZTS_SO_KEEPALIVE, (void *)&optval, &optlen)) < 0) { + return err; + } + return optval != 0; +} + +//----------------------------------------------------------------------------// +// Statistics // +//----------------------------------------------------------------------------// #ifdef ZTS_ENABLE_STATS diff --git a/test/selftest-c-api.c b/test/selftest-c-api.c new file mode 100644 index 0000000..9d7ce68 --- /dev/null +++ b/test/selftest-c-api.c @@ -0,0 +1,816 @@ +/** + * Selftest. To be run for every commit. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#pragma GCC diagnostic ignored "-Wunused-value" + +int random32() { + const int BITS_PER_RAND = (int)(log2(RAND_MAX/2 + 1) + 1.0); + int ret = 0; + for (int i = 0; i < sizeof(int) * CHAR_BIT; i += BITS_PER_RAND) { + ret <<= BITS_PER_RAND; + ret |= rand(); + } + return ret; +} + +uint64_t random64() { + return ((uint64_t)random32() << 32) | random32(); +} + +int is_online = 0; +int has_ip4 = 0; +int has_ip6 = 0; + +//----------------------------------------------------------------------------// +// Event Handler // +//----------------------------------------------------------------------------// + +void on_zts_event(void *msgPtr) +{ + struct zts_callback_msg *msg = (struct zts_callback_msg *)msgPtr; + fprintf(stderr, "event=%d\n", msg->eventCode); + if (msg->eventCode == ZTS_EVENT_NODE_ONLINE) { + fprintf(stderr, "ZTS_EVENT_NODE_ONLINE\n"); + is_online = 1; + } + if (msg->eventCode == ZTS_EVENT_NETWORK_READY_IP4) { + fprintf(stderr, "ZTS_EVENT_NETWORK_READY_IP4\n"); + has_ip4 = 1; + } + if (msg->eventCode == ZTS_EVENT_NETWORK_READY_IP6) { + fprintf(stderr, "ZTS_EVENT_NETWORK_READY_IP6\n"); + has_ip6 = 1; + } +} + +void api_value_arg_test( + int8_t i8, int16_t i16, int32_t i32, int64_t i64, void* nullable) +{ + //fprintf(stderr, "%d, %d, %d, %lld, %p\n", i8, i16, i32, i64, nullable); + int res = ZTS_ERR_OK; + +//----------------------------------------------------------------------------// +// Test uninitialized Network Stack API usage // +//----------------------------------------------------------------------------// +/* + res = zts_get_all_stats((struct zts_stats *)nullable); + assert(("pre-init call to zts_get_all_stats(): res != ZTS_ERR_SERVICE", + res == ZTS_ERR_SERVICE)); + res = zts_get_protocol_stats(i32, nullable); + assert(("pre-init call to zts_get_protocol_stats(): res != ZTS_ERR_SERVICE", + res == ZTS_ERR_SERVICE)); +*/ + res = zts_dns_set_server(i8, (const zts_ip_addr *)nullable); + assert(("pre-init call to zts_add_dns_nameserver(): res != ZTS_ERR_SERVICE", + res == ZTS_ERR_SERVICE)); + const zts_ip_addr *res_ptr = zts_dns_get_server(i8); + assert(("pre-init call to zts_del_dns_nameserver(): res != ZTS_ERR_SERVICE", + res == ZTS_ERR_SERVICE)); + +//----------------------------------------------------------------------------// +// Test uninitialized Node API usage // +//----------------------------------------------------------------------------// + + res = zts_stop(); + assert(("pre-init call to zts_stop(): res != ZTS_ERR_SERVICE", + res == ZTS_ERR_SERVICE)); + res = zts_restart(); + assert(("pre-init call to zts_restart(): res != ZTS_ERR_SERVICE", + res == ZTS_ERR_SERVICE)); + res = zts_free(); + assert(("pre-init call to zts_free(): res != ZTS_ERR_SERVICE", + res == ZTS_ERR_SERVICE)); + res = zts_join(i64); + assert(("pre-init call to zts_join(): res != ZTS_ERR_SERVICE", + res == ZTS_ERR_SERVICE)); + res = zts_leave(i64); + assert(("pre-init call to zts_leave(): res != ZTS_ERR_SERVICE", + res == ZTS_ERR_SERVICE)); + res = zts_orbit(i64,i64); + assert(("pre-init call to zts_orbit(): res != ZTS_ERR_SERVICE", + res == ZTS_ERR_SERVICE)); + res = zts_deorbit(i64); + assert(("pre-init call to zts_deorbit(): res != ZTS_ERR_SERVICE", + res == ZTS_ERR_SERVICE)); + +//----------------------------------------------------------------------------// +// Test uninitialized Socket API usage // +//----------------------------------------------------------------------------// + + res = zts_socket(i32,i32,i32); + assert(("pre-init call to zts_socket(): res != ZTS_ERR_SERVICE", + res == ZTS_ERR_SERVICE)); + res = zts_connect(i32, (const struct zts_sockaddr *)nullable, i32); + assert(("pre-init call to zts_connect(): res != ZTS_ERR_SERVICE", + res == ZTS_ERR_SERVICE)); + res = zts_bind(i32, (const struct zts_sockaddr *)nullable, i32); + assert(("pre-init call to zts_bind(): res != ZTS_ERR_SERVICE", + res == ZTS_ERR_SERVICE)); + res = zts_listen(i32, i32); + assert(("pre-init call to zts_listen(): res != ZTS_ERR_SERVICE", + res == ZTS_ERR_SERVICE)); + res = zts_accept(i32, (struct zts_sockaddr *)nullable, (zts_socklen_t *)nullable); + assert(("pre-init call to zts_accept(): res != ZTS_ERR_SERVICE", + res == ZTS_ERR_SERVICE)); + res = zts_setsockopt(i32, i32, i32, nullable, i32); + assert(("pre-init call to zts_setsockopt(): res != ZTS_ERR_SERVICE", + res == ZTS_ERR_SERVICE)); + res = zts_getsockopt(i32, i32, i32, nullable, (zts_socklen_t *)nullable); + assert(("pre-init call to zts_getsockopt(): res != ZTS_ERR_SERVICE", + res == ZTS_ERR_SERVICE)); + res = zts_getsockname(i32, (struct zts_sockaddr *)nullable, (zts_socklen_t *)nullable); + assert(("pre-init call to zts_getsockname(): res != ZTS_ERR_SERVICE", + res == ZTS_ERR_SERVICE)); + res = zts_getpeername(i32, (struct zts_sockaddr *)nullable, (zts_socklen_t *)nullable); + assert(("pre-init call to zts_getpeername(): res != ZTS_ERR_SERVICE", + res == ZTS_ERR_SERVICE)); + res = zts_close(i32); + assert(("pre-init call to zts_close(): res != ZTS_ERR_SERVICE", + res == ZTS_ERR_SERVICE)); + res = zts_select(i32, (zts_fd_set *)nullable, (zts_fd_set *)nullable, (zts_fd_set *)nullable, (struct zts_timeval *)nullable); + assert(("pre-init call to zts_select(): res != ZTS_ERR_SERVICE", + res == ZTS_ERR_SERVICE)); + res = zts_fcntl(i32, i32, i32); + assert(("pre-init call to zts_fcntl(): res != ZTS_ERR_SERVICE", + res == ZTS_ERR_SERVICE)); + res = zts_poll((struct zts_pollfd *)nullable, i32, i32); + assert(("pre-init call to zts_poll(): res != ZTS_ERR_SERVICE", + res == ZTS_ERR_SERVICE)); + res = zts_ioctl(i32, i64, nullable); + assert(("pre-init call to zts_ioctl(): res != ZTS_ERR_SERVICE", + res == ZTS_ERR_SERVICE)); + res = zts_send(i32, nullable, i32, i32); + assert(("pre-init call to zts_send(): res != ZTS_ERR_SERVICE", + res == ZTS_ERR_SERVICE)); + res = zts_sendto(i32, nullable, i32, i32, (const struct zts_sockaddr *)nullable, i32); + assert(("pre-init call to zts_sendto(): res != ZTS_ERR_SERVICE", + res == ZTS_ERR_SERVICE)); + res = zts_sendmsg(i32, (const struct zts_msghdr *)nullable, i32); + assert(("pre-init call to zts_sendmsg(): res != ZTS_ERR_SERVICE", + res == ZTS_ERR_SERVICE)); + res = zts_recv(i32, nullable, i32, i32); + assert(("pre-init call to zts_recv(): res != ZTS_ERR_SERVICE", + res == ZTS_ERR_SERVICE)); + res = zts_recvfrom(i32, nullable, i32, i32, (struct zts_sockaddr *)nullable, (zts_socklen_t *)nullable); + assert(("pre-init call to zts_recvfrom(): res != ZTS_ERR_SERVICE", + res == ZTS_ERR_SERVICE)); + res = zts_recvmsg(i32, (struct zts_msghdr *)nullable, i32); + assert(("pre-init call to zts_recvmsg(): res != ZTS_ERR_SERVICE", + res == ZTS_ERR_SERVICE)); + res = zts_read(i32, nullable, i32); + assert(("pre-init call to zts_read(): res != ZTS_ERR_SERVICE", + res == ZTS_ERR_SERVICE)); + res = zts_readv(i32, (const struct zts_iovec *)nullable, i32); + assert(("pre-init call to zts_readv(): res != ZTS_ERR_SERVICE", + res == ZTS_ERR_SERVICE)); + res = zts_write(i32, nullable, i32); + assert(("pre-init call to zts_write(): res != ZTS_ERR_SERVICE", + res == ZTS_ERR_SERVICE)); + res = zts_writev(i32, (const struct zts_iovec *)nullable, i32); + assert(("pre-init call to zts_writev(): res != ZTS_ERR_SERVICE", + res == ZTS_ERR_SERVICE)); + res = zts_shutdown(i32, i32); + assert(("pre-init call to zts_shutdown(): res != ZTS_ERR_SERVICE", + res == ZTS_ERR_SERVICE)); +} + +void test_pre_service() +{ + +//----------------------------------------------------------------------------// +// Test service-related API functions before initializing service // +//----------------------------------------------------------------------------// + + // Test null values + api_value_arg_test(0,0,0,0,NULL); + + // Test wild values + for (int i=0; i<4096; i++) { + int8_t i8 = (uint8_t)random64(); + int16_t i16 = (uint16_t)random64(); + int32_t i32 = (uint32_t)random64(); + int64_t i64 = (uint64_t)random64(); + int x; + void* nullable = &x; + api_value_arg_test(i8,i16,i32,i64,nullable); + } + +//----------------------------------------------------------------------------// +// Test non-service helper functions // +//----------------------------------------------------------------------------// + + // (B) Test zts_inet_ntop + + char ipstr[ZTS_INET6_ADDRSTRLEN]; + int16_t port = 0; + struct zts_sockaddr_in in4; + + in4.sin_port = htons(8080); +#if defined(_WIN32) + zts_inet_pton(ZTS_AF_INET, "192.168.22.1", &(in4.sin_addr.S_addr)); +#else + zts_inet_pton(ZTS_AF_INET, "192.168.22.1", &(in4.sin_addr.s_addr)); +#endif + + in4.sin_family = ZTS_AF_INET; + + struct zts_sockaddr *sa = (struct zts_sockaddr *)&in4; + if (sa->sa_family == ZTS_AF_INET) { + struct zts_sockaddr_in *in4 = (struct zts_sockaddr_in*)sa; + zts_inet_ntop(ZTS_AF_INET, &(in4->sin_addr), + ipstr, ZTS_INET_ADDRSTRLEN); + port = ntohs(in4->sin_port); + } + if (sa->sa_family == ZTS_AF_INET6) { + struct zts_sockaddr_in6 *in6 = (struct zts_sockaddr_in6*)sa; + zts_inet_ntop(ZTS_AF_INET6, &(in6->sin6_addr), + ipstr, ZTS_INET6_ADDRSTRLEN); + } + + assert(("zts_inet_ntop(): port != 8080", port == 8080)); + assert(("zts_inet_ntop(): strcmp(ipstr, \"192.168.22.1\") != 0", + !strcmp(ipstr, "192.168.22.1"))); + + // (C) Test zts_inet_pton + + uint8_t buf[sizeof(struct zts_in6_addr)]; + char str[ZTS_INET6_ADDRSTRLEN]; + + zts_inet_pton(ZTS_AF_INET, "192.168.22.2", buf); + zts_inet_ntop(ZTS_AF_INET, buf, str, ZTS_INET6_ADDRSTRLEN); + assert(("zts_inet_pton(): strcmp(ipstr, \"192.168.22.2\") != 0", + !strcmp(str, "192.168.22.2"))); +} + +void test_service() +{ + int res = ZTS_ERR_OK; + +//----------------------------------------------------------------------------// +// Test simplified API, proxy for setsockopt/getsockopt/ioctl etc // +//----------------------------------------------------------------------------// + + int s4 = zts_socket(ZTS_AF_INET6, ZTS_SOCK_STREAM, 0); + assert(s4 >= 0); + + // TCP_NODELAY + + // Check value before doing anything + res = zts_get_no_delay(s4); + assert(res == 0); + // Turn on + res = zts_set_no_delay(s4, 1); + assert(res == ZTS_ERR_OK); + res = zts_get_no_delay(s4); + // Should return value instead of error code + assert(res == 1); + // Turn off + res = zts_set_no_delay(s4, 0); + assert(res == ZTS_ERR_OK); + res = zts_get_no_delay(s4); + assert(res == ZTS_ERR_OK); + assert(res == 0); + + // SO_LINGER + + // Check value before doing anything + res = zts_get_linger_enabled(s4); + assert(res == 0); + res = zts_get_linger_value(s4); + assert(res == 0); + // Turn on, set to 7 seconds + res = zts_set_linger(s4, 1, 7); + res = zts_get_linger_enabled(s4); + assert(res == 1); + res = zts_get_linger_value(s4); + assert(res == 7); + res = zts_set_linger(s4, 0, 0); + // Turn off + res = zts_get_linger_enabled(s4); + assert(res == 0); + res = zts_get_linger_value(s4); + assert(res == 0); + + // SO_REUSEADDR + + // Check value before doing anything + res = zts_get_reuse_addr(s4); + assert(res == 0); + // Turn on + res = zts_set_reuse_addr(s4, 1); + assert(res == ZTS_ERR_OK); + res = zts_get_reuse_addr(s4); + // Should return value instead of error code + assert(res == 1); + // Turn off + res = zts_set_reuse_addr(s4, 0); + assert(res == ZTS_ERR_OK); + res = zts_get_reuse_addr(s4); + assert(res == ZTS_ERR_OK); + assert(res == 0); + + // SO_RCVTIMEO + + // Check value before doing anything + res = zts_get_recv_timeout(s4); + assert(res == 0); + // Set to value + res = zts_set_recv_timeout(s4, 3, 0); + res = zts_get_recv_timeout(s4); + assert(res == 3); + res = zts_set_recv_timeout(s4, 0, 0); + // Set to zero + res = zts_get_recv_timeout(s4); + assert(res == 0); + + // SO_SNDTIMEO + + // Check value before doing anything + res = zts_get_send_timeout(s4); + assert(res == 0); + // Set to value + res = zts_set_send_timeout(s4, 4, 0); + res = zts_get_send_timeout(s4); + assert(res == 4); + res = zts_set_send_timeout(s4, 0, 0); + // Set to zero + res = zts_get_send_timeout(s4); + assert(res == 0); + + // SO_SNDBUF + + // Check value before doing anything + res = zts_get_send_buf_size(s4); + assert(res == -1); // Unimplemented as of writing of test + // Set to 7 seconds + res = zts_set_send_buf_size(s4, 1024); + res = zts_get_send_buf_size(s4); + assert(res == -1); // Unimplemented as of writing of test + res = zts_set_send_buf_size(s4, 0); + // Set to zero + res = zts_get_send_buf_size(s4); + assert(res == -1); // Unimplemented as of writing of test + + // SO_RCVBUF + + // Check value before doing anything + res = zts_get_recv_buf_size(s4); + assert(res > 0); + // Set to value + res = zts_set_recv_buf_size(s4, 1024); + res = zts_get_recv_buf_size(s4); + assert(res == 1024); + res = zts_set_recv_buf_size(s4, 0); + // Set to zero + res = zts_get_recv_buf_size(s4); + assert(res == 0); + + // IP_TTL + + // Check value before doing anything + res = zts_get_ttl(s4); + assert(res == 255); // Defaults to max + // Set to value + res = zts_set_ttl(s4, 128); + res = zts_get_ttl(s4); + assert(res == 128); + res = zts_set_ttl(s4, 0); + // Set to zero + res = zts_get_ttl(s4); + assert(res == 0); + + // O_NONBLOCK + + // Check value before doing anything + res = zts_get_blocking(s4); + assert(res == 1); + // Turn off (non-blocking) + res = zts_set_blocking(s4, 0); + assert(res == ZTS_ERR_OK); + res = zts_get_blocking(s4); + // Should return value instead of error code + assert(res == 0); + // Turn off + res = zts_set_blocking(s4, 1); + assert(res == ZTS_ERR_OK); + res = zts_get_blocking(s4); + assert(res == 1); + + // SO_KEEPALIVE + + // Check value before doing anything + res = zts_get_keepalive(s4); + assert(res == 0); + // Turn on + res = zts_set_keepalive(s4, 1); + assert(res == ZTS_ERR_OK); + res = zts_get_keepalive(s4); + // Should return value instead of error code + assert(res == 1); + // Turn off + res = zts_set_keepalive(s4, 0); + assert(res == ZTS_ERR_OK); + res = zts_get_keepalive(s4); + assert(res == ZTS_ERR_OK); + assert(res == 0); + +//----------------------------------------------------------------------------// +// Test *_easy API // +//----------------------------------------------------------------------------// + + //zts_connect_easy(0, ZTS_AF_INET, "192.168.7.9", 7878); + //zts_connect_easy(0, ZTS_AF_INET6, "FCC5:205E:4FF5:5311:DFF0::1", 7878); + //res = zts_bind_easy(0, ZTS_AF_INET6, "::", 8080); + //fprintf(stderr, "res=%d, zts_errno=%d\n", res, zts_errno); + //zts_delay_ms(60000); + +//----------------------------------------------------------------------------// +// Test DNS client functionality // +//----------------------------------------------------------------------------// + +/* + // Set first nameserver + + char *ns1_addr_str = "FCC5:205E:4FF5:5311:DFF0::1"; + zts_ip_addr ns1; + zts_ipaddr_aton(ns1_addr_str, &ns1); + zts_dns_set_server(0, &ns1); + + // Get first nameserver + + const zts_ip_addr *ns1_result; + ns1_result = zts_dns_get_server(0); + printf("dns1 = %s\n", zts_ipaddr_ntoa(ns1_result)); + + // Set second nameserver + + char *ns2_addr_str = "192.168.22.1"; + zts_ip_addr ns2; + zts_ipaddr_aton(ns2_addr_str, &ns2); + zts_dns_set_server(1, &ns2); + + // Get second nameserver + + const zts_ip_addr *ns2_result; + ns2_result = zts_dns_get_server(1); + printf("dns1 = %s\n", zts_ipaddr_ntoa(ns2_result)); + + // Check that each nameserver address was properly set and get + + assert(("zts_dns_get_server(): Address mismatch", !strcmp(ns1_addr_str, zts_ipaddr_ntoa(ns1_result)))); + assert(("zts_dns_get_server(): Address mismatch", !strcmp(ns2_addr_str, zts_ipaddr_ntoa(ns2_result)))); +*/ + +//----------------------------------------------------------------------------// +// Test shutting down the service // +//----------------------------------------------------------------------------// + + zts_stop(); + s4 = zts_socket(ZTS_AF_INET, ZTS_SOCK_STREAM, 0); + assert(("s4 != ZTS_ERR_SERVICE, not shut down", s4 == ZTS_ERR_SERVICE)); +} + +//----------------------------------------------------------------------------// +// Server // +//----------------------------------------------------------------------------// + +#define MAX_CONNECT_TIME 60 +#define BUFLEN 128 +char *msg = "welcome to the machine"; + +void start_server_app(uint16_t port4, uint16_t port6) +{ + int err = ZTS_ERR_OK; + int bytes_read = 0; + int bytes_sent = 0; + + int msglen = strlen(msg); + char dstbuf[BUFLEN]; + int buflen = BUFLEN; + + struct timespec start, now; + int time_diff = 0; + + // + // IPv4 test + // + + fprintf(stderr, "server4: will listen on: 0.0.0.0:%d\n", port4); + int s4 = zts_socket(ZTS_AF_INET, ZTS_SOCK_STREAM, 0); + assert(s4 == 0 && zts_errno == 0); + + err = zts_bind_easy(s4, ZTS_AF_INET, "0.0.0.0", port4); + assert(err == ZTS_ERR_OK && zts_errno == 0); + + err = zts_listen(s4, 1); + assert(err == ZTS_ERR_OK && zts_errno == 0); + + struct zts_sockaddr_in in4; + zts_socklen_t addrlen4 = sizeof(in4); + + int acc4 = -1; + clock_gettime(CLOCK_MONOTONIC, &start); + do { + fprintf(stderr, "server4: accepting...\n"); + acc4 = zts_accept(s4, &in4, &addrlen4); + zts_delay_ms(250); + clock_gettime(CLOCK_MONOTONIC, &now); + time_diff = (now.tv_sec - start.tv_sec); + } while (err < 0 && time_diff < MAX_CONNECT_TIME); + + assert(acc4 == 1 && zts_errno == 0); + + // Read message + memset(dstbuf, 0, buflen); + bytes_read = zts_read(acc4, dstbuf, buflen); + fprintf(stderr, "server4: read (%d) bytes\n", bytes_read); + assert(bytes_read == msglen && zts_errno == 0); + + // Send message + bytes_sent = zts_write(acc4, msg, msglen); + fprintf(stderr, "server4: wrote (%d) bytes\n", bytes_sent); + assert(bytes_sent == msglen && zts_errno == 0); + + zts_close(s4); + assert(err == ZTS_ERR_OK && zts_errno == 0); + + zts_close(acc4); + assert(err == ZTS_ERR_OK && zts_errno == 0); + + // + // IPv6 test + // + + fprintf(stderr, "server: will listen on: [::]:%d\n", port6); + int s6 = zts_socket(ZTS_AF_INET6, ZTS_SOCK_STREAM, 0); + assert(s6 == 0 && zts_errno == 0); + + err = zts_bind_easy(s6, ZTS_AF_INET6, "::", port6); + assert(err == ZTS_ERR_OK && zts_errno == 0); + + err = zts_listen(s6, 1); + assert(err == ZTS_ERR_OK && zts_errno == 0); + + struct zts_sockaddr_in6 in6; + zts_socklen_t addrlen6 = sizeof(in6); + + int acc6 = -1; + clock_gettime(CLOCK_MONOTONIC, &start); + do { + fprintf(stderr, "server6: accepting...\n"); + acc6 = zts_accept(s6, &in6, &addrlen6); + zts_delay_ms(250); + clock_gettime(CLOCK_MONOTONIC, &now); + time_diff = (now.tv_sec - start.tv_sec); + } while (err < 0 && time_diff < MAX_CONNECT_TIME); + + fprintf(stderr, "server6: accepted connection (fd=%d)\n", acc6); + assert(acc6 == 1 && zts_errno == 0); + + // Read message + memset(dstbuf, 0, buflen); + bytes_read = zts_read(acc6, dstbuf, buflen); + fprintf(stderr, "server6: read (%d) bytes\n", bytes_read); + assert(bytes_read == msglen && zts_errno == 0); + + // Send message + bytes_sent = zts_write(acc6, msg, msglen); + fprintf(stderr, "server6: wrote (%d) bytes\n", bytes_sent); + assert(bytes_sent == msglen && zts_errno == 0); + + zts_close(s6); + assert(err == ZTS_ERR_OK && zts_errno == 0); + + zts_close(acc6); + assert(err == ZTS_ERR_OK && zts_errno == 0); + + zts_stop(); + assert(err == ZTS_ERR_OK && zts_errno == 0); + int s = zts_socket(ZTS_AF_INET, ZTS_SOCK_STREAM, 0); + assert(("s != ZTS_ERR_SERVICE, not shut down", s == ZTS_ERR_SERVICE)); +} + +//----------------------------------------------------------------------------// +// Client // +//----------------------------------------------------------------------------// + +void start_client_app(char *ip4, uint16_t port4, char *ip6, uint16_t port6) +{ + int err = ZTS_ERR_OK; + int bytes_read = 0; + int bytes_sent = 0; + + int msglen = strlen(msg); + char dstbuf[BUFLEN]; + int buflen = BUFLEN; + + struct timespec start, now; + int time_diff = 0; + + // + // IPv4 test + // + + err = ZTS_ERR_OK; + int s4 = zts_socket(ZTS_AF_INET, ZTS_SOCK_STREAM, 0); + assert(err == ZTS_ERR_OK && zts_errno == 0); + + zts_set_blocking(s4, 1); + assert(err == ZTS_ERR_OK && zts_errno == 0); + + clock_gettime(CLOCK_MONOTONIC, &start); + do { + fprintf(stderr, "client4: connecting to: %s:%d\n", ip4, port4); + err = zts_connect_easy(s4, ZTS_AF_INET, ip4, port4); + zts_delay_ms(500); + clock_gettime(CLOCK_MONOTONIC, &now); + time_diff = (now.tv_sec - start.tv_sec); + } while (err < 0 && time_diff < MAX_CONNECT_TIME); + assert(err == ZTS_ERR_OK && zts_errno == 0); + + fprintf(stderr, "client4: connected\n"); + // Send message + bytes_sent = zts_write(s4, msg, msglen); + fprintf(stderr, "client4: wrote (%d) bytes\n", bytes_sent); + assert(bytes_sent == msglen && zts_errno == 0); + + // Read message + memset(dstbuf, 0, buflen); + bytes_read = zts_read(s4, dstbuf, buflen); + assert(bytes_read == msglen && zts_errno == 0); + + fprintf(stderr, "client4: read (%d) bytes\n", bytes_read); + assert(bytes_sent == bytes_read && zts_errno == 0); + + zts_close(s4); + assert(err == ZTS_ERR_OK && zts_errno == 0); + + // + // IPv6 test + // + + err = ZTS_ERR_OK; + int s6 = zts_socket(ZTS_AF_INET6, ZTS_SOCK_STREAM, 0); + assert(err == ZTS_ERR_OK && zts_errno == 0); + + zts_set_blocking(s6, 1); + assert(err == ZTS_ERR_OK && zts_errno == 0); + + clock_gettime(CLOCK_MONOTONIC, &start); + do { + fprintf(stderr, "client6: connecting to: %s:%d\n", ip6, port6); + err = zts_connect_easy(s6, ZTS_AF_INET6, ip6, port6); + zts_delay_ms(500); + clock_gettime(CLOCK_MONOTONIC, &now); + time_diff = (now.tv_sec - start.tv_sec); + } while (err < 0 && time_diff < MAX_CONNECT_TIME); + assert(err == ZTS_ERR_OK && zts_errno == 0); + + fprintf(stderr, "client6: connected\n"); + // Send message + bytes_sent = zts_write(s6, msg, msglen); + fprintf(stderr, "client6: wrote (%d) bytes\n", bytes_sent); + assert(bytes_sent == msglen && zts_errno == 0); + + // Read message + memset(dstbuf, 0, buflen); + bytes_read = zts_read(s6, dstbuf, buflen); + assert(bytes_read == msglen && zts_errno == 0); + + fprintf(stderr, "client6: read (%d) bytes\n", bytes_read); + assert(bytes_sent == bytes_read && zts_errno == 0); + + zts_close(s6); + assert(err == ZTS_ERR_OK && zts_errno == 0); + + zts_stop(); + assert(err == ZTS_ERR_OK && zts_errno == 0); + int s = zts_socket(ZTS_AF_INET, ZTS_SOCK_STREAM, 0); + assert(("s != ZTS_ERR_SERVICE, not shut down", s == ZTS_ERR_SERVICE)); +} + +//----------------------------------------------------------------------------// +// Start node // +//----------------------------------------------------------------------------// + +void start_node(char *path, uint64_t nwid) +{ + struct timespec start, now; + int time_diff = 0; + + fprintf(stderr, "starting node...\n"); + clock_gettime(CLOCK_MONOTONIC, &start); + int res = zts_start(path, &on_zts_event, 0); + assert(("error starting service: res != ZTS_ERR_OK", res == ZTS_ERR_OK)); + do { + zts_delay_ms(25); + clock_gettime(CLOCK_MONOTONIC, &now); + time_diff = (now.tv_sec - start.tv_sec); + } while (!is_online && (time_diff < MAX_CONNECT_TIME)); + if (!is_online) { + fprintf(stderr, "node failed to come online\n"); + exit(-1); + } + + fprintf(stderr, "joining: %llx\n", nwid); + clock_gettime(CLOCK_MONOTONIC, &start); + if (nwid) { + zts_join(nwid); + do { + zts_delay_ms(25); + clock_gettime(CLOCK_MONOTONIC, &now); + time_diff = (now.tv_sec - start.tv_sec); + } while ((!has_ip4 || !has_ip6) && (time_diff < MAX_CONNECT_TIME)); + if (!has_ip4 || !has_ip6) { + fprintf(stderr, "node failed to receive assigned addresses\n"); + exit(-1); + } + } +} + +//----------------------------------------------------------------------------// +// Main // +//----------------------------------------------------------------------------// + +int main(int argc, char **argv) +{ + if (argc != 1 && argc != 5 && argc != 7) { + fprintf(stderr, "Invalid number of arguments.\n"); + exit(-1); + } + + // + // API fuzz test + // + + test_pre_service(); + + // + // Default test + // + + // selftest + if (argc == 1) { + srand(time(NULL)); + // Store identities in cwd, join 0x0 + start_node(".",0x0); + test_service(); + exit(0); + } + + // Default test (single node) + // selftest + /* + if (argc == 2) { + srand(time(NULL)); + start_node(argv[1],0x0); + test_service(); + exit(0); + }*/ + + // + // Client/Server communication test + // + + // Server test + if (argc == 5) { + //fprintf(stderr, "server.path = %s\n", argv[1]); + //fprintf(stderr, "server.nwid = %s\n", argv[2]); + //fprintf(stderr, "server.port4 = %s\n", argv[3]); + //fprintf(stderr, "server.port6 = %s\n", argv[4]); + uint64_t nwid = strtoull(argv[2],NULL,16); + int port4 = atoi(argv[3]); + int port6 = atoi(argv[4]); + start_node(argv[1],nwid); + start_server_app(port4, port6); + exit(0); + } + // Client test + if (argc == 7) { + //fprintf(stderr, "client.path = %s\n", argv[1]); + //fprintf(stderr, "client.nwid = %s\n", argv[2]); + //fprintf(stderr, "client.port4 = %s\n", argv[3]); + //fprintf(stderr, "client.ip4 = %s\n", argv[4]); + //fprintf(stderr, "client.port6 = %s\n", argv[5]); + //fprintf(stderr, "client.ip6 = %s\n", argv[6]); + uint64_t nwid = strtoull(argv[2],NULL,16); + int port4 = atoi(argv[3]); + int port6 = atoi(argv[5]); + start_node(argv[1],nwid); + start_client_app(argv[4], port4, argv[6], port6); + exit(0); + } + return 0; +} diff --git a/test/selftest.c b/test/selftest.c deleted file mode 100644 index d02f2ac..0000000 --- a/test/selftest.c +++ /dev/null @@ -1,272 +0,0 @@ -/** - * Selftest. To be run for every commit. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include - -#pragma GCC diagnostic ignored "-Wunused-value" - -int random32() { - const int BITS_PER_RAND = (int)(log2(RAND_MAX/2 + 1) + 1.0); - int ret = 0; - for (int i = 0; i < sizeof(int) * CHAR_BIT; i += BITS_PER_RAND) { - ret <<= BITS_PER_RAND; - ret |= rand(); - } - return ret; -} - -uint64_t random64() { - return ((uint64_t)random32() << 32) | random32(); -} - -void api_value_arg_test(int8_t i8, int16_t i16, int32_t i32, int64_t i64, void* nullable) -{ - //fprintf(stderr, "%d, %d, %d, %lld, %p\n", i8, i16, i32, i64, nullable); - int res = ZTS_ERR_OK; - -//------------------------------------------------------------------------------ -// Test uninitialized Network Stack API usage | -//------------------------------------------------------------------------------ - - res = zts_get_all_stats((struct zts_stats *)nullable); - assert(("pre-init call to zts_get_all_stats(): res != ZTS_ERR_SERVICE", - res == ZTS_ERR_SERVICE)); - res = zts_get_protocol_stats(i32, nullable); - assert(("pre-init call to zts_get_protocol_stats(): res != ZTS_ERR_SERVICE", - res == ZTS_ERR_SERVICE)); - res = zts_dns_set_server(i8, (const zts_ip_addr *)nullable); - assert(("pre-init call to zts_add_dns_nameserver(): res != ZTS_ERR_SERVICE", - res == ZTS_ERR_SERVICE)); - const zts_ip_addr *res_ptr = zts_dns_get_server(i8); - assert(("pre-init call to zts_del_dns_nameserver(): res != ZTS_ERR_SERVICE", - res == ZTS_ERR_SERVICE)); - -//------------------------------------------------------------------------------ -// Test uninitialized Node API usage | -//------------------------------------------------------------------------------ - - res = zts_stop(); - assert(("pre-init call to zts_stop(): res != ZTS_ERR_SERVICE", - res == ZTS_ERR_SERVICE)); - res = zts_restart(); - assert(("pre-init call to zts_restart(): res != ZTS_ERR_SERVICE", - res == ZTS_ERR_SERVICE)); - res = zts_free(); - assert(("pre-init call to zts_free(): res != ZTS_ERR_SERVICE", - res == ZTS_ERR_SERVICE)); - res = zts_join(i64); - assert(("pre-init call to zts_join(): res != ZTS_ERR_SERVICE", - res == ZTS_ERR_SERVICE)); - res = zts_leave(i64); - assert(("pre-init call to zts_leave(): res != ZTS_ERR_SERVICE", - res == ZTS_ERR_SERVICE)); - res = zts_orbit(i64,i64); - assert(("pre-init call to zts_orbit(): res != ZTS_ERR_SERVICE", - res == ZTS_ERR_SERVICE)); - res = zts_deorbit(i64); - assert(("pre-init call to zts_deorbit(): res != ZTS_ERR_SERVICE", - res == ZTS_ERR_SERVICE)); - -//------------------------------------------------------------------------------ -// Test uninitialized Socket API usage | -//------------------------------------------------------------------------------ - - res = zts_socket(i32,i32,i32); - assert(("pre-init call to zts_socket(): res != ZTS_ERR_SERVICE", - res == ZTS_ERR_SERVICE)); - res = zts_connect(i32, (const struct zts_sockaddr *)nullable, i32); - assert(("pre-init call to zts_connect(): res != ZTS_ERR_SERVICE", - res == ZTS_ERR_SERVICE)); - res = zts_bind(i32, (const struct zts_sockaddr *)nullable, i32); - assert(("pre-init call to zts_bind(): res != ZTS_ERR_SERVICE", - res == ZTS_ERR_SERVICE)); - res = zts_listen(i32, i32); - assert(("pre-init call to zts_listen(): res != ZTS_ERR_SERVICE", - res == ZTS_ERR_SERVICE)); - res = zts_accept(i32, (struct zts_sockaddr *)nullable, (zts_socklen_t *)nullable); - assert(("pre-init call to zts_accept(): res != ZTS_ERR_SERVICE", - res == ZTS_ERR_SERVICE)); - res = zts_setsockopt(i32, i32, i32, nullable, i32); - assert(("pre-init call to zts_setsockopt(): res != ZTS_ERR_SERVICE", - res == ZTS_ERR_SERVICE)); - res = zts_getsockopt(i32, i32, i32, nullable, (zts_socklen_t *)nullable); - assert(("pre-init call to zts_getsockopt(): res != ZTS_ERR_SERVICE", - res == ZTS_ERR_SERVICE)); - res = zts_getsockname(i32, (struct zts_sockaddr *)nullable, (zts_socklen_t *)nullable); - assert(("pre-init call to zts_getsockname(): res != ZTS_ERR_SERVICE", - res == ZTS_ERR_SERVICE)); - res = zts_getpeername(i32, (struct zts_sockaddr *)nullable, (zts_socklen_t *)nullable); - assert(("pre-init call to zts_getpeername(): res != ZTS_ERR_SERVICE", - res == ZTS_ERR_SERVICE)); - res = zts_close(i32); - assert(("pre-init call to zts_close(): res != ZTS_ERR_SERVICE", - res == ZTS_ERR_SERVICE)); - res = zts_select(i32, (zts_fd_set *)nullable, (zts_fd_set *)nullable, (zts_fd_set *)nullable, (struct zts_timeval *)nullable); - assert(("pre-init call to zts_select(): res != ZTS_ERR_SERVICE", - res == ZTS_ERR_SERVICE)); - res = zts_fcntl(i32, i32, i32); - assert(("pre-init call to zts_fcntl(): res != ZTS_ERR_SERVICE", - res == ZTS_ERR_SERVICE)); - res = zts_poll((struct zts_pollfd *)nullable, i32, i32); - assert(("pre-init call to zts_poll(): res != ZTS_ERR_SERVICE", - res == ZTS_ERR_SERVICE)); - res = zts_ioctl(i32, i64, nullable); - assert(("pre-init call to zts_ioctl(): res != ZTS_ERR_SERVICE", - res == ZTS_ERR_SERVICE)); - res = zts_send(i32, nullable, i32, i32); - assert(("pre-init call to zts_send(): res != ZTS_ERR_SERVICE", - res == ZTS_ERR_SERVICE)); - res = zts_sendto(i32, nullable, i32, i32, (const struct zts_sockaddr *)nullable, i32); - assert(("pre-init call to zts_sendto(): res != ZTS_ERR_SERVICE", - res == ZTS_ERR_SERVICE)); - res = zts_sendmsg(i32, (const struct zts_msghdr *)nullable, i32); - assert(("pre-init call to zts_sendmsg(): res != ZTS_ERR_SERVICE", - res == ZTS_ERR_SERVICE)); - res = zts_recv(i32, nullable, i32, i32); - assert(("pre-init call to zts_recv(): res != ZTS_ERR_SERVICE", - res == ZTS_ERR_SERVICE)); - res = zts_recvfrom(i32, nullable, i32, i32, (struct zts_sockaddr *)nullable, (zts_socklen_t *)nullable); - assert(("pre-init call to zts_recvfrom(): res != ZTS_ERR_SERVICE", - res == ZTS_ERR_SERVICE)); - res = zts_recvmsg(i32, (struct zts_msghdr *)nullable, i32); - assert(("pre-init call to zts_recvmsg(): res != ZTS_ERR_SERVICE", - res == ZTS_ERR_SERVICE)); - res = zts_read(i32, nullable, i32); - assert(("pre-init call to zts_read(): res != ZTS_ERR_SERVICE", - res == ZTS_ERR_SERVICE)); - res = zts_readv(i32, (const struct zts_iovec *)nullable, i32); - assert(("pre-init call to zts_readv(): res != ZTS_ERR_SERVICE", - res == ZTS_ERR_SERVICE)); - res = zts_write(i32, nullable, i32); - assert(("pre-init call to zts_write(): res != ZTS_ERR_SERVICE", - res == ZTS_ERR_SERVICE)); - res = zts_writev(i32, (const struct zts_iovec *)nullable, i32); - assert(("pre-init call to zts_writev(): res != ZTS_ERR_SERVICE", - res == ZTS_ERR_SERVICE)); - res = zts_shutdown(i32, i32); - assert(("pre-init call to zts_shutdown(): res != ZTS_ERR_SERVICE", - res == ZTS_ERR_SERVICE)); -} - -int main() -{ - srand(time(NULL)); - -//------------------------------------------------------------------------------ -// Test service-related API functions before initializing service | -//------------------------------------------------------------------------------ - - // Test null values - api_value_arg_test(0,0,0,0,NULL); - - // Test wild values - for (int i=0; i<1024; i++) { - int8_t i8 = (uint8_t)random64(); - int16_t i16 = (uint16_t)random64(); - int32_t i32 = (uint32_t)random64(); - int64_t i64 = (uint64_t)random64(); - int x; - void* nullable = &x; - api_value_arg_test(i8,i16,i32,i64,nullable); - } - -//------------------------------------------------------------------------------ -// Test non-service helper functions | -//------------------------------------------------------------------------------ - - // (B) Test zts_inet_ntop - - char ipstr[ZTS_INET6_ADDRSTRLEN]; - int16_t port = 0; - struct zts_sockaddr_in in4; - - in4.sin_port = htons(8080); -#if defined(_WIN32) - zts_inet_pton(ZTS_AF_INET, "192.168.22.1", &(in4.sin_addr.S_addr)); -#else - zts_inet_pton(ZTS_AF_INET, "192.168.22.1", &(in4.sin_addr.s_addr)); -#endif - - in4.sin_family = ZTS_AF_INET; - - struct zts_sockaddr *sa = (struct zts_sockaddr *)&in4; - if (sa->sa_family == ZTS_AF_INET) { - struct zts_sockaddr_in *in4 = (struct zts_sockaddr_in*)sa; - zts_inet_ntop(ZTS_AF_INET, &(in4->sin_addr), - ipstr, ZTS_INET_ADDRSTRLEN); - port = ntohs(in4->sin_port); - } - if (sa->sa_family == ZTS_AF_INET6) { - struct zts_sockaddr_in6 *in6 = (struct zts_sockaddr_in6*)sa; - zts_inet_ntop(ZTS_AF_INET6, &(in6->sin6_addr), - ipstr, ZTS_INET6_ADDRSTRLEN); - } - - assert(("zts_inet_ntop(): port != 8080", port == 8080)); - assert(("zts_inet_ntop(): strcmp(ipstr, \"192.168.22.1\") != 0", - !strcmp(ipstr, "192.168.22.1"))); - - // (C) Test zts_inet_pton - - uint8_t buf[sizeof(struct zts_in6_addr)]; - char str[ZTS_INET6_ADDRSTRLEN]; - - zts_inet_pton(ZTS_AF_INET, "192.168.22.2", buf); - zts_inet_ntop(ZTS_AF_INET, buf, str, ZTS_INET6_ADDRSTRLEN); - assert(("zts_inet_pton(): strcmp(ipstr, \"192.168.22.2\") != 0", - !strcmp(str, "192.168.22.2"))); - -//------------------------------------------------------------------------------ -// Start the service and test a few things | -//------------------------------------------------------------------------------ - - // zts_start(); - -//------------------------------------------------------------------------------ -// Test DNS client functionality | -//------------------------------------------------------------------------------ - -/* - // Set first nameserver - - char *ns1_addr_str = "FCC5:205E:4FF5:5311:DFF0::1"; - zts_ip_addr ns1; - zts_ipaddr_aton(ns1_addr_str, &ns1); - zts_dns_set_server(0, &ns1); - - // Get first nameserver - - const zts_ip_addr *ns1_result; - ns1_result = zts_dns_get_server(0); - printf("dns1 = %s\n", zts_ipaddr_ntoa(ns1_result)); - - // Set second nameserver - - char *ns2_addr_str = "192.168.22.1"; - zts_ip_addr ns2; - zts_ipaddr_aton(ns2_addr_str, &ns2); - zts_dns_set_server(1, &ns2); - - // Get second nameserver - - const zts_ip_addr *ns2_result; - ns2_result = zts_dns_get_server(1); - printf("dns1 = %s\n", zts_ipaddr_ntoa(ns2_result)); - - // Check that each nameserver address was properly set and get - - assert(("zts_dns_get_server(): Address mismatch", !strcmp(ns1_addr_str, zts_ipaddr_ntoa(ns1_result)))); - assert(("zts_dns_get_server(): Address mismatch", !strcmp(ns2_addr_str, zts_ipaddr_ntoa(ns2_result)))); -*/ - - return 0; -}