libcouchbase 0.3.3 → 1.0.0

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