libcouchbase 0.3.3 → 1.0.0

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 (167) hide show
  1. checksums.yaml +4 -4
  2. data/ext/libcouchbase/CMakeLists.txt +6 -8
  3. data/ext/libcouchbase/README.markdown +2 -2
  4. data/ext/libcouchbase/RELEASE_NOTES.markdown +229 -2
  5. data/ext/libcouchbase/cmake/Modules/ConfigureDtrace.cmake +11 -0
  6. data/ext/libcouchbase/cmake/Modules/GenerateConfigDotH.cmake +18 -0
  7. data/ext/libcouchbase/cmake/Modules/GetLibcouchbaseFlags.cmake +3 -2
  8. data/ext/libcouchbase/cmake/Modules/GetVersionInfo.cmake +3 -3
  9. data/ext/libcouchbase/cmake/config-cmake.h.in +4 -0
  10. data/ext/libcouchbase/cmake/defs.mk.in +0 -2
  11. data/ext/libcouchbase/cmake/source_files.cmake +21 -5
  12. data/ext/libcouchbase/contrib/cJSON/cJSON.c +1 -1
  13. data/ext/libcouchbase/contrib/cbsasl/src/client.c +2 -0
  14. data/ext/libcouchbase/example/users/README +48 -0
  15. data/ext/libcouchbase/example/users/users.c +147 -0
  16. data/ext/libcouchbase/include/libcouchbase/auth.h +175 -31
  17. data/ext/libcouchbase/include/libcouchbase/cntl.h +82 -1
  18. data/ext/libcouchbase/include/libcouchbase/couchbase.h +45 -3
  19. data/ext/libcouchbase/include/libcouchbase/error.h +19 -1
  20. data/ext/libcouchbase/include/libcouchbase/iops.h +3 -0
  21. data/ext/libcouchbase/include/libcouchbase/n1ql.h +31 -1
  22. data/ext/libcouchbase/include/libcouchbase/plugins/io/bsdio-inl.c +4 -1
  23. data/ext/libcouchbase/include/libcouchbase/subdoc.h +36 -2
  24. data/ext/libcouchbase/include/libcouchbase/views.h +7 -1
  25. data/ext/libcouchbase/include/libcouchbase/visibility.h +1 -0
  26. data/ext/libcouchbase/include/memcached/protocol_binary.h +24 -1146
  27. data/ext/libcouchbase/packaging/parse-git-describe.pl +1 -1
  28. data/ext/libcouchbase/plugins/io/libev/libev_io_opts.h +3 -2
  29. data/ext/libcouchbase/src/README.md +0 -2
  30. data/ext/libcouchbase/src/auth-priv.h +23 -4
  31. data/ext/libcouchbase/src/auth.cc +51 -43
  32. data/ext/libcouchbase/src/bootstrap.cc +244 -0
  33. data/ext/libcouchbase/src/bootstrap.h +58 -38
  34. data/ext/libcouchbase/src/bucketconfig/bc_cccp.cc +120 -158
  35. data/ext/libcouchbase/src/bucketconfig/bc_file.cc +281 -0
  36. data/ext/libcouchbase/src/bucketconfig/bc_http.cc +526 -0
  37. data/ext/libcouchbase/src/bucketconfig/bc_http.h +50 -25
  38. data/ext/libcouchbase/src/bucketconfig/bc_static.cc +150 -0
  39. data/ext/libcouchbase/src/bucketconfig/clconfig.h +410 -386
  40. data/ext/libcouchbase/src/bucketconfig/confmon.cc +393 -0
  41. data/ext/libcouchbase/src/cbft.cc +22 -27
  42. data/ext/libcouchbase/src/cntl.cc +56 -22
  43. data/ext/libcouchbase/src/connspec.cc +47 -6
  44. data/ext/libcouchbase/src/connspec.h +27 -0
  45. data/ext/libcouchbase/src/dns-srv.cc +147 -0
  46. data/ext/libcouchbase/src/dump.cc +3 -3
  47. data/ext/libcouchbase/src/errmap.cc +173 -0
  48. data/ext/libcouchbase/src/errmap.h +198 -0
  49. data/ext/libcouchbase/src/getconfig.cc +7 -33
  50. data/ext/libcouchbase/src/handler.cc +118 -7
  51. data/ext/libcouchbase/src/hostlist.cc +0 -36
  52. data/ext/libcouchbase/src/hostlist.h +44 -62
  53. data/ext/libcouchbase/src/http/http-priv.h +125 -112
  54. data/ext/libcouchbase/src/http/http.cc +27 -35
  55. data/ext/libcouchbase/src/http/http.h +1 -34
  56. data/ext/libcouchbase/src/http/http_io.cc +28 -36
  57. data/ext/libcouchbase/src/instance.cc +131 -34
  58. data/ext/libcouchbase/src/internal.h +58 -26
  59. data/ext/libcouchbase/src/jsparse/parser.cc +136 -210
  60. data/ext/libcouchbase/src/jsparse/parser.h +84 -98
  61. data/ext/libcouchbase/src/lcbht/lcbht.cc +177 -0
  62. data/ext/libcouchbase/src/lcbht/lcbht.h +174 -163
  63. data/ext/libcouchbase/src/lcbio/connect.cc +569 -0
  64. data/ext/libcouchbase/src/lcbio/connect.h +16 -7
  65. data/ext/libcouchbase/src/lcbio/ctx.c +1 -1
  66. data/ext/libcouchbase/src/lcbio/iotable.h +101 -16
  67. data/ext/libcouchbase/src/lcbio/{ioutils.c → ioutils.cc} +30 -51
  68. data/ext/libcouchbase/src/lcbio/ioutils.h +29 -90
  69. data/ext/libcouchbase/src/lcbio/manager.cc +543 -0
  70. data/ext/libcouchbase/src/lcbio/manager.h +133 -96
  71. data/ext/libcouchbase/src/lcbio/protoctx.c +2 -2
  72. data/ext/libcouchbase/src/lcbio/timer-cxx.h +87 -0
  73. data/ext/libcouchbase/src/mc/mcreq.c +11 -2
  74. data/ext/libcouchbase/src/mc/mcreq.h +9 -2
  75. data/ext/libcouchbase/src/mcserver/mcserver.cc +175 -43
  76. data/ext/libcouchbase/src/mcserver/mcserver.h +9 -13
  77. data/ext/libcouchbase/src/mcserver/negotiate.cc +181 -62
  78. data/ext/libcouchbase/src/mcserver/negotiate.h +1 -3
  79. data/ext/libcouchbase/src/mctx-helper.h +51 -0
  80. data/ext/libcouchbase/src/n1ql/ixmgmt.cc +1 -2
  81. data/ext/libcouchbase/src/n1ql/n1ql.cc +74 -42
  82. data/ext/libcouchbase/src/netbuf/netbuf.c +4 -4
  83. data/ext/libcouchbase/src/newconfig.cc +6 -6
  84. data/ext/libcouchbase/src/nodeinfo.cc +2 -2
  85. data/ext/libcouchbase/src/operations/{cbflush.c → cbflush.cc} +7 -15
  86. data/ext/libcouchbase/src/operations/{counter.c → counter.cc} +0 -0
  87. data/ext/libcouchbase/src/operations/durability.cc +6 -26
  88. data/ext/libcouchbase/src/operations/durability_internal.h +6 -3
  89. data/ext/libcouchbase/src/operations/{get.c → get.cc} +24 -26
  90. data/ext/libcouchbase/src/operations/{observe.c → observe.cc} +68 -93
  91. data/ext/libcouchbase/src/operations/{pktfwd.c → pktfwd.cc} +0 -0
  92. data/ext/libcouchbase/src/operations/{remove.c → remove.cc} +0 -0
  93. data/ext/libcouchbase/src/operations/stats.cc +3 -8
  94. data/ext/libcouchbase/src/operations/{store.c → store.cc} +27 -32
  95. data/ext/libcouchbase/src/operations/subdoc.cc +129 -42
  96. data/ext/libcouchbase/src/operations/{touch.c → touch.cc} +0 -0
  97. data/ext/libcouchbase/src/packetutils.h +30 -2
  98. data/ext/libcouchbase/src/probes.d +1 -1
  99. data/ext/libcouchbase/src/rdb/rope.c +1 -1
  100. data/ext/libcouchbase/src/{retrychk.c → retrychk.cc} +2 -3
  101. data/ext/libcouchbase/src/retryq.cc +52 -14
  102. data/ext/libcouchbase/src/retryq.h +3 -3
  103. data/ext/libcouchbase/src/settings.c +5 -0
  104. data/ext/libcouchbase/src/settings.h +11 -0
  105. data/ext/libcouchbase/src/ssl/ssl_c.c +1 -0
  106. data/ext/libcouchbase/src/ssl/ssl_common.c +2 -0
  107. data/ext/libcouchbase/src/ssl/ssl_e.c +0 -1
  108. data/ext/libcouchbase/src/strcodecs/strcodecs.h +1 -1
  109. data/ext/libcouchbase/src/trace.h +4 -4
  110. data/ext/libcouchbase/src/vbucket/vbucket.c +6 -10
  111. data/ext/libcouchbase/src/views/{docreq.c → docreq.cc} +48 -54
  112. data/ext/libcouchbase/src/views/docreq.h +24 -30
  113. data/ext/libcouchbase/src/views/viewreq.cc +318 -0
  114. data/ext/libcouchbase/src/views/viewreq.h +43 -13
  115. data/ext/libcouchbase/tests/basic/t_connstr.cc +88 -50
  116. data/ext/libcouchbase/tests/basic/t_creds.cc +47 -5
  117. data/ext/libcouchbase/tests/basic/t_host.cc +67 -75
  118. data/ext/libcouchbase/tests/basic/t_jsparse.cc +27 -82
  119. data/ext/libcouchbase/tests/basic/t_misc.cc +1 -1
  120. data/ext/libcouchbase/tests/basic/t_n1qlstrings.cc +0 -1
  121. data/ext/libcouchbase/tests/htparse/t_basic.cc +58 -78
  122. data/ext/libcouchbase/tests/ioserver/connection.cc +1 -1
  123. data/ext/libcouchbase/tests/ioserver/ioserver.cc +19 -6
  124. data/ext/libcouchbase/tests/iotests/mock-environment.cc +28 -2
  125. data/ext/libcouchbase/tests/iotests/mock-environment.h +51 -1
  126. data/ext/libcouchbase/tests/iotests/t_behavior.cc +1 -7
  127. data/ext/libcouchbase/tests/iotests/t_confmon.cc +97 -115
  128. data/ext/libcouchbase/tests/iotests/t_durability.cc +0 -1
  129. data/ext/libcouchbase/tests/iotests/t_eerrs.cc +119 -0
  130. data/ext/libcouchbase/tests/iotests/t_errmap.cc +178 -0
  131. data/ext/libcouchbase/tests/iotests/t_misc.cc +3 -3
  132. data/ext/libcouchbase/tests/iotests/t_netfail.cc +1 -1
  133. data/ext/libcouchbase/tests/iotests/t_obseqno.cc +0 -1
  134. data/ext/libcouchbase/tests/iotests/t_subdoc.cc +18 -11
  135. data/ext/libcouchbase/tests/mc/t_alloc.cc +9 -9
  136. data/ext/libcouchbase/tests/socktests/socktest.cc +7 -10
  137. data/ext/libcouchbase/tests/socktests/socktest.h +2 -3
  138. data/ext/libcouchbase/tests/socktests/t_basic.cc +6 -6
  139. data/ext/libcouchbase/tests/socktests/t_manager.cc +5 -6
  140. data/ext/libcouchbase/tests/socktests/t_ssl.cc +1 -1
  141. data/ext/libcouchbase/tests/vbucket/confdata/ketama_expected.json +2562 -0
  142. data/ext/libcouchbase/tests/vbucket/confdata/memd_ketama_config.json +31 -0
  143. data/ext/libcouchbase/tests/vbucket/t_config.cc +35 -5
  144. data/ext/libcouchbase/tools/CMakeLists.txt +2 -2
  145. data/ext/libcouchbase/tools/cbc-handlers.h +128 -0
  146. data/ext/libcouchbase/tools/cbc-n1qlback.cc +64 -10
  147. data/ext/libcouchbase/tools/cbc-pillowfight.cc +2 -2
  148. data/ext/libcouchbase/tools/cbc.cc +143 -10
  149. data/ext/libcouchbase/tools/docgen/loc.h +1 -1
  150. data/lib/libcouchbase/connection.rb +4 -3
  151. data/lib/libcouchbase/version.rb +1 -1
  152. metadata +37 -28
  153. data/ext/libcouchbase/include/memcached/vbucket.h +0 -42
  154. data/ext/libcouchbase/src/bootstrap.c +0 -269
  155. data/ext/libcouchbase/src/bucketconfig/bc_file.c +0 -347
  156. data/ext/libcouchbase/src/bucketconfig/bc_http.c +0 -630
  157. data/ext/libcouchbase/src/bucketconfig/bc_mcraw.c +0 -150
  158. data/ext/libcouchbase/src/bucketconfig/confmon.c +0 -474
  159. data/ext/libcouchbase/src/lcbht/lcbht.c +0 -282
  160. data/ext/libcouchbase/src/lcbio/connect.c +0 -557
  161. data/ext/libcouchbase/src/lcbio/manager.c +0 -584
  162. data/ext/libcouchbase/src/packetutils.c +0 -37
  163. data/ext/libcouchbase/src/simplestring.c +0 -211
  164. data/ext/libcouchbase/src/simplestring.h +0 -228
  165. data/ext/libcouchbase/src/ssobuf.h +0 -82
  166. data/ext/libcouchbase/src/views/viewreq.c +0 -358
  167. data/ext/libcouchbase/tests/basic/t_string.cc +0 -112
