ffi-nats-core 0.3.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. checksums.yaml +4 -4
  2. data/ffi-nats-core.gemspec +8 -0
  3. data/lib/ffi/nats/core/version.rb +1 -1
  4. data/vendor/cnats/CMakeLists.txt +137 -0
  5. data/vendor/cnats/adapters/libevent.h +220 -0
  6. data/vendor/cnats/adapters/libuv.h +472 -0
  7. data/vendor/cnats/examples/CMakeLists.txt +56 -0
  8. data/vendor/cnats/examples/asynctimeout.c +83 -0
  9. data/vendor/cnats/examples/examples.h +322 -0
  10. data/vendor/cnats/examples/libevent-pub.c +136 -0
  11. data/vendor/cnats/examples/libevent-sub.c +104 -0
  12. data/vendor/cnats/examples/libuv-pub.c +120 -0
  13. data/vendor/cnats/examples/libuv-sub.c +114 -0
  14. data/vendor/cnats/examples/publisher.c +62 -0
  15. data/vendor/cnats/examples/queuegroup.c +132 -0
  16. data/vendor/cnats/examples/replier.c +149 -0
  17. data/vendor/cnats/examples/requestor.c +75 -0
  18. data/vendor/cnats/examples/subscriber.c +133 -0
  19. data/vendor/cnats/src/CMakeLists.txt +31 -0
  20. data/vendor/cnats/src/asynccb.c +66 -0
  21. data/vendor/cnats/src/asynccb.h +42 -0
  22. data/vendor/cnats/src/buf.c +246 -0
  23. data/vendor/cnats/src/buf.h +116 -0
  24. data/vendor/cnats/src/comsock.c +474 -0
  25. data/vendor/cnats/src/comsock.h +81 -0
  26. data/vendor/cnats/src/conn.c +2725 -0
  27. data/vendor/cnats/src/conn.h +75 -0
  28. data/vendor/cnats/src/err.h +31 -0
  29. data/vendor/cnats/src/gc.h +27 -0
  30. data/vendor/cnats/src/hash.c +725 -0
  31. data/vendor/cnats/src/hash.h +141 -0
  32. data/vendor/cnats/src/include/n-unix.h +56 -0
  33. data/vendor/cnats/src/include/n-win.h +59 -0
  34. data/vendor/cnats/src/mem.h +20 -0
  35. data/vendor/cnats/src/msg.c +155 -0
  36. data/vendor/cnats/src/msg.h +43 -0
  37. data/vendor/cnats/src/nats.c +1734 -0
  38. data/vendor/cnats/src/nats.h +2024 -0
  39. data/vendor/cnats/src/natsp.h +518 -0
  40. data/vendor/cnats/src/natstime.c +79 -0
  41. data/vendor/cnats/src/natstime.h +27 -0
  42. data/vendor/cnats/src/nuid.c +265 -0
  43. data/vendor/cnats/src/nuid.h +21 -0
  44. data/vendor/cnats/src/opts.c +1030 -0
  45. data/vendor/cnats/src/opts.h +19 -0
  46. data/vendor/cnats/src/parser.c +869 -0
  47. data/vendor/cnats/src/parser.h +87 -0
  48. data/vendor/cnats/src/pub.c +293 -0
  49. data/vendor/cnats/src/srvpool.c +380 -0
  50. data/vendor/cnats/src/srvpool.h +71 -0
  51. data/vendor/cnats/src/stats.c +54 -0
  52. data/vendor/cnats/src/stats.h +21 -0
  53. data/vendor/cnats/src/status.c +60 -0
  54. data/vendor/cnats/src/status.h +95 -0
  55. data/vendor/cnats/src/sub.c +956 -0
  56. data/vendor/cnats/src/sub.h +34 -0
  57. data/vendor/cnats/src/timer.c +86 -0
  58. data/vendor/cnats/src/timer.h +57 -0
  59. data/vendor/cnats/src/unix/cond.c +103 -0
  60. data/vendor/cnats/src/unix/mutex.c +107 -0
  61. data/vendor/cnats/src/unix/sock.c +105 -0
  62. data/vendor/cnats/src/unix/thread.c +162 -0
  63. data/vendor/cnats/src/url.c +134 -0
  64. data/vendor/cnats/src/url.h +24 -0
  65. data/vendor/cnats/src/util.c +823 -0
  66. data/vendor/cnats/src/util.h +75 -0
  67. data/vendor/cnats/src/version.h +29 -0
  68. data/vendor/cnats/src/version.h.in +29 -0
  69. data/vendor/cnats/src/win/cond.c +86 -0
  70. data/vendor/cnats/src/win/mutex.c +54 -0
  71. data/vendor/cnats/src/win/sock.c +158 -0
  72. data/vendor/cnats/src/win/strings.c +108 -0
  73. data/vendor/cnats/src/win/thread.c +180 -0
  74. data/vendor/cnats/test/CMakeLists.txt +35 -0
  75. data/vendor/cnats/test/certs/ca.pem +38 -0
  76. data/vendor/cnats/test/certs/client-cert.pem +30 -0
  77. data/vendor/cnats/test/certs/client-key.pem +51 -0
  78. data/vendor/cnats/test/certs/server-cert.pem +31 -0
  79. data/vendor/cnats/test/certs/server-key.pem +51 -0
  80. data/vendor/cnats/test/dylib/CMakeLists.txt +10 -0
  81. data/vendor/cnats/test/dylib/nonats.c +13 -0
  82. data/vendor/cnats/test/list.txt +125 -0
  83. data/vendor/cnats/test/test.c +11655 -0
  84. data/vendor/cnats/test/tls.conf +15 -0
  85. data/vendor/cnats/test/tlsverify.conf +19 -0
  86. metadata +83 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 043c01bc38fc465f9821578a42577235e5ab4991
