libcouchbase 0.0.4 → 0.0.5
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.
- checksums.yaml +4 -4
- data/ext/libcouchbase/cmake/Modules/GetLibcouchbaseFlags.cmake +1 -0
- data/ext/libcouchbase/cmake/source_files.cmake +2 -2
- data/ext/libcouchbase/contrib/cliopts/cliopts.c +32 -1
- data/ext/libcouchbase/contrib/cliopts/cliopts.h +9 -1
- data/ext/libcouchbase/src/aspend.h +9 -10
- data/ext/libcouchbase/src/connspec.h +13 -0
- data/ext/libcouchbase/src/instance.cc +26 -34
- data/ext/libcouchbase/src/mcserver/negotiate.cc +617 -0
- data/ext/libcouchbase/src/mcserver/negotiate.h +1 -1
- data/ext/libcouchbase/src/n1ql/params.cc +1 -1
- data/ext/libcouchbase/src/packetutils.h +88 -2
- data/ext/libcouchbase/tests/iotests/t_misc.cc +20 -0
- data/ext/libcouchbase/tools/cbc-handlers.h +5 -5
- data/ext/libcouchbase/tools/cbc.cc +10 -1
- data/ext/libcouchbase/tools/docgen/docgen.h +1 -1
- data/lib/libcouchbase/bucket.rb +28 -5
- data/lib/libcouchbase/connection.rb +14 -2
- data/lib/libcouchbase/version.rb +1 -1
- data/spec/bucket_spec.rb +6 -0
- data/spec/connection_spec.rb +5 -0
- data/spec/fts_spec.rb +6 -0
- data/spec/n1ql_spec.rb +5 -0
- data/spec/view_spec.rb +6 -0
- metadata +3 -6
- data/ext/libcouchbase/src/hashset.c +0 -164
- data/ext/libcouchbase/src/hashset.h +0 -86
- data/ext/libcouchbase/src/mcserver/negotiate.c +0 -657
- data/ext/libcouchbase/tests/basic/t_hashset.cc +0 -262
@@ -1,86 +0,0 @@
|
|
1
|
-
/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
2
|
-
/*
|
3
|
-
* Copyright 2012 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
|
-
#ifndef LIBCOUCHBASE_HASHSET_H
|
19
|
-
#define LIBCOUCHBASE_HASHSET_H 1
|
20
|
-
|
21
|
-
#ifdef __cplusplus
|
22
|
-
extern "C" {
|
23
|
-
#endif
|
24
|
-
|
25
|
-
struct hashset_st {
|
26
|
-
lcb_size_t nbits;
|
27
|
-
lcb_size_t mask;
|
28
|
-
|
29
|
-
lcb_size_t capacity;
|
30
|
-
lcb_size_t *items;
|
31
|
-
lcb_size_t nitems;
|
32
|
-
};
|
33
|
-
|
34
|
-
typedef struct hashset_st *hashset_t;
|
35
|
-
|
36
|
-
/* create hashset instance */
|
37
|
-
hashset_t hashset_create(void);
|
38
|
-
|
39
|
-
/* destroy hashset instance */
|
40
|
-
void hashset_destroy(hashset_t set);
|
41
|
-
|
42
|
-
lcb_size_t hashset_num_items(hashset_t set);
|
43
|
-
|
44
|
-
/**
|
45
|
-
* Makes a list of items inside the hashset.
|
46
|
-
* @param set the hashset
|
47
|
-
* @param itemlist an allocated array large enough to hold the number
|
48
|
-
* of items in the hashset (use hashset_num_items). If this is NULL
|
49
|
-
* then a list is allocated for you
|
50
|
-
*
|
51
|
-
* @return the item list. If the @itemlist param argument was
|
52
|
-
* not-null, then this is the same list; if it was NULL then this
|
53
|
-
* is an allocated list which should be released using @itemlist
|
54
|
-
* free(). It will return NULL if the hashset is empty or memory
|
55
|
-
* allocation for @itemlist was failed.
|
56
|
-
*/
|
57
|
-
void **hashset_get_items(hashset_t set, void **itemlist);
|
58
|
-
|
59
|
-
|
60
|
-
/* add item into the hashset.
|
61
|
-
*
|
62
|
-
* @note 0 and 1 is special values, meaning nil and deleted items. the
|
63
|
-
* function will return -1 indicating error.
|
64
|
-
*
|
65
|
-
* returns zero if the item already in the set and non-zero otherwise
|
66
|
-
*/
|
67
|
-
int hashset_add(hashset_t set, void *item);
|
68
|
-
|
69
|
-
/* remove item from the hashset
|
70
|
-
*
|
71
|
-
* returns non-zero if the item was removed and zero if the item wasn't
|
72
|
-
* exist
|
73
|
-
*/
|
74
|
-
int hashset_remove(hashset_t set, void *item);
|
75
|
-
|
76
|
-
/* check if existence of the item
|
77
|
-
*
|
78
|
-
* returns non-zero if the item exists and zero otherwise
|
79
|
-
*/
|
80
|
-
int hashset_is_member(hashset_t set, void *item);
|
81
|
-
|
82
|
-
#ifdef __cplusplus
|
83
|
-
}
|
84
|
-
#endif
|
85
|
-
|
86
|
-
#endif
|
@@ -1,657 +0,0 @@
|
|
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 "packetutils.h"
|
19
|
-
#include "simplestring.h"
|
20
|
-
#include "mcserver.h"
|
21
|
-
#include "logging.h"
|
22
|
-
#include "settings.h"
|
23
|
-
#include <lcbio/lcbio.h>
|
24
|
-
#include <lcbio/timer-ng.h>
|
25
|
-
#include <lcbio/ssl.h>
|
26
|
-
#include <cbsasl/cbsasl.h>
|
27
|
-
#include "negotiate.h"
|
28
|
-
#include "ctx-log-inl.h"
|
29
|
-
|
30
|
-
#define LOGARGS(ctx, lvl) ctx->inner->settings, "negotiation", LCB_LOG_##lvl, __FILE__, __LINE__
|
31
|
-
static void cleanup_pending(mc_pSESSREQ);
|
32
|
-
static void cleanup_negotiated(mc_pSESSINFO);
|
33
|
-
static void bail_pending(mc_pSESSREQ sreq);
|
34
|
-
#define SESSREQ_LOGFMT "<%s:%s> (SASLREQ=%p) "
|
35
|
-
|
36
|
-
/**
|
37
|
-
* Inner negotiation structure which is maintained as part of a 'protocol
|
38
|
-
* context'.
|
39
|
-
*/
|
40
|
-
struct mc_SESSINFO {
|
41
|
-
lcbio_PROTOCTX base;
|
42
|
-
cbsasl_conn_t *sasl;
|
43
|
-
char *mech;
|
44
|
-
unsigned int nmech;
|
45
|
-
lcb_settings *settings;
|
46
|
-
lcbio_CONNDONE_cb complete;
|
47
|
-
union {
|
48
|
-
cbsasl_secret_t secret;
|
49
|
-
char buffer[256];
|
50
|
-
} u_auth;
|
51
|
-
cbsasl_callback_t sasl_callbacks[4];
|
52
|
-
lcb_U16 features[MEMCACHED_TOTAL_HELLO_FEATURES+1];
|
53
|
-
};
|
54
|
-
|
55
|
-
/**
|
56
|
-
* Structure used only for initialization. This is only used for the duration
|
57
|
-
* of the request for negotiation and is deleted once negotiation has
|
58
|
-
* completed (or failed).
|
59
|
-
*/
|
60
|
-
typedef struct mc_SESSREQ {
|
61
|
-
lcbio_CTX *ctx;
|
62
|
-
lcbio_CONNDONE_cb cb;
|
63
|
-
void *data;
|
64
|
-
lcbio_pTIMER timer;
|
65
|
-
lcb_error_t err;
|
66
|
-
mc_pSESSINFO inner;
|
67
|
-
} neg_PENDING;
|
68
|
-
|
69
|
-
#define SESSREQ_LOGID(s) get_ctx_host(s->ctx), get_ctx_port(s->ctx), (void*)s
|
70
|
-
|
71
|
-
static int
|
72
|
-
sasl_get_username(void *context, int id, const char **result, unsigned int *len)
|
73
|
-
{
|
74
|
-
struct mc_SESSINFO *ctx = context;
|
75
|
-
const char *u = NULL, *p = NULL;
|
76
|
-
if (!context || !result || (id != CBSASL_CB_USER && id != CBSASL_CB_AUTHNAME)) {
|
77
|
-
return SASL_BADPARAM;
|
78
|
-
}
|
79
|
-
u = ctx->settings->bucket;
|
80
|
-
p = lcbauth_get_bpass(ctx->settings->auth, ctx->settings->bucket);
|
81
|
-
*result = u;
|
82
|
-
if (len) {
|
83
|
-
*len = (unsigned int)strlen(*result);
|
84
|
-
}
|
85
|
-
|
86
|
-
return SASL_OK;
|
87
|
-
}
|
88
|
-
|
89
|
-
static int
|
90
|
-
sasl_get_password(cbsasl_conn_t *conn, void *context, int id,
|
91
|
-
cbsasl_secret_t **psecret)
|
92
|
-
{
|
93
|
-
struct mc_SESSINFO *ctx = context;
|
94
|
-
if (!conn || ! psecret || id != CBSASL_CB_PASS || ctx == NULL) {
|
95
|
-
return SASL_BADPARAM;
|
96
|
-
}
|
97
|
-
|
98
|
-
*psecret = &ctx->u_auth.secret;
|
99
|
-
return SASL_OK;
|
100
|
-
}
|
101
|
-
|
102
|
-
static lcb_error_t
|
103
|
-
setup_sasl_params(struct mc_SESSINFO *ctx)
|
104
|
-
{
|
105
|
-
int ii;
|
106
|
-
cbsasl_callback_t *callbacks = ctx->sasl_callbacks;
|
107
|
-
const char *pass = NULL, *user = NULL;
|
108
|
-
|
109
|
-
callbacks[0].id = CBSASL_CB_USER;
|
110
|
-
callbacks[0].proc = (int( *)(void)) &sasl_get_username;
|
111
|
-
|
112
|
-
callbacks[1].id = CBSASL_CB_AUTHNAME;
|
113
|
-
callbacks[1].proc = (int( *)(void)) &sasl_get_username;
|
114
|
-
|
115
|
-
callbacks[2].id = CBSASL_CB_PASS;
|
116
|
-
callbacks[2].proc = (int( *)(void)) &sasl_get_password;
|
117
|
-
|
118
|
-
callbacks[3].id = CBSASL_CB_LIST_END;
|
119
|
-
callbacks[3].proc = NULL;
|
120
|
-
callbacks[3].context = NULL;
|
121
|
-
|
122
|
-
for (ii = 0; ii < 3; ii++) {
|
123
|
-
callbacks[ii].context = ctx;
|
124
|
-
}
|
125
|
-
|
126
|
-
memset(&ctx->u_auth, 0, sizeof(ctx->u_auth));
|
127
|
-
user = ctx->settings->bucket;
|
128
|
-
pass = lcbauth_get_bpass(ctx->settings->auth, user);
|
129
|
-
|
130
|
-
if (pass) {
|
131
|
-
unsigned long pwlen;
|
132
|
-
lcb_size_t maxlen;
|
133
|
-
|
134
|
-
pwlen = (unsigned long)strlen(pass);
|
135
|
-
maxlen = sizeof(ctx->u_auth.buffer) - offsetof(cbsasl_secret_t, data);
|
136
|
-
ctx->u_auth.secret.len = pwlen;
|
137
|
-
|
138
|
-
if (pwlen < maxlen) {
|
139
|
-
memcpy(ctx->u_auth.secret.data, pass, pwlen);
|
140
|
-
} else {
|
141
|
-
return LCB_EINVAL;
|
142
|
-
}
|
143
|
-
}
|
144
|
-
return LCB_SUCCESS;
|
145
|
-
}
|
146
|
-
|
147
|
-
static void
|
148
|
-
close_cb(lcbio_SOCKET *s, int reusable, void *arg)
|
149
|
-
{
|
150
|
-
*(lcbio_SOCKET **)arg = s;
|
151
|
-
lcbio_ref(s);
|
152
|
-
lcb_assert(reusable);
|
153
|
-
}
|
154
|
-
|
155
|
-
static void
|
156
|
-
negotiation_success(mc_pSESSREQ sreq)
|
157
|
-
{
|
158
|
-
/** Dislodge the connection, and return it back to the caller */
|
159
|
-
lcbio_SOCKET *s;
|
160
|
-
|
161
|
-
lcbio_ctx_close(sreq->ctx, close_cb, &s);
|
162
|
-
sreq->ctx = NULL;
|
163
|
-
|
164
|
-
lcbio_protoctx_add(s, &sreq->inner->base);
|
165
|
-
sreq->inner = NULL;
|
166
|
-
|
167
|
-
/** Invoke the callback, marking it a success */
|
168
|
-
sreq->cb(s, sreq->data, LCB_SUCCESS, 0);
|
169
|
-
lcbio_unref(s);
|
170
|
-
cleanup_pending(sreq);
|
171
|
-
}
|
172
|
-
|
173
|
-
static void
|
174
|
-
bail_pending(mc_pSESSREQ sreq)
|
175
|
-
{
|
176
|
-
sreq->cb(NULL, sreq->data, sreq->err, 0);
|
177
|
-
cleanup_pending(sreq);
|
178
|
-
}
|
179
|
-
|
180
|
-
static void
|
181
|
-
set_error_ex(mc_pSESSREQ sreq, lcb_error_t err, const char *msg)
|
182
|
-
{
|
183
|
-
lcb_log(LOGARGS(sreq, ERR), SESSREQ_LOGFMT "Error: 0x%x, %s", SESSREQ_LOGID(sreq), err, msg);
|
184
|
-
if (sreq->err == LCB_SUCCESS) {
|
185
|
-
sreq->err = err;
|
186
|
-
}
|
187
|
-
}
|
188
|
-
|
189
|
-
static void
|
190
|
-
timeout_handler(void *arg)
|
191
|
-
{
|
192
|
-
mc_pSESSREQ sreq = arg;
|
193
|
-
set_error_ex(sreq, LCB_ETIMEDOUT, "Negotiation timed out");
|
194
|
-
bail_pending(sreq);
|
195
|
-
}
|
196
|
-
|
197
|
-
/**
|
198
|
-
* Called to retrive the mechlist from the packet.
|
199
|
-
* @return 0 to continue authentication, 1 if no authentication needed, or
|
200
|
-
* -1 on error.
|
201
|
-
*/
|
202
|
-
static int
|
203
|
-
set_chosen_mech(mc_pSESSREQ sreq, lcb_string *mechlist, const char **data,
|
204
|
-
unsigned int *ndata)
|
205
|
-
{
|
206
|
-
cbsasl_error_t saslerr;
|
207
|
-
const char *chosenmech;
|
208
|
-
mc_pSESSINFO ctx = sreq->inner;
|
209
|
-
|
210
|
-
lcb_assert(sreq->inner);
|
211
|
-
if (ctx->settings->sasl_mech_force) {
|
212
|
-
char *forcemech = ctx->settings->sasl_mech_force;
|
213
|
-
if (!strstr(mechlist->base, forcemech)) {
|
214
|
-
/** Requested mechanism not found */
|
215
|
-
set_error_ex(sreq, LCB_SASLMECH_UNAVAILABLE, mechlist->base);
|
216
|
-
return -1;
|
217
|
-
}
|
218
|
-
|
219
|
-
lcb_string_clear(mechlist);
|
220
|
-
if (lcb_string_appendz(mechlist, forcemech)) {
|
221
|
-
set_error_ex(sreq, LCB_CLIENT_ENOMEM, NULL);
|
222
|
-
return -1;
|
223
|
-
}
|
224
|
-
}
|
225
|
-
|
226
|
-
saslerr = cbsasl_client_start(ctx->sasl, mechlist->base,
|
227
|
-
NULL, data, ndata, &chosenmech);
|
228
|
-
switch (saslerr) {
|
229
|
-
case SASL_OK:
|
230
|
-
ctx->nmech = strlen(chosenmech);
|
231
|
-
if (! (ctx->mech = strdup(chosenmech)) ) {
|
232
|
-
set_error_ex(sreq, LCB_CLIENT_ENOMEM, NULL);
|
233
|
-
return -1;
|
234
|
-
}
|
235
|
-
return 0;
|
236
|
-
case SASL_NOMECH:
|
237
|
-
lcb_log(LOGARGS(sreq, INFO), SESSREQ_LOGFMT "Server does not support SASL (no mechanisms supported)", SESSREQ_LOGID(sreq));
|
238
|
-
return 1;
|
239
|
-
break;
|
240
|
-
default:
|
241
|
-
lcb_log(LOGARGS(sreq, INFO), SESSREQ_LOGFMT "cbsasl_client_start returned %d", SESSREQ_LOGID(sreq), saslerr);
|
242
|
-
set_error_ex(sreq, LCB_EINTERNAL, "Couldn't start SASL client");
|
243
|
-
return -1;
|
244
|
-
}
|
245
|
-
}
|
246
|
-
|
247
|
-
/**
|
248
|
-
* Given the specific mechanisms, send the auth packet to the server.
|
249
|
-
*/
|
250
|
-
static int
|
251
|
-
send_sasl_auth(neg_PENDING *pend, const char *sasl_data, unsigned ndata)
|
252
|
-
{
|
253
|
-
mc_pSESSINFO ctx = pend->inner;
|
254
|
-
protocol_binary_request_no_extras req;
|
255
|
-
protocol_binary_request_header *hdr = &req.message.header;
|
256
|
-
memset(&req, 0, sizeof(req));
|
257
|
-
|
258
|
-
hdr->request.magic = PROTOCOL_BINARY_REQ;
|
259
|
-
hdr->request.opcode = PROTOCOL_BINARY_CMD_SASL_AUTH;
|
260
|
-
hdr->request.keylen = htons((lcb_uint16_t)ctx->nmech);
|
261
|
-
hdr->request.datatype = PROTOCOL_BINARY_RAW_BYTES;
|
262
|
-
hdr->request.bodylen = htonl((lcb_uint32_t)ndata + ctx->nmech);
|
263
|
-
|
264
|
-
lcbio_ctx_put(pend->ctx, req.bytes, sizeof(req.bytes));
|
265
|
-
lcbio_ctx_put(pend->ctx, ctx->mech, ctx->nmech);
|
266
|
-
lcbio_ctx_put(pend->ctx, sasl_data, ndata);
|
267
|
-
lcbio_ctx_rwant(pend->ctx, 24);
|
268
|
-
return 0;
|
269
|
-
}
|
270
|
-
|
271
|
-
static int
|
272
|
-
send_sasl_step(mc_pSESSREQ sreq, packet_info *packet)
|
273
|
-
{
|
274
|
-
protocol_binary_request_no_extras req;
|
275
|
-
protocol_binary_request_header *hdr = &req.message.header;
|
276
|
-
cbsasl_error_t saslerr;
|
277
|
-
const char *step_data;
|
278
|
-
unsigned int ndata;
|
279
|
-
mc_pSESSINFO ctx = sreq->inner;
|
280
|
-
|
281
|
-
saslerr = cbsasl_client_step(
|
282
|
-
ctx->sasl, packet->payload, PACKET_NBODY(packet), NULL, &step_data,
|
283
|
-
&ndata);
|
284
|
-
|
285
|
-
if (saslerr != SASL_CONTINUE) {
|
286
|
-
set_error_ex(sreq, LCB_EINTERNAL, "Unable to perform SASL STEP");
|
287
|
-
return -1;
|
288
|
-
}
|
289
|
-
|
290
|
-
memset(&req, 0, sizeof(req));
|
291
|
-
hdr->request.magic = PROTOCOL_BINARY_REQ;
|
292
|
-
hdr->request.opcode = PROTOCOL_BINARY_CMD_SASL_STEP;
|
293
|
-
hdr->request.keylen = htons((uint16_t)ctx->nmech);
|
294
|
-
hdr->request.bodylen = htonl((uint32_t)ndata + ctx->nmech);
|
295
|
-
hdr->request.datatype = PROTOCOL_BINARY_RAW_BYTES;
|
296
|
-
|
297
|
-
lcbio_ctx_put(sreq->ctx, req.bytes, sizeof(req.bytes));
|
298
|
-
lcbio_ctx_put(sreq->ctx, ctx->mech, ctx->nmech);
|
299
|
-
lcbio_ctx_put(sreq->ctx, step_data, ndata);
|
300
|
-
lcbio_ctx_rwant(sreq->ctx, 24);
|
301
|
-
return 0;
|
302
|
-
}
|
303
|
-
|
304
|
-
static int
|
305
|
-
send_hello(mc_pSESSREQ sreq)
|
306
|
-
{
|
307
|
-
protocol_binary_request_no_extras req;
|
308
|
-
protocol_binary_request_header *hdr = &req.message.header;
|
309
|
-
unsigned ii;
|
310
|
-
const char *external_id = "";
|
311
|
-
const char *comma = "";
|
312
|
-
char client_id[200] = { 0 };
|
313
|
-
lcb_U16 features[MEMCACHED_TOTAL_HELLO_FEATURES];
|
314
|
-
unsigned nfeatures = 0;
|
315
|
-
size_t nclistr;
|
316
|
-
|
317
|
-
features[nfeatures++] = PROTOCOL_BINARY_FEATURE_TLS;
|
318
|
-
if (sreq->inner->settings->tcp_nodelay) {
|
319
|
-
features[nfeatures++] = PROTOCOL_BINARY_FEATURE_TCPNODELAY;
|
320
|
-
}
|
321
|
-
|
322
|
-
#ifndef LCB_NO_SNAPPY
|
323
|
-
if (sreq->inner->settings->compressopts != LCB_COMPRESS_NONE) {
|
324
|
-
features[nfeatures++] = PROTOCOL_BINARY_FEATURE_DATATYPE;
|
325
|
-
}
|
326
|
-
#endif
|
327
|
-
|
328
|
-
if (sreq->inner->settings->fetch_mutation_tokens) {
|
329
|
-
features[nfeatures++] = PROTOCOL_BINARY_FEATURE_MUTATION_SEQNO;
|
330
|
-
}
|
331
|
-
|
332
|
-
if (sreq->inner->settings->client_string) {
|
333
|
-
external_id = sreq->inner->settings->client_string;
|
334
|
-
comma = ", ";
|
335
|
-
}
|
336
|
-
|
337
|
-
snprintf(client_id, 199, "libcouchbase/%s%s%s",
|
338
|
-
LCB_VERSION_STRING, comma, external_id);
|
339
|
-
nclistr = strlen(client_id);
|
340
|
-
|
341
|
-
memset(&req, 0, sizeof req);
|
342
|
-
hdr->request.opcode = PROTOCOL_BINARY_CMD_HELLO;
|
343
|
-
hdr->request.magic = PROTOCOL_BINARY_REQ;
|
344
|
-
hdr->request.keylen = htons((lcb_U16)nclistr);
|
345
|
-
hdr->request.bodylen = htonl((lcb_U32)(nclistr+ (sizeof features[0]) * nfeatures));
|
346
|
-
hdr->request.datatype = PROTOCOL_BINARY_RAW_BYTES;
|
347
|
-
|
348
|
-
lcbio_ctx_put(sreq->ctx, req.bytes, sizeof req.bytes);
|
349
|
-
lcbio_ctx_put(sreq->ctx, client_id, strlen(client_id));
|
350
|
-
for (ii = 0; ii < nfeatures; ii++) {
|
351
|
-
lcb_U16 tmp = htons(features[ii]);
|
352
|
-
lcbio_ctx_put(sreq->ctx, &tmp, sizeof tmp);
|
353
|
-
}
|
354
|
-
lcbio_ctx_rwant(sreq->ctx, 24);
|
355
|
-
return 0;
|
356
|
-
}
|
357
|
-
|
358
|
-
static int
|
359
|
-
parse_hello(mc_pSESSREQ sreq, packet_info *packet)
|
360
|
-
{
|
361
|
-
/* some caps */
|
362
|
-
const char *cur;
|
363
|
-
const char *payload = PACKET_BODY(packet);
|
364
|
-
const char *limit = payload + PACKET_NBODY(packet);
|
365
|
-
for (cur = payload; cur < limit; cur += 2) {
|
366
|
-
lcb_U16 tmp;
|
367
|
-
memcpy(&tmp, cur, sizeof(tmp));
|
368
|
-
tmp = ntohs(tmp);
|
369
|
-
lcb_log(LOGARGS(sreq, DEBUG), SESSREQ_LOGFMT "Found feature 0x%x (%s)", SESSREQ_LOGID(sreq), tmp, protocol_feature_2_text(tmp));
|
370
|
-
sreq->inner->features[tmp] = 1;
|
371
|
-
}
|
372
|
-
return 0;
|
373
|
-
}
|
374
|
-
|
375
|
-
|
376
|
-
typedef enum {
|
377
|
-
SREQ_S_WAIT,
|
378
|
-
SREQ_S_AUTHDONE,
|
379
|
-
SREQ_S_HELLODONE,
|
380
|
-
SREQ_S_ERROR
|
381
|
-
} sreq_STATE;
|
382
|
-
|
383
|
-
/**
|
384
|
-
* It's assumed the server buffers will be reset upon close(), so we must make
|
385
|
-
* sure to _not_ release the ringbuffer if that happens.
|
386
|
-
*/
|
387
|
-
static void
|
388
|
-
handle_read(lcbio_CTX *ioctx, unsigned nb)
|
389
|
-
{
|
390
|
-
mc_pSESSREQ sreq = lcbio_ctx_data(ioctx);
|
391
|
-
packet_info info;
|
392
|
-
unsigned required;
|
393
|
-
uint16_t status;
|
394
|
-
sreq_STATE state = SREQ_S_WAIT;
|
395
|
-
int rc;
|
396
|
-
|
397
|
-
GT_NEXT_PACKET:
|
398
|
-
|
399
|
-
memset(&info, 0, sizeof(info));
|
400
|
-
rc = lcb_pktinfo_ectx_get(&info, ioctx, &required);
|
401
|
-
if (rc == 0) {
|
402
|
-
LCBIO_CTX_RSCHEDULE(ioctx, required);
|
403
|
-
return;
|
404
|
-
} else if (rc < 0) {
|
405
|
-
state = SREQ_S_ERROR;
|
406
|
-
}
|
407
|
-
|
408
|
-
status = PACKET_STATUS(&info);
|
409
|
-
|
410
|
-
switch (PACKET_OPCODE(&info)) {
|
411
|
-
case PROTOCOL_BINARY_CMD_SASL_LIST_MECHS: {
|
412
|
-
lcb_string str;
|
413
|
-
int saslrc;
|
414
|
-
const char *mechlist_data;
|
415
|
-
unsigned int nmechlist_data;
|
416
|
-
if (lcb_string_init(&str)) {
|
417
|
-
set_error_ex(sreq, LCB_CLIENT_ENOMEM, NULL);
|
418
|
-
state = SREQ_S_ERROR;
|
419
|
-
break;
|
420
|
-
}
|
421
|
-
|
422
|
-
if (lcb_string_append(&str, info.payload, PACKET_NBODY(&info))) {
|
423
|
-
lcb_string_release(&str);
|
424
|
-
set_error_ex(sreq, LCB_CLIENT_ENOMEM, NULL);
|
425
|
-
state = SREQ_S_ERROR;
|
426
|
-
break;
|
427
|
-
}
|
428
|
-
|
429
|
-
saslrc = set_chosen_mech(sreq, &str, &mechlist_data, &nmechlist_data);
|
430
|
-
if (saslrc == 0) {
|
431
|
-
if (0 == send_sasl_auth(sreq, mechlist_data, nmechlist_data)) {
|
432
|
-
state = SREQ_S_WAIT;
|
433
|
-
} else {
|
434
|
-
state = SREQ_S_ERROR;
|
435
|
-
}
|
436
|
-
|
437
|
-
} else if (saslrc < 0) {
|
438
|
-
state = SREQ_S_ERROR;
|
439
|
-
|
440
|
-
} else {
|
441
|
-
state = SREQ_S_HELLODONE;
|
442
|
-
}
|
443
|
-
lcb_string_release(&str);
|
444
|
-
break;
|
445
|
-
}
|
446
|
-
|
447
|
-
case PROTOCOL_BINARY_CMD_SASL_AUTH: {
|
448
|
-
if (status == PROTOCOL_BINARY_RESPONSE_SUCCESS) {
|
449
|
-
send_hello(sreq);
|
450
|
-
state = SREQ_S_AUTHDONE;
|
451
|
-
break;
|
452
|
-
}
|
453
|
-
|
454
|
-
if (status != PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE) {
|
455
|
-
set_error_ex(sreq, LCB_AUTH_ERROR, "SASL AUTH failed");
|
456
|
-
state = SREQ_S_ERROR;
|
457
|
-
break;
|
458
|
-
}
|
459
|
-
if (send_sasl_step(sreq, &info) == 0 && send_hello(sreq) == 0) {
|
460
|
-
state = SREQ_S_WAIT;
|
461
|
-
} else {
|
462
|
-
state = SREQ_S_ERROR;
|
463
|
-
}
|
464
|
-
break;
|
465
|
-
}
|
466
|
-
|
467
|
-
case PROTOCOL_BINARY_CMD_SASL_STEP: {
|
468
|
-
if (status != PROTOCOL_BINARY_RESPONSE_SUCCESS) {
|
469
|
-
lcb_log(LOGARGS(sreq, WARN), SESSREQ_LOGFMT "SASL auth failed with STATUS=0x%x", SESSREQ_LOGID(sreq), status);
|
470
|
-
set_error_ex(sreq, LCB_AUTH_ERROR, "SASL Step Failed");
|
471
|
-
state = SREQ_S_ERROR;
|
472
|
-
} else {
|
473
|
-
/* Wait for pipelined HELLO response */
|
474
|
-
state = SREQ_S_AUTHDONE;
|
475
|
-
}
|
476
|
-
break;
|
477
|
-
}
|
478
|
-
|
479
|
-
case PROTOCOL_BINARY_CMD_HELLO: {
|
480
|
-
state = SREQ_S_HELLODONE;
|
481
|
-
if (status == PROTOCOL_BINARY_RESPONSE_SUCCESS) {
|
482
|
-
parse_hello(sreq, &info);
|
483
|
-
} else if (status == PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND ||
|
484
|
-
status == PROTOCOL_BINARY_RESPONSE_NOT_SUPPORTED) {
|
485
|
-
lcb_log(LOGARGS(sreq, DEBUG), SESSREQ_LOGFMT "Server does not support HELLO", SESSREQ_LOGID(sreq));
|
486
|
-
/* nothing */
|
487
|
-
} else {
|
488
|
-
set_error_ex(sreq, LCB_PROTOCOL_ERROR, "Hello response unexpected");
|
489
|
-
state = SREQ_S_ERROR;
|
490
|
-
}
|
491
|
-
break;
|
492
|
-
}
|
493
|
-
|
494
|
-
default: {
|
495
|
-
state = SREQ_S_ERROR;
|
496
|
-
lcb_log(LOGARGS(sreq, ERROR), SESSREQ_LOGFMT "Received unknown response. OP=0x%x. RC=0x%x", SESSREQ_LOGID(sreq), PACKET_OPCODE(&info), PACKET_STATUS(&info));
|
497
|
-
set_error_ex(sreq, LCB_NOT_SUPPORTED, "Received unknown response");
|
498
|
-
break;
|
499
|
-
}
|
500
|
-
}
|
501
|
-
|
502
|
-
lcb_pktinfo_ectx_done(&info, ioctx);
|
503
|
-
if (sreq->err != LCB_SUCCESS) {
|
504
|
-
bail_pending(sreq);
|
505
|
-
} else if (state == SREQ_S_ERROR) {
|
506
|
-
set_error_ex(sreq, LCB_ERROR, "FIXME: Error code set without description");
|
507
|
-
} else if (state == SREQ_S_HELLODONE) {
|
508
|
-
negotiation_success(sreq);
|
509
|
-
} else {
|
510
|
-
goto GT_NEXT_PACKET;
|
511
|
-
}
|
512
|
-
|
513
|
-
(void)nb;
|
514
|
-
}
|
515
|
-
|
516
|
-
static void
|
517
|
-
handle_ioerr(lcbio_CTX *ctx, lcb_error_t err)
|
518
|
-
{
|
519
|
-
mc_pSESSREQ sreq = lcbio_ctx_data(ctx);
|
520
|
-
set_error_ex(sreq, err, "IO Error");
|
521
|
-
bail_pending(sreq);
|
522
|
-
}
|
523
|
-
|
524
|
-
static void
|
525
|
-
cleanup_negotiated(mc_pSESSINFO ctx)
|
526
|
-
{
|
527
|
-
if (ctx->sasl) {
|
528
|
-
cbsasl_dispose(&ctx->sasl);
|
529
|
-
}
|
530
|
-
if (ctx->mech) {
|
531
|
-
free(ctx->mech);
|
532
|
-
}
|
533
|
-
free(ctx);
|
534
|
-
}
|
535
|
-
|
536
|
-
static void
|
537
|
-
cleanup_pending(mc_pSESSREQ sreq)
|
538
|
-
{
|
539
|
-
if (sreq->inner) {
|
540
|
-
cleanup_negotiated(sreq->inner);
|
541
|
-
sreq->inner = NULL;
|
542
|
-
}
|
543
|
-
if (sreq->timer) {
|
544
|
-
lcbio_timer_destroy(sreq->timer);
|
545
|
-
sreq->timer = NULL;
|
546
|
-
}
|
547
|
-
if (sreq->ctx) {
|
548
|
-
lcbio_ctx_close(sreq->ctx, NULL, NULL);
|
549
|
-
sreq->ctx = NULL;
|
550
|
-
}
|
551
|
-
free(sreq);
|
552
|
-
}
|
553
|
-
|
554
|
-
void
|
555
|
-
mc_sessreq_cancel(mc_pSESSREQ sreq)
|
556
|
-
{
|
557
|
-
cleanup_pending(sreq);
|
558
|
-
}
|
559
|
-
|
560
|
-
mc_pSESSREQ
|
561
|
-
mc_sessreq_start(lcbio_SOCKET *sock, lcb_settings *settings,
|
562
|
-
uint32_t tmo, lcbio_CONNDONE_cb callback, void *data)
|
563
|
-
{
|
564
|
-
lcb_error_t err;
|
565
|
-
cbsasl_error_t saslerr;
|
566
|
-
protocol_binary_request_no_extras req;
|
567
|
-
const lcb_host_t *curhost;
|
568
|
-
struct lcbio_NAMEINFO nistrs;
|
569
|
-
mc_pSESSREQ sreq;
|
570
|
-
mc_pSESSINFO sasl;
|
571
|
-
lcbio_CTXPROCS procs;
|
572
|
-
|
573
|
-
if ((sreq = calloc(1, sizeof(*sreq))) == NULL) {
|
574
|
-
return NULL;
|
575
|
-
}
|
576
|
-
|
577
|
-
if ((sasl = calloc(1, sizeof(*sasl))) == NULL) {
|
578
|
-
cleanup_pending(sreq);
|
579
|
-
return NULL;
|
580
|
-
}
|
581
|
-
|
582
|
-
procs.cb_err = handle_ioerr;
|
583
|
-
procs.cb_read = handle_read;
|
584
|
-
|
585
|
-
lcbio_get_nameinfo(sock, &nistrs);
|
586
|
-
sreq->cb = callback;
|
587
|
-
sreq->data = data;
|
588
|
-
sreq->inner = sasl;
|
589
|
-
sreq->timer = lcbio_timer_new(sock->io, sreq, timeout_handler);
|
590
|
-
|
591
|
-
if ((err = lcbio_sslify_if_needed(sock, settings)) != LCB_SUCCESS) {
|
592
|
-
set_error_ex(sreq, err, "Couldn't initialize SSL on socket");
|
593
|
-
lcbio_async_signal(sreq->timer);
|
594
|
-
return sreq;
|
595
|
-
}
|
596
|
-
|
597
|
-
sreq->ctx = lcbio_ctx_new(sock, sreq, &procs);
|
598
|
-
sreq->ctx->subsys = "sasl";
|
599
|
-
|
600
|
-
if (tmo) {
|
601
|
-
lcbio_timer_rearm(sreq->timer, tmo);
|
602
|
-
}
|
603
|
-
|
604
|
-
sasl->base.id = LCBIO_PROTOCTX_SESSINFO;
|
605
|
-
sasl->base.dtor = (void (*)(struct lcbio_PROTOCTX *))cleanup_negotiated;
|
606
|
-
sasl->settings = settings;
|
607
|
-
|
608
|
-
err = setup_sasl_params(sasl);
|
609
|
-
if (err != LCB_SUCCESS) {
|
610
|
-
cleanup_pending(sreq);
|
611
|
-
return NULL;
|
612
|
-
}
|
613
|
-
|
614
|
-
|
615
|
-
curhost = lcbio_get_host(sock);
|
616
|
-
saslerr = cbsasl_client_new(
|
617
|
-
"couchbase", curhost->host, nistrs.local, nistrs.remote,
|
618
|
-
sasl->sasl_callbacks, 0, &sasl->sasl);
|
619
|
-
|
620
|
-
if (saslerr != SASL_OK) {
|
621
|
-
cleanup_pending(sreq);
|
622
|
-
return NULL;
|
623
|
-
}
|
624
|
-
|
625
|
-
memset(&req, 0, sizeof(req));
|
626
|
-
req.message.header.request.magic = PROTOCOL_BINARY_REQ;
|
627
|
-
req.message.header.request.opcode = PROTOCOL_BINARY_CMD_SASL_LIST_MECHS;
|
628
|
-
req.message.header.request.datatype = PROTOCOL_BINARY_RAW_BYTES;
|
629
|
-
req.message.header.request.bodylen = 0;
|
630
|
-
req.message.header.request.keylen = 0;
|
631
|
-
req.message.header.request.opaque = 0;
|
632
|
-
|
633
|
-
lcbio_ctx_put(sreq->ctx, req.bytes, sizeof(req.bytes));
|
634
|
-
LCBIO_CTX_RSCHEDULE(sreq->ctx, 24);
|
635
|
-
return sreq;
|
636
|
-
}
|
637
|
-
|
638
|
-
mc_pSESSINFO
|
639
|
-
mc_sess_get(lcbio_SOCKET *sock)
|
640
|
-
{
|
641
|
-
return (void *)lcbio_protoctx_get(sock, LCBIO_PROTOCTX_SESSINFO);
|
642
|
-
}
|
643
|
-
|
644
|
-
const char *
|
645
|
-
mc_sess_get_saslmech(mc_pSESSINFO info)
|
646
|
-
{
|
647
|
-
return info->mech;
|
648
|
-
}
|
649
|
-
|
650
|
-
int
|
651
|
-
mc_sess_chkfeature(mc_pSESSINFO info, lcb_U16 feature)
|
652
|
-
{
|
653
|
-
if (feature > MEMCACHED_TOTAL_HELLO_FEATURES) {
|
654
|
-
return 0;
|
655
|
-
}
|
656
|
-
return info->features[feature];
|
657
|
-
}
|