@@ -0,0 +1,569 @@
1
+ /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
+ /*
3
+ * Copyright 2014 Couchbase, Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ #include "config.h"
19
+ #include "connect.h"
20
+ #include "ioutils.h"
21
+ #include "iotable.h"
22
+ #include "settings.h"
23
+ #include "timer-ng.h"
24
+ #include "timer-cxx.h"
25
+ #include <errno.h>
26
+
27
+ using namespace lcb::io;
28
+
29
+ /* win32 lacks EAI_SYSTEM */
30
+ #ifndef EAI_SYSTEM
31
+ #define EAI_SYSTEM 0
32
+ #endif
33
+ #define LOGARGS(conn, lvl) conn->settings, "connection", LCB_LOG_##lvl, __FILE__, __LINE__
34
+ static const lcb_host_t *get_loghost(lcbio_SOCKET *s) {
35
+ static lcb_host_t host = { "NOHOST", "NOPORT" };
36
+ if (!s) { return &host; }
37
+ if (!s->info) { return &host; }
38
+ return &s->info->ep;
39
+ }
40
+
41
+ /** Format string arguments for %p%s:%s */
42
+ #define CSLOGID(sock) get_loghost(sock)->host, get_loghost(sock)->port, (void*)sock
43
+ #define CSLOGFMT "<%s:%s> (SOCK=%p) "
44
+
45
+ #define LOGARGS_T(lvl) LOGARGS(this->sock, lvl)
46
+ #define CSLOGID_T() CSLOGID(this->sock)
47
+
48
+ namespace lcb {
49
+ namespace io {
50
+ struct Connstart : ConnectionRequest {
51
+ Connstart(lcbio_TABLE*, lcb_settings*, const lcb_host_t*,
52
+ uint32_t, lcbio_CONNDONE_cb, void*);
53
+
54
+ ~Connstart();
55
+ void unwatch();
56
+ void handler();
57
+ void cancel();
58
+ void C_connect();
59
+
60
+ enum State {
61
+ CS_PENDING, CS_CANCELLED, CS_CONNECTED, CS_ERROR
62
+ };
63
+
64
+ void state_signal(State next_state, lcb_error_t status);
65
+ void notify_success();
66
+ void notify_error(lcb_error_t err);
67
+ bool ensure_sock();
68
+ void clear_sock();
69
+
70
+ lcbio_CONNDONE_cb user_handler;
71
+ void *user_arg;
72
+
73
+ lcbio_SOCKET *sock;
74
+ lcbio_OSERR syserr;
75
+ void *event;
76
+ bool ev_active; /* whether the event pointer is active (Event only) */
77
+ bool in_uhandler; /* Whether we're inside the user-defined handler */
78
+ addrinfo *ai_root;
79
+ addrinfo *ai;
80
+ State state;
81
+ lcb_error_t last_error;
82
+ Timer<Connstart, &Connstart::handler> timer;
83
+ };
84
+ }
85
+ }
86
+
87
+ void Connstart::unwatch() {
88
+ if (sock && ev_active) {
89
+ lcb_assert(sock->u.fd != INVALID_SOCKET);
90
+ sock->io->E_event_cancel(sock->u.fd, event);
91
+ ev_active = false;
92
+ }
93
+ }
94
+
95
+ static void try_enable_sockopt(lcbio_SOCKET *sock, int cntl) {
96
+ lcb_error_t rv = lcbio_enable_sockopt(sock, cntl);
97
+ if (rv == LCB_SUCCESS) {
98
+ lcb_log(LOGARGS(sock, DEBUG), CSLOGFMT "Successfully set %s", CSLOGID(sock), lcbio_strsockopt(cntl));
99
+ } else {
100
+ lcb_log(LOGARGS(sock, INFO), CSLOGFMT "Couldn't set %s", CSLOGID(sock), lcbio_strsockopt(cntl));
101
+ }
102
+ }
103
+
104
+ /**
105
+ * Handler invoked to deliver final status for a connection. This will invoke
106
+ * the user supplied callback with the relevant status (if it has not been
107
+ * cancelled) and then free the CONNSTART object.
108
+ */
109
+ void Connstart::handler() {
110
+ lcb_error_t err;
111
+
112
+ if (sock && event) {
113
+ unwatch();
114
+ sock->io->E_event_destroy(event);
115
+ }
116
+
117
+ if (state == CS_PENDING) {
118
+ /* state was not changed since initial scheduling */
119
+ err = LCB_ETIMEDOUT;
120
+ } else if (state == CS_CONNECTED) {
121
+ /* clear pending error */
122
+ err = LCB_SUCCESS;
123
+ } else {
124
+ if (sock != NULL && last_error == LCB_CONNECT_ERROR) {
125
+ err = lcbio_mklcberr(syserr, sock->settings);
126
+ } else {
127
+ err = last_error;
128
+ }
129
+ }
130
+
131
+ if (state == CS_CANCELLED) {
132
+ /* ignore everything. Clean up resources */
133
+ goto GT_DTOR;
134
+ }
135
+
136
+ if (sock) {
137
+ lcbio__load_socknames(sock);
138
+ if (err == LCB_SUCCESS) {
139
+ lcb_log(LOGARGS_T(INFO), CSLOGFMT "Connected established", CSLOGID_T());
140
+
141
+ if (sock->settings->tcp_nodelay) {
142
+ try_enable_sockopt(sock, LCB_IO_CNTL_TCP_NODELAY);
143
+ }
144
+ if (sock->settings->tcp_keepalive) {
145
+ try_enable_sockopt(sock, LCB_IO_CNTL_TCP_KEEPALIVE);
146
+ }
147
+ } else {
148
+ lcb_log(LOGARGS_T(ERR), CSLOGFMT "Failed to establish connection: %s, os errno=%u", CSLOGID_T(), lcb_strerror_short(err), syserr);
149
+ }
150
+ }
151
+
152
+ /** Handler section */
153
+ in_uhandler = true;
154
+ user_handler(err == LCB_SUCCESS ? sock : NULL, user_arg, err, syserr);
155
+ in_uhandler = false;
156
+
157
+ GT_DTOR:
158
+ delete this;
159
+ }
160
+
161
+ Connstart::~Connstart() {
162
+ timer.release();
163
+ if (sock) {
164
+ lcbio_unref(sock);
165
+ }
166
+ if (ai_root) {
167
+ freeaddrinfo(ai_root);
168
+ }
169
+ }
170
+
171
+ void Connstart::state_signal(State next_state, lcb_error_t err) {
172
+ if (state != CS_PENDING) {
173
+ /** State already set */
174
+ return;
175
+ }
176
+
177
+
178
+ if (state == CS_CONNECTED) {
179
+ /* clear last errors if we're successful */
180
+ last_error = LCB_SUCCESS;
181
+ } else if (last_error == LCB_SUCCESS) {
182
+ /* set error code only if previous code was not a failure */
183
+ last_error = err;
184
+ }
185
+
186
+ state = next_state;
187
+ timer.signal();
188
+ }
189
+
190
+ void Connstart::notify_success() {
191
+ state_signal(CS_CONNECTED, LCB_SUCCESS);
192
+ }
193
+
194
+ void Connstart::notify_error(lcb_error_t err) {
195
+ state_signal(CS_ERROR, err);
196
+ }
197
+
198
+ /** Cancels and mutes any pending event */
199
+ void lcbio_connect_cancel(lcbio_pCONNSTART cs) {
200
+ cs->cancel();
201
+ }
202
+
203
+ void Connstart::cancel() {
204
+ if (in_uhandler) {
205
+ /* already inside user-defined handler */
206
+ return;
207
+ }
208
+ state = CS_CANCELLED;
209
+ handler();
210
+ }
211
+
212
+
213
+ bool Connstart::ensure_sock() {
214
+ lcbio_TABLE *io = sock->io;
215
+ int errtmp = 0;
216
+
217
+ if (ai == NULL) {
218
+ return false;
219
+ }
220
+
221
+ if (io->is_E()) {
222
+ if (sock->u.fd != INVALID_SOCKET) {
223
+ /* already have one? */
224
+ return true;
225
+ }
226
+
227
+ while (sock->u.fd == INVALID_SOCKET && ai != NULL) {
228
+ sock->u.fd = lcbio_E_ai2sock(io, &ai, &errtmp);
229
+ if (sock->u.fd != INVALID_SOCKET) {
230
+ lcb_log(LOGARGS_T(DEBUG), CSLOGFMT "Created new socket with FD=%d", CSLOGID_T(), sock->u.fd);
231
+ return true;
232
+ }
233
+ }
234
+ } else {
235
+ if (sock->u.sd) {
236
+ return true;
237
+ }
238
+
239
+ while (sock->u.sd == NULL && ai != NULL) {
240
+ sock->u.sd = lcbio_C_ai2sock(io, &ai, &errtmp);
241
+ if (sock->u.sd) {
242
+ sock->u.sd->lcbconn = const_cast<lcbio_SOCKET*>(sock);
243
+ sock->u.sd->parent = IOT_ARG(io);
244
+ return true;
245
+ }
246
+ }
247
+ }
248
+
249
+ if (ai == NULL) {
250
+ lcbio_mksyserr(IOT_ERRNO(io), &syserr);
251
+ return false;
252
+ }
253
+ return true;
254
+ }
255
+
256
+ void Connstart::clear_sock() {
257
+ lcbio_TABLE *iot = sock->io;
258
+ if (ai) {
259
+ ai = ai->ai_next;
260
+ }
261
+
262
+ if (!ai) {
263
+ return;
264
+ }
265
+
266
+ if (iot->is_E()) {
267
+ unwatch();
268
+ iot->E_close(sock->u.fd);
269
+ sock->u.fd = INVALID_SOCKET;
270
+ } else {
271
+ if (sock->u.sd) {
272
+ iot->C_close(sock->u.sd);
273
+ sock->u.sd = NULL;
274
+ }
275
+ }
276
+ }
277
+
278
+ static void
279
+ E_conncb(lcb_socket_t, short events, void *arg)
280
+ {
281
+ Connstart *cs = reinterpret_cast<Connstart*>(arg);
282
+ lcbio_SOCKET *s = cs->sock;
283
+ lcbio_TABLE *io = s->io;
284
+ int retry_once = 0;
285
+ lcbio_CSERR connstatus;
286
+ int rv = 0;
287
+ addrinfo *ai = NULL;
288
+
289
+ GT_NEXTSOCK:
290
+ if (!cs->ensure_sock()) {
291
+ cs->notify_error(LCB_CONNECT_ERROR);
292
+ return;
293
+ }
294
+
295
+ if (events & LCB_ERROR_EVENT) {
296
+ socklen_t errlen = sizeof(int);
297
+ int sockerr = 0;
298
+ lcb_log(LOGARGS(s, TRACE), CSLOGFMT "Received ERROR_EVENT", CSLOGID(s));
299
+ getsockopt(s->u.fd, SOL_SOCKET, SO_ERROR, (char *)&sockerr, &errlen);
300
+ lcbio_mksyserr(sockerr, &cs->syserr);
301
+ cs->clear_sock();
302
+ goto GT_NEXTSOCK;
303
+
304
+ } else {
305
+ rv = 0;
306
+ ai = cs->ai;
307
+
308
+ GT_CONNECT:
309
+ rv = io->E_connect(s->u.fd, ai->ai_addr, ai->ai_addrlen);
310
+ if (rv == 0) {
311
+ cs->unwatch();
312
+ cs->notify_success();
313
+ return;
314
+ }
315
+ }
316
+
317
+ connstatus = lcbio_mkcserr(io->get_errno());
318
+ lcbio_mksyserr(io->get_errno(), &cs->syserr);
319
+
320
+
321
+ switch (connstatus) {
322
+
323
+ case LCBIO_CSERR_INTR:
324
+ goto GT_CONNECT;
325
+
326
+ case LCBIO_CSERR_CONNECTED:
327
+ cs->unwatch();
328
+ cs->notify_success();
329
+ return;
330
+
331
+ case LCBIO_CSERR_BUSY:
332
+ lcb_log(LOGARGS(s, TRACE), CSLOGFMT "Scheduling I/O watcher for asynchronous connection completion.", CSLOGID(s));
333
+ io->E_event_watch(s->u.fd, cs->event, LCB_WRITE_EVENT, cs, E_conncb);
334
+ cs->ev_active = 1;
335
+ return;
336
+
337
+ case LCBIO_CSERR_EINVAL:
338
+ if (!retry_once) {
339
+ retry_once = 1;
340
+ goto GT_CONNECT;
341
+ }
342
+ /* fallthrough */
343
+
344
+ case LCBIO_CSERR_EFAIL:
345
+ default:
346
+ /* close the current socket and try again */
347
+ lcb_log(LOGARGS(s, TRACE), CSLOGFMT "connect() failed. errno=%d [%s]", CSLOGID(s), IOT_ERRNO(io), strerror(IOT_ERRNO(io)));
348
+ cs->clear_sock();
349
+ goto GT_NEXTSOCK;
350
+ }
351
+ }
352
+
353
+
354
+ static void
355
+ C_conncb(lcb_sockdata_t *sock, int status)
356
+ {
357
+ lcbio_SOCKET *s = reinterpret_cast<lcbio_SOCKET*>(sock->lcbconn);
358
+ Connstart *cs = reinterpret_cast<Connstart*>(s->ctx);
359
+
360
+ lcb_log(LOGARGS(s, TRACE), CSLOGFMT "Received completion handler. Status=%d. errno=%d", CSLOGID(s), status, IOT_ERRNO(s->io));
361
+
362
+ if (!--s->refcount) {
363
+ lcbio__destroy(s);
364
+ return;
365
+ }
366
+
367
+ if (!status) {
368
+ if (cs->state == Connstart::CS_PENDING) {
369
+ cs->state = Connstart::CS_CONNECTED;
370
+ }
371
+ cs->handler();
372
+ } else {
373
+ lcbio_mksyserr(s->io->get_errno(), &cs->syserr);
374
+ cs->clear_sock();
375
+ cs->C_connect();
376
+ }
377
+ }
378
+
379
+ void Connstart::C_connect()
380
+ {
381
+ int rv;
382
+ bool retry_once = 0;
383
+ lcbio_CSERR status;
384
+ lcbio_TABLE *io = sock->io;
385
+
386
+ GT_NEXTSOCK:
387
+ if (!ensure_sock()) {
388
+ lcbio_mksyserr(IOT_ERRNO(io), &syserr);
389
+ notify_error(LCB_CONNECT_ERROR);
390
+ return;
391
+ }
392
+
393
+ GT_CONNECT:
394
+ rv = io->C_connect(sock->u.sd, ai->ai_addr, ai->ai_addrlen, C_conncb);
395
+ if (rv == 0) {
396
+ lcbio_ref(sock);
397
+ return;
398
+ }
399
+
400
+ lcbio_mksyserr(io->get_errno(), &syserr);
401
+ status = lcbio_mkcserr(io->get_errno());
402
+ switch (status) {
403
+
404
+ case LCBIO_CSERR_INTR:
405
+ goto GT_CONNECT;
406
+
407
+ case LCBIO_CSERR_CONNECTED:
408
+ notify_success();
409
+ return;
410
+
411
+ case LCBIO_CSERR_BUSY:
412
+ return;
413
+
414
+ case LCBIO_CSERR_EINVAL:
415
+ if (!retry_once) {
416
+ retry_once = 1;
417
+ goto GT_CONNECT;
418
+ }
419
+ /* fallthrough */
420
+
421
+ case LCBIO_CSERR_EFAIL:
422
+ default:
423
+ clear_sock();
424
+ goto GT_NEXTSOCK;
425
+ }
426
+ }
427
+
428
+ ConnectionRequest *
429
+ lcbio_connect(lcbio_TABLE *iot, lcb_settings *settings, const lcb_host_t *dest,
430
+ uint32_t timeout, lcbio_CONNDONE_cb handler, void *arg)
431
+ {
432
+ return new Connstart(iot, settings, dest, timeout, handler, arg);
433
+ }
434
+
435
+ Connstart::Connstart(lcbio_TABLE* iot_, lcb_settings* settings_,
436
+ const lcb_host_t *dest, uint32_t timeout,
437
+ lcbio_CONNDONE_cb handler, void *arg)
438
+ : user_handler(handler), user_arg(arg), sock(NULL), syserr(0),
439
+ event(NULL), ev_active(false), in_uhandler(false),
440
+ ai_root(NULL), ai(NULL), state(CS_PENDING), last_error(LCB_SUCCESS),
441
+ timer(iot_, this) {
442
+
443
+ addrinfo hints;
444
+ int rv;
445
+
446
+ sock = reinterpret_cast<lcbio_SOCKET*>(calloc(1, sizeof(*sock)));
447
+
448
+ /** Initialize the socket first */
449
+ sock->io = iot_;
450
+ sock->settings = settings_;
451
+ sock->ctx = this;
452
+ sock->refcount = 1;
453
+ sock->info = reinterpret_cast<lcbio_CONNINFO*>(calloc(1, sizeof(*sock->info)));
454
+ sock->info->ep = *dest;
455
+ lcbio_table_ref(sock->io);
456
+ lcb_settings_ref(sock->settings);
457
+ lcb_list_init(&sock->protos);
458
+
459
+ if (iot_->is_E()) {
460
+ sock->u.fd = INVALID_SOCKET;
461
+ event = iot_->E_event_create();
462
+ }
463
+
464
+ timer.rearm(timeout);
465
+ lcb_log(LOGARGS_T(INFO), CSLOGFMT "Starting. Timeout=%uus", CSLOGID_T(), timeout);
466
+
467
+ /** Hostname lookup: */
468
+ memset(&hints, 0, sizeof(hints));
469
+ hints.ai_flags = AI_PASSIVE;
470
+ hints.ai_socktype = SOCK_STREAM;
471
+ if (settings_->ipv6 == LCB_IPV6_DISABLED) {
472
+ hints.ai_family = AF_INET;
473
+ } else if (settings_->ipv6 == LCB_IPV6_ONLY) {
474
+ hints.ai_family = AF_INET6;
475
+ } else {
476
+ hints.ai_family = AF_UNSPEC;
477
+ }
478
+
479
+ if ((rv = getaddrinfo(dest->host, dest->port, &hints, &ai_root))) {
480
+ const char *errstr = rv != EAI_SYSTEM ? gai_strerror(rv) : "";
481
+ lcb_log(LOGARGS_T(ERR), CSLOGFMT "Couldn't look up %s (%s) [EAI=%d]", CSLOGID_T(), dest->host, errstr, rv);
482
+ notify_error(LCB_UNKNOWN_HOST);
483
+ } else {
484
+ ai = ai_root;
485
+
486
+ /** Figure out how to connect */
487
+ if (iot_->is_E()) {
488
+ E_conncb(-1, LCB_WRITE_EVENT, this);
489
+ } else {
490
+ C_connect();
491
+ }
492
+ }
493
+ }
494
+
495
+ ConnectionRequest *
496
+ lcbio_connect_hl(lcbio_TABLE *iot, lcb_settings *settings,
497
+ lcb::Hostlist* hl, int rollover, uint32_t timeout,
498
+ lcbio_CONNDONE_cb handler, void *arg)
499
+ {
500
+ const lcb_host_t *cur;
501
+ unsigned ii = 0, hlmax = hl->size();
502
+
503
+ while ( (cur = hl->next(rollover)) && ii++ < hlmax) {
504
+ ConnectionRequest *ret = lcbio_connect(
505
+ iot, settings, cur, timeout, handler, arg);
506
+ if (ret) {
507
+ return ret;
508
+ }
509
+ }
510
+
511
+ return NULL;
512
+ }
513
+
514
+ lcbio_SOCKET *
515
+ lcbio_wrap_fd(lcbio_pTABLE iot, lcb_settings *settings, lcb_socket_t fd)
516
+ {
517
+ lcbio_SOCKET *ret = reinterpret_cast<lcbio_SOCKET*>(calloc(1, sizeof(*ret)));
518
+ lcbio_CONNDONE_cb *ci = reinterpret_cast<lcbio_CONNDONE_cb*>(calloc(1, sizeof(*ci)));
519
+
520
+ if (ret == NULL || ci == NULL) {
521
+ free(ret);
522
+ free(ci);
523
+ return NULL;
524
+ }
525
+
526
+ assert(iot->model = LCB_IOMODEL_EVENT);
527
+
528
+ lcb_list_init(&ret->protos);
529
+ ret->settings = settings;
530
+ ret->io = iot;
531
+ ret->refcount = 1;
532
+ ret->u.fd = fd;
533
+
534
+ lcbio_table_ref(ret->io);
535
+ lcb_settings_ref(ret->settings);
536
+ lcbio__load_socknames(ret);
537
+ return ret;
538
+ }
539
+
540
+ void
541
+ lcbio_shutdown(lcbio_SOCKET *s)
542
+ {
543
+ lcbio_TABLE *io = s->io;
544
+
545
+ lcbio__protoctx_delall(s);
546
+ if (IOT_IS_EVENT(io)) {
547
+ if (s->u.fd != INVALID_SOCKET) {
548
+ io->E_close(s->u.fd);
549
+ s->u.fd = INVALID_SOCKET;
550
+ }
551
+ } else {
552
+ if (s->u.sd) {
553
+ io->C_close(s->u.sd);
554
+ s->u.sd = NULL;
555
+ }
556
+ }
557
+ }
558
+
559
+ void
560
+ lcbio__destroy(lcbio_SOCKET *s)
561
+ {
562
+ lcbio_shutdown(s);
563
+ if (s->info) {
564
+ free(s->info);
565
+ }
566
+ lcbio_table_unref(s->io);
567
+ lcb_settings_unref(s->settings);
568
+ free(s);
569
+ }