4
- data.tar.gz: ed03d81c41b868b9c694800364cd2b0ceef7739c
3
+ metadata.gz: 329ed5a98e503504856fb08d3eb7ad5339ef9460
4
+ data.tar.gz: b853d48d011a9510ee6003823687153b3afff86f
5
5
  SHA512:
6
- metadata.gz: 136c51044e57100eabc6357e48795185058a9006ba057dde970786fb35d6aaccaff4605511cb131b8807b9b27636c0a5cddccc46bc5860cce696f69d5b0b85a0
7
- data.tar.gz: 51460c9f09582ef1f9eae1120cee8054150d5a424e3adf91b834a16d991cf72a05787f81f89d4b71e0cc715e8603ed64c4e07490df0981c9bf18c640768e6652
6
+ metadata.gz: 36f22cd210b091b727ca62f11c39764c4d9473b3cebb79880a112c38f0fbb7dd8558ccbbec92e4b48e2831adbab2883a915fa8784f61a5e5fa2c47280213e6d0
7
+ data.tar.gz: 1e6102bf76d582972363e3cdc520d3ff6f15e0e9d14cde4c3200c9867a61f2a9074ec42cb0c56bb84f91d57db64d14b36114af3e5e5af311747d2fecd7dd9766
@@ -16,6 +16,14 @@ Gem::Specification.new do |spec|
16
16
  spec.files = `git ls-files -z`.split("\x0").reject do |f|
17
17
  f.match(%r{^(test|spec|features)/})
18
18
  end
19
+
20
+ # cnats files
21
+ spec.files += Dir.glob("vendor/cnats/CMakeLists.txt")
22
+ spec.files += Dir.glob("vendor/cnats/adapters/**/*")
23
+ spec.files += Dir.glob("vendor/cnats/src/**/*")
24
+ spec.files += Dir.glob("vendor/cnats/test/**/*")
25
+ spec.files += Dir.glob("vendor/cnats/examples/**/*")
26
+
19
27
  spec.bindir = "exe"
20
28
  spec.extensions = "ext/ffi/nats/core/Rakefile"
21
29
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
@@ -1,7 +1,7 @@
1
1
  module FFI
2
2
  module Nats
3
3
  module Core
4
- VERSION = "0.3.0"
4
+ VERSION = "0.3.1"
5
5
  end
6
6
  end
7
7
  end
