Base port to Windows (#2810)
authorSean Campbell <seancampbell04@gmail.com>
Fri, 27 Jul 2018 13:21:03 +0000 (09:21 -0400)
committerSebastian Harl <sh@tokkee.org>
Fri, 27 Jul 2018 13:21:03 +0000 (15:21 +0200)
* Update configure.ac / Makefile.am to build for Windows using Cygwin.
* Update build.sh to build for Windows.
* Base port of the daemon.
* Include gnulib as a submodule.

23 files changed:
.gitmodules [new file with mode: 0644]
Makefile.am
README
build.sh
configure.ac
gnulib [new submodule]
src/daemon/cmd_windows.c [new file with mode: 0755]
src/daemon/collectd.c
src/daemon/collectd.h
src/daemon/common.c
src/daemon/common.h
src/daemon/globals.h
src/daemon/plugin.c
src/daemon/plugin.h
src/daemon/utils_heap.c
src/daemon/utils_random.c
src/libcollectdclient/client.c
src/libcollectdclient/collectd/network.h
src/libcollectdclient/collectd/server.h
src/libcollectdclient/network.c
src/libcollectdclient/network_buffer.c
src/libcollectdclient/server.c
src/liboconfig/scanner.l

diff --git a/.gitmodules b/.gitmodules
new file mode 100644 (file)
index 0000000..009ae43
--- /dev/null
@@ -0,0 +1,3 @@
+[submodule "gnulib"]
+       path = gnulib
+       url = git://git.savannah.gnu.org/gnulib.git
index 4d32f74..cb40148 100644 (file)
@@ -1,6 +1,13 @@
 ACLOCAL_AMFLAGS = -I m4
 AM_YFLAGS = -d
 
+if BUILD_WIN32
+pkgdatadir=$(datadir)
+pkglibdir=$(libdir)/plugins
+pkglocalstatedir=${localstatedir}
+else
+pkglocalstatedir=${localstatedir}/lib/${PACKAGE_NAME}
+endif
 
 BUILT_SOURCES = \
        src/libcollectdclient/collectd/lcc_features.h \
@@ -99,7 +106,13 @@ pkginclude_HEADERS = \
 
 lib_LTLIBRARIES = libcollectdclient.la
 
+if BUILD_WIN32
+# TODO: Build all executables on Windows as well.
+sbin_PROGRAMS = \
+        collectd
 
+bin_PROGRAMS =
+else
 sbin_PROGRAMS = \
        collectd \
        collectdmon
@@ -109,9 +122,10 @@ bin_PROGRAMS = \
        collectd-nagios \
        collectd-tg \
        collectdctl
+endif # BUILD_WIN32
 
 
-noinst_LTLIBRARIES = \
+EXTRA_LTLIBRARIES = \
        libavltree.la \
        libcmds.la \
        libcommon.la \
@@ -160,6 +174,9 @@ PLUGIN_LDFLAGS = \
        -module \
        -avoid-version \
        -export-symbols-regex '\<module_register\>'
+if BUILD_WIN32
+PLUGIN_LDFLAGS += -shared -no-undefined -lcollectd -L.
+endif
 
 
 AM_CPPFLAGS = \
@@ -167,13 +184,26 @@ AM_CPPFLAGS = \
        -DPREFIX='"${prefix}"' \
        -DCONFIGFILE='"${sysconfdir}/${PACKAGE_NAME}.conf"' \
        -DLOCALSTATEDIR='"${localstatedir}"' \
-       -DPKGLOCALSTATEDIR='"${localstatedir}/lib/${PACKAGE_NAME}"' \
+       -DPKGLOCALSTATEDIR='"${pkglocalstatedir}"' \
        -DPLUGINDIR='"${pkglibdir}"' \
        -DPKGDATADIR='"${pkgdatadir}"'
+if BUILD_WIN32
+AM_CPPFLAGS += -DNOGDI
+endif
 
+COMMON_DEPS =
+if BUILD_WIN32
+COMMON_DEPS += collectd.exe
+endif
 
 # Link to these libraries..
 COMMON_LIBS = $(PTHREAD_LIBS)
+if BUILD_WIN32
+COMMON_LIBS += -lws2_32
+endif
+if BUILD_WITH_GNULIB
+COMMON_LIBS += -lgnu
+endif
 if BUILD_WITH_CAPABILITY
 COMMON_LIBS += -lcap
 endif
@@ -195,7 +225,6 @@ endif
 
 
 collectd_SOURCES = \
-       src/daemon/cmd.c \
        src/daemon/cmd.h \
        src/daemon/collectd.c \
        src/daemon/collectd.h \
@@ -239,6 +268,13 @@ collectd_LDADD = \
        $(COMMON_LIBS) \
        $(DLOPEN_LIBS)
 
+if BUILD_WIN32
+collectd_SOURCES += src/daemon/cmd_windows.c
+collectd_LDFLAGS += -ldl -Wl,--out-implib,libcollectd.a
+else
+collectd_SOURCES += src/daemon/cmd.c
+endif
+       
 if BUILD_FEATURE_DAEMON
 collectd_CPPFLAGS += -DPIDFILE='"${localstatedir}/run/${PACKAGE_NAME}.pid"'
 endif
@@ -250,6 +286,9 @@ collectd_CFLAGS += $(BUILD_WITH_LIBSTATGRAB_CFLAGS)
 collectd_LDADD += $(BUILD_WITH_LIBSTATGRAB_LDFLAGS)
 endif
 
+if BUILD_WIN32
+collectd_LDFLAGS += -Wl,--out-implib,libcollectd.a
+endif
 
 collectdmon_SOURCES = src/collectdmon.c
 
@@ -501,6 +540,10 @@ libcollectdclient_la_CPPFLAGS = \
        -I$(srcdir)/src/daemon
 libcollectdclient_la_LDFLAGS = -version-info 2:0:1
 libcollectdclient_la_LIBADD = -lm
+if BUILD_WIN32
+libcollectdclient_la_LDFLAGS += -shared -no-undefined
+libcollectdclient_la_LIBADD += -lgnu -lws2_32 -liphlpapi
+endif
 if BUILD_WITH_LIBGCRYPT
 libcollectdclient_la_CPPFLAGS += $(GCRYPT_CPPFLAGS)
 libcollectdclient_la_LDFLAGS += $(GCRYPT_LDFLAGS)
@@ -1042,6 +1085,7 @@ if BUILD_PLUGIN_LOGFILE
 pkglib_LTLIBRARIES += logfile.la
 logfile_la_SOURCES = src/logfile.c
 logfile_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+logfile_la_DEPENDENCIES = $(COMMON_DEPS)
 endif
 
 if BUILD_PLUGIN_LOG_LOGSTASH
@@ -1471,7 +1515,7 @@ python_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(LIBPYTHON_LDFLAGS)
 endif
 
 if HAVE_LIBMNL
-noinst_LTLIBRARIES += libtaskstats.la
+EXTRA_LTLIBRARIES += libtaskstats.la
 libtaskstats_la_SOURCES = \
        src/utils_taskstats.c \
        src/utils_taskstats.h
@@ -2138,3 +2182,4 @@ generic-jmx.jar: $(JAVA_TIMESTAMP_FILE)
 
 jar_DATA = collectd-api.jar generic-jmx.jar
 endif
+
diff --git a/README b/README
index a111e84..a594703 100644 (file)
--- a/README
+++ b/README
@@ -1044,6 +1044,37 @@ To generate the `configure` script, you'll need the following dependencies:
 The `build.sh' script takes no arguments.
 
 
+Building on Windows
+-----------------------------------------------
+
+Collectd can be built on Windows using Cygwin, and the result is a binary that
+runs natively on Windows. That is, Cygwin is only needed for building, not running,
+collectd.
+
+You will need to install the following Cygwin packages:
+- automake
+- bison
+- flex
+- git
+- libtool
+- make
+- mingw64-x86_64-dlfcn
+- mingw64-x86_64-gcc-core
+- mingw64-x86_64-zlib
+- pkg-config
+
+To build, just run the `build.sh' script in your Cygwin terminal. By default, it installs
+to "C:/Program Files/collectd". You can change the location by setting the INSTALL_DIR
+variable:
+
+$ export INSTALL_DIR="C:/some/other/install/directory"
+$ ./build.sh
+
+or:
+
+$ INSTALL_DIR="C:/some/other/install/directory" ./build.sh
+
+
 Crosscompiling
 --------------
 
index bd4c1a3..c7d557a 100755 (executable)
--- a/build.sh
+++ b/build.sh
@@ -18,34 +18,152 @@ EOF
     done
 }
 
