libcouchbase 0.0.7 → 0.0.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/ext/libcouchbase/.gitignore +2 -0
- data/ext/libcouchbase/CMakeLists.txt +5 -7
- data/ext/libcouchbase/README.markdown +2 -2
- data/ext/libcouchbase/RELEASE_NOTES.markdown +49 -0
- data/ext/libcouchbase/cmake/Modules/ConfigureDtrace.cmake +11 -0
- data/ext/libcouchbase/cmake/Modules/GenerateConfigDotH.cmake +2 -0
- data/ext/libcouchbase/cmake/Modules/GetLibcouchbaseFlags.cmake +2 -1
- data/ext/libcouchbase/cmake/Modules/GetVersionInfo.cmake +3 -3
- data/ext/libcouchbase/cmake/config-cmake.h.in +2 -0
- data/ext/libcouchbase/cmake/defs.mk.in +0 -2
- data/ext/libcouchbase/cmake/source_files.cmake +34 -14
- data/ext/libcouchbase/configure.pl +1 -1
- data/ext/libcouchbase/contrib/genhash/genhash.h +6 -0
- data/ext/libcouchbase/include/libcouchbase/auth.h +10 -0
- data/ext/libcouchbase/include/libcouchbase/couchbase.h +10 -0
- data/ext/libcouchbase/include/libcouchbase/error.h +7 -0
- data/ext/libcouchbase/include/libcouchbase/n1ql.h +13 -1
- data/ext/libcouchbase/include/libcouchbase/plugins/io/bsdio-inl.c +1 -1
- data/ext/libcouchbase/include/libcouchbase/subdoc.h +9 -0
- data/ext/libcouchbase/include/libcouchbase/views.h +7 -1
- data/ext/libcouchbase/include/libcouchbase/visibility.h +1 -0
- data/ext/libcouchbase/include/memcached/protocol_binary.h +21 -1132
- data/ext/libcouchbase/packaging/parse-git-describe.pl +1 -1
- data/ext/libcouchbase/plugins/io/libev/libev_io_opts.h +3 -2
- data/ext/libcouchbase/src/README.md +0 -2
- data/ext/libcouchbase/src/auth-priv.h +1 -0
- data/ext/libcouchbase/src/auth.cc +10 -0
- data/ext/libcouchbase/src/bootstrap.cc +216 -0
- data/ext/libcouchbase/src/bootstrap.h +50 -39
- data/ext/libcouchbase/src/bucketconfig/bc_cccp.cc +455 -0
- data/ext/libcouchbase/src/bucketconfig/bc_file.cc +281 -0
- data/ext/libcouchbase/src/bucketconfig/bc_http.cc +528 -0
- data/ext/libcouchbase/src/bucketconfig/bc_http.h +50 -25
- data/ext/libcouchbase/src/bucketconfig/bc_mcraw.cc +115 -0
- data/ext/libcouchbase/src/bucketconfig/clconfig.h +407 -386
- data/ext/libcouchbase/src/bucketconfig/confmon.cc +378 -0
- data/ext/libcouchbase/src/cbft.cc +22 -27
- data/ext/libcouchbase/src/cntl.cc +24 -24
- data/ext/libcouchbase/src/connspec.cc +30 -1
- data/ext/libcouchbase/src/connspec.h +17 -0
- data/ext/libcouchbase/src/dns-srv.cc +143 -0
- data/ext/libcouchbase/src/{dump.c → dump.cc} +8 -11
- data/ext/libcouchbase/src/getconfig.cc +73 -0
- data/ext/libcouchbase/src/handler.cc +84 -85
- data/ext/libcouchbase/src/hostlist.cc +0 -1
- data/ext/libcouchbase/src/hostlist.h +6 -1
- data/ext/libcouchbase/src/http/http-priv.h +125 -112
- data/ext/libcouchbase/src/http/http.cc +9 -29
- data/ext/libcouchbase/src/http/http.h +1 -34
- data/ext/libcouchbase/src/http/http_io.cc +22 -26
- data/ext/libcouchbase/src/instance.cc +102 -28
- data/ext/libcouchbase/src/internal.h +47 -29
- data/ext/libcouchbase/src/jsparse/parser.cc +146 -202
- data/ext/libcouchbase/src/jsparse/parser.h +91 -98
- data/ext/libcouchbase/src/lcbht/lcbht.cc +177 -0
- data/ext/libcouchbase/src/lcbht/lcbht.h +174 -163
- data/ext/libcouchbase/src/lcbio/connect.cc +562 -0
- data/ext/libcouchbase/src/lcbio/connect.h +9 -2
- data/ext/libcouchbase/src/lcbio/ctx.c +1 -1
- data/ext/libcouchbase/src/lcbio/iotable.h +61 -16
- data/ext/libcouchbase/src/lcbio/ioutils.h +1 -1
- data/ext/libcouchbase/src/lcbio/manager.c +2 -2
- data/ext/libcouchbase/src/lcbio/timer-cxx.h +87 -0
- data/ext/libcouchbase/src/mc/mcreq.h +9 -2
- data/ext/libcouchbase/src/mcserver/mcserver.cc +723 -0
- data/ext/libcouchbase/src/mcserver/mcserver.h +160 -70
- data/ext/libcouchbase/src/mcserver/negotiate.cc +118 -152
- data/ext/libcouchbase/src/mcserver/negotiate.h +85 -74
- data/ext/libcouchbase/src/mctx-helper.h +51 -0
- data/ext/libcouchbase/src/n1ql/ixmgmt.cc +1 -2
- data/ext/libcouchbase/src/n1ql/n1ql.cc +56 -32
- data/ext/libcouchbase/src/{newconfig.c → newconfig.cc} +42 -70
- data/ext/libcouchbase/src/nodeinfo.cc +4 -8
- data/ext/libcouchbase/src/operations/{cbflush.c → cbflush.cc} +7 -15
- data/ext/libcouchbase/src/operations/{counter.c → counter.cc} +0 -0
- data/ext/libcouchbase/src/operations/{durability-cas.c → durability-cas.cc} +92 -76
- data/ext/libcouchbase/src/operations/{durability-seqno.c → durability-seqno.cc} +55 -49
- data/ext/libcouchbase/src/operations/durability.cc +643 -0
- data/ext/libcouchbase/src/operations/durability_internal.h +212 -124
- data/ext/libcouchbase/src/operations/{get.c → get.cc} +24 -26
- data/ext/libcouchbase/src/operations/{observe-seqno.c → observe-seqno.cc} +5 -8
- data/ext/libcouchbase/src/operations/{observe.c → observe.cc} +69 -94
- data/ext/libcouchbase/src/operations/{pktfwd.c → pktfwd.cc} +0 -0
- data/ext/libcouchbase/src/operations/{remove.c → remove.cc} +0 -0
- data/ext/libcouchbase/src/operations/{stats.c → stats.cc} +66 -78
- data/ext/libcouchbase/src/operations/{store.c → store.cc} +27 -32
- data/ext/libcouchbase/src/operations/subdoc.cc +38 -18
- data/ext/libcouchbase/src/operations/{touch.c → touch.cc} +0 -0
- data/ext/libcouchbase/src/packetutils.h +200 -137
- data/ext/libcouchbase/src/probes.d +1 -1
- data/ext/libcouchbase/src/{retrychk.c → retrychk.cc} +3 -4
- data/ext/libcouchbase/src/retryq.cc +394 -0
- data/ext/libcouchbase/src/retryq.h +116 -104
- data/ext/libcouchbase/src/settings.h +2 -1
- data/ext/libcouchbase/src/ssl/ssl_c.c +1 -0
- data/ext/libcouchbase/src/ssl/ssl_e.c +0 -1
- data/ext/libcouchbase/src/trace.h +8 -8
- data/ext/libcouchbase/src/vbucket/vbucket.c +0 -1
- data/ext/libcouchbase/src/views/{docreq.c → docreq.cc} +48 -54
- data/ext/libcouchbase/src/views/docreq.h +24 -30
- data/ext/libcouchbase/src/views/viewreq.cc +318 -0
- data/ext/libcouchbase/src/views/viewreq.h +43 -13
- data/ext/libcouchbase/src/{wait.c → wait.cc} +12 -17
- data/ext/libcouchbase/tests/basic/t_connstr.cc +89 -50
- data/ext/libcouchbase/tests/basic/t_jsparse.cc +27 -78
- data/ext/libcouchbase/tests/basic/t_packet.cc +35 -42
- data/ext/libcouchbase/tests/htparse/t_basic.cc +58 -78
- data/ext/libcouchbase/tests/iotests/t_confmon.cc +94 -111
- data/ext/libcouchbase/tests/iotests/t_sched.cc +1 -2
- data/ext/libcouchbase/tests/mc/t_alloc.cc +9 -9
- data/ext/libcouchbase/tools/cbc-pillowfight.cc +1 -1
- data/lib/libcouchbase/version.rb +1 -1
- metadata +36 -39
- data/ext/libcouchbase/include/memcached/vbucket.h +0 -42
- data/ext/libcouchbase/src/bootstrap.c +0 -269
- data/ext/libcouchbase/src/bucketconfig/bc_cccp.c +0 -495
- data/ext/libcouchbase/src/bucketconfig/bc_file.c +0 -347
- data/ext/libcouchbase/src/bucketconfig/bc_http.c +0 -630
- data/ext/libcouchbase/src/bucketconfig/bc_mcraw.c +0 -150
- data/ext/libcouchbase/src/bucketconfig/confmon.c +0 -474
- data/ext/libcouchbase/src/getconfig.c +0 -100
- data/ext/libcouchbase/src/lcbht/lcbht.c +0 -282
- data/ext/libcouchbase/src/lcbio/connect.c +0 -557
- data/ext/libcouchbase/src/mcserver/mcserver.c +0 -784
- data/ext/libcouchbase/src/operations/durability.c +0 -668
- data/ext/libcouchbase/src/packetutils.c +0 -60
- data/ext/libcouchbase/src/retryq.c +0 -424
- data/ext/libcouchbase/src/simplestring.c +0 -211
- data/ext/libcouchbase/src/simplestring.h +0 -228
- data/ext/libcouchbase/src/ssobuf.h +0 -82
- data/ext/libcouchbase/src/views/viewreq.c +0 -358
- data/ext/libcouchbase/tests/basic/t_string.cc +0 -112
@@ -24,98 +24,188 @@
|
|
24
24
|
#include <netbuf/netbuf.h>
|
25
25
|
|
26
26
|
#ifdef __cplusplus
|
27
|
-
|
28
|
-
#endif
|
27
|
+
namespace lcb {
|
29
28
|
|
30
|
-
|
31
|
-
struct
|
29
|
+
class RetryQueue;
|
30
|
+
struct RetryOp;
|
32
31
|
|
33
32
|
/**
|
34
33
|
* The structure representing each couchbase server
|
35
34
|
*/
|
36
|
-
|
37
|
-
|
38
|
-
|
35
|
+
class Server : public mc_PIPELINE {
|
36
|
+
public:
|
37
|
+
/**
|
38
|
+
* Allocate and initialize a new server object. The object will not be
|
39
|
+
* connected
|
40
|
+
* @param instance the instance to which the server belongs
|
41
|
+
* @param ix the server index in the configuration
|
42
|
+
*/
|
43
|
+
Server(lcb_t, int);
|
44
|
+
|
45
|
+
/**
|
46
|
+
* Close the server. The resources of the server may still continue to persist
|
47
|
+
* internally for a bit until all callbacks have been delivered and all buffers
|
48
|
+
* flushed and/or failed.
|
49
|
+
*/
|
50
|
+
void close();
|
51
|
+
|
52
|
+
/**
|
53
|
+
* Schedule a flush and potentially flush some immediate data on the server.
|
54
|
+
* This is safe to call multiple times, however performance considerations
|
55
|
+
* should be taken into account
|
56
|
+
*/
|
57
|
+
void flush();
|
58
|
+
|
59
|
+
/**
|
60
|
+
* Wrapper around mcreq_pipeline_timeout() and/or mcreq_pipeline_fail(). This
|
61
|
+
* function will purge all pending requests within the server and invoke
|
62
|
+
* their callbacks with the given error code passed as `err`. Depending on
|
63
|
+
* the error code, some operations may be retried.
|
64
|
+
*
|
65
|
+
* @param err the error code by which to fail the commands
|
66
|
+
*
|
67
|
+
* @note This function does not modify the server's socket or state in itself,
|
68
|
+
* but rather simply wipes the commands from its queue
|
69
|
+
*/
|
70
|
+
void purge(lcb_error_t err) {
|
71
|
+
purge(err, 0, NULL, Server::REFRESH_NEVER);
|
72
|
+
}
|
73
|
+
|
74
|
+
/** Callback for mc_pipeline_fail_chain */
|
75
|
+
inline void purge_single(mc_PACKET*, lcb_error_t);
|
76
|
+
|
77
|
+
/**
|
78
|
+
* Returns true or false depending on whether there are pending commands on
|
79
|
+
* this server
|
80
|
+
*/
|
81
|
+
bool has_pending() const {
|
82
|
+
return !SLLIST_IS_EMPTY(&requests);
|
83
|
+
}
|
84
|
+
|
85
|
+
int get_index() const {
|
86
|
+
return mc_PIPELINE::index;
|
87
|
+
}
|
88
|
+
|
89
|
+
lcb_t get_instance() const {
|
90
|
+
return instance;
|
91
|
+
}
|
92
|
+
|
93
|
+
const lcb_settings* get_settings() const {
|
94
|
+
return settings;
|
95
|
+
}
|
96
|
+
|
97
|
+
void set_new_index(int new_index) {
|
98
|
+
mc_PIPELINE::index = new_index;
|
99
|
+
}
|
100
|
+
|
101
|
+
const lcb_host_t& get_host() const {
|
102
|
+
return *curhost;
|
103
|
+
}
|
104
|
+
|
105
|
+
bool supports_mutation_tokens() const {
|
106
|
+
return mutation_tokens;
|
107
|
+
}
|
108
|
+
|
109
|
+
bool supports_compression() const {
|
110
|
+
return compsupport;
|
111
|
+
}
|
112
|
+
|
113
|
+
bool is_connected() const {
|
114
|
+
return connctx != NULL;
|
115
|
+
}
|
116
|
+
|
117
|
+
/** "Temporary" constructor. Only for use in retry queue */
|
118
|
+
Server();
|
119
|
+
~Server();
|
120
|
+
|
121
|
+
enum State {
|
122
|
+
/* There are no known errored commands on this server */
|
123
|
+
S_CLEAN,
|
124
|
+
|
125
|
+
/* In the process of draining remaining commands to be flushed. The commands
|
126
|
+
* being drained may have already been rescheduled to another server or
|
127
|
+
* placed inside the error queue, but are pending being flushed. This will
|
128
|
+
* only happen in completion-style I/O plugins. When this state is in effect,
|
129
|
+
* subsequent attempts to connect will be blocked until all commands have
|
130
|
+
* been properly drained.
|
131
|
+
*/
|
132
|
+
S_ERRDRAIN,
|
133
|
+
|
134
|
+
/* The server object has been closed, either because it has been removed
|
135
|
+
* from the cluster or because the related lcb_t has been destroyed.
|
136
|
+
*/
|
137
|
+
S_CLOSED,
|
138
|
+
|
139
|
+
/*
|
140
|
+
* Server has been temporarily constructed.
|
141
|
+
*/
|
142
|
+
S_TEMPORARY
|
143
|
+
};
|
144
|
+
|
145
|
+
static Server* get(lcbio_CTX *ctx) {
|
146
|
+
return reinterpret_cast<Server*>(lcbio_ctx_data(ctx));
|
147
|
+
}
|
148
|
+
|
149
|
+
uint32_t default_timeout() const {
|
150
|
+
return settings->operation_timeout;
|
151
|
+
}
|
152
|
+
|
153
|
+
uint32_t next_timeout() const;
|
154
|
+
|
155
|
+
bool check_closed();
|
156
|
+
void start_errored_ctx(State next_state);
|
157
|
+
void finalize_errored_ctx();
|
158
|
+
void socket_failed(lcb_error_t);
|
159
|
+
void io_timeout();
|
160
|
+
|
161
|
+
enum RefreshPolicy {
|
162
|
+
REFRESH_ALWAYS,
|
163
|
+
REFRESH_ONFAILED,
|
164
|
+
REFRESH_NEVER
|
165
|
+
};
|
166
|
+
|
167
|
+
int purge(lcb_error_t error, hrtime_t thresh, hrtime_t *next,
|
168
|
+
RefreshPolicy policy);
|
169
|
+
|
170
|
+
void connect();
|
171
|
+
|
172
|
+
void handle_connected(lcbio_SOCKET *socket, lcb_error_t err, lcbio_OSERR syserr);
|
173
|
+
|
174
|
+
enum ReadState {
|
175
|
+
PKT_READ_COMPLETE,
|
176
|
+
PKT_READ_PARTIAL
|
177
|
+
};
|
178
|
+
|
179
|
+
ReadState try_read(lcbio_CTX *ctx, rdb_IOROPE *ior);
|
180
|
+
bool handle_nmv(MemcachedResponse& resinfo, mc_PACKET *oldpkt);
|
181
|
+
bool maybe_retry_packet(mc_PACKET *pkt, lcb_error_t err);
|
182
|
+
bool maybe_reconnect_on_fake_timeout(lcb_error_t received_error);
|
183
|
+
|
184
|
+
/** Disable */
|
185
|
+
Server(const Server&);
|
186
|
+
|
187
|
+
State state;
|
188
|
+
|
189
|
+
/** IO/Operation timer */
|
190
|
+
lcbio_pTIMER io_timer;
|
39
191
|
|
40
192
|
/** Pointer back to the instance */
|
41
193
|
lcb_t instance;
|
42
194
|
|
43
195
|
lcb_settings *settings;
|
44
196
|
|
45
|
-
/* Defined in mcserver.c */
|
46
|
-
int state;
|
47
|
-
|
48
197
|
/** Whether compression is supported */
|
49
198
|
short compsupport;
|
50
199
|
|
51
200
|
/** Whether extended 'UUID' and 'seqno' are available for each mutation */
|
52
201
|
short mutation_tokens;
|
53
202
|
|
54
|
-
/** IO/Operation timer */
|
55
|
-
lcbio_pTIMER io_timer;
|
56
|
-
|
57
203
|
lcbio_CTX *connctx;
|
58
204
|
lcbio_CONNREQ connreq;
|
59
205
|
|
60
206
|
/** Request for current connection */
|
61
207
|
lcb_host_t *curhost;
|
62
|
-
}
|
63
|
-
|
64
|
-
#define MCSERVER_TIMEOUT(c) (c)->settings->operation_timeout
|
65
|
-
|
66
|
-
/**
|
67
|
-
* Allocate and initialize a new server object. The object will not be
|
68
|
-
* connected
|
69
|
-
* @param instance the instance to which the server belongs
|
70
|
-
* @param ix the server index in the configuration
|
71
|
-
* @return the new object or NULL on allocation failure.
|
72
|
-
*/
|
73
|
-
mc_SERVER *
|
74
|
-
mcserver_alloc(lcb_t instance, int ix);
|
75
|
-
|
76
|
-
/**
|
77
|
-
* Close the server. The resources of the server may still continue to persist
|
78
|
-
* internally for a bit until all callbacks have been delivered and all buffers
|
79
|
-
* flushed and/or failed.
|
80
|
-
* @param server the server to release
|
81
|
-
*/
|
82
|
-
void
|
83
|
-
mcserver_close(mc_SERVER *server);
|
84
|
-
|
85
|
-
/**
|
86
|
-
* Schedule a flush and potentially flush some immediate data on the server.
|
87
|
-
* This is safe to call multiple times, however performance considerations
|
88
|
-
* should be taken into account
|
89
|
-
*/
|
90
|
-
void
|
91
|
-
mcserver_flush(mc_SERVER *server);
|
92
|
-
|
93
|
-
/**
|
94
|
-
* Wrapper around mcreq_pipeline_timeout() and/or mcreq_pipeline_fail(). This
|
95
|
-
* function will purge all pending requests within the server and invoke
|
96
|
-
* their callbacks with the given error code passed as `err`. Depending on
|
97
|
-
* the error code, some operations may be retried.
|
98
|
-
* @param server the server to fail
|
99
|
-
* @param err the error code by which to fail the commands
|
100
|
-
*
|
101
|
-
* @note This function does not modify the server's socket or state in itself,
|
102
|
-
* but rather simply wipes the commands from its queue
|
103
|
-
*/
|
104
|
-
void
|
105
|
-
mcserver_fail_chain(mc_SERVER *server, lcb_error_t err);
|
106
|
-
|
107
|
-
/**
|
108
|
-
* Returns true or false depending on whether there are pending commands on
|
109
|
-
* this server
|
110
|
-
*/
|
111
|
-
LCB_INTERNAL_API
|
112
|
-
int
|
113
|
-
mcserver_has_pending(mc_SERVER *server);
|
114
|
-
|
115
|
-
#define mcserver_get_host(server) (server)->curhost->host
|
116
|
-
#define mcserver_get_port(server) (server)->curhost->port
|
117
|
-
|
118
|
-
#ifdef __cplusplus
|
208
|
+
};
|
119
209
|
}
|
120
210
|
#endif /* __cplusplus */
|
121
211
|
#endif /* LCB_MCSERVER_H */
|
@@ -15,6 +15,7 @@
|
|
15
15
|
* limitations under the License.
|
16
16
|
*/
|
17
17
|
|
18
|
+
#include <algorithm>
|
18
19
|
#include "packetutils.h"
|
19
20
|
#include "mcserver.h"
|
20
21
|
#include "logging.h"
|
@@ -26,47 +27,13 @@
|
|
26
27
|
#include "negotiate.h"
|
27
28
|
#include "ctx-log-inl.h"
|
28
29
|
|
29
|
-
|
30
|
-
#include <sstream>
|
31
|
-
#include <vector>
|
30
|
+
using namespace lcb;
|
32
31
|
|
33
|
-
#define LOGARGS(ctx, lvl) ctx->
|
34
|
-
static void cleanup_negotiated(
|
32
|
+
#define LOGARGS(ctx, lvl) ctx->settings, "negotiation", LCB_LOG_##lvl, __FILE__, __LINE__
|
33
|
+
static void cleanup_negotiated(SessionInfo* info);
|
35
34
|
static void handle_ioerr(lcbio_CTX *ctx, lcb_error_t err);
|
36
|
-
static void handle_read(lcbio_CTX *ioctx, unsigned);
|
37
35
|
#define SESSREQ_LOGFMT "<%s:%s> (SASLREQ=%p) "
|
38
36
|
|
39
|
-
/**
|
40
|
-
* Inner negotiation structure which is maintained as part of a 'protocol
|
41
|
-
* context'.
|
42
|
-
*/
|
43
|
-
struct mc_SESSINFO : public lcbio_PROTOCTX {
|
44
|
-
union {
|
45
|
-
cbsasl_secret_t secret;
|
46
|
-
char buffer[256];
|
47
|
-
} u_auth;
|
48
|
-
|
49
|
-
static mc_SESSINFO *get(void *arg) {
|
50
|
-
return reinterpret_cast<mc_SESSINFO*>(arg);
|
51
|
-
}
|
52
|
-
|
53
|
-
mc_SESSINFO(lcb_settings *settings_);
|
54
|
-
bool setup(const lcbio_NAMEINFO& nistrs, const lcb_host_t& host,
|
55
|
-
const lcb::Authenticator& auth);
|
56
|
-
|
57
|
-
~mc_SESSINFO() {
|
58
|
-
if (sasl_client != NULL) {
|
59
|
-
cbsasl_dispose(&sasl_client);
|
60
|
-
sasl_client = NULL;
|
61
|
-
}
|
62
|
-
}
|
63
|
-
|
64
|
-
cbsasl_conn_t *sasl_client;
|
65
|
-
std::string mech;
|
66
|
-
std::vector<uint16_t> server_features;
|
67
|
-
lcb_settings *settings;
|
68
|
-
};
|
69
|
-
|
70
37
|
static void timeout_handler(void *arg);
|
71
38
|
|
72
39
|
#define SESSREQ_LOGID(s) get_ctx_host(s->ctx), get_ctx_port(s->ctx), (void*)s
|
@@ -84,28 +51,37 @@ close_cb(lcbio_SOCKET *s, int reusable, void *arg)
|
|
84
51
|
* of the request for negotiation and is deleted once negotiation has
|
85
52
|
* completed (or failed).
|
86
53
|
*/
|
87
|
-
|
88
|
-
|
89
|
-
|
54
|
+
class lcb::SessionRequestImpl : public SessionRequest {
|
55
|
+
public:
|
56
|
+
static SessionRequestImpl *get(void *arg) {
|
57
|
+
return reinterpret_cast<SessionRequestImpl*>(arg);
|
90
58
|
}
|
91
59
|
|
92
|
-
|
60
|
+
bool setup(const lcbio_NAMEINFO& nistrs, const lcb_host_t& host,
|
61
|
+
const lcb::Authenticator& auth);
|
62
|
+
void start(lcbio_SOCKET *sock);
|
93
63
|
bool send_hello();
|
94
64
|
bool send_step(const lcb::MemcachedResponse& packet);
|
95
65
|
bool read_hello(const lcb::MemcachedResponse& packet);
|
66
|
+
void send_auth(const char *sasl_data, unsigned ndata);
|
67
|
+
void handle_read(lcbio_CTX *ioctx);
|
68
|
+
|
69
|
+
enum MechStatus { MECH_UNAVAILABLE, MECH_NOT_NEEDED, MECH_OK };
|
70
|
+
MechStatus set_chosen_mech(std::string& mechlist, const char **data, unsigned int *ndata);
|
96
71
|
|
97
|
-
|
98
|
-
lcbio_TABLE *iot)
|
72
|
+
SessionRequestImpl(lcbio_CONNDONE_cb callback, void *data, uint32_t timeout, lcbio_TABLE *iot, lcb_settings* settings_)
|
99
73
|
: ctx(NULL), cb(callback), cbdata(data),
|
100
74
|
timer(lcbio_timer_new(iot, this, timeout_handler)),
|
101
|
-
last_err(LCB_SUCCESS),
|
75
|
+
last_err(LCB_SUCCESS), info(NULL),
|
76
|
+
settings(settings_) {
|
102
77
|
|
103
78
|
if (timeout) {
|
104
79
|
lcbio_timer_rearm(timer, timeout);
|
105
80
|
}
|
81
|
+
memset(&u_auth, 0, sizeof(u_auth));
|
106
82
|
}
|
107
83
|
|
108
|
-
~
|
84
|
+
virtual ~SessionRequestImpl();
|
109
85
|
|
110
86
|
void cancel() {
|
111
87
|
cb = NULL;
|
@@ -132,8 +108,8 @@ struct mc_SESSREQ {
|
|
132
108
|
lcbio_ctx_close(ctx, close_cb, &s);
|
133
109
|
ctx = NULL;
|
134
110
|
|
135
|
-
lcbio_protoctx_add(s,
|
136
|
-
|
111
|
+
lcbio_protoctx_add(s, info);
|
112
|
+
info = NULL;
|
137
113
|
|
138
114
|
/** Invoke the callback, marking it a success */
|
139
115
|
cb(s, cbdata, LCB_SUCCESS, 0);
|
@@ -153,19 +129,29 @@ struct mc_SESSREQ {
|
|
153
129
|
return last_err != LCB_SUCCESS;
|
154
130
|
}
|
155
131
|
|
132
|
+
union {
|
133
|
+
cbsasl_secret_t secret;
|
134
|
+
char buffer[256];
|
135
|
+
} u_auth;
|
136
|
+
|
156
137
|
lcbio_CTX *ctx;
|
157
138
|
lcbio_CONNDONE_cb cb;
|
158
139
|
void *cbdata;
|
159
140
|
lcbio_pTIMER timer;
|
160
141
|
lcb_error_t last_err;
|
161
|
-
|
142
|
+
cbsasl_conn_t *sasl_client;
|
143
|
+
SessionInfo* info;
|
144
|
+
lcb_settings *settings;
|
162
145
|
};
|
163
146
|
|
147
|
+
static void handle_read(lcbio_CTX *ioctx, unsigned) {
|
148
|
+
SessionRequestImpl::get(lcbio_ctx_data(ioctx))->handle_read(ioctx);
|
149
|
+
}
|
164
150
|
|
165
151
|
static int
|
166
152
|
sasl_get_username(void *context, int id, const char **result, unsigned int *len)
|
167
153
|
{
|
168
|
-
|
154
|
+
SessionRequestImpl *ctx = SessionRequestImpl::get(context);
|
169
155
|
const char *u = NULL, *p = NULL;
|
170
156
|
if (!context || !result || (id != CBSASL_CB_USER && id != CBSASL_CB_AUTHNAME)) {
|
171
157
|
return SASL_BADPARAM;
|
@@ -184,7 +170,7 @@ static int
|
|
184
170
|
sasl_get_password(cbsasl_conn_t *conn, void *context, int id,
|
185
171
|
cbsasl_secret_t **psecret)
|
186
172
|
{
|
187
|
-
|
173
|
+
SessionRequestImpl *ctx = SessionRequestImpl::get(context);
|
188
174
|
if (!conn || ! psecret || id != CBSASL_CB_PASS || ctx == NULL) {
|
189
175
|
return SASL_BADPARAM;
|
190
176
|
}
|
@@ -193,19 +179,14 @@ sasl_get_password(cbsasl_conn_t *conn, void *context, int id,
|
|
193
179
|
return SASL_OK;
|
194
180
|
}
|
195
181
|
|
196
|
-
|
182
|
+
SessionInfo::SessionInfo()
|
197
183
|
{
|
198
|
-
sasl_client = NULL;
|
199
|
-
memset(&u_auth, 0, sizeof(u_auth));
|
200
|
-
|
201
184
|
lcbio_PROTOCTX::id = LCBIO_PROTOCTX_SESSINFO;
|
202
|
-
lcbio_PROTOCTX::dtor = (void (*)(
|
203
|
-
|
204
|
-
settings = settings_;
|
185
|
+
lcbio_PROTOCTX::dtor = (void (*)(lcbio_PROTOCTX *))cleanup_negotiated;
|
205
186
|
}
|
206
187
|
|
207
188
|
bool
|
208
|
-
|
189
|
+
SessionRequestImpl::setup(const lcbio_NAMEINFO& nistrs, const lcb_host_t& host,
|
209
190
|
const lcb::Authenticator& auth)
|
210
191
|
{
|
211
192
|
cbsasl_callback_t sasl_callbacks[4];
|
@@ -251,7 +232,7 @@ mc_SESSINFO::setup(const lcbio_NAMEINFO& nistrs, const lcb_host_t& host,
|
|
251
232
|
static void
|
252
233
|
timeout_handler(void *arg)
|
253
234
|
{
|
254
|
-
|
235
|
+
SessionRequestImpl *sreq = SessionRequestImpl::get(arg);
|
255
236
|
sreq->fail(LCB_ETIMEDOUT, "Negotiation timed out");
|
256
237
|
}
|
257
238
|
|
@@ -260,66 +241,62 @@ timeout_handler(void *arg)
|
|
260
241
|
* @return 0 to continue authentication, 1 if no authentication needed, or
|
261
242
|
* -1 on error.
|
262
243
|
*/
|
263
|
-
|
264
|
-
set_chosen_mech(
|
244
|
+
SessionRequestImpl::MechStatus
|
245
|
+
SessionRequestImpl::set_chosen_mech(std::string& mechlist,
|
265
246
|
const char **data, unsigned int *ndata)
|
266
247
|
{
|
267
248
|
cbsasl_error_t saslerr;
|
268
|
-
|
269
|
-
|
270
|
-
if (ctx->settings->sasl_mech_force) {
|
271
|
-
char *forcemech = ctx->settings->sasl_mech_force;
|
249
|
+
if (settings->sasl_mech_force) {
|
250
|
+
char *forcemech = settings->sasl_mech_force;
|
272
251
|
if (mechlist.find(forcemech) == std::string::npos) {
|
273
252
|
/** Requested mechanism not found */
|
274
|
-
|
275
|
-
return
|
253
|
+
set_error(LCB_SASLMECH_UNAVAILABLE, mechlist.c_str());
|
254
|
+
return MECH_UNAVAILABLE;
|
276
255
|
}
|
277
256
|
mechlist.assign(forcemech);
|
278
257
|
}
|
279
258
|
|
280
259
|
const char *chosenmech;
|
281
|
-
saslerr = cbsasl_client_start(
|
260
|
+
saslerr = cbsasl_client_start(sasl_client, mechlist.c_str(),
|
282
261
|
NULL, data, ndata, &chosenmech);
|
283
262
|
switch (saslerr) {
|
284
263
|
case SASL_OK:
|
285
|
-
|
286
|
-
return
|
264
|
+
info->mech.assign(chosenmech);
|
265
|
+
return MECH_OK;
|
287
266
|
case SASL_NOMECH:
|
288
|
-
lcb_log(LOGARGS(
|
289
|
-
return
|
267
|
+
lcb_log(LOGARGS(this, INFO), SESSREQ_LOGFMT "Server does not support SASL (no mechanisms supported)", SESSREQ_LOGID(this));
|
268
|
+
return MECH_NOT_NEEDED;
|
290
269
|
break;
|
291
270
|
default:
|
292
|
-
lcb_log(LOGARGS(
|
293
|
-
|
294
|
-
return
|
271
|
+
lcb_log(LOGARGS(this, INFO), SESSREQ_LOGFMT "cbsasl_client_start returned %d", SESSREQ_LOGID(this), saslerr);
|
272
|
+
set_error(LCB_EINTERNAL, "Couldn't start SASL client");
|
273
|
+
return MECH_UNAVAILABLE;
|
295
274
|
}
|
296
275
|
}
|
297
276
|
|
298
277
|
/**
|
299
278
|
* Given the specific mechanisms, send the auth packet to the server.
|
300
279
|
*/
|
301
|
-
|
302
|
-
|
280
|
+
void
|
281
|
+
SessionRequestImpl::send_auth(const char *sasl_data, unsigned ndata)
|
303
282
|
{
|
304
|
-
mc_pSESSINFO ctx = pend->sasl;
|
305
283
|
lcb::MemcachedRequest hdr(PROTOCOL_BINARY_CMD_SASL_AUTH);
|
306
|
-
hdr.sizes(0,
|
284
|
+
hdr.sizes(0, info->mech.size(), ndata);
|
307
285
|
|
308
|
-
lcbio_ctx_put(
|
309
|
-
lcbio_ctx_put(
|
310
|
-
lcbio_ctx_put(
|
311
|
-
lcbio_ctx_rwant(
|
312
|
-
return 0;
|
286
|
+
lcbio_ctx_put(ctx, hdr.data(), hdr.size());
|
287
|
+
lcbio_ctx_put(ctx, info->mech.c_str(), info->mech.size());
|
288
|
+
lcbio_ctx_put(ctx, sasl_data, ndata);
|
289
|
+
lcbio_ctx_rwant(ctx, 24);
|
313
290
|
}
|
314
291
|
|
315
292
|
bool
|
316
|
-
|
293
|
+
SessionRequestImpl::send_step(const lcb::MemcachedResponse& packet)
|
317
294
|
{
|
318
295
|
cbsasl_error_t saslerr;
|
319
296
|
const char *step_data;
|
320
297
|
unsigned int ndata;
|
321
298
|
|
322
|
-
saslerr = cbsasl_client_step(
|
299
|
+
saslerr = cbsasl_client_step(sasl_client,
|
323
300
|
packet.body<const char*>(), packet.bodylen(), NULL, &step_data, &ndata);
|
324
301
|
|
325
302
|
if (saslerr != SASL_CONTINUE) {
|
@@ -328,9 +305,9 @@ mc_SESSREQ::send_step(const lcb::MemcachedResponse& packet)
|
|
328
305
|
}
|
329
306
|
|
330
307
|
lcb::MemcachedRequest hdr(PROTOCOL_BINARY_CMD_SASL_STEP);
|
331
|
-
hdr.sizes(0,
|
308
|
+
hdr.sizes(0, info->mech.size(), ndata);
|
332
309
|
lcbio_ctx_put(ctx, hdr.data(), hdr.size());
|
333
|
-
lcbio_ctx_put(ctx,
|
310
|
+
lcbio_ctx_put(ctx, info->mech.c_str(), info->mech.size());
|
334
311
|
lcbio_ctx_put(ctx, step_data, ndata);
|
335
312
|
lcbio_ctx_rwant(ctx, 24);
|
336
313
|
return true;
|
@@ -340,13 +317,13 @@ mc_SESSREQ::send_step(const lcb::MemcachedResponse& packet)
|
|
340
317
|
#define LCB_HELLO_DEFL_LENGTH (sizeof(LCB_HELLO_DEFL_STRING)-1)
|
341
318
|
|
342
319
|
bool
|
343
|
-
|
320
|
+
SessionRequestImpl::send_hello()
|
344
321
|
{
|
345
|
-
const lcb_settings *settings = sasl->settings;
|
346
322
|
lcb_U16 features[MEMCACHED_TOTAL_HELLO_FEATURES];
|
347
323
|
|
348
324
|
unsigned nfeatures = 0;
|
349
325
|
features[nfeatures++] = PROTOCOL_BINARY_FEATURE_TLS;
|
326
|
+
features[nfeatures++] = PROTOCOL_BINARY_FEATURE_XATTR;
|
350
327
|
if (settings->tcp_nodelay) {
|
351
328
|
features[nfeatures++] = PROTOCOL_BINARY_FEATURE_TCPNODELAY;
|
352
329
|
}
|
@@ -388,7 +365,7 @@ mc_SESSREQ::send_hello()
|
|
388
365
|
}
|
389
366
|
|
390
367
|
bool
|
391
|
-
|
368
|
+
SessionRequestImpl::read_hello(const lcb::MemcachedResponse& resp)
|
392
369
|
{
|
393
370
|
/* some caps */
|
394
371
|
const char *cur;
|
@@ -398,8 +375,8 @@ mc_SESSREQ::read_hello(const lcb::MemcachedResponse& resp)
|
|
398
375
|
lcb_U16 tmp;
|
399
376
|
memcpy(&tmp, cur, sizeof(tmp));
|
400
377
|
tmp = ntohs(tmp);
|
401
|
-
lcb_log(LOGARGS(this, DEBUG), SESSREQ_LOGFMT "
|
402
|
-
|
378
|
+
lcb_log(LOGARGS(this, DEBUG), SESSREQ_LOGFMT "Server supports feature: 0x%x (%s)", SESSREQ_LOGID(this), tmp, protocol_feature_2_text(tmp));
|
379
|
+
info->server_features.push_back(tmp);
|
403
380
|
}
|
404
381
|
return true;
|
405
382
|
}
|
@@ -415,10 +392,9 @@ typedef enum {
|
|
415
392
|
* It's assumed the server buffers will be reset upon close(), so we must make
|
416
393
|
* sure to _not_ release the ringbuffer if that happens.
|
417
394
|
*/
|
418
|
-
|
419
|
-
handle_read(lcbio_CTX *ioctx
|
395
|
+
void
|
396
|
+
SessionRequestImpl::handle_read(lcbio_CTX *ioctx)
|
420
397
|
{
|
421
|
-
mc_pSESSREQ sreq = mc_SESSREQ::get(lcbio_ctx_data(ioctx));
|
422
398
|
lcb::MemcachedResponse resp;
|
423
399
|
unsigned required;
|
424
400
|
sreq_STATE state = SREQ_S_WAIT;
|
@@ -433,20 +409,15 @@ handle_read(lcbio_CTX *ioctx, unsigned)
|
|
433
409
|
|
434
410
|
switch (resp.opcode()) {
|
435
411
|
case PROTOCOL_BINARY_CMD_SASL_LIST_MECHS: {
|
436
|
-
int mechrc;
|
437
412
|
const char *mechlist_data;
|
438
413
|
unsigned int nmechlist_data;
|
439
414
|
std::string mechs(resp.body<const char*>(), resp.bodylen());
|
440
415
|
|
441
|
-
mechrc = set_chosen_mech(
|
442
|
-
if (mechrc ==
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
state = SREQ_S_ERROR;
|
447
|
-
}
|
448
|
-
|
449
|
-
} else if (mechrc < 0) {
|
416
|
+
MechStatus mechrc = set_chosen_mech(mechs, &mechlist_data, &nmechlist_data);
|
417
|
+
if (mechrc == MECH_OK) {
|
418
|
+
send_auth(mechlist_data, nmechlist_data);
|
419
|
+
state = SREQ_S_WAIT;
|
420
|
+
} else if (mechrc == MECH_UNAVAILABLE) {
|
450
421
|
state = SREQ_S_ERROR;
|
451
422
|
} else {
|
452
423
|
state = SREQ_S_HELLODONE;
|
@@ -456,17 +427,17 @@ handle_read(lcbio_CTX *ioctx, unsigned)
|
|
456
427
|
|
457
428
|
case PROTOCOL_BINARY_CMD_SASL_AUTH: {
|
458
429
|
if (status == PROTOCOL_BINARY_RESPONSE_SUCCESS) {
|
459
|
-
|
430
|
+
send_hello();
|
460
431
|
state = SREQ_S_AUTHDONE;
|
461
432
|
break;
|
462
433
|
}
|
463
434
|
|
464
435
|
if (status != PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE) {
|
465
|
-
|
436
|
+
set_error(LCB_AUTH_ERROR, "SASL AUTH failed");
|
466
437
|
state = SREQ_S_ERROR;
|
467
438
|
break;
|
468
439
|
}
|
469
|
-
if (
|
440
|
+
if (send_step(resp) && send_hello()) {
|
470
441
|
state = SREQ_S_WAIT;
|
471
442
|
} else {
|
472
443
|
state = SREQ_S_ERROR;
|
@@ -476,8 +447,8 @@ handle_read(lcbio_CTX *ioctx, unsigned)
|
|
476
447
|
|
477
448
|
case PROTOCOL_BINARY_CMD_SASL_STEP: {
|
478
449
|
if (status != PROTOCOL_BINARY_RESPONSE_SUCCESS) {
|
479
|
-
lcb_log(LOGARGS(
|
480
|
-
|
450
|
+
lcb_log(LOGARGS(this, WARN), SESSREQ_LOGFMT "SASL auth failed with STATUS=0x%x", SESSREQ_LOGID(this), status);
|
451
|
+
set_error(LCB_AUTH_ERROR, "SASL Step Failed");
|
481
452
|
state = SREQ_S_ERROR;
|
482
453
|
} else {
|
483
454
|
/* Wait for pipelined HELLO response */
|
@@ -489,15 +460,15 @@ handle_read(lcbio_CTX *ioctx, unsigned)
|
|
489
460
|
case PROTOCOL_BINARY_CMD_HELLO: {
|
490
461
|
state = SREQ_S_HELLODONE;
|
491
462
|
if (status == PROTOCOL_BINARY_RESPONSE_SUCCESS) {
|
492
|
-
if (!
|
493
|
-
|
463
|
+
if (!read_hello(resp)) {
|
464
|
+
set_error(LCB_PROTOCOL_ERROR, "Couldn't parse HELLO");
|
494
465
|
}
|
495
466
|
} else if (status == PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND ||
|
496
467
|
status == PROTOCOL_BINARY_RESPONSE_NOT_SUPPORTED) {
|
497
|
-
lcb_log(LOGARGS(
|
468
|
+
lcb_log(LOGARGS(this, DEBUG), SESSREQ_LOGFMT "Server does not support HELLO", SESSREQ_LOGID(this));
|
498
469
|
/* nothing */
|
499
470
|
} else {
|
500
|
-
|
471
|
+
set_error(LCB_PROTOCOL_ERROR, "Hello response unexpected");
|
501
472
|
state = SREQ_S_ERROR;
|
502
473
|
}
|
503
474
|
break;
|
@@ -505,8 +476,8 @@ handle_read(lcbio_CTX *ioctx, unsigned)
|
|
505
476
|
|
506
477
|
default: {
|
507
478
|
state = SREQ_S_ERROR;
|
508
|
-
lcb_log(LOGARGS(
|
509
|
-
|
479
|
+
lcb_log(LOGARGS(this, ERROR), SESSREQ_LOGFMT "Received unknown response. OP=0x%x. RC=0x%x", SESSREQ_LOGID(this), resp.opcode(), resp.status());
|
480
|
+
set_error(LCB_NOT_SUPPORTED, "Received unknown response");
|
510
481
|
break;
|
511
482
|
}
|
512
483
|
}
|
@@ -517,12 +488,12 @@ handle_read(lcbio_CTX *ioctx, unsigned)
|
|
517
488
|
|
518
489
|
// Once there is no more any dependencies on the buffers, we can succeed
|
519
490
|
// or fail the request, potentially destroying the underlying connection
|
520
|
-
if (
|
521
|
-
|
491
|
+
if (has_error()) {
|
492
|
+
fail();
|
522
493
|
} else if (state == SREQ_S_ERROR) {
|
523
|
-
|
494
|
+
fail(LCB_ERROR, "FIXME: Error code set without description");
|
524
495
|
} else if (state == SREQ_S_HELLODONE) {
|
525
|
-
|
496
|
+
success();
|
526
497
|
} else {
|
527
498
|
goto GT_NEXT_PACKET;
|
528
499
|
}
|
@@ -531,17 +502,17 @@ handle_read(lcbio_CTX *ioctx, unsigned)
|
|
531
502
|
static void
|
532
503
|
handle_ioerr(lcbio_CTX *ctx, lcb_error_t err)
|
533
504
|
{
|
534
|
-
|
505
|
+
SessionRequestImpl* sreq = SessionRequestImpl::get(lcbio_ctx_data(ctx));
|
535
506
|
sreq->fail(err, "IO Error");
|
536
507
|
}
|
537
508
|
|
538
|
-
static void cleanup_negotiated(
|
509
|
+
static void cleanup_negotiated(SessionInfo* ctx) {
|
539
510
|
delete ctx;
|
540
511
|
}
|
541
512
|
|
542
513
|
void
|
543
|
-
|
544
|
-
|
514
|
+
SessionRequestImpl::start(lcbio_SOCKET *sock) {
|
515
|
+
info = new SessionInfo();
|
545
516
|
|
546
517
|
lcb_error_t err = lcbio_sslify_if_needed(sock, settings);
|
547
518
|
if (err != LCB_SUCCESS) {
|
@@ -551,16 +522,16 @@ mc_SESSREQ::start(lcbio_SOCKET *sock, lcb_settings *settings) {
|
|
551
522
|
}
|
552
523
|
|
553
524
|
lcbio_CTXPROCS procs;
|
554
|
-
procs.cb_err = handle_ioerr;
|
555
|
-
procs.cb_read = handle_read;
|
525
|
+
procs.cb_err = ::handle_ioerr;
|
526
|
+
procs.cb_read = ::handle_read;
|
556
527
|
ctx = lcbio_ctx_new(sock, this, &procs);
|
557
528
|
ctx->subsys = "sasl";
|
558
529
|
|
559
530
|
const lcb_host_t *curhost = lcbio_get_host(sock);
|
560
|
-
|
531
|
+
lcbio_NAMEINFO nistrs;
|
561
532
|
lcbio_get_nameinfo(sock, &nistrs);
|
562
533
|
|
563
|
-
if (!
|
534
|
+
if (!setup(nistrs, *curhost, *settings->auth)) {
|
564
535
|
set_error(LCB_EINTERNAL, "Couldn't start SASL client");
|
565
536
|
lcbio_async_signal(timer);
|
566
537
|
return;
|
@@ -571,11 +542,10 @@ mc_SESSREQ::start(lcbio_SOCKET *sock, lcb_settings *settings) {
|
|
571
542
|
LCBIO_CTX_RSCHEDULE(ctx, 24);
|
572
543
|
}
|
573
544
|
|
574
|
-
|
575
|
-
mc_SESSREQ::~mc_SESSREQ()
|
545
|
+
SessionRequestImpl::~SessionRequestImpl()
|
576
546
|
{
|
577
|
-
if (
|
578
|
-
delete
|
547
|
+
if (info) {
|
548
|
+
delete info;
|
579
549
|
}
|
580
550
|
if (timer) {
|
581
551
|
lcbio_timer_destroy(timer);
|
@@ -583,35 +553,31 @@ mc_SESSREQ::~mc_SESSREQ()
|
|
583
553
|
if (ctx) {
|
584
554
|
lcbio_ctx_close(ctx, NULL, NULL);
|
585
555
|
}
|
556
|
+
if (sasl_client) {
|
557
|
+
cbsasl_dispose(&sasl_client);
|
558
|
+
}
|
586
559
|
}
|
587
560
|
|
588
|
-
void
|
561
|
+
void lcb::sessreq_cancel(SessionRequest *sreq) {
|
589
562
|
sreq->cancel();
|
590
563
|
}
|
591
564
|
|
592
|
-
|
593
|
-
|
565
|
+
SessionRequest *
|
566
|
+
SessionRequest::start(lcbio_SOCKET *sock, lcb_settings_st *settings,
|
594
567
|
uint32_t tmo, lcbio_CONNDONE_cb callback, void *data)
|
595
568
|
{
|
596
|
-
|
597
|
-
sreq->start(sock
|
569
|
+
SessionRequestImpl* sreq = new SessionRequestImpl(callback, data, tmo, sock->io, settings);
|
570
|
+
sreq->start(sock);
|
598
571
|
return sreq;
|
599
572
|
}
|
600
573
|
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
}
|
605
|
-
|
606
|
-
const char *mc_sess_get_saslmech(mc_pSESSINFO info) {
|
607
|
-
return info->mech.c_str();
|
574
|
+
SessionInfo*
|
575
|
+
SessionInfo::get(lcbio_SOCKET *sock) {
|
576
|
+
return static_cast<SessionInfo*>(lcbio_protoctx_get(sock, LCBIO_PROTOCTX_SESSINFO));
|
608
577
|
}
|
609
578
|
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
}
|
615
|
-
}
|
616
|
-
return 0;
|
579
|
+
bool
|
580
|
+
SessionInfo::has_feature(uint16_t feature) const {
|
581
|
+
return std::find(server_features.begin(), server_features.end(), feature)
|
582
|
+
!= server_features.end();
|
617
583
|
}
|