@@ -0,0 +1,137 @@
1
+ cmake_minimum_required(VERSION 2.8)
2
+
3
+ project(cnats)
4
+ include(CTest)
5
+
6
+ # Uncomment to have the build process verbose
7
+ #set(CMAKE_VERBOSE_MAKEFILE TRUE)
8
+
9
+ # Uncomment to have the executable moved to 'build' instead of their respective 'build/xxx' directories
10
+ #set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
11
+
12
+ set(NATS_INSTALL_PREFIX ../install CACHE PATH "Install prefix")
13
+ set(CMAKE_INSTALL_PREFIX ${NATS_INSTALL_PREFIX} CACHE INTERNAL "")
14
+
15
+ option(NATS_UPDATE_VERSION "Update the version file" OFF)
16
+ option(NATS_COVERAGE "Code coverage" OFF)
17
+ option(NATS_BUILD_WITH_TLS "Build with TLS support" ON)
18
+ option(NATS_BUILD_WITH_TLS_CLIENT_METHOD "Use TLS_client_method()" OFF)
19
+ option(NATS_BUILD_LIBUV_EXAMPLE "Compile libuv example" OFF)
20
+ option(NATS_BUILD_LIBEVENT_EXAMPLE "Compile libevent example" OFF)
21
+
22
+ if(NATS_BUILD_WITH_TLS)
23
+ find_package(OpenSSL REQUIRED)
24
+ endif(NATS_BUILD_WITH_TLS)
25
+
26
+ set(LIBUV_DIR "/usr/local/" CACHE PATH "Libuv install directory")
27
+ set(LIBEVENT_DIR "/usr/local/" CACHE PATH "Libevent install directory")
28
+
29
+ # Platform specific settings
30
+ if(UNIX)
31
+ #---------------------------------------------------------------------------
32
+ # Define NATS cache variables that override the CMAKE and MEMCHECK variables
33
+ #---------------------------------------------------------------------------
34
+ set(NATS_BUILD_TYPE Release CACHE STRING "Build type: Release, Debug, RelWithDebInfo, MinRelSize")
35
+ set(CMAKE_BUILD_TYPE ${NATS_BUILD_TYPE} CACHE INTERNAL "")
36
+
37
+ set(NATS_BUILD_ARCH "64" CACHE STRING "32 for 32bits builds")
38
+
39
+ set(NATS_MEMCHECK_CMD "/usr/bin/valgrind" CACHE FILE "Memcheck tool")
40
+ set(MEMORYCHECK_COMMAND ${NATS_MEMCHECK_CMD} CACHE INTERNAL "")
41
+
42
+ set(NATS_MEMCHECK_CMD_OPTS "--leak-check=full --track-fds=yes --show-reachable=yes --num-callers=50" CACHE STRING "Memcheck options")
43
+ set(MEMORYCHECK_COMMAND_OPTIONS ${NATS_MEMCHECK_CMD_OPTS} CACHE INTERNAL "")
44
+
45
+ set(NATS_COMMON_C_FLAGS "-std=c99 -pedantic")
46
+
47
+ if(NATS_BUILD_TYPE MATCHES "Debug")
48
+ set(NATS_COMMON_C_FLAGS "${NATS_COMMON_C_FLAGS} -ggdb")
49
+ endif(NATS_BUILD_TYPE MATCHES "Debug")
50
+
51
+ set(NATS_WARNINGS "-Wall -W -Wno-unused-variable -Wno-unused-parameter -Wno-unused-function -Wstrict-prototypes -Wwrite-strings")
52
+ set(NATS_PLATFORM_INCLUDE "unix")
53
+
54
+ if(APPLE)
55
+ set(CMAKE_MACOSX_RPATH OFF)
56
+ set(NATS_OS "DARWIN")
57
+ else(APPLE)
58
+ set(NATS_OS "LINUX")
59
+ set(NATS_USE_PTHREAD "-pthread")
60
+ set(NATS_EXTRA_LIB "rt")
61
+ if(NATS_COVERAGE)
62
+ set(NATS_CODE_COVERAGE "--coverage")
63
+ endif()
64
+ endif(APPLE)
65
+
66
+ if (${NATS_BUILD_ARCH} MATCHES "32")
67
+ if(NOT APPLE)
68
+ message("-----------------------------------------------------------")
69
+ message("If build fails, you probably need to install libc6-dev-i386")
70
+ message("apt-get install libc6-dev-i386")
71
+ message("-----------------------------------------------------------")
72
+ endif(NOT APPLE)
73
+
74
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32")
75
+ set(CMAKE_C_LINKER_FLAGS "${CMAKE_C_LINKER_FLAGS} -m32")
76
+ endif(${NATS_BUILD_ARCH} MATCHES "32")
77
+
78
+ elseif(WIN32)
79
+ set(NATS_OS "_WIN32")
80
+ set(NATS_PLATFORM_INCLUDE "win")
81
+ endif(UNIX)
82
+
83
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${NATS_CODE_COVERAGE} ${NATS_COMMON_C_FLAGS} ${NATS_USE_PTHREAD} ${NATS_WARNINGS}")
84
+
85
+ add_definitions(-D${NATS_OS})
86
+ add_definitions(-D_REENTRANT)
87
+ if(NATS_BUILD_WITH_TLS)
88
+ add_definitions(-DNATS_HAS_TLS)
89
+ if(NATS_BUILD_WITH_TLS_CLIENT_METHOD)
90
+ add_definitions(-DNATS_USE_TLS_CLIENT_METHOD)
91
+ endif(NATS_BUILD_WITH_TLS_CLIENT_METHOD)
92
+ endif(NATS_BUILD_WITH_TLS)
93
+
94
+ #---------------------------------------------------------------------
95
+ # Add to the 'clean' target the list (and location) of files to remove
96
+
97
+ list(APPEND NATS_INSTALLED_FILES "${CMAKE_INSTALL_PREFIX}/include/nats.h")
98
+ list(APPEND NATS_INSTALLED_FILES "${CMAKE_INSTALL_PREFIX}/include/status.h")
99
+ list(APPEND NATS_INSTALLED_FILES "${CMAKE_INSTALL_PREFIX}/include/version.h")
100
+ list(APPEND NATS_INSTALLED_FILES "${CMAKE_INSTALL_PREFIX}/lib/${nats}")
101
+ list(APPEND NATS_INSTALLED_FILES "${CMAKE_INSTALL_PREFIX}/lib/${nats_static}")
102
+
103
+ set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${NATS_INSTALLED_FILES}")
104
+ #---------------------------------------------------------------------
105
+
106
+ if(NATS_UPDATE_VERSION)
107
+ #------------
108
+ # Versionning
109
+
110
+ set(NATS_VERSION_MAJOR 1)
111
+ set(NATS_VERSION_MINOR 5)
112
+ set(NATS_VERSION_PATCH 0)
113
+ set(NATS_VERSION_SUFFIX "")
114
+
115
+ set(NATS_VERSION_REQUIRED_NUMBER 0x010100)
116
+
117
+ configure_file(
118
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/version.h.in
119
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/version.h
120
+ @ONLY)
121
+
122
+ configure_file(
123
+ ${CMAKE_SOURCE_DIR}/doc/DoxyFile.NATS.Client.in
124
+ ${CMAKE_SOURCE_DIR}/doc/DoxyFile.NATS.Client
125
+ @ONLY)
126
+ #------------
127
+ endif()
128
+
129
+ #----------------------------
130
+ # Add the project directories
131
+
132
+ add_subdirectory(src)
133
+ add_subdirectory(examples)
134
+ add_subdirectory(test)
135
+ add_subdirectory(test/dylib)
136
+ #----------------------------
137
+
@@ -0,0 +1,220 @@
1
+ // Copyright 2016 Apcera Inc. All rights reserved.
2
+
3
+ #ifndef LIBEVENT_H_
4
+ #define LIBEVENT_H_
5
+
6
+ /** \cond
7
+ *
8
+ */
9
+ #include <event.h>
10
+ #include <event2/thread.h>
11
+ #include "nats.h"
12
+
13
+ typedef struct
14
+ {
15
+ natsConnection *nc;
16
+ struct event_base *loop;
17
+ struct event *read;
18
+ struct event *write;
19
+ struct event *keepActive;
20
+
21
+ } natsLibeventEvents;
22
+
23
+ // Forward declarations
24
+ natsStatus natsLibevent_Read(void *userData, bool add);
25
+ natsStatus natsLibevent_Detach(void *userData);
26
+
27
+ /** \endcond
28
+ *
29
+ */
30
+
31
+
32
+ /** \defgroup libeventFunctions Libevent Adapter
33
+ *
34
+ * Adapter to plug a `NATS` connection to a `libevent` event loop.
35
+ * @{
36
+ */
37
+
38
+ /** \brief Initialize the adapter.
39
+ *
40
+ * Needs to be called once so that the adapter can initialize some state.
41
+ */
42
+ void
43
+ natsLibevent_Init(void)
44
+ {
45
+ #if _WIN32
46
+ evthread_use_windows_threads();
47
+ #else
48
+ evthread_use_pthreads();
49
+ #endif
50
+ }
51
+
52
+ static void
53
+ natsLibevent_ProcessEvent(int fd, short event, void *arg)
54
+ {
55
+ natsLibeventEvents *nle = (natsLibeventEvents*) arg;
56
+
57
+ if (event & EV_READ)
58
+ natsConnection_ProcessReadEvent(nle->nc);
59
+
60
+ if (event & EV_WRITE)
61
+ natsConnection_ProcessWriteEvent(nle->nc);
62
+ }
63
+
64
+ static void
65
+ keepAliveCb(evutil_socket_t fd, short flags, void * arg)
66
+ {
67
+ // do nothing...
68
+ }
69
+
70
+ /** \brief Attach a connection to the given event loop.
71
+ *
72
+ * This callback is invoked after `NATS` library has connected, or reconnected.
73
+ * For a reconnect event, `*userData` will not be `NULL`. This function will
74
+ * start polling on READ events for the given `socket`.
75
+ *
76
+ * @param userData the location where the adapter stores the user object passed
77
+ * to the other callbacks.
78
+ * @param loop the event loop as a generic pointer. Cast to appropriate type.
79
+ * @param nc the connection to attach to the event loop
80
+ * @param socket the socket to start polling on.
81
+ */
82
+ natsStatus
83
+ natsLibevent_Attach(void **userData, void *loop, natsConnection *nc, int socket)
84
+ {
85
+ struct event_base *libeventLoop = (struct event_base*) loop;
86
+ natsLibeventEvents *nle = (natsLibeventEvents*) (*userData);
87
+ natsStatus s = NATS_OK;
88
+
89
+ // This is the first attach (when reconnecting, nle will be non-NULL).
90
+ if (nle == NULL)
91
+ {
92
+ nle = (natsLibeventEvents*) calloc(1, sizeof(natsLibeventEvents));
93
+ if (nle == NULL)
94
+ return NATS_NO_MEMORY;
95
+
96
+ nle->nc = nc;
97
+ nle->loop = libeventLoop;
98
+
99
+ nle->keepActive = event_new(nle->loop, -1, EV_PERSIST, keepAliveCb, NULL);
100
+ if (nle->keepActive == NULL)
101
+ s = NATS_NO_MEMORY;
102
+
103
+ if (s == NATS_OK)
104
+ {
105
+ struct timeval timeout;
106
+
107
+ timeout.tv_sec = 100000;
108
+ timeout.tv_usec = 0;
109
+
110
+ if (event_add(nle->keepActive, &timeout) != 0)
111
+ s = NATS_ERR;
112
+ }
113
+ }
114
+ else
115
+ {
116
+ if (nle->read != NULL)
117
+ {
118
+ event_free(nle->read);
119
+ nle->read = NULL;
120
+ }
121
+ if (nle->write != NULL)
122
+ {
123
+ event_free(nle->write);
124
+ nle->write = NULL;
125
+ }
126
+ }
127
+
128
+ if (s == NATS_OK)
129
+ {
130
+ nle->read = event_new(nle->loop, socket, EV_READ|EV_PERSIST,
131
+ natsLibevent_ProcessEvent, (void*) nle);
132
+ natsLibevent_Read((void*) nle, true);
133
+
134
+ nle->write = event_new(nle->loop, socket, EV_WRITE|EV_PERSIST,
135
+ natsLibevent_ProcessEvent, (void*) nle);
136
+ }
137
+
138
+ if (s == NATS_OK)
139
+ *userData = (void*) nle;
140
+ else
141
+ natsLibevent_Detach((void*) nle);
142
+
143
+ return s;
144
+ }
145
+
146
+ /** \brief Start or stop polling on READ events.
147
+ *
148
+ * This callback is invoked to notify that the event library should start
149
+ * or stop polling for READ events.
150
+ *
151
+ * @param userData the user object created in #natsLibuv_Attach
152
+ * @param add `true` if the library needs to start polling, `false` otherwise.
153
+ */
154
+ natsStatus
155
+ natsLibevent_Read(void *userData, bool add)
156
+ {
157
+ natsLibeventEvents *nle = (natsLibeventEvents*) userData;
158
+ int res;
159
+
160
+ if (add)
161
+ res = event_add(nle->read, NULL);
162
+ else
163
+ res = event_del(nle->read);
164
+
165
+ return (res == 0 ? NATS_OK : NATS_ERR);
166
+ }
167
+
168
+ /** \brief Start or stop polling on WRITE events.
169
+ *
170
+ * This callback is invoked to notify that the event library should start
171
+ * or stop polling for WRITE events.
172
+ *
173
+ * @param userData the user object created in #natsLibuv_Attach
174
+ * @param add `true` if the library needs to start polling, `false` otherwise.
175
+ */
176
+ natsStatus
177
+ natsLibevent_Write(void *userData, bool add)
178
+ {
179
+ natsLibeventEvents *nle = (natsLibeventEvents*) userData;
180
+ int res;
181
+
182
+ if (add)
183
+ res = event_add(nle->write, NULL);
184
+ else
185
+ res = event_del(nle->write);
186
+
187
+ return (res == 0 ? NATS_OK : NATS_ERR);
188
+ }
189
+
190
+ /** \brief The connection is closed, it can be safely detached.
191
+ *
192
+ * When a connection is closed (not disconnected, pending a reconnect), this
193
+ * callback will be invoked. This is the opportunity to cleanup the state
194
+ * maintained by the adapter for this connection.
195
+ *
196
+ * @param userData the user object created in #natsLibuv_Attach
197
+ */
198
+ natsStatus
199
+ natsLibevent_Detach(void *userData)
200
+ {
201
+ natsLibeventEvents *nle = (natsLibeventEvents*) userData;
202
+
203
+ if (nle->read != NULL)
204
+ event_free(nle->read);
205
+ if (nle->write != NULL)
206
+ event_free(nle->write);
207
+ if (nle->keepActive != NULL)
208
+ {
209
+ event_active(nle->keepActive, 0, 0);
210
+ event_free(nle->keepActive);
211
+ }
212
+
213
+ free(nle);
214
+
215
+ return NATS_OK;
216
+ }
217
+
218
+ /** @} */ // end of libeventFunctions
219
+
220
+ #endif /* LIBEVENT_H_ */
@@ -0,0 +1,472 @@
1
+ // Copyright 2016 Apcera Inc. All rights reserved.
2
+
3
+ #ifndef LIBUV_H_
4
+ #define LIBUV_H_
5
+
6
+ /** \cond
7
+ *
8
+ */
9
+ #ifndef _GNU_SOURCE
10
+ #define _GNU_SOURCE
11
+ #endif
12
+
13
+ #define NATS_LIBUV_INCLUDE
14
+
15
+ #include <uv.h>
16
+ #include "nats.h"
17
+
18
+ #define NATS_LIBUV_ATTACH (1)
19
+ #define NATS_LIBUV_READ (2)
20
+ #define NATS_LIBUV_WRITE (3)
21
+ #define NATS_LIBUV_DETACH (4)
22
+
23
+ struct __natsLibuvEvent;
24
+
25
+ typedef struct __natsLibuvEvent
26
+ {
27
+ int type;
28
+ bool add;
29
+ struct __natsLibuvEvent *next;
30
+
31
+ } natsLibuvEvent;
32
+
33
+ typedef struct
34
+ {
35
+ natsConnection *nc;
36
+ uv_loop_t *loop;
37
+ uv_poll_t *handle;
38
+ uv_async_t *scheduler;
39
+ int events;
40
+ int socket;
41
+ uv_mutex_t *lock;
42
+ natsLibuvEvent *head;
43
+ natsLibuvEvent *tail;
44
+
45
+ } natsLibuvEvents;
46
+
47
+ // Forward declarations
48
+ natsStatus natsLibuv_Detach(void *userData);
49
+
50
+ /** \endcond
51
+ *
52
+ */
53
+
54
+ static uv_once_t uvOnce = UV_ONCE_INIT;
55
+ static uv_key_t uvLoopThreadKey;
56
+
57
+ static void
58
+ _initOnce(void)
59
+ {
60
+ if (uv_key_create(&uvLoopThreadKey) != 0)
61
+ abort();
62
+ }
63
+
64
+ /** \defgroup libuvFunctions Libuv Adapter
65
+ *
66
+ * Adapter to plug a `NATS` connection to a `libuv` event loop.
67
+ * @{
68
+ */
69
+
70
+ /** \brief Initialize the adapter.
71
+ *
72
+ * Needs to be called once so that the adapter can initialize some state.
73
+ */
74
+ void
75
+ natsLibuv_Init(void)
76
+ {
77
+ uv_once(&uvOnce, _initOnce);
78
+ }
79
+
80
+ /** \brief Register the event loop with the thread running `uv_run()`.
81
+ *
82
+ * Since `libuv` is not thread-safe, the adapter needs to know in which
83
+ * thread `uv_run()` will run for the given `loop`. It allows the adapter
84
+ * to schedule events so that they are executed in the event loop thread.
85
+ *
86
+ * @param loop an event loop.
87
+ */
88
+ void
89
+ natsLibuv_SetThreadLocalLoop(uv_loop_t *loop)
90
+ {
91
+ uv_key_set(&uvLoopThreadKey, (void*) loop);
92
+ }
93
+
94
+ static natsStatus
95
+ uvScheduleToEventLoop(natsLibuvEvents *nle, int eventType, bool add)
96
+ {
97
+ natsLibuvEvent *newEvent = NULL;
98
+ int res;
99
+
100
+ newEvent = (natsLibuvEvent*) malloc(sizeof(natsLibuvEvent));
101
+ if (newEvent == NULL)
102
+ return NATS_NO_MEMORY;
103
+
104
+ newEvent->type = eventType;
105
+ newEvent->add = add;
106
+ newEvent->next = NULL;
107
+
108
+ uv_mutex_lock(nle->lock);
109
+
110
+ if (nle->head == NULL)
111
+ nle->head = newEvent;
112
+
113
+ if (nle->tail != NULL)
114
+ nle->tail->next = newEvent;
115
+
116
+ nle->tail = newEvent;
117
+
118
+ uv_mutex_unlock(nle->lock);
119
+
120
+ res = uv_async_send(nle->scheduler);
121
+
122
+ return (res == 0 ? NATS_OK : NATS_ERR);
123
+ }
124
+
125
+ static void
126
+ natsLibuvPoll(uv_poll_t* handle, int status, int events)
127
+ {
128
+ natsLibuvEvents *nle = (natsLibuvEvents*)handle->data;
129
+
130
+ if (status != 0)
131
+ return;
132
+
133
+ if (events & UV_READABLE)
134
+ natsConnection_ProcessReadEvent(nle->nc);
135
+
136
+ if (events & UV_WRITABLE)
137
+ natsConnection_ProcessWriteEvent(nle->nc);
138
+ }
139
+
140
+ static natsStatus
141
+ uvPollUpdate(natsLibuvEvents *nle, int eventType, bool add)
142
+ {
143
+ int res;
144
+
145
+ if (eventType == NATS_LIBUV_READ)
146
+ {
147
+ if (add)
148
+ nle->events |= UV_READABLE;
149
+ else
150
+ nle->events &= ~UV_READABLE;
151
+ }
152
+ else
153
+ {
154
+ if (add)
155
+ nle->events |= UV_WRITABLE;
156
+ else
157
+ nle->events &= ~UV_WRITABLE;
158
+ }
159
+
160
+ if (nle->events)
161
+ res = uv_poll_start(nle->handle, nle->events, natsLibuvPoll);
162
+ else
163
+ res = uv_poll_stop(nle->handle);
164
+
165
+ if (res != 0)
166
+ return NATS_ERR;
167
+
168
+ return NATS_OK;
169
+ }
170
+
171
+ static void
172
+ uvHandleClosedCb(uv_handle_t *handle)
173
+ {
174
+ free(handle);
175
+ }
176
+
177
+ static natsStatus
178
+ uvAsyncAttach(natsLibuvEvents *nle)
179
+ {
180
+ natsStatus s = NATS_OK;
181
+
182
+ // We are reconnecting, destroy the old handle, create a new one
183
+ if (nle->handle != NULL)
184
+ {
185
+ uv_close((uv_handle_t*) nle->handle, uvHandleClosedCb);
186
+ nle->handle = NULL;
187
+ }
188
+
189
+ nle->handle = (uv_poll_t*) malloc(sizeof(uv_poll_t));
190
+ if (nle->handle == NULL)
191
+ s = NATS_NO_MEMORY;
192
+
193
+ if ((s == NATS_OK)
194
+ && (uv_poll_init_socket(nle->loop, nle->handle, nle->socket) != 0))
195
+ {
196
+ s = NATS_ERR;
197
+ }
198
+
199
+ if ((s == NATS_OK)
200
+ && (nle->handle->data = (void*) nle)
201
+ && (uv_poll_start(nle->handle, UV_READABLE, natsLibuvPoll) != 0))
202
+ {
203
+ s = NATS_ERR;
204
+ }
205
+
206
+ return s;
207
+ }
208
+
209
+ static void
210
+ finalCloseCb(uv_handle_t* handle)
211
+ {
212
+ natsLibuvEvents *nle = (natsLibuvEvents*)handle->data;
213
+ natsLibuvEvent *event;
214
+
215
+ while ((event = nle->head) != NULL)
216
+ {
217
+ nle->head = event->next;
218
+ free(event);
219
+ }
220
+ free(nle->handle);
221
+ free(nle->scheduler);
222
+ uv_mutex_destroy(nle->lock);
223
+ free(nle->lock);
224
+ free(nle);
225
+ }
226
+
227
+ static void
228
+ closeSchedulerCb(uv_handle_t* scheduler)
229
+ {
230
+ natsLibuvEvents *nle = (natsLibuvEvents*) scheduler->data;
231
+
232
+ uv_close((uv_handle_t*) nle->handle, finalCloseCb);
233
+ }
234
+
235
+ static void
236
+ uvAsyncDetach(natsLibuvEvents *nle)
237
+ {
238
+ uv_close((uv_handle_t*) nle->scheduler, closeSchedulerCb);
239
+ }
240
+
241
+ static void
242
+ uvAsyncCb(uv_async_t *handle)
243
+ {
244
+ natsLibuvEvents *nle = (natsLibuvEvents*) handle->data;
245
+ natsStatus s = NATS_OK;
246
+ natsLibuvEvent *event = NULL;
247
+ bool remove = false;
248
+ bool more = false;
249
+
250
+ while (1)
251
+ {
252
+ uv_mutex_lock(nle->lock);
253
+
254
+ event = nle->head;
255
+ if (event == NULL)
256
+ {
257
+ // This is possible, even on entry of this function because
258
+ // the callback is called when the handle is initialized.
259
+ uv_mutex_unlock(nle->lock);
260
+ return;
261
+ }
262
+
263
+ nle->head = event->next;
264
+ if (event == nle->tail)
265
+ nle->tail = NULL;
266
+
267
+ more = (nle->head != NULL ? true : false);
268
+
269
+ uv_mutex_unlock(nle->lock);
270
+
271
+ switch (event->type)
272
+ {
273
+ case NATS_LIBUV_ATTACH:
274
+ {
275
+ s = uvAsyncAttach(nle);
276
+ break;
277
+ }
278
+ case NATS_LIBUV_READ:
279
+ case NATS_LIBUV_WRITE:
280
+ {
281
+ s = uvPollUpdate(nle, event->type, event->add);
282
+ break;
283
+ }
284
+ case NATS_LIBUV_DETACH:
285
+ {
286
+ uvAsyncDetach(nle);
287
+ break;
288
+ }
289
+ default:
290
+ {
291
+ s = NATS_ERR;
292
+ break;
293
+ }
294
+ }
295
+
296
+ free(event);
297
+
298
+ if ((s != NATS_OK) || !more)
299
+ break;
300
+ }
301
+
302
+ if (s != NATS_OK)
303
+ natsConnection_Close(nle->nc);
304
+ }
305
+
306
+ /** \brief Attach a connection to the given event loop.
307
+ *
308
+ * This callback is invoked after `NATS` library has connected, or reconnected.
309
+ * For a reconnect event, `*userData` will not be `NULL`. This function will
310
+ * start polling on READ events for the given `socket`.
311
+ *
312
+ * @param userData the location where the adapter stores the user object passed
313
+ * to the other callbacks.
314
+ * @param loop the event loop as a generic pointer. Cast to appropriate type.
315
+ * @param nc the connection to attach to the event loop
316
+ * @param socket the socket to start polling on.
317
+ */
318
+ natsStatus
319
+ natsLibuv_Attach(void **userData, void *loop, natsConnection *nc, int socket)
320
+ {
321
+ uv_loop_t *uvLoop = (uv_loop_t*) loop;
322
+ bool sched = false;
323
+ natsLibuvEvents *nle = (natsLibuvEvents*) (*userData);
324
+ natsStatus s = NATS_OK;
325
+
326
+ sched = ((uv_key_get(&uvLoopThreadKey) != loop) ? true : false);
327
+
328
+ // This is the first attach (when reconnecting, nle will be non-NULL).
329
+ if (nle == NULL)
330
+ {
331
+ // This has to run from the event loop!
332
+ if (sched)
333
+ return NATS_ILLEGAL_STATE;
334
+
335
+ nle = (natsLibuvEvents*) calloc(1, sizeof(natsLibuvEvents));
336
+ if (nle == NULL)
337
+ return NATS_NO_MEMORY;
338
+
339
+ nle->lock = (uv_mutex_t*) malloc(sizeof(uv_mutex_t));
340
+ if (nle->lock == NULL)
341
+ s = NATS_NO_MEMORY;
342
+
343
+ if ((s == NATS_OK) && (uv_mutex_init(nle->lock) != 0))
344
+ s = NATS_ERR;
345
+
346
+ if ((s == NATS_OK)
347
+ && ((nle->scheduler = (uv_async_t*) malloc(sizeof(uv_async_t))) == NULL))
348
+ {
349
+ s = NATS_NO_MEMORY;
350
+ }
351
+
352
+ if ((s == NATS_OK)
353
+ && (uv_async_init(uvLoop, nle->scheduler, uvAsyncCb) != 0))
354
+ {
355
+ s = NATS_ERR;
356
+ }
357
+
358
+ if (s == NATS_OK)
359
+ {
360
+ nle->nc = nc;
361
+ nle->loop = uvLoop;
362
+ nle->scheduler->data = (void*) nle;
363
+ }
364
+ }
365
+
366
+ if (s == NATS_OK)
367
+ {
368
+ nle->socket = socket;
369
+ nle->events = UV_READABLE;
370
+
371
+ if (sched)
372
+ s = uvScheduleToEventLoop(nle, NATS_LIBUV_ATTACH, true);
373
+ else
374
+ s = uvAsyncAttach(nle);
375
+ }
376
+
377
+ if (s == NATS_OK)
378
+ *userData = (void*) nle;
379
+ else
380
+ natsLibuv_Detach((void*) nle);
381
+
382
+ return s;
383
+ }
384
+
385
+ /** \brief Start or stop polling on READ events.
386
+ *
387
+ * This callback is invoked to notify that the event library should start
388
+ * or stop polling for READ events.
389
+ *
390
+ * @param userData the user object created in #natsLibuv_Attach
391
+ * @param add `true` if the library needs to start polling, `false` otherwise.
392
+ */
393
+ natsStatus
394
+ natsLibuv_Read(void *userData, bool add)
395
+ {
396
+ natsLibuvEvents *nle = (natsLibuvEvents*) userData;
397
+ natsStatus s = NATS_OK;
398
+ bool sched;
399
+
400
+ sched = ((uv_key_get(&uvLoopThreadKey) != nle->loop) ? true : false);
401
+
402
+ // If this call is made from a different thread than the event loop's
403
+ // thread, or if there are already scheduled events, then schedule
404
+ // this new event.
405
+
406
+ // We don't need to get the lock for nle->head because if sched is
407
+ // false, we are in the event loop thread, which is the thread removing
408
+ // events from the list. Also, all calls to the read/write/etc.. callbacks
409
+ // are protected by the connection's lock in the NATS library.
410
+ if (sched || (nle->head != NULL))
411
+ s = uvScheduleToEventLoop(nle, NATS_LIBUV_READ, add);
412
+ else
413
+ s = uvPollUpdate(nle, NATS_LIBUV_READ, add);
414
+
415
+ return s;
416
+ }
417
+
418
+ /** \brief Start or stop polling on WRITE events.
419
+ *
420
+ * This callback is invoked to notify that the event library should start
421
+ * or stop polling for WRITE events.
422
+ *
423
+ * @param userData the user object created in #natsLibuv_Attach
424
+ * @param add `true` if the library needs to start polling, `false` otherwise.
425
+ */
426
+ natsStatus
427
+ natsLibuv_Write(void *userData, bool add)
428
+ {
429
+ natsLibuvEvents *nle = (natsLibuvEvents*) userData;
430
+ natsStatus s = NATS_OK;
431
+ bool sched;
432
+
433
+ sched = ((uv_key_get(&uvLoopThreadKey) != nle->loop) ? true : false);
434
+
435
+ // See comment in natsLibuvRead
436
+ if (sched || (nle->head != NULL))
437
+ s = uvScheduleToEventLoop(nle, NATS_LIBUV_WRITE, add);
438
+ else
439
+ s = uvPollUpdate(nle, NATS_LIBUV_WRITE, add);
440
+
441
+ return s;
442
+ }
443
+
444
+ /** \brief The connection is closed, it can be safely detached.
445
+ *
446
+ * When a connection is closed (not disconnected, pending a reconnect), this
447
+ * callback will be invoked. This is the opportunity to cleanup the state
448
+ * maintained by the adapter for this connection.
449
+ *
450
+ * @param userData the user object created in #natsLibuv_Attach
451
+ */
452
+ natsStatus
453
+ natsLibuv_Detach(void *userData)
454
+ {
455
+ natsLibuvEvents *nle = (natsLibuvEvents*) userData;
456
+ natsStatus s = NATS_OK;
457
+ bool sched;
458
+
459
+ sched = ((uv_key_get(&uvLoopThreadKey) != nle->loop) ? true : false);
460
+
461
+ // See comment in natsLibuvRead
462
+ if (sched || (nle->head != NULL))
463
+ s = uvScheduleToEventLoop(nle, NATS_LIBUV_DETACH, true);
464
+ else
465
+ uvAsyncDetach(nle);
466
+
467
+ return s;
468
+ }
469
+
470
+ /** @} */ // end of libuvFunctions
471
+
472
+ #endif /* LIBUV_H_ */