diff --git a/zookeeper-client/zookeeper-client-c/CMakeLists.txt b/zookeeper-client/zookeeper-client-c/CMakeLists.txt index da1351e20f5..c506d114369 100644 --- a/zookeeper-client/zookeeper-client-c/CMakeLists.txt +++ b/zookeeper-client/zookeeper-client-c/CMakeLists.txt @@ -23,24 +23,24 @@ set(description "zookeeper C client") list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/../../tools/cmake/Modules") # general options -if(UNIX) - add_compile_options(-Wall -fPIC) -elseif(WIN32) +if(MSVC) add_compile_options(/W3) +elseif(MINGW) + add_compile_options(-Wall) +else() + add_compile_options(-Wall -fPIC) endif() -add_definitions(-DUSE_STATIC_LIB) + +option(BUILD_SHARED_LIBS "Build ZooKeeper client shared libraries" OFF) +option(BUILD_STATIC_LIBS "Also build ZooKeeper client static libraries" OFF) # TODO: Enable /WX and /W4 on Windows. Currently there are ~1000 warnings. # TODO: Add Solaris support. -# TODO: Add a shared library option. # TODO: Specify symbols to export. # TODO: Generate doxygen documentation. # Sync API option option(WANT_SYNCAPI "Enables Sync API support" ON) -if(WANT_SYNCAPI) - add_definitions(-DTHREADED) -endif() # CppUnit option if(WIN32 OR APPLE) @@ -130,6 +130,11 @@ endforeach() # function checks include(CheckFunctionExists) +set(ZOOKEEPER_SAVED_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}) +if(WIN32) + # Winsock functions cannot be detected unless the probe links ws2_32. + list(APPEND CMAKE_REQUIRED_LIBRARIES ws2_32) +endif() set(check_functions getcwd gethostbyname @@ -147,10 +152,20 @@ set(check_functions strerror strtol) +# CheckFunctionExists cannot detect 32-bit stdcall Winsock symbols because it +# does not include their declarations, so record the known Windows APIs. +if(WIN32) + set(HAVE_GETHOSTBYNAME 1) + set(HAVE_GETHOSTNAME 1) + set(HAVE_SOCKET 1) +endif() + foreach(fn ${check_functions}) to_have(${fn} name) check_function_exists(${fn} ${name}) endforeach() +set(CMAKE_REQUIRED_LIBRARIES ${ZOOKEEPER_SAVED_REQUIRED_LIBRARIES}) +unset(ZOOKEEPER_SAVED_REQUIRED_LIBRARIES) # library checks set(check_libraries rt m pthread) @@ -161,7 +176,13 @@ endforeach() # IPv6 check include(CheckStructHasMember) -check_struct_has_member("struct sockaddr_in6" sin6_addr "netinet/in.h" ZOO_IPV6_ENABLED) +if(WIN32) + check_struct_has_member("struct sockaddr_in6" sin6_addr + "winsock2.h;ws2tcpip.h" ZOO_IPV6_ENABLED) +else() + check_struct_has_member("struct sockaddr_in6" sin6_addr + "netinet/in.h" ZOO_IPV6_ENABLED) +endif() # configure configure_file(cmake_config.h.in ${CMAKE_CURRENT_BINARY_DIR}/include/config.h) @@ -172,8 +193,8 @@ add_library(hashtable STATIC ${hashtable_sources}) target_include_directories(hashtable PUBLIC include) target_link_libraries(hashtable PUBLIC $<$,$>:m>) -# zookeeper library -set(zookeeper_sources +# ZooKeeper client libraries +set(zookeeper_common_sources src/zookeeper.c src/recordio.c generated/zookeeper.jute.c @@ -181,37 +202,72 @@ set(zookeeper_sources src/zk_hashtable.c src/addrvec.c) -if(WANT_SYNCAPI) - list(APPEND zookeeper_sources src/mt_adaptor.c) -else() - list(APPEND zookeeper_sources src/st_adaptor.c) -endif() - if(CYRUS_SASL_FOUND) - list(APPEND zookeeper_sources src/zk_sasl.c) + list(APPEND zookeeper_common_sources src/zk_sasl.c) endif() if(WIN32) - list(APPEND zookeeper_sources src/winport.c) + list(APPEND zookeeper_common_sources src/winport.c) endif() -add_library(zookeeper STATIC ${zookeeper_sources}) -target_include_directories(zookeeper PUBLIC include ${CMAKE_CURRENT_BINARY_DIR}/include generated) -target_link_libraries(zookeeper PUBLIC - hashtable - $<$:rt> # clock_gettime - $<$:ws2_32>) # Winsock 2.0 +function(add_zookeeper_library target variant library_type adaptor) + add_library(${target} ${library_type} + ${zookeeper_common_sources} ${adaptor}) + target_include_directories(${target} PUBLIC + include ${CMAKE_CURRENT_BINARY_DIR}/include generated) + target_link_libraries(${target} PUBLIC + hashtable + $<$:rt> # clock_gettime + $<$:ws2_32>) # Winsock 2.0 + set_target_properties(${target} PROPERTIES OUTPUT_NAME zookeeper_${variant}) + + if("${library_type}" STREQUAL "SHARED") + if(WIN32) + # ZOOAPI expands to dllexport while compiling the DLL and dllimport for + # consumers. Export the remaining public generated/Jute entry points too. + target_compile_definitions(${target} PRIVATE DLL_EXPORT) + set_target_properties(${target} PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON) + endif() + else() + target_compile_definitions(${target} PUBLIC USE_STATIC_LIB) + endif() + + if("${variant}" STREQUAL "mt") + target_compile_definitions(${target} PUBLIC THREADED) + endif() + + set(zookeeper_library_targets ${zookeeper_library_targets} ${target} PARENT_SCOPE) +endfunction() + +# Keep the historical CMake default (static only). Turning on both options +# produces static and shared artifacts in one build tree. +set(zookeeper_library_targets) +if(BUILD_SHARED_LIBS) + add_zookeeper_library(zookeeper_st_shared st SHARED src/st_adaptor.c) + if(WANT_SYNCAPI) + add_zookeeper_library(zookeeper_mt_shared mt SHARED src/mt_adaptor.c) + endif() +endif() + +if(NOT BUILD_SHARED_LIBS OR BUILD_STATIC_LIBS) + add_zookeeper_library(zookeeper_st_static st STATIC src/st_adaptor.c) + if(WANT_SYNCAPI) + add_zookeeper_library(zookeeper_mt_static mt STATIC src/mt_adaptor.c) + endif() +endif() option(WITH_OPENSSL "turn ON/OFF SSL support, or define openssl library location (default: ON)" ON) message("-- using WITH_OPENSSL=${WITH_OPENSSL}") if(NOT WITH_OPENSSL STREQUAL "OFF") if(NOT WITH_OPENSSL STREQUAL "ON") - set(OPENSSL_ROOT_DIR,${WITH_OPENSSL}) + set(OPENSSL_ROOT_DIR ${WITH_OPENSSL}) endif() find_package(OpenSSL) if(OPENSSL_FOUND) - target_compile_definitions(zookeeper PUBLIC HAVE_OPENSSL_H) - target_link_libraries(zookeeper PUBLIC OpenSSL::SSL OpenSSL::Crypto) + foreach(target ${zookeeper_library_targets}) + target_compile_definitions(${target} PUBLIC HAVE_OPENSSL_H) + target_link_libraries(${target} PUBLIC OpenSSL::SSL OpenSSL::Crypto) + endforeach() message("-- OpenSSL libraries found! will build with SSL support.") else() message("-- WARNING: unable to find OpenSSL libraries! will build without SSL support.") @@ -220,22 +276,47 @@ endif() if(WANT_SYNCAPI AND NOT WIN32) find_package(Threads REQUIRED) - target_link_libraries(zookeeper PUBLIC Threads::Threads) + foreach(target zookeeper_mt_shared zookeeper_mt_static) + if(TARGET ${target}) + target_link_libraries(${target} PUBLIC Threads::Threads) + endif() + endforeach() endif() if(CYRUS_SASL_FOUND) - target_compile_definitions(zookeeper PUBLIC HAVE_CYRUS_SASL_H) - target_link_libraries(zookeeper PUBLIC CyrusSASL) + foreach(target ${zookeeper_library_targets}) + target_compile_definitions(${target} PUBLIC HAVE_CYRUS_SASL_H) + target_link_libraries(${target} PUBLIC CyrusSASL) + endforeach() endif() -# cli executable -add_executable(cli src/cli.c) -target_link_libraries(cli zookeeper) +# Command-line clients follow the Autotools layout. When both library kinds +# are requested, link the samples against the shared libraries. +if(TARGET zookeeper_st_shared) + set(zookeeper_st_cli_target zookeeper_st_shared) +else() + set(zookeeper_st_cli_target zookeeper_st_static) +endif() +add_executable(cli_st src/cli.c) +target_link_libraries(cli_st ${zookeeper_st_cli_target}) + +# Multithreaded client and load generator are only available with Sync API. +if(WANT_SYNCAPI) + if(TARGET zookeeper_mt_shared) + set(zookeeper_mt_cli_target zookeeper_mt_shared) + else() + set(zookeeper_mt_cli_target zookeeper_mt_static) + endif() + add_executable(cli_mt src/cli.c) + target_link_libraries(cli_mt ${zookeeper_mt_cli_target}) -# load_gen executable -if(WANT_SYNCAPI AND NOT WIN32) add_executable(load_gen src/load_gen.c) - target_link_libraries(load_gen zookeeper) + target_link_libraries(load_gen ${zookeeper_mt_cli_target}) + if(WIN32) + # winport is an internal part of the client DLL, while load_gen uses its + # pthread compatibility helpers directly. + target_sources(load_gen PRIVATE src/winport.c) + endif() endif() # tests @@ -273,7 +354,11 @@ if(WANT_CPPUNIT) target_compile_definitions(zktest PRIVATE -DZKSERVER_CMD="${CMAKE_CURRENT_SOURCE_DIR}/tests/zkServer.sh") # TODO: Use `find_library()` for `cppunit`. - target_link_libraries(zktest zookeeper cppunit dl) + if(WANT_SYNCAPI) + target_link_libraries(zktest ${zookeeper_mt_cli_target} cppunit dl) + else() + target_link_libraries(zktest ${zookeeper_st_cli_target} cppunit dl) + endif() # This reads the link flags from the file `tests/wrappers.opt` into # the variable `symbol_wrappers` for use in `target_link_libraries`. diff --git a/zookeeper-client/zookeeper-client-c/README b/zookeeper-client/zookeeper-client-c/README index a31c6aa060b..a34824671fe 100644 --- a/zookeeper-client/zookeeper-client-c/README +++ b/zookeeper-client/zookeeper-client-c/README @@ -39,6 +39,29 @@ Please refer to the "Installation" item under "C Binding" in the Programmer's Guide: https://zookeeper.apache.org/doc/current/developer/programmers-guide/bindings#installation +MINGW-W64 + +The CMake build supports both 32-bit and 64-bit MinGW-w64 toolchains. Before +configuring, run `mvn -pl zookeeper-jute generate-sources -DskipTests` from the +ZooKeeper top-level directory to generate the Jute C sources. A typical 64-bit +cross-build from Linux is: + + cmake -S . -B build-mingw64 \ + -DCMAKE_SYSTEM_NAME=Windows \ + -DCMAKE_C_COMPILER=x86_64-w64-mingw32-gcc \ + -DCMAKE_CXX_COMPILER=x86_64-w64-mingw32-g++ \ + -DBUILD_SHARED_LIBS=ON \ + -DWITH_OPENSSL=OFF -DWITH_CYRUS_SASL=OFF + cmake --build build-mingw64 + +Use i686-w64-mingw32-gcc and i686-w64-mingw32-g++ for a 32-bit build. OpenSSL +and Cyrus SASL can be enabled when MinGW-built versions of those dependencies +are available to CMake. CMake always builds the single-threaded zookeeper_st +library and, unless `-DWANT_SYNCAPI=OFF` is used, also builds the multithreaded +zookeeper_mt library. Set `-DBUILD_STATIC_LIBS=ON` alongside +`-DBUILD_SHARED_LIBS=ON` to produce both static and shared libraries in one +build directory. + EXAMPLE/SAMPLE C CLIENT SHELL NOTE: the ZooKeeper C client shell (cli_st and cli_mt) is meant as a diff --git a/zookeeper-client/zookeeper-client-c/include/win_getopt.h b/zookeeper-client/zookeeper-client-c/include/win_getopt.h index c50c7a47140..479efbc30dd 100644 --- a/zookeeper-client/zookeeper-client-c/include/win_getopt.h +++ b/zookeeper-client/zookeeper-client-c/include/win_getopt.h @@ -77,7 +77,9 @@ #ifndef __GETOPT_H__ -#pragma warning(disable:4996); +#ifdef _MSC_VER +#pragma warning(disable:4996) +#endif #define __GETOPT_H__ @@ -136,6 +138,7 @@ static char EMSG[] = ""; #define EMSG "" #endif +struct option; static int getopt_internal(int, char * const *, const char *, const struct option *, int *, int); static int parse_long_options(char * const *, const char *, diff --git a/zookeeper-client/zookeeper-client-c/include/winconfig.h b/zookeeper-client/zookeeper-client-c/include/winconfig.h index c273a932a24..ff3bac52cf6 100644 --- a/zookeeper-client/zookeeper-client-c/include/winconfig.h +++ b/zookeeper-client/zookeeper-client-c/include/winconfig.h @@ -1,14 +1,14 @@ #ifndef WINCONFIG_H_ #define WINCONFIG_H_ -/* Define to `__inline__' or `__inline' if that's what the C compiler - calls it, or to nothing if 'inline' is not supported under any name. */ +/* GCC-compatible attributes and C99 keywords are supported by MinGW. */ +#ifdef _MSC_VER #ifndef __cplusplus #define inline __inline #endif - #define __attribute__(x) #define __func__ __FUNCTION__ +#endif #define ACL ZKACL /* Conflict with windows API */ diff --git a/zookeeper-client/zookeeper-client-c/src/addrvec.h b/zookeeper-client/zookeeper-client-c/src/addrvec.h index 2a9a8ad9117..ee362df1eaf 100644 --- a/zookeeper-client/zookeeper-client-c/src/addrvec.h +++ b/zookeeper-client/zookeeper-client-c/src/addrvec.h @@ -25,7 +25,7 @@ #include #include #else -#include +#include #include #endif @@ -135,4 +135,3 @@ int addrvec_eq(const addrvec_t *a1, const addrvec_t *a2); #endif // ADDRVEC_H - diff --git a/zookeeper-client/zookeeper-client-c/src/cli.c b/zookeeper-client/zookeeper-client-c/src/cli.c index c34be8d5961..3934210becc 100644 --- a/zookeeper-client/zookeeper-client-c/src/cli.c +++ b/zookeeper-client/zookeeper-client-c/src/cli.c @@ -1054,13 +1054,21 @@ int main(int argc, char **argv) { FD_ZERO(&wfds); FD_ZERO(&efds); while (!shutdownThisThing) { +#ifdef WIN32 + SOCKET fd; +#else int fd; +#endif int interest; int events; struct timeval tv; int rc; zookeeper_interest(zh, &fd, &interest, &tv); +#ifdef WIN32 + if (fd != INVALID_SOCKET) { +#else if (fd != -1) { +#endif if (interest&ZOOKEEPER_READ) { FD_SET(fd, &rfds); } else { diff --git a/zookeeper-client/zookeeper-client-c/src/load_gen.c b/zookeeper-client/zookeeper-client-c/src/load_gen.c index f25edcbe928..84c7192d1dc 100644 --- a/zookeeper-client/zookeeper-client-c/src/load_gen.c +++ b/zookeeper-client/zookeeper-client-c/src/load_gen.c @@ -19,7 +19,9 @@ #include #include "zookeeper_log.h" #include -#ifdef THREADED +#ifdef WIN32 +#include "winport.h" +#else #include #endif #include @@ -29,11 +31,11 @@ static zhandle_t *zh; // ***************************************************************************** // -static pthread_cond_t cond=PTHREAD_COND_INITIALIZER; -static pthread_mutex_t lock=PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t cond; +static pthread_mutex_t lock; -static pthread_cond_t counterCond=PTHREAD_COND_INITIALIZER; -static pthread_mutex_t counterLock=PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t counterCond; +static pthread_mutex_t counterLock; static int counter; @@ -230,6 +232,12 @@ void usage(char *argv[]){ int main(int argc, char **argv) { int nodeCount; int cleaning=0; + + pthread_mutex_init(&lock, 0); + pthread_cond_init(&cond, 0); + pthread_mutex_init(&counterLock, 0); + pthread_cond_init(&counterCond, 0); + if (argc < 4) { usage(argv); } diff --git a/zookeeper-client/zookeeper-client-c/src/mt_adaptor.c b/zookeeper-client/zookeeper-client-c/src/mt_adaptor.c index 174701c7358..a5c76ae911c 100644 --- a/zookeeper-client/zookeeper-client-c/src/mt_adaptor.c +++ b/zookeeper-client/zookeeper-client-c/src/mt_adaptor.c @@ -316,8 +316,13 @@ void adaptor_destroy(zhandle_t *zh) pthread_mutex_destroy(&zh->auth_h.lock); +#ifdef WIN32 + closesocket(adaptor->self_pipe[0]); + closesocket(adaptor->self_pipe[1]); +#else close(adaptor->self_pipe[0]); close(adaptor->self_pipe[1]); +#endif free(adaptor); zh->adaptor_priv=0; } @@ -443,7 +448,7 @@ void *do_io(void *v) } } else if (rc < 0) { - LOG_ERROR(LOGCALLBACK(zh), ("select() failed %d [%d].", rc, WSAGetLastError())); + LOG_ERROR(LOGCALLBACK(zh), "select() failed %d [%d].", rc, WSAGetLastError()); // Clear interest events for zookeeper_process if select() fails. interest = 0; @@ -503,7 +508,7 @@ int32_t fetch_and_add(volatile int32_t* operand, int incr) #ifndef WIN32 return __sync_fetch_and_add(operand, incr); #else - return InterlockedExchangeAdd(operand, incr); + return InterlockedExchangeAdd((volatile LONG *)operand, incr); #endif } diff --git a/zookeeper-client/zookeeper-client-c/src/winport.c b/zookeeper-client/zookeeper-client-c/src/winport.c index 8d8698ee6c5..3a9229833e8 100644 --- a/zookeeper-client/zookeeper-client-c/src/winport.c +++ b/zookeeper-client/zookeeper-client-c/src/winport.c @@ -73,7 +73,11 @@ pthread_t pthread_self(){ int pthread_join(pthread_t _thread, void** ignore) { int rc = WaitForSingleObject( _thread.thread_handle, INFINITE ); - return ((rc == WAIT_OBJECT_0) ? 0: rc); + if (rc == WAIT_OBJECT_0) { + CloseHandle(_thread.thread_handle); + return 0; + } + return rc; } int pthread_detach(pthread_t _thread) @@ -163,6 +167,8 @@ pthread_cond_broadcast (pthread_cond_t *cv) } else LeaveCriticalSection (&cv->waiters_count_lock_); + + return 0; } @@ -202,43 +208,29 @@ pthread_cond_wait (pthread_cond_t *cv, // Always regain the external mutex since that's the guarantee we // give to our callers. WaitForSingleObject (*external_mutex, INFINITE); + + return 0; } int pthread_key_create(pthread_key_t *key, void (*destructor)(void *) ) { - int result = 0; - pthread_key_t* newkey; - - if ((newkey = (pthread_key_t*) calloc (1, sizeof (pthread_key_t))) == NULL) - { - result = ENOMEM; - } - else if ((newkey->key = TlsAlloc ()) == TLS_OUT_OF_INDEXES) - { - result = EAGAIN; - free (newkey); - newkey = NULL; - } - else if (destructor != NULL) - { - //--we have to store the function pointer for destructor, so that we can call it - //--to free up the user allocated storage-- - newkey->destructor = destructor; - } - key = newkey; - return (result); + key->key = TlsAlloc(); + if (key->key == TLS_OUT_OF_INDEXES) + return EAGAIN; + + key->destructor = destructor; + return 0; } int pthread_key_delete(pthread_key_t key) { - int rc = 0; + int rc; LPVOID lpvData = TlsGetValue(key.key); - rc = TlsFree (key.key); - rc = (rc != 0 ) ? 0 : GetLastError(); if (key.destructor != NULL && lpvData != 0){ key.destructor(lpvData); //we take control of calling destructor, instead of calling it on thread exit. } - free (&key); + rc = TlsFree (key.key); + rc = (rc != 0 ) ? 0 : GetLastError(); return (rc); } @@ -253,7 +245,7 @@ void *pthread_getspecific(pthread_key_t key) int pthread_setspecific(pthread_key_t key, const void *value) { - int rc = TlsSetValue (key.key, value); + int rc = TlsSetValue (key.key, (LPVOID)value); return ((rc != 0 ) ? 0 : GetLastError()); } @@ -266,10 +258,6 @@ int gettimeofday(struct timeval *tp, void *tzp) { return 0; } -int close(SOCKET fd) { - return closesocket(fd); -} - int Win32WSAStartup() { WORD wVersionRq; @@ -302,6 +290,3 @@ double drand48(void) } #endif //WIN32 - - - diff --git a/zookeeper-client/zookeeper-client-c/src/winport.h b/zookeeper-client/zookeeper-client-c/src/winport.h index e8f10ba046b..b60afdf2fd0 100644 --- a/zookeeper-client/zookeeper-client-c/src/winport.h +++ b/zookeeper-client/zookeeper-client-c/src/winport.h @@ -31,18 +31,22 @@ #include /* must always be included before ws2tcpip.h */ #include /* for struct sock_addr used in zookeeper.h */ -/* POSIX names are deprecated, use ISO conformant names instead. */ +/* POSIX names are deprecated by Microsoft's CRT. MinGW provides them. */ +#ifdef _MSC_VER #define strdup _strdup #define getcwd _getcwd #define getpid _getpid /* Windows "secure" versions of POSIX reentrant functions */ #define strtok_r strtok_s -#define localtime_r(a,b) localtime_s(b,a) +#endif + +/* MinGW's CRT also exposes localtime_s rather than localtime_r. */ +#define localtime_r(a,b) (localtime_s((b),(a)) == 0 ? (b) : NULL) /* After this version of MSVC, snprintf became a defined function, and so cannot be redefined, nor can #ifndef be used to guard it. */ -#if ((defined(_MSC_VER) && _MSC_VER < 1900) || !defined(_MSC_VER)) +#if defined(_MSC_VER) && _MSC_VER < 1900 #define snprintf _snprintf #endif @@ -54,7 +58,9 @@ #include +#ifdef _MSC_VER typedef int ssize_t; +#endif typedef HANDLE pthread_mutex_t; struct pthread_t_ @@ -128,7 +134,6 @@ void *pthread_getspecific(pthread_key_t key); int pthread_setspecific(pthread_key_t key, const void *value); int gettimeofday(struct timeval *tp, void *tzp); -int close(SOCKET fd); int Win32WSAStartup(); void Win32WSACleanup(); double drand48(void); diff --git a/zookeeper-client/zookeeper-client-c/src/zk_log.c b/zookeeper-client/zookeeper-client-c/src/zk_log.c index 79ebd61f18e..dec703ab8c4 100644 --- a/zookeeper-client/zookeeper-client-c/src/zk_log.c +++ b/zookeeper-client/zookeeper-client-c/src/zk_log.c @@ -24,8 +24,11 @@ #ifndef WIN32 #include #else +#ifdef _MSC_VER typedef DWORD pid_t; +#endif #include /* for getpid */ +#include "winport.h" #endif #include @@ -200,4 +203,3 @@ void zoo_set_debug_level(ZooLogLevel level) if(level>ZOO_LOG_LEVEL_DEBUG)level=ZOO_LOG_LEVEL_DEBUG; logLevel=level; } - diff --git a/zookeeper-client/zookeeper-client-c/src/zookeeper.c b/zookeeper-client/zookeeper-client-c/src/zookeeper.c index cdd9d74a537..7dccc583c80 100644 --- a/zookeeper-client/zookeeper-client-c/src/zookeeper.c +++ b/zookeeper-client/zookeeper-client-c/src/zookeeper.c @@ -95,11 +95,15 @@ #endif #ifdef WIN32 +#include "winport.h" #include /* for getpid */ #include /* for getcwd */ #define EAI_ADDRFAMILY WSAEINVAL /* is this still needed? */ #define EHOSTDOWN EPIPE #define ESTALE ENODEV +#define ZOO_INVALID_SOCKET INVALID_SOCKET +#else +#define ZOO_INVALID_SOCKET -1 #endif #define IF_DEBUG(x) if(logLevel==ZOO_LOG_LEVEL_DEBUG) {x;} @@ -433,7 +437,19 @@ void get_system_time(struct timeval *tv) { int ret; -#ifdef __MACH__ // OS X +#ifdef _WIN32 + LARGE_INTEGER counts, countsPerSecond, countsPerMicrosecond; + if (QueryPerformanceFrequency(&countsPerSecond) && + QueryPerformanceCounter(&counts)) { + countsPerMicrosecond.QuadPart = countsPerSecond.QuadPart / 1000000; + tv->tv_sec = (long)(counts.QuadPart / countsPerSecond.QuadPart); + tv->tv_usec = (long)((counts.QuadPart % countsPerSecond.QuadPart) / + countsPerMicrosecond.QuadPart); + ret = 0; + } else { + ret = gettimeofday(tv, NULL); + } +#elif defined(__MACH__) // OS X clock_serv_t cclock; mach_timespec_t mts; ret = host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock); @@ -462,18 +478,6 @@ void get_system_time(struct timeval *tv) ret = clock_gettime(CLOCK_MONOTONIC, &ts); tv->tv_sec = ts.tv_sec; tv->tv_usec = ts.tv_nsec / 1000; -#elif _WIN32 - LARGE_INTEGER counts, countsPerSecond, countsPerMicrosecond; - if (QueryPerformanceFrequency(&countsPerSecond) && - QueryPerformanceCounter(&counts)) { - countsPerMicrosecond.QuadPart = countsPerSecond.QuadPart / 1000000; - tv->tv_sec = (long)(counts.QuadPart / countsPerSecond.QuadPart); - tv->tv_usec = (long)((counts.QuadPart % countsPerSecond.QuadPart) / - countsPerMicrosecond.QuadPart); - ret = 0; - } else { - ret = gettimeofday(tv, NULL); - } #else ret = gettimeofday(tv, NULL); #endif @@ -646,7 +650,7 @@ zk_hashtable *child_result_checker(zhandle_t *zh, int rc) void close_zsock(zsock_t *fd) { - if (fd->sock != -1) { + if (fd->sock != ZOO_INVALID_SOCKET) { #ifdef HAVE_OPENSSL_H if (fd->ssl_sock) { SSL_free(fd->ssl_sock); @@ -655,8 +659,12 @@ void close_zsock(zsock_t *fd) fd->ssl_ctx = NULL; } #endif +#ifdef _WIN32 + closesocket(fd->sock); +#else close(fd->sock); - fd->sock = -1; +#endif + fd->sock = ZOO_INVALID_SOCKET; } } @@ -678,7 +686,7 @@ static void destroy(zhandle_t *zh) free(zh->hostname); zh->hostname = NULL; } - if (zh->fd->sock != -1) { + if (zh->fd->sock != ZOO_INVALID_SOCKET) { close_zsock(zh->fd); memset(&zh->addr_cur, 0, sizeof(zh->addr_cur)); zh->state = 0; @@ -1065,7 +1073,7 @@ int update_addrs(zhandle_t *zh, const struct timeval *ref_time) // Check if we are due for a host name resolution. (See // zoo_set_servers_resolution_delay. The answer is always "yes" // if no reference is provided or the file descriptor is invalid.) - if (ref_time && zh->fd->sock != -1) { + if (ref_time && zh->fd->sock != ZOO_INVALID_SOCKET) { int do_resolve; if (zh->resolve_delay_ms <= 0) { @@ -1180,7 +1188,7 @@ int update_addrs(zhandle_t *zh, const struct timeval *ref_time) // If we need to do a reconfig and we're currently connected to a server, // then force close that connection so on next interest() call we'll make a // new connection - if (zh->reconfig == 1 && zh->fd->sock != -1) + if (zh->reconfig == 1 && zh->fd->sock != ZOO_INVALID_SOCKET) { close_zsock(zh->fd); zh->state = ZOO_NOTCONNECTED_STATE; @@ -1267,8 +1275,14 @@ static void log_env(zhandle_t *zh) { LOG_INFO(LOGCALLBACK(zh), "Client environment:os.version="); #endif -#ifdef HAVE_GETLOGIN +#if defined(HAVE_GETLOGIN) && !defined(WIN32) LOG_INFO(LOGCALLBACK(zh), "Client environment:user.name=%s", getlogin()); +#elif defined(WIN32) + { + const char *username = getenv("USERNAME"); + LOG_INFO(LOGCALLBACK(zh), "Client environment:user.name=%s", + username ? username : ""); + } #else LOG_INFO(LOGCALLBACK(zh), "Client environment:user.name="); #endif @@ -1328,7 +1342,7 @@ static zhandle_t *zookeeper_init_internal(const char *host, watcher_fn watcher, } zh->fd = calloc(1, sizeof(zsock_t)); - zh->fd->sock = -1; + zh->fd->sock = ZOO_INVALID_SOCKET; if (cert) { zh->fd->cert = calloc(1, sizeof(zcert_t)); memcpy(zh->fd->cert, cert, sizeof(zcert_t)); @@ -2373,7 +2387,7 @@ static int ping_rw_server(zhandle_t* zh) sock_flags = SOCK_STREAM; #endif fd.sock = socket(zh->addr_rw_server.ss_family, sock_flags, 0); - if (fd.sock < 0) { + if (fd.sock == ZOO_INVALID_SOCKET) { return 0; } @@ -2440,11 +2454,18 @@ static void zookeeper_set_sock_noblock(zhandle_t *zh, socket_t sock) static void zookeeper_set_sock_timeout(zhandle_t *zh, socket_t s, int timeout) { +#ifdef _WIN32 + DWORD timeout_ms = (DWORD)timeout * 1000; + + setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, (const char *)&timeout_ms, sizeof(timeout_ms)); + setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (const char *)&timeout_ms, sizeof(timeout_ms)); +#else struct timeval tv; tv.tv_sec = timeout; setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(struct timeval)); setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(struct timeval)); +#endif } static void zookeeper_set_sock_nodelay(zhandle_t *zh, socket_t sock) @@ -2551,7 +2572,7 @@ int zookeeper_interest(zhandle_t *zh, socket_t *fd, int *interest, tv->tv_sec = 0; tv->tv_usec = 0; - if (*fd == -1) { + if (*fd == ZOO_INVALID_SOCKET) { /* * If we previously failed to connect to server pool (zh->delay == 1) * then we need delay our connection on this iteration 1/60 of the @@ -2578,7 +2599,7 @@ int zookeeper_interest(zhandle_t *zh, socket_t *fd, int *interest, zoo_cycle_next_server(zh); } zh->fd->sock = socket(zh->addr_cur.ss_family, sock_flags, 0); - if (zh->fd->sock < 0) { + if (zh->fd->sock == ZOO_INVALID_SOCKET) { rc = handle_socket_error_msg(zh, __LINE__, __func__, @@ -2638,7 +2659,7 @@ int zookeeper_interest(zhandle_t *zh, socket_t *fd, int *interest, zh->ping_rw_timeout = MIN_RW_TIMEOUT; } - if (zh->fd->sock != -1) { + if (zh->fd->sock != ZOO_INVALID_SOCKET) { int idle_recv = calculate_interval(&zh->last_recv, &now); int idle_send = calculate_interval(&zh->last_send, &now); int recv_to = zh->recv_timeout*2/3 - idle_recv; @@ -2955,14 +2976,20 @@ static int process_sasl_response(zhandle_t *zh, char *buffer, int len) static int check_events(zhandle_t *zh, int events) { - if (zh->fd->sock == -1) + if (zh->fd->sock == ZOO_INVALID_SOCKET) return ZINVALIDSTATE; #ifdef HAVE_OPENSSL_H if ((events&ZOOKEEPER_WRITE) && (zh->state == ZOO_SSL_CONNECTING_STATE) && zh->fd->cert != NULL) { int rc, error; socklen_t len = sizeof(error); - rc = getsockopt(zh->fd->sock, SOL_SOCKET, SO_ERROR, &error, &len); + rc = getsockopt(zh->fd->sock, SOL_SOCKET, SO_ERROR, +#ifdef _WIN32 + (char *)&error, +#else + &error, +#endif + &len); /* the description in section 16.4 "Non-blocking connect" * in UNIX Network Programming vol 1, 3rd edition, points out * that sometimes the error is in errno and sometimes in error */ @@ -2982,7 +3009,13 @@ static int check_events(zhandle_t *zh, int events) if ((events&ZOOKEEPER_WRITE)&&(zh->state == ZOO_CONNECTING_STATE)) { int rc, error; socklen_t len = sizeof(error); - rc = getsockopt(zh->fd->sock, SOL_SOCKET, SO_ERROR, &error, &len); + rc = getsockopt(zh->fd->sock, SOL_SOCKET, SO_ERROR, +#ifdef _WIN32 + (char *)&error, +#else + &error, +#endif + &len); /* the description in section 16.4 "Non-blocking connect" * in UNIX Network Programming vol 1, 3rd edition, points out * that sometimes the error is in errno and sometimes in error */ @@ -3379,7 +3412,7 @@ static void isSocketReadable(zhandle_t* zh) fd_set rfds; struct timeval waittime = {0, 0}; FD_ZERO(&rfds); - FD_SET( zh->fd , &rfds); + FD_SET(zh->fd->sock, &rfds); if (select(0, &rfds, NULL, NULL, &waittime) <= 0){ // socket not readable -- no more responses to process zh->socket_readable.tv_sec=zh->socket_readable.tv_usec=0; @@ -3986,7 +4019,7 @@ static int Request_path_watch_init(zhandle_t *zh, int mode, static int nonblocking_send(zhandle_t *zh, int rc) { if (adaptor_send_queue(zh, 0) < 0) { - if (zh->fd->sock != -1) { + if (zh->fd->sock != ZOO_INVALID_SOCKET) { close_zsock(zh->fd); zh->state = ZOO_NOTCONNECTED_STATE; } @@ -5136,7 +5169,9 @@ static const char* format_endpoint_info(const struct sockaddr_storage* ep) #else static __thread char buf[134] = { 0 }; #endif +#ifndef _WIN32 char addrstr[INET6_ADDRSTRLEN] = { 0 }; +#endif const char *fmtstring; void *inaddr; char is_inet6 = 0; // poor man's boolean