-check_for_application lex bison autoheader aclocal automake autoconf pkg-config
-
-libtoolize=""
-libtoolize --version >/dev/null 2>/dev/null
-if test $? -eq 0; then
-    libtoolize=libtoolize
-else
-    glibtoolize --version >/dev/null 2>/dev/null
+setup_libtool()
+{
+    libtoolize=""
+    libtoolize --version >/dev/null 2>/dev/null
     if test $? -eq 0; then
-        libtoolize=glibtoolize
+        libtoolize=libtoolize
     else
-        cat >&2 <<EOF
+        glibtoolize --version >/dev/null 2>/dev/null
+        if test $? -eq 0; then
+            libtoolize=glibtoolize
+        else
+            cat >&2 <<EOF
 WARNING: Neither \`libtoolize' nor \`glibtoolize' have been found!
     Please make sure that one of them is installed and is in one of the
     directories listed in the PATH environment variable.
 EOF
-        GLOBAL_ERROR_INDICATOR=1
+            GLOBAL_ERROR_INDICATOR=1
+        fi
     fi
- fi
 
-if test "$GLOBAL_ERROR_INDICATOR" != "0"; then
-    exit 1
-fi
+    if test "$GLOBAL_ERROR_INDICATOR" != "0"; then
+        exit 1
+    fi
+}
+
+build()
+{
+    echo "Building..."
+    check_for_application lex bison autoheader aclocal automake autoconf pkg-config
+    setup_libtool
+
+    set -x
+    autoheader \
+    && aclocal -I m4 \
+    && $libtoolize --copy --force \
+    && automake --add-missing --copy \
+    && autoconf
+}
+
+build_cygwin()
+{
+    echo "Building for Cygwin..."
+    check_for_application aclocal autoconf autoheader automake bison flex git make pkg-config x86_64-w64-mingw32-gcc
+    setup_libtool
+
+    set -e
+
+    : ${INSTALL_DIR:="C:/PROGRA~1/collectd"}
+    : ${LIBDIR:="${INSTALL_DIR}"}
+    : ${BINDIR:="${INSTALL_DIR}"}
+    : ${SBINDIR:="${INSTALL_DIR}"}
+    : ${SYSCONFDIR:="${INSTALL_DIR}"}
+    : ${LOCALSTATEDIR:="${INSTALL_DIR}"}
+    : ${DATAROOTDIR:="${INSTALL_DIR}"}
+    : ${DATADIR:="${INSTALL_DIR}"}
 
-set -x
+    echo "Installing collectd to ${INSTALL_DIR}."
+    TOP_SRCDIR=$(pwd)
+    MINGW_ROOT="$(x86_64-w64-mingw32-gcc -print-sysroot)/mingw"
+    GNULIB_DIR="${TOP_SRCDIR}/gnulib/build/gllib"
+
+    export CC="x86_64-w64-mingw32-gcc"
+
+    if [ -d "${TOP_SRCDIR}/gnulib/build" ]; then
+        echo "Assuming that gnulib is already built, because gnulib/build exists."
+    else
+        git submodule init
+        git submodule update
+        cd gnulib
+        ./gnulib-tool \
+          --create-testdir \
+          --source-base=lib \
+          --dir=${TOP_SRCDIR}/gnulib/build \
+          canonicalize-lgpl \
+          fcntl-h \
+          getsockopt \
+          gettimeofday \
+          nanosleep \
+          netdb \
+          net_if \
+          poll \
+          recv \
+          regex \
+          sendto \
+          setlocale \
+          strtok_r \
+          sys_resource \
+          sys_socket \
+          sys_stat \
+          sys_wait \
+          time_r
+
+        cd ${TOP_SRCDIR}/gnulib/build
+        ./configure --host="mingw32" LIBS="-lws2_32 -lpthread"
+        make 
+        cd gllib
+
+        # We have to rebuild libgnu.a to get the list of *.o files to build a dll later
+        rm libgnu.a
+        OBJECT_LIST=`make V=1 | grep "ar" | cut -d' ' -f4-`
+        $CC -shared -o libgnu.dll $OBJECT_LIST -lws2_32 -lpthread
+        rm libgnu.a # get rid of it, to use libgnu.dll
+       fi
+    cd "${TOP_SRCDIR}"
+
+    set -x
+    autoreconf --install
+
+    export LDFLAGS="-L${GNULIB_DIR}"
+    export LIBS="-lgnu"
+    export CFLAGS="-Drestrict=__restrict -I${GNULIB_DIR}"
+
+    ./configure \
+      --prefix="${INSTALL_DIR}" \
+      --libdir="${LIBDIR}" \
+      --bindir="${BINDIR}" \
+      --sbindir="${SBINDIR}" \
+      --sysconfdir="${SYSCONFDIR}" \
+      --localstatedir="${LOCALSTATEDIR}" \
+      --datarootdir="${DATAROOTDIR}" \
+      --datarootdir="${DATADIR}" \
+      --disable-all-plugins \
+      --host="mingw32" \
+      --enable-logfile
+
+    cp ${GNULIB_DIR}/../config.h src/gnulib_config.h
+    echo "#include <config.h.in>" >> src/gnulib_config.h
+
+    cp libtool libtool_bak
+    sed -i "s%\$LTCC \$LTCFLAGS\(.*cwrapper.*\)%\$LTCC \1%" libtool
+
+    make
+    make install
+
+    cp "${GNULIB_DIR}/libgnu.dll" "${INSTALL_DIR}"
+    cp "${MINGW_ROOT}/bin/zlib1.dll" "${INSTALL_DIR}"
+    cp "${MINGW_ROOT}/bin/libwinpthread-1.dll" "${INSTALL_DIR}"
+    cp "${MINGW_ROOT}/bin/libdl.dll" "${INSTALL_DIR}"
+
+    echo "Done."
+}
+
+os_name="$(uname)"
+if test "${os_name#CYGWIN}" != "$os_name"; then
+    build_cygwin
+else
+    build
+fi
 
-autoheader \
-&& aclocal -I m4 \
-&& $libtoolize --copy --force \
-&& automake --add-missing --copy \
-&& autoconf
index 54eb7f6..36b66e5 100644 (file)
@@ -99,6 +99,10 @@ case $host_os in
     AC_DEFINE([KERNEL_SOLARIS], [1], [True if program is to be compiled for a Solaris kernel])
     ac_system="Solaris"
     ;;
+  *mingw32*)
+    AC_DEFINE([KERNEL_WIN32], [1], [True if program is to be compiled for a Windows kernel])
+    ac_system="Windows"
+    ;;
   *)
     ac_system="unknown"
     ;;
@@ -111,6 +115,7 @@ AM_CONDITIONAL([BUILD_FREEBSD], [test "x$ac_system" = "xFreeBSD"])
 AM_CONDITIONAL([BUILD_LINUX], [test "x$ac_system" = "xLinux"])
 AM_CONDITIONAL([BUILD_OPENBSD], [test "x$ac_system" = "xOpenBSD"])
 AM_CONDITIONAL([BUILD_SOLARIS], [test "x$ac_system" = "xSolaris"])
+AM_CONDITIONAL([BUILD_WIN32], [test "x$ac_system" = "xWindows"])
 
 if test "x$ac_system" = "xSolaris"; then
   AC_DEFINE([_POSIX_PTHREAD_SEMANTICS], [1], [Define to enforce POSIX thread semantics under Solaris.])
@@ -751,6 +756,7 @@ AC_CHECK_FUNCS_ONCE([ \
     getaddrinfo \
     getgrnam_r \
     getnameinfo \
+    getpwnam \
     getpwnam_r \
     gettimeofday \
     if_indextoname \
@@ -857,11 +863,17 @@ AC_CHECK_FUNCS([socket],
   [
     AC_CHECK_LIB([socket], [socket],
       [socket_needs_socket="yes"],
-      [AC_MSG_ERROR([cannot find socket() in libsocket])]
+      [
+        AC_CHECK_LIB([gnu], [rpl_socket],
+          [socket_needs_gnulib="yes"],
+          [AC_MSG_ERROR([cannot find socket() in libsocket])]
+        )
+      ]
     )
   ]
 )
 AM_CONDITIONAL([BUILD_WITH_LIBSOCKET], [test "x$socket_needs_socket" = "xyes"])
+AM_CONDITIONAL([BUILD_WITH_GNULIB], [test "x$socket_needs_gnulib" = "xyes"])
 
 clock_gettime_needs_posix4="no"
 AC_CHECK_FUNCS([clock_gettime],
@@ -7253,3 +7265,4 @@ if test "x$dependency_warning" = "xyes"; then
 fi
 
 # vim: set fdm=marker sw=2 sts=2 ts=2 et :
+
diff --git a/gnulib b/gnulib
new file mode 160000 (submodule)
index 0000000..2f8140b
--- /dev/null
+++ b/gnulib
@@ -0,0 +1 @@
+Subproject commit 2f8140bc8ce5501e31dcc665b42b5df64f84c20c
diff --git a/src/daemon/cmd_windows.c b/src/daemon/cmd_windows.c
new file mode 100755 (executable)
index 0000000..2542be5
--- /dev/null
@@ -0,0 +1,40 @@
+/**\r
+ * collectd - src/collectd_windows.c\r
+ * Copyright (C) 2017  Google LLC\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person obtaining a\r
+ * copy of this software and associated documentation files (the "Software"),\r
+ * to deal in the Software without restriction, including without limitation\r
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,\r
+ * and/or sell copies of the Software, and to permit persons to whom the\r
+ * Software is furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be included in\r
+ * all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\r
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\r
+ * DEALINGS IN THE SOFTWARE.\r
+ **/\r
+\r
+#include "cmd.h"\r
+#include "plugin.h"\r
+#include <stdio.h>\r
+#include <windows.h>\r
+\r
+int main(int argc, char **argv) {\r
+  WSADATA wsaData;\r
+  WORD wVersionRequested = MAKEWORD(2, 2);\r
+  int err = WSAStartup(wVersionRequested, &wsaData);\r
+  if (err != 0) {\r
+    ERROR("WSAStartup failed with error: %d\n", err);\r
+    return 1;\r
+  }\r
+\r
+  struct cmdline_config config = init_config(argc, argv);\r
+  return run_loop(config.test_readall);\r
+}\r
index 0149f40..f1a4923 100644 (file)
 #define COLLECTD_LOCALE "C"
 #endif
 
+#ifdef WIN32
+#undef COLLECT_DAEMON
+#include <unistd.h>
+#undef gethostname
+#include <locale.h>
+#include <winsock2.h>
+#endif
+
 static int loop;
 
 static int init_hostname(void) {
@@ -60,10 +68,14 @@ static int init_hostname(void) {
     return 0;
   }
 
+#ifdef WIN32
+  long hostname_len = NI_MAXHOST;
+#else
   long hostname_len = sysconf(_SC_HOST_NAME_MAX);
   if (hostname_len == -1) {
     hostname_len = NI_MAXHOST;
   }
+#endif /* WIN32 */
   char hostname[hostname_len];
 
   if (gethostname(hostname, hostname_len) != 0) {
index 459da4d..07597d3 100644 (file)
 #ifndef COLLECTD_H
 #define COLLECTD_H
 
+#ifdef WIN32
+typedef int uid_t;
+#include "gnulib_config.h"
+#endif
+
 #if HAVE_CONFIG_H
 #include "config.h"
 #endif
 #include <sys/isa_defs.h>
 #endif
 
+#if HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
 #ifndef BYTE_ORDER
 #if defined(_BYTE_ORDER)
 #define BYTE_ORDER _BYTE_ORDER
 #endif
 #endif
 
-#if HAVE_SYS_PARAM_H
-#include <sys/param.h>
-#endif
-
 #ifndef PACKAGE_NAME
 #define PACKAGE_NAME "collectd"
 #endif
index 76c7036..99f48ca 100644 (file)
  *   MichaÅ‚ MirosÅ‚aw <mirq-linux at rere.qmqm.pl>
 **/
 
-#if HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 #include "collectd.h"
 
 #include "common.h"
 extern kstat_ctl_t *kc;
 #endif
 
+#if !defined(MSG_DONTWAIT)
+#if defined(MSG_NONBLOCK)
 /* AIX doesn't have MSG_DONTWAIT */
-#ifndef MSG_DONTWAIT
 #define MSG_DONTWAIT MSG_NONBLOCK
-#endif
+#else
+/* Windows doesn't have MSG_DONTWAIT or MSG_NONBLOCK */
+#define MSG_DONTWAIT 0
+#endif /* defined(MSG_NONBLOCK) */
+#endif /* !defined(MSG_DONTWAIT) */
 
-#if !HAVE_GETPWNAM_R
+#if !HAVE_GETPWNAM_R && defined(HAVE_GETPWNAM)
 static pthread_mutex_t getpwnam_r_lock = PTHREAD_MUTEX_INITIALIZER;
 #endif
 
@@ -1132,6 +1133,9 @@ int parse_value_file(char const *path, value_t *ret_value, int ds_type) {
 #if !HAVE_GETPWNAM_R
 int getpwnam_r(const char *name, struct passwd *pwbuf, char *buf, size_t buflen,
                struct passwd **pwbufp) {
+#ifndef HAVE_GETPWNAM
+  return -1;
+#else
   int status = 0;
   struct passwd *pw;
 
@@ -1174,6 +1178,7 @@ int getpwnam_r(const char *name, struct passwd *pwbuf, char *buf, size_t buflen,
   pthread_mutex_unlock(&getpwnam_r_lock);
 
   return status;
+#endif /* HAVE_GETPWNAM */
 } /* int getpwnam_r */
 #endif /* !HAVE_GETPWNAM_R */
 
index db1b465..8cd4e22 100644 (file)
@@ -335,6 +335,7 @@ int parse_values(char *buffer, value_list_t *vl, const data_set_t *ds);
 int parse_value_file(char const *path, value_t *ret_value, int ds_type);
 
 #if !HAVE_GETPWNAM_R
+struct passwd;
 int getpwnam_r(const char *name, struct passwd *pwbuf, char *buf, size_t buflen,
                struct passwd **pwbufp);
 #endif
index 5a277c0..9ec72f0 100644 (file)
 #endif
 
 #ifndef PRIsz
+#ifdef WIN32
+#define PRIsz "Iu"
+#else
 #define PRIsz "zu"
-#endif /* PRIsz */
+#endif /* WIN32 */
+#endif /* !PRIsz */
 
 /* Type for time as used by "utils_time.h" */
 typedef uint64_t cdtime_t;
index 73d7c84..b93e9cc 100644 (file)
 #include "utils_random.h"
 #include "utils_time.h"
 
+#ifdef WIN32
+#define EXPORT __declspec(dllexport)
+#include <sys/stat.h>
+#include <unistd.h>
+#else
+#define EXPORT
+#endif
+
 #if HAVE_PTHREAD_NP_H
 #include <pthread_np.h> /* for pthread_set_name_np(3) */
 #endif
@@ -640,7 +648,7 @@ static void start_read_threads(size_t num) /* {{{ */
     }
 
     char name[THREAD_NAME_MAX];
-    snprintf(name, sizeof(name), "reader#%" PRIsz, read_threads_num);
+    snprintf(name, sizeof(name), "reader#%" PRIu64, (uint64_t)read_threads_num);
     set_thread_name(read_threads[read_threads_num], name);
 
     read_threads_num++;
@@ -829,7 +837,8 @@ static void start_write_threads(size_t num) /* {{{ */
     }
 
     char name[THREAD_NAME_MAX];
-    snprintf(name, sizeof(name), "writer#%" PRIsz, write_threads_num);
+    snprintf(name, sizeof(name), "writer#%" PRIu64,
+             (uint64_t)write_threads_num);
     set_thread_name(write_threads[write_threads_num], name);
 
     write_threads_num++;
@@ -940,6 +949,11 @@ static void plugin_free_loaded(void) {
 }
 
 #define BUFSIZE 512
+#ifdef WIN32
+#define SHLIB_SUFFIX ".dll"
+#else
+#define SHLIB_SUFFIX ".so"
+#endif
 int plugin_load(char const *plugin_name, bool global) {
   DIR *dh;
   const char *dir;
@@ -976,11 +990,12 @@ int plugin_load(char const *plugin_name, bool global) {
       (strcasecmp("python", plugin_name) == 0))
     global = true;
 
-  /* `cpu' should not match `cpufreq'. To solve this we add `.so' to the
+  /* `cpu' should not match `cpufreq'. To solve this we add SHLIB_SUFFIX to the
    * type when matching the filename */
-  status = snprintf(typename, sizeof(typename), "%s.so", plugin_name);
+  status = snprintf(typename, sizeof(typename), "%s" SHLIB_SUFFIX, plugin_name);
   if ((status < 0) || ((size_t)status >= sizeof(typename))) {
-    WARNING("plugin_load: Filename too long: \"%s.so\"", plugin_name);
+    WARNING("plugin_load: Filename too long: \"%s" SHLIB_SUFFIX "\"",
+            plugin_name);
     return -1;
   }
 
@@ -1033,19 +1048,20 @@ int plugin_load(char const *plugin_name, bool global) {
 /*
  * The `register_*' functions follow
  */
-int plugin_register_config(const char *name,
-                           int (*callback)(const char *key, const char *val),
-                           const char **keys, int keys_num) {
+EXPORT int plugin_register_config(const char *name,
+                                  int (*callback)(const char *key,
+                                                  const char *val),
+                                  const char **keys, int keys_num) {
   cf_register(name, callback, keys, keys_num);
   return 0;
 } /* int plugin_register_config */
 
-int plugin_register_complex_config(const char *type,
-                                   int (*callback)(oconfig_item_t *)) {
+EXPORT int plugin_register_complex_config(const char *type,
+                                          int (*callback)(oconfig_item_t *)) {
   return cf_register_complex(type, callback);
 } /* int plugin_register_complex_config */
 
-int plugin_register_init(const char *name, int (*callback)(void)) {
+EXPORT int plugin_register_init(const char *name, int (*callback)(void)) {
   return create_register_callback(&list_init, name, (void *)callback, NULL);
 } /* plugin_register_init */
 
@@ -1127,7 +1143,7 @@ static int plugin_insert_read(read_func_t *rf) {
   return 0;
 } /* int plugin_insert_read */
 
-int plugin_register_read(const char *name, int (*callback)(void)) {
+EXPORT int plugin_register_read(const char *name, int (*callback)(void)) {
   read_func_t *rf;
   int status;
 
@@ -1156,9 +1172,10 @@ int plugin_register_read(const char *name, int (*callback)(void)) {
   return status;
 } /* int plugin_register_read */
 
-int plugin_register_complex_read(const char *group, const char *name,
-                                 plugin_read_cb callback, cdtime_t interval,
-                                 user_data_t const *user_data) {
+EXPORT int plugin_register_complex_read(const char *group, const char *name,
+                                        plugin_read_cb callback,
+                                        cdtime_t interval,
+                                        user_data_t const *user_data) {
   read_func_t *rf;
   int status;
 
@@ -1199,8 +1216,8 @@ int plugin_register_complex_read(const char *group, const char *name,
   return status;
 } /* int plugin_register_complex_read */
 
-int plugin_register_write(const char *name, plugin_write_cb callback,
-                          user_data_t const *ud) {
+EXPORT int plugin_register_write(const char *name, plugin_write_cb callback,
+                                 user_data_t const *ud) {
   return create_register_callback(&list_write, name, (void *)callback, ud);
 } /* int plugin_register_write */
 
@@ -1241,8 +1258,8 @@ static char *plugin_flush_callback_name(const char *name) {
   return flush_name;
 } /* static char *plugin_flush_callback_name */
 
-int plugin_register_flush(const char *name, plugin_flush_cb callback,
-                          user_data_t const *ud) {
+EXPORT int plugin_register_flush(const char *name, plugin_flush_cb callback,
+                                 user_data_t const *ud) {
   int status;
   plugin_ctx_t ctx = plugin_get_ctx();
 
@@ -1290,12 +1307,12 @@ int plugin_register_flush(const char *name, plugin_flush_cb callback,
   return 0;
 } /* int plugin_register_flush */
 
-int plugin_register_missing(const char *name, plugin_missing_cb callback,
-                            user_data_t const *ud) {
+EXPORT int plugin_register_missing(const char *name, plugin_missing_cb callback,
+                                   user_data_t const *ud) {
   return create_register_callback(&list_missing, name, (void *)callback, ud);
 } /* int plugin_register_missing */
 
-int plugin_register_shutdown(const char *name, int (*callback)(void)) {
+EXPORT int plugin_register_shutdown(const char *name, int (*callback)(void)) {
   return create_register_callback(&list_shutdown, name, (void *)callback, NULL);
 } /* int plugin_register_shutdown */
 
@@ -1318,7 +1335,7 @@ static void plugin_free_data_sets(void) {
   data_sets = NULL;
 } /* void plugin_free_data_sets */
 
-int plugin_register_data_set(const data_set_t *ds) {
+EXPORT int plugin_register_data_set(const data_set_t *ds) {
   data_set_t *ds_copy;
 
   if ((data_sets != NULL) && (c_avl_get(data_sets, ds->type, NULL) == 0)) {
@@ -1347,33 +1364,33 @@ int plugin_register_data_set(const data_set_t *ds) {
   return c_avl_insert(data_sets, (void *)ds_copy->type, (void *)ds_copy);
 } /* int plugin_register_data_set */
 
-int plugin_register_log(const char *name, plugin_log_cb callback,
-                        user_data_t const *ud) {
+EXPORT int plugin_register_log(const char *name, plugin_log_cb callback,
+                               user_data_t const *ud) {
   return create_register_callback(&list_log, name, (void *)callback, ud);
 } /* int plugin_register_log */
 
-int plugin_register_notification(const char *name,
-                                 plugin_notification_cb callback,
-                                 user_data_t const *ud) {
+EXPORT int plugin_register_notification(const char *name,
+                                        plugin_notification_cb callback,
+                                        user_data_t const *ud) {
   return create_register_callback(&list_notification, name, (void *)callback,
                                   ud);
 } /* int plugin_register_log */
 
-int plugin_unregister_config(const char *name) {
+EXPORT int plugin_unregister_config(const char *name) {
   cf_unregister(name);
   return 0;
 } /* int plugin_unregister_config */
 
-int plugin_unregister_complex_config(const char *name) {
+EXPORT int plugin_unregister_complex_config(const char *name) {
   cf_unregister_complex(name);
   return 0;
 } /* int plugin_unregister_complex_config */
 
-int plugin_unregister_init(const char *name) {
+EXPORT int plugin_unregister_init(const char *name) {
   return plugin_unregister(list_init, name);
 }
 
-int plugin_unregister_read(const char *name) /* {{{ */
+EXPORT int plugin_unregister_read(const char *name) /* {{{ */
 {
   llentry_t *le;
   read_func_t *rf;
@@ -1410,7 +1427,7 @@ int plugin_unregister_read(const char *name) /* {{{ */
   return 0;
 } /* }}} int plugin_unregister_read */
 
-void plugin_log_available_writers(void) {
+EXPORT void plugin_log_available_writers(void) {
   log_list_callbacks(&list_write, "Available write targets:");
 }
 
@@ -1422,7 +1439,7 @@ static int compare_read_func_group(llentry_t *e, void *ud) /* {{{ */
   return strcmp(rf->rf_group, (const char *)group);
 } /* }}} int compare_read_func_group */
 
-int plugin_unregister_read_group(const char *group) /* {{{ */
+EXPORT int plugin_unregister_read_group(const char *group) /* {{{ */
 {
   llentry_t *le;
   read_func_t *rf;
@@ -1472,11 +1489,11 @@ int plugin_unregister_read_group(const char *group) /* {{{ */
   return 0;
 } /* }}} int plugin_unregister_read_group */
 
-int plugin_unregister_write(const char *name) {
+EXPORT int plugin_unregister_write(const char *name) {
   return plugin_unregister(list_write, name);
 }
 
-int plugin_unregister_flush(const char *name) {
+EXPORT int plugin_unregister_flush(const char *name) {
   plugin_ctx_t ctx = plugin_get_ctx();
 
   if (ctx.flush_interval != 0) {
@@ -1492,15 +1509,15 @@ int plugin_unregister_flush(const char *name) {
   return plugin_unregister(list_flush, name);
 }
 
-int plugin_unregister_missing(const char *name) {
+EXPORT int plugin_unregister_missing(const char *name) {
   return plugin_unregister(list_missing, name);
 }
 
-int plugin_unregister_shutdown(const char *name) {
+EXPORT int plugin_unregister_shutdown(const char *name) {
   return plugin_unregister(list_shutdown, name);
 }
 
-int plugin_unregister_data_set(const char *name) {
+EXPORT int plugin_unregister_data_set(const char *name) {
   data_set_t *ds;
 
   if (data_sets == NULL)
@@ -1515,15 +1532,15 @@ int plugin_unregister_data_set(const char *name) {
   return 0;
 } /* int plugin_unregister_data_set */
 
-int plugin_unregister_log(const char *name) {
+EXPORT int plugin_unregister_log(const char *name) {
   return plugin_unregister(list_log, name);
 }
 
-int plugin_unregister_notification(const char *name) {
+EXPORT int plugin_unregister_notification(const char *name) {
   return plugin_unregister(list_notification, name);
 }
 
-int plugin_init_all(void) {
+EXPORT int plugin_init_all(void) {
   char const *chain_name;
   llentry_t *le;
   int status;
@@ -1622,14 +1639,14 @@ int plugin_init_all(void) {
 } /* void plugin_init_all */
 
 /* TODO: Rename this function. */
-void plugin_read_all(void) {
+EXPORT void plugin_read_all(void) {
   uc_check_timeout();
 
   return;
 } /* void plugin_read_all */
 
 /* Read function called when the `-T' command line argument is given. */
-int plugin_read_all_once(void) {
+EXPORT int plugin_read_all_once(void) {
   int status;
   int return_status = 0;
 
@@ -1674,8 +1691,8 @@ int plugin_read_all_once(void) {
   return return_status;
 } /* int plugin_read_all_once */
 
-int plugin_write(const char *plugin, /* {{{ */
-                 const data_set_t *ds, const value_list_t *vl) {
+EXPORT int plugin_write(const char *plugin, /* {{{ */
+                        const data_set_t *ds, const value_list_t *vl) {
   llentry_t *le;
   int status;
 
@@ -1754,7 +1771,8 @@ int plugin_write(const char *plugin, /* {{{ */
   return status;
 } /* }}} int plugin_write */
 
-int plugin_flush(const char *plugin, cdtime_t timeout, const char *identifier) {
+EXPORT int plugin_flush(const char *plugin, cdtime_t timeout,
+                        const char *identifier) {
   llentry_t *le;
 
   if (list_flush == NULL)
@@ -1784,7 +1802,7 @@ int plugin_flush(const char *plugin, cdtime_t timeout, const char *identifier) {
   return 0;
 } /* int plugin_flush */
 
-int plugin_shutdown_all(void) {
+EXPORT int plugin_shutdown_all(void) {
   llentry_t *le;
   int ret = 0; // Assume success.
 
@@ -1850,7 +1868,7 @@ int plugin_shutdown_all(void) {
   return ret;
 } /* void plugin_shutdown_all */
 
-int plugin_dispatch_missing(const value_list_t *vl) /* {{{ */
+EXPORT int plugin_dispatch_missing(const value_list_t *vl) /* {{{ */
 {
   if (list_missing == NULL)
     return 0;
@@ -2056,7 +2074,7 @@ static bool check_drop_value(void) /* {{{ */
     return false;
 } /* }}} bool check_drop_value */
 
-int plugin_dispatch_values(value_list_t const *vl) {
+EXPORT int plugin_dispatch_values(value_list_t const *vl) {
   int status;
   static pthread_mutex_t statistics_lock = PTHREAD_MUTEX_INITIALIZER;
 
@@ -2155,7 +2173,7 @@ plugin_dispatch_multivalue(value_list_t const *template, /* {{{ */
   return failed;
 } /* }}} int plugin_dispatch_multivalue */
 
-int plugin_dispatch_notification(const notification_t *notif) {
+EXPORT int plugin_dispatch_notification(const notification_t *notif) {
   llentry_t *le;
   /* Possible TODO: Add flap detection here */
 
@@ -2192,7 +2210,7 @@ int plugin_dispatch_notification(const notification_t *notif) {
   return 0;
 } /* int plugin_dispatch_notification */
 
-void plugin_log(int level, const char *format, ...) {
+EXPORT void plugin_log(int level, const char *format, ...) {
   char msg[1024];
   va_list ap;
   llentry_t *le;
@@ -2265,7 +2283,7 @@ int parse_log_severity(const char *severity) {
   return log_level;
 } /* int parse_log_severity */
 
-int parse_notif_severity(const char *severity) {
+EXPORT int parse_notif_severity(const char *severity) {
   int notif_severity = -1;
 
   if (strcasecmp(severity, "FAILURE") == 0)
@@ -2279,7 +2297,7 @@ int parse_notif_severity(const char *severity) {
   return notif_severity;
 } /* int parse_notif_severity */
 
-const data_set_t *plugin_get_ds(const char *name) {
+EXPORT const data_set_t *plugin_get_ds(const char *name) {
   data_set_t *ds;
 
   if (data_sets == NULL) {
@@ -2466,12 +2484,12 @@ static plugin_ctx_t *plugin_ctx_create(void) {
   return ctx;
 } /* int plugin_ctx_create */
 
-void plugin_init_ctx(void) {
+EXPORT void plugin_init_ctx(void) {
   pthread_key_create(&plugin_ctx_key, plugin_ctx_destructor);
   plugin_ctx_key_initialized = true;
 } /* void plugin_init_ctx */
 
-plugin_ctx_t plugin_get_ctx(void) {
+EXPORT plugin_ctx_t plugin_get_ctx(void) {
   plugin_ctx_t *ctx;
 
   assert(plugin_ctx_key_initialized);
@@ -2487,7 +2505,7 @@ plugin_ctx_t plugin_get_ctx(void) {
   return *ctx;
 } /* plugin_ctx_t plugin_get_ctx */
 
-plugin_ctx_t plugin_set_ctx(plugin_ctx_t ctx) {
+EXPORT plugin_ctx_t plugin_set_ctx(plugin_ctx_t ctx) {
   plugin_ctx_t *c;
   plugin_ctx_t old;
 
@@ -2507,7 +2525,7 @@ plugin_ctx_t plugin_set_ctx(plugin_ctx_t ctx) {
   return old;
 } /* void plugin_set_ctx */
 
-cdtime_t plugin_get_interval(void) {
+EXPORT cdtime_t plugin_get_interval(void) {
   cdtime_t interval;
 
   interval = plugin_get_ctx().interval;
index 871eccd..2d903cb 100644 (file)
@@ -34,6 +34,7 @@
 #include "meta_data.h"
 #include "utils_time.h"
 
+#include <inttypes.h>
 #include <pthread.h>
 
 #define DS_TYPE_COUNTER 0
index d36d410..3cecd89 100644 (file)
@@ -24,6 +24,8 @@
  *   Florian octo Forster <octo at collectd.org>
  **/
 
+#include "collectd.h"
+
 #include <assert.h>
 #include <errno.h>
 #include <pthread.h>
index 7a9ce7b..5500aaa 100644 (file)
 
 #include <pthread.h>
 
+#ifdef WIN32
+double erand48(unsigned short unused[3]) {
+  return (double)rand() / (double)RAND_MAX;
+}
+
+long int jrand48(unsigned short unused[3]) { return rand(); }
+#endif
+
 static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
 static bool have_seed;
 static unsigned short seed[3];
@@ -47,6 +55,10 @@ static void cdrand_seed(void) {
   seed[1] = (unsigned short)(t >> 16);
   seed[2] = (unsigned short)(t >> 32);
 
+#ifdef WIN32
+  srand((unsigned)t);
+#endif
+
   have_seed = true;
 }
 
index d470324..df6fd96 100644 (file)
  *   Florian octo Forster <octo at collectd.org>
  **/
 
+#ifdef WIN32
+#include "gnulib_config.h"
+#include <winsock2.h>
+#endif
+
 #include "config.h"
 
 #if !defined(__GNUC__) || !__GNUC__
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <sys/socket.h>
 #include <sys/types.h>
-#include <sys/un.h>
 #include <unistd.h>
 
+#ifndef WIN32
+#include <sys/socket.h>
+#include <sys/un.h>
+#endif
+
 #include "collectd/client.h"
 
 /* NI_MAXHOST has been obsoleted by RFC 3493 which is a reason for SunOS 5.11
 #endif
 #endif
 
+#ifdef WIN32
+#define AI_ADDRCONFIG 0
+#endif
+
 /* Secure/static macros. They work like `strcpy' and `strcat', but assure null
  * termination. They work for static buffers only, because they use `sizeof'.
  * The `SSTRCATF' combines the functionality of `snprintf' and `strcat' which
@@ -367,6 +379,10 @@ static int lcc_sendreceive(lcc_connection_t *c, /* {{{ */
 
 static int lcc_open_unixsocket(lcc_connection_t *c, const char *path) /* {{{ */
 {
+#ifdef WIN32
+  lcc_set_errno(c, ENOTSUP);
+  return -1;
+#else
   struct sockaddr_un sa = {0};
   int fd;
   int status;
@@ -401,6 +417,7 @@ static int lcc_open_unixsocket(lcc_connection_t *c, const char *path) /* {{{ */
   }
 
   return 0;
+#endif /* WIN32 */
 } /* }}} int lcc_open_unixsocket */
 
 static int lcc_open_netsocket(lcc_connection_t *c, /* {{{ */
index c8a5da5..0b97362 100644 (file)
 #include <inttypes.h>
 #include <stdint.h>
 
+#ifdef WIN32
+extern unsigned int if_nametoindex(const char *interface_name);
+#endif
+
 #define NET_DEFAULT_V4_ADDR "239.192.74.66"
 #define NET_DEFAULT_V6_ADDR "ff18::efc0:4a42"
 #define NET_DEFAULT_PORT "25826"
@@ -60,7 +64,7 @@ int lcc_server_destroy(lcc_network_t *net, lcc_server_t *srv);
 
 /* Configure servers */
 int lcc_server_set_ttl(lcc_server_t *srv, uint8_t ttl);
-int lcc_server_set_interface(lcc_server_t *srv, char const *interface);
+int lcc_server_set_interface(lcc_server_t *srv, char const *iface);
 int lcc_server_set_security_level(lcc_server_t *srv, lcc_security_level_t level,
                                   const char *username, const char *password);
 
index ef6b792..e50df17 100644 (file)
@@ -74,7 +74,7 @@ typedef struct {
 
   /* interface is the name of the interface to use when subscribing to a
    * multicast group. Has no effect when using unicast. */
-  char *interface;
+  char *iface;
 } lcc_listener_t;
 
 /* lcc_listen_and_write listens on the provided UDP socket (or opens one using
index 49257d4..2d6b3ed 100644 (file)
 #include <net/if.h>
 #endif
 
+#ifdef WIN32
+#define AI_ADDRCONFIG 0
+#endif
+
 #include "collectd/network.h"
 #include "collectd/network_buffer.h"
 
@@ -364,15 +368,15 @@ int lcc_server_set_ttl(lcc_server_t *srv, uint8_t ttl) /* {{{ */
   return 0;
 } /* }}} int lcc_server_set_ttl */
 
-int lcc_server_set_interface(lcc_server_t *srv, char const *interface) /* {{{ */
+int lcc_server_set_interface(lcc_server_t *srv, char const *iface) /* {{{ */
 {
   unsigned int if_index;
   int status;
 
-  if ((srv == NULL) || (interface == NULL))
+  if ((srv == NULL) || (iface == NULL))
     return EINVAL;
 
-  if_index = if_nametoindex(interface);
+  if_index = if_nametoindex(iface);
   if (if_index == 0)
     return ENOENT;
 
@@ -420,8 +424,8 @@ int lcc_server_set_interface(lcc_server_t *srv, char const *interface) /* {{{ */
 
 /* else: Not a multicast interface. */
 #if defined(SO_BINDTODEVICE)
-  status = setsockopt(srv->fd, SOL_SOCKET, SO_BINDTODEVICE, interface,
-                      (socklen_t)(strlen(interface) + 1));
+  status = setsockopt(srv->fd, SOL_SOCKET, SO_BINDTODEVICE, iface,
+                      (socklen_t)(strlen(iface) + 1));
   if (status != 0)
     return -1;
 #endif
index 5a1ee8d..44d93e0 100644 (file)
  *   Florian octo Forster <octo at collectd.org>
  **/
 
+#ifdef WIN32
+#include "gnulib_config.h"
+#endif
+
 #include "config.h"
 
 #include <arpa/inet.h> /* htons */
index 1095eba..2687616 100644 (file)
  *   Florian octo Forster <octo at collectd.org>
  **/
 
+#ifdef WIN32
+#include "gnulib_config.h"
+#endif
+
 #include "config.h"
 
 #if !defined(__GNUC__) || !__GNUC__
 #include <stdio.h>
 #define DEBUG(...) printf(__VA_ARGS__)
 
+#ifdef WIN32
+#include <ws2tcpip.h>
+#define AI_ADDRCONFIG 0
+#endif
+
 static bool is_multicast(struct addrinfo const *ai) {
   if (ai->ai_family == AF_INET) {
     struct sockaddr_in *addr = (struct sockaddr_in *)ai->ai_addr;
@@ -81,13 +90,20 @@ static int server_multicast_join(lcc_listener_t *srv,
     struct ip_mreqn mreq = {
         .imr_address.s_addr = INADDR_ANY,
         .imr_multiaddr.s_addr = sa->sin_addr.s_addr,
-        .imr_ifindex = if_nametoindex(srv->interface),
+        .imr_ifindex = if_nametoindex(srv->iface),
     };
 #else
+#ifdef WIN32
     struct ip_mreq mreq = {
+        .imr_interface.s_addr = INADDR_ANY,
         .imr_multiaddr.s_addr = sa->sin_addr.s_addr,
     };
-#endif
+#else
+    struct ip_mreq mreq = {
+        .imr_address.s_addr = INADDR_ANY, .imr_multiaddr.s_addr = sa->s_addr,
+    };
+#endif /* WIN32 */
+#endif /* HAVE_STRUCT_IP_MREQN_IMR_IFINDEX */
     status = setsockopt(srv->conn, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq,
                         sizeof(mreq));
     if (status == -1)
@@ -106,7 +122,7 @@ static int server_multicast_join(lcc_listener_t *srv,
       return errno;
 
     struct ipv6_mreq mreq6 = {
-        .ipv6mr_interface = if_nametoindex(srv->interface),
+        .ipv6mr_interface = if_nametoindex(srv->iface),
     };
     memmove(&mreq6.ipv6mr_multiaddr, &sa->sin6_addr, sizeof(struct in6_addr));
 
index cfd9a5c..7efa78a 100644 (file)
  */
 
 %{
+#ifdef WIN32
+#include "gnulib_config.h"
+#include "config.h"
+#endif
+
 #include <stdlib.h>
 #include <string.h>
 #include "oconfig.h"