ffi-nats-core 0.3.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
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_ */