libcouchbase 0.0.4 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- 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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f0c53dfe8623cf0faa99de16e9045f53fc67b218
|
4
|
+
data.tar.gz: 501f00181489330d8f2e13d6e5eaa252d0d52297
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 891511712ed931c40defe204d5604764af650e42224f8abd6c3992a87ab44482c66de3c863b313c92feeb3ccd85dc1df4a61b6fdc96270ebb7d9f3c534ee1bb4
|
7
|
+
data.tar.gz: 72ac448fffbd391bab23f7bbea809f3ecf8517e90b66282cf90e9f322df84e1402f2788ed40a1d5ffde95997321f38e616808cdf846f340841b191297dc58f62
|
@@ -8,7 +8,6 @@ SET(LCB_UTILS_SRC
|
|
8
8
|
src/strcodecs/base64.c
|
9
9
|
src/gethrtime.c
|
10
10
|
src/hashtable.c
|
11
|
-
src/hashset.c
|
12
11
|
src/list.c
|
13
12
|
src/logging.c
|
14
13
|
src/packetutils.c
|
@@ -47,7 +46,7 @@ SET(LCB_CORE_SRC
|
|
47
46
|
src/handler.c
|
48
47
|
src/getconfig.c
|
49
48
|
src/legacy.c
|
50
|
-
src/mcserver/negotiate.c
|
49
|
+
# src/mcserver/negotiate.c
|
51
50
|
src/mcserver/mcserver.c
|
52
51
|
src/newconfig.c
|
53
52
|
src/iofactory.c
|
@@ -70,4 +69,5 @@ SET(LCB_CORE_CXXSRC
|
|
70
69
|
src/n1ql/ixmgmt.cc
|
71
70
|
src/cbft.cc
|
72
71
|
src/operations/subdoc.cc
|
72
|
+
src/mcserver/negotiate.cc
|
73
73
|
src/cntl.cc)
|
@@ -133,6 +133,29 @@ extract_uint(const char *s, void *dest, char **errp)
|
|
133
133
|
return 0;
|
134
134
|
}
|
135
135
|
|
136
|
+
#ifdef ULLONG_MAX
|
137
|
+
static int
|
138
|
+
extract_ulonglong(const char *s, void *dest, char **errp)
|
139
|
+
{
|
140
|
+
unsigned long long value;
|
141
|
+
char *endptr = NULL;
|
142
|
+
#ifdef _WIN32
|
143
|
+
value = _strtoui64(s, &endptr, 10);
|
144
|
+
#else
|
145
|
+
value = strtoull(s, &endptr, 10);
|
146
|
+
#endif
|
147
|
+
_VERIFY_INT_COMMON(ULLONG_MAX, ULLONG_MAX);
|
148
|
+
*(unsigned long long *)dest = value;
|
149
|
+
return 0;
|
150
|
+
}
|
151
|
+
#else
|
152
|
+
static int extract_ulonglong(const char *s, void *dest, char **errp)
|
153
|
+
{
|
154
|
+
*errp = "long long not available";
|
155
|
+
return -1;
|
156
|
+
}
|
157
|
+
#endif /* ULLONG_MAX */
|
158
|
+
|
136
159
|
static int
|
137
160
|
extract_hex(const char *s, void *dest, char **errp)
|
138
161
|
{
|
@@ -224,8 +247,11 @@ parse_value(struct cliopts_priv *ctx,
|
|
224
247
|
exfn = extract_int;
|
225
248
|
} else if (entry->ktype == CLIOPTS_ARGT_UINT) {
|
226
249
|
exfn = extract_uint;
|
250
|
+
} else if (entry->ktype == CLIOPTS_ARGT_ULONGLONG) {
|
251
|
+
exfn = extract_ulonglong;
|
227
252
|
} else {
|
228
|
-
fprintf(stderr, "Unrecognized type %d
|
253
|
+
fprintf(stderr, "Unrecognized type %d.\n", entry->ktype);
|
254
|
+
return MODE_ERROR;
|
229
255
|
}
|
230
256
|
|
231
257
|
exret = exfn(value, entry->dest, &ctx->errstr);
|
@@ -582,6 +608,11 @@ print_help(struct cliopts_priv *ctx, struct cliopts_extra_settings *settings)
|
|
582
608
|
case CLIOPTS_ARGT_UINT:
|
583
609
|
fprintf(stderr, "%u", *(unsigned int*)cur->dest);
|
584
610
|
break;
|
611
|
+
#ifdef ULLONG_MAX
|
612
|
+
case CLIOPTS_ARGT_ULONGLONG:
|
613
|
+
fprintf(stderr, "%llu", *(unsigned long long*)cur->dest);
|
614
|
+
break;
|
615
|
+
#endif
|
585
616
|
case CLIOPTS_ARGT_NONE:
|
586
617
|
fprintf(stderr, "%s", *(int*)cur->dest ? "TRUE" : "FALSE");
|
587
618
|
break;
|
@@ -2,6 +2,7 @@
|
|
2
2
|
#define CLIOPTS_H_
|
3
3
|
|
4
4
|
#include <stddef.h> /* size_t */
|
5
|
+
#include <limits.h>
|
5
6
|
|
6
7
|
#ifdef __cplusplus
|
7
8
|
extern "C" {
|
@@ -28,6 +29,9 @@ typedef enum {
|
|
28
29
|
/** dest should be an unsigned int */
|
29
30
|
CLIOPTS_ARGT_UINT,
|
30
31
|
|
32
|
+
/** dest should be an unsigned long long */
|
33
|
+
CLIOPTS_ARGT_ULONGLONG,
|
34
|
+
|
31
35
|
/** dest should be an unsigned int, but command line format is hex */
|
32
36
|
CLIOPTS_ARGT_HEX,
|
33
37
|
|
@@ -341,6 +345,10 @@ typedef TOption<unsigned,
|
|
341
345
|
CLIOPTS_ARGT_UINT,
|
342
346
|
unsigned> UIntOption;
|
343
347
|
|
348
|
+
typedef TOption<unsigned long long,
|
349
|
+
CLIOPTS_ARGT_ULONGLONG,
|
350
|
+
unsigned long long> ULongLongOption;
|
351
|
+
|
344
352
|
typedef TOption<int,
|
345
353
|
CLIOPTS_ARGT_INT,
|
346
354
|
int> IntOption;
|
@@ -374,7 +382,7 @@ template<> inline void StringOption::doCopy(StringOption& other) {
|
|
374
382
|
innerVal = priv.c_str();
|
375
383
|
}
|
376
384
|
}
|
377
|
-
template<> inline const char* StringOption::createDefault() { return
|
385
|
+
template<> inline const char* StringOption::createDefault() { return ""; }
|
378
386
|
|
379
387
|
// LIST ROUTINES
|
380
388
|
template<> inline std::vector<std::string>& ListOption::const_result() {
|
@@ -18,8 +18,13 @@
|
|
18
18
|
#ifndef LCB_ASPEND_H
|
19
19
|
#define LCB_ASPEND_H
|
20
20
|
|
21
|
-
#
|
22
|
-
#include
|
21
|
+
#ifdef __cplusplus
|
22
|
+
#include <set>
|
23
|
+
typedef std::set<void*> lcb_ASPEND_SETTYPE;
|
24
|
+
#else
|
25
|
+
typedef void lcb_ASPEND_SETTYPE;
|
26
|
+
#endif
|
27
|
+
|
23
28
|
#ifdef __cplusplus
|
24
29
|
extern "C" {
|
25
30
|
#endif
|
@@ -48,9 +53,10 @@ typedef enum {
|
|
48
53
|
LCB_PENDTYPE_MAX
|
49
54
|
} lcb_ASPENDTYPE;
|
50
55
|
|
56
|
+
|
51
57
|
/** Items for pending operations */
|
52
58
|
typedef struct {
|
53
|
-
|
59
|
+
lcb_ASPEND_SETTYPE* items[LCB_PENDTYPE_MAX];
|
54
60
|
unsigned count;
|
55
61
|
} lcb_ASPEND;
|
56
62
|
|
@@ -87,13 +93,6 @@ void lcb_aspend_add(lcb_ASPEND *ops, lcb_ASPENDTYPE type, const void *item);
|
|
87
93
|
*/
|
88
94
|
void lcb_aspend_del(lcb_ASPEND *ops, lcb_ASPENDTYPE type, const void *item);
|
89
95
|
|
90
|
-
/**
|
91
|
-
* Get a queue for a given type
|
92
|
-
* @param ops
|
93
|
-
* @param type
|
94
|
-
*/
|
95
|
-
#define lcb_aspend_get(ops, type) (ops)->items[type]
|
96
|
-
|
97
96
|
/**
|
98
97
|
* Determine whether there are pending items in any of the queues
|
99
98
|
* @param ops
|
@@ -24,6 +24,15 @@
|
|
24
24
|
#include <vector>
|
25
25
|
#include <set>
|
26
26
|
|
27
|
+
#ifdef _MSC_VER
|
28
|
+
/*
|
29
|
+
* Disable DLL interface warning. This isn't an issue since this API is
|
30
|
+
* private anyway
|
31
|
+
*/
|
32
|
+
#pragma warning(push)
|
33
|
+
#pragma warning(disable : 4251)
|
34
|
+
#endif
|
35
|
+
|
27
36
|
namespace lcb {
|
28
37
|
struct Spechost {
|
29
38
|
Spechost() : port(0), type(0) {}
|
@@ -103,3 +112,7 @@ private:
|
|
103
112
|
#define LCB_SPECSCHEME_MCCOMPAT "memcached://"
|
104
113
|
} // namespace
|
105
114
|
#endif
|
115
|
+
|
116
|
+
#ifdef _MSC_VER
|
117
|
+
#pragma warning(pop)
|
118
|
+
#endif
|
@@ -380,8 +380,8 @@ lcb_error_t lcb_create(lcb_t *instance,
|
|
380
380
|
obj->http_sockpool->maxidle = 1;
|
381
381
|
obj->http_sockpool->tmoidle = 10000000;
|
382
382
|
obj->confmon = lcb_confmon_create(settings, obj->iotable);
|
383
|
-
obj->ht_nodes =
|
384
|
-
obj->mc_nodes =
|
383
|
+
obj->ht_nodes = new Hostlist();
|
384
|
+
obj->mc_nodes = new Hostlist();
|
385
385
|
obj->retryq = lcb_retryq_new(&obj->cmdq, obj->iotable, obj->settings);
|
386
386
|
obj->n1ql_cache = lcb_n1qlcache_create();
|
387
387
|
lcb_initialize_packet_handlers(obj);
|
@@ -438,52 +438,44 @@ void lcb_destroy(lcb_t instance)
|
|
438
438
|
{
|
439
439
|
#define DESTROY(fn,fld) if(instance->fld){fn(instance->fld);instance->fld=NULL;}
|
440
440
|
|
441
|
-
lcb_size_t ii;
|
442
|
-
hashset_t hs;
|
443
441
|
lcb_ASPEND *po = &instance->pendops;
|
442
|
+
lcb_ASPEND_SETTYPE::iterator it;
|
443
|
+
lcb_ASPEND_SETTYPE *pendq;
|
444
444
|
|
445
445
|
DESTROY(lcb_clconfig_decref, cur_configinfo);
|
446
446
|
instance->cmdq.config = NULL;
|
447
447
|
|
448
448
|
lcb_bootstrap_destroy(instance);
|
449
|
-
DESTROY(
|
450
|
-
DESTROY(
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
}
|
449
|
+
DESTROY(delete, ht_nodes);
|
450
|
+
DESTROY(delete, mc_nodes);
|
451
|
+
|
452
|
+
if ((pendq = po->items[LCB_PENDTYPE_TIMER])) {
|
453
|
+
for (it = pendq->begin(); it != pendq->end(); ++it) {
|
454
|
+
lcb__timer_destroy_nowarn(instance, (lcb_timer_t)*it);
|
456
455
|
}
|
457
456
|
}
|
458
457
|
|
459
|
-
if ((
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
if (dset_list) {
|
464
|
-
for (ii = 0; ii < nitems; ii++) {
|
465
|
-
lcbdur_destroy(dset_list[ii]);
|
466
|
-
}
|
467
|
-
free(dset_list);
|
458
|
+
if ((pendq = po->items[LCB_PENDTYPE_DURABILITY])) {
|
459
|
+
std::vector<void*> dsets(pendq->begin(), pendq->end());
|
460
|
+
for (size_t ii = 0; ii < dsets.size(); ++ii) {
|
461
|
+
lcbdur_destroy(reinterpret_cast<lcb_DURSET_st*>(dsets[ii]));
|
468
462
|
}
|
463
|
+
pendq->clear();
|
469
464
|
}
|
470
465
|
|
471
|
-
for (ii = 0; ii < LCBT_NSERVERS(instance); ++ii) {
|
466
|
+
for (size_t ii = 0; ii < LCBT_NSERVERS(instance); ++ii) {
|
472
467
|
mc_SERVER *server = LCBT_GET_SERVER(instance, ii);
|
473
468
|
mcserver_close(server);
|
474
469
|
}
|
475
470
|
|
476
|
-
if ((
|
477
|
-
for (
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
/* Prevents lcb's globals from being modified during destruction */
|
482
|
-
lcb_htreq_block_callback(htreq);
|
483
|
-
lcb_htreq_finish(instance, htreq, LCB_ERROR);
|
484
|
-
}
|
471
|
+
if ((pendq = po->items[LCB_PENDTYPE_HTTP])) {
|
472
|
+
for (it = pendq->begin(); it != pendq->end(); ++it) {
|
473
|
+
lcb_http_request_t htreq = reinterpret_cast<lcb_http_request_t>(*it);
|
474
|
+
lcb_htreq_block_callback(htreq);
|
475
|
+
lcb_htreq_finish(instance, htreq, LCB_ERROR);
|
485
476
|
}
|
486
477
|
}
|
478
|
+
|
487
479
|
DESTROY(lcb_retryq_destroy, retryq);
|
488
480
|
DESTROY(lcb_confmon_destroy, confmon);
|
489
481
|
DESTROY(lcbio_mgr_destroy, memd_sockpool);
|
@@ -579,7 +571,7 @@ lcb_aspend_init(lcb_ASPEND *ops)
|
|
579
571
|
{
|
580
572
|
unsigned ii;
|
581
573
|
for (ii = 0; ii < LCB_PENDTYPE_MAX; ++ii) {
|
582
|
-
ops->items[ii] =
|
574
|
+
ops->items[ii] = new lcb_ASPEND_SETTYPE();
|
583
575
|
}
|
584
576
|
ops->count = 0;
|
585
577
|
}
|
@@ -591,7 +583,7 @@ lcb_aspend_add(lcb_ASPEND *ops, lcb_ASPENDTYPE type, const void *item)
|
|
591
583
|
if (type == LCB_PENDTYPE_COUNTER) {
|
592
584
|
return;
|
593
585
|
}
|
594
|
-
|
586
|
+
ops->items[type]->insert(const_cast<void*>(item));
|
595
587
|
}
|
596
588
|
|
597
589
|
void
|
@@ -601,7 +593,7 @@ lcb_aspend_del(lcb_ASPEND *ops, lcb_ASPENDTYPE type, const void *item)
|
|
601
593
|
ops->count--;
|
602
594
|
return;
|
603
595
|
}
|
604
|
-
if (
|
596
|
+
if (ops->items[type]->erase(const_cast<void*>(item)) != 0) {
|
605
597
|
ops->count--;
|
606
598
|
}
|
607
599
|
}
|
@@ -611,7 +603,7 @@ lcb_aspend_cleanup(lcb_ASPEND *ops)
|
|
611
603
|
{
|
612
604
|
unsigned ii;
|
613
605
|
for (ii = 0; ii < LCB_PENDTYPE_MAX; ii++) {
|
614
|
-
|
606
|
+
delete ops->items[ii];
|
615
607
|
}
|
616
608
|
}
|
617
609
|
|
@@ -0,0 +1,617 @@
|
|
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 "mcserver.h"
|
20
|
+
#include "logging.h"
|
21
|
+
#include "settings.h"
|
22
|
+
#include <lcbio/lcbio.h>
|
23
|
+
#include <lcbio/timer-ng.h>
|
24
|
+
#include <lcbio/ssl.h>
|
25
|
+
#include <cbsasl/cbsasl.h>
|
26
|
+
#include "negotiate.h"
|
27
|
+
#include "ctx-log-inl.h"
|
28
|
+
|
29
|
+
#include <string>
|
30
|
+
#include <sstream>
|
31
|
+
#include <vector>
|
32
|
+
|
33
|
+
#define LOGARGS(ctx, lvl) ctx->sasl->settings, "negotiation", LCB_LOG_##lvl, __FILE__, __LINE__
|
34
|
+
static void cleanup_negotiated(mc_pSESSINFO info);
|
35
|
+
static void handle_ioerr(lcbio_CTX *ctx, lcb_error_t err);
|
36
|
+
static void handle_read(lcbio_CTX *ioctx, unsigned);
|
37
|
+
#define SESSREQ_LOGFMT "<%s:%s> (SASLREQ=%p) "
|
38
|
+
|
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
|
+
static void timeout_handler(void *arg);
|
71
|
+
|
72
|
+
#define SESSREQ_LOGID(s) get_ctx_host(s->ctx), get_ctx_port(s->ctx), (void*)s
|
73
|
+
|
74
|
+
static void
|
75
|
+
close_cb(lcbio_SOCKET *s, int reusable, void *arg)
|
76
|
+
{
|
77
|
+
*(lcbio_SOCKET **)arg = s;
|
78
|
+
lcbio_ref(s);
|
79
|
+
lcb_assert(reusable);
|
80
|
+
}
|
81
|
+
|
82
|
+
/**
|
83
|
+
* Structure used only for initialization. This is only used for the duration
|
84
|
+
* of the request for negotiation and is deleted once negotiation has
|
85
|
+
* completed (or failed).
|
86
|
+
*/
|
87
|
+
struct mc_SESSREQ {
|
88
|
+
static mc_SESSREQ *get(void *arg) {
|
89
|
+
return reinterpret_cast<mc_SESSREQ*>(arg);
|
90
|
+
}
|
91
|
+
|
92
|
+
void start(lcbio_SOCKET *sock, lcb_settings *settings);
|
93
|
+
bool send_hello();
|
94
|
+
bool send_step(const lcb::MemcachedResponse& packet);
|
95
|
+
bool read_hello(const lcb::MemcachedResponse& packet);
|
96
|
+
|
97
|
+
mc_SESSREQ(lcbio_CONNDONE_cb callback, void *data, uint32_t timeout,
|
98
|
+
lcbio_TABLE *iot)
|
99
|
+
: ctx(NULL), cb(callback), cbdata(data),
|
100
|
+
timer(lcbio_timer_new(iot, this, timeout_handler)),
|
101
|
+
last_err(LCB_SUCCESS), sasl(NULL) {
|
102
|
+
|
103
|
+
if (timeout) {
|
104
|
+
lcbio_timer_rearm(timer, timeout);
|
105
|
+
}
|
106
|
+
}
|
107
|
+
|
108
|
+
~mc_SESSREQ();
|
109
|
+
|
110
|
+
void cancel() {
|
111
|
+
cb = NULL;
|
112
|
+
delete this;
|
113
|
+
}
|
114
|
+
|
115
|
+
void fail() {
|
116
|
+
if (cb != NULL) {
|
117
|
+
cb(NULL, cbdata, last_err, 0);
|
118
|
+
cb = NULL;
|
119
|
+
}
|
120
|
+
delete this;
|
121
|
+
}
|
122
|
+
|
123
|
+
void fail(lcb_error_t error, const char *msg) {
|
124
|
+
set_error(error, msg);
|
125
|
+
fail();
|
126
|
+
}
|
127
|
+
|
128
|
+
void success() {
|
129
|
+
/** Dislodge the connection, and return it back to the caller */
|
130
|
+
lcbio_SOCKET *s;
|
131
|
+
|
132
|
+
lcbio_ctx_close(ctx, close_cb, &s);
|
133
|
+
ctx = NULL;
|
134
|
+
|
135
|
+
lcbio_protoctx_add(s, sasl);
|
136
|
+
sasl = NULL;
|
137
|
+
|
138
|
+
/** Invoke the callback, marking it a success */
|
139
|
+
cb(s, cbdata, LCB_SUCCESS, 0);
|
140
|
+
lcbio_unref(s);
|
141
|
+
|
142
|
+
delete this;
|
143
|
+
}
|
144
|
+
|
145
|
+
void set_error(lcb_error_t error, const char *msg = "") {
|
146
|
+
lcb_log(LOGARGS(this, ERR), SESSREQ_LOGFMT "Error: 0x%x, %s", SESSREQ_LOGID(this), error, msg);
|
147
|
+
if (last_err == LCB_SUCCESS) {
|
148
|
+
last_err = error;
|
149
|
+
}
|
150
|
+
}
|
151
|
+
|
152
|
+
bool has_error() const {
|
153
|
+
return last_err != LCB_SUCCESS;
|
154
|
+
}
|
155
|
+
|
156
|
+
lcbio_CTX *ctx;
|
157
|
+
lcbio_CONNDONE_cb cb;
|
158
|
+
void *cbdata;
|
159
|
+
lcbio_pTIMER timer;
|
160
|
+
lcb_error_t last_err;
|
161
|
+
mc_pSESSINFO sasl;
|
162
|
+
};
|
163
|
+
|
164
|
+
|
165
|
+
static int
|
166
|
+
sasl_get_username(void *context, int id, const char **result, unsigned int *len)
|
167
|
+
{
|
168
|
+
mc_SESSINFO *ctx = mc_SESSINFO::get(context);
|
169
|
+
const char *u = NULL, *p = NULL;
|
170
|
+
if (!context || !result || (id != CBSASL_CB_USER && id != CBSASL_CB_AUTHNAME)) {
|
171
|
+
return SASL_BADPARAM;
|
172
|
+
}
|
173
|
+
|
174
|
+
lcbauth_get_upass(ctx->settings->auth, &u, &p);
|
175
|
+
*result = u;
|
176
|
+
if (len) {
|
177
|
+
*len = (unsigned int)strlen(*result);
|
178
|
+
}
|
179
|
+
|
180
|
+
return SASL_OK;
|
181
|
+
}
|
182
|
+
|
183
|
+
static int
|
184
|
+
sasl_get_password(cbsasl_conn_t *conn, void *context, int id,
|
185
|
+
cbsasl_secret_t **psecret)
|
186
|
+
{
|
187
|
+
struct mc_SESSINFO *ctx = mc_SESSINFO::get(context);
|
188
|
+
if (!conn || ! psecret || id != CBSASL_CB_PASS || ctx == NULL) {
|
189
|
+
return SASL_BADPARAM;
|
190
|
+
}
|
191
|
+
|
192
|
+
*psecret = &ctx->u_auth.secret;
|
193
|
+
return SASL_OK;
|
194
|
+
}
|
195
|
+
|
196
|
+
mc_SESSINFO::mc_SESSINFO(lcb_settings *settings_)
|
197
|
+
{
|
198
|
+
sasl_client = NULL;
|
199
|
+
memset(&u_auth, 0, sizeof(u_auth));
|
200
|
+
|
201
|
+
lcbio_PROTOCTX::id = LCBIO_PROTOCTX_SESSINFO;
|
202
|
+
lcbio_PROTOCTX::dtor = (void (*)(struct lcbio_PROTOCTX *))cleanup_negotiated;
|
203
|
+
|
204
|
+
settings = settings_;
|
205
|
+
}
|
206
|
+
|
207
|
+
bool
|
208
|
+
mc_SESSINFO::setup(const lcbio_NAMEINFO& nistrs, const lcb_host_t& host,
|
209
|
+
const lcb::Authenticator& auth)
|
210
|
+
{
|
211
|
+
cbsasl_callback_t sasl_callbacks[4];
|
212
|
+
sasl_callbacks[0].id = CBSASL_CB_USER;
|
213
|
+
sasl_callbacks[0].proc = (int( *)(void)) &sasl_get_username;
|
214
|
+
|
215
|
+
sasl_callbacks[1].id = CBSASL_CB_AUTHNAME;
|
216
|
+
sasl_callbacks[1].proc = (int( *)(void)) &sasl_get_username;
|
217
|
+
|
218
|
+
sasl_callbacks[2].id = CBSASL_CB_PASS;
|
219
|
+
sasl_callbacks[2].proc = (int( *)(void)) &sasl_get_password;
|
220
|
+
|
221
|
+
sasl_callbacks[3].id = CBSASL_CB_LIST_END;
|
222
|
+
sasl_callbacks[3].proc = NULL;
|
223
|
+
sasl_callbacks[3].context = NULL;
|
224
|
+
|
225
|
+
for (size_t ii = 0; ii < 3; ii++) {
|
226
|
+
sasl_callbacks[ii].context = this;
|
227
|
+
}
|
228
|
+
|
229
|
+
const char *pass = NULL, *user = NULL;
|
230
|
+
lcbauth_get_upass(&auth, &user, &pass);
|
231
|
+
|
232
|
+
if (pass) {
|
233
|
+
unsigned long pwlen = (unsigned long)strlen(pass);
|
234
|
+
size_t maxlen = sizeof(u_auth.buffer) - offsetof(cbsasl_secret_t, data);
|
235
|
+
u_auth.secret.len = pwlen;
|
236
|
+
|
237
|
+
if (pwlen < maxlen) {
|
238
|
+
memcpy(u_auth.secret.data, pass, pwlen);
|
239
|
+
} else {
|
240
|
+
return false;
|
241
|
+
}
|
242
|
+
}
|
243
|
+
|
244
|
+
|
245
|
+
cbsasl_error_t saslerr = cbsasl_client_new(
|
246
|
+
"couchbase", host.host, nistrs.local, nistrs.remote,
|
247
|
+
sasl_callbacks, 0, &sasl_client);
|
248
|
+
return saslerr == SASL_OK;
|
249
|
+
}
|
250
|
+
|
251
|
+
static void
|
252
|
+
timeout_handler(void *arg)
|
253
|
+
{
|
254
|
+
mc_pSESSREQ sreq = mc_SESSREQ::get(arg);
|
255
|
+
sreq->fail(LCB_ETIMEDOUT, "Negotiation timed out");
|
256
|
+
}
|
257
|
+
|
258
|
+
/**
|
259
|
+
* Called to retrive the mechlist from the packet.
|
260
|
+
* @return 0 to continue authentication, 1 if no authentication needed, or
|
261
|
+
* -1 on error.
|
262
|
+
*/
|
263
|
+
static int
|
264
|
+
set_chosen_mech(mc_pSESSREQ sreq, std::string& mechlist,
|
265
|
+
const char **data, unsigned int *ndata)
|
266
|
+
{
|
267
|
+
cbsasl_error_t saslerr;
|
268
|
+
mc_pSESSINFO ctx = sreq->sasl;
|
269
|
+
|
270
|
+
if (ctx->settings->sasl_mech_force) {
|
271
|
+
char *forcemech = ctx->settings->sasl_mech_force;
|
272
|
+
if (mechlist.find(forcemech) == std::string::npos) {
|
273
|
+
/** Requested mechanism not found */
|
274
|
+
sreq->set_error(LCB_SASLMECH_UNAVAILABLE, mechlist.c_str());
|
275
|
+
return -1;
|
276
|
+
}
|
277
|
+
mechlist.assign(forcemech);
|
278
|
+
}
|
279
|
+
|
280
|
+
const char *chosenmech;
|
281
|
+
saslerr = cbsasl_client_start(ctx->sasl_client, mechlist.c_str(),
|
282
|
+
NULL, data, ndata, &chosenmech);
|
283
|
+
switch (saslerr) {
|
284
|
+
case SASL_OK:
|
285
|
+
ctx->mech.assign(chosenmech);
|
286
|
+
return 0;
|
287
|
+
case SASL_NOMECH:
|
288
|
+
lcb_log(LOGARGS(sreq, INFO), SESSREQ_LOGFMT "Server does not support SASL (no mechanisms supported)", SESSREQ_LOGID(sreq));
|
289
|
+
return 1;
|
290
|
+
break;
|
291
|
+
default:
|
292
|
+
lcb_log(LOGARGS(sreq, INFO), SESSREQ_LOGFMT "cbsasl_client_start returned %d", SESSREQ_LOGID(sreq), saslerr);
|
293
|
+
sreq->set_error(LCB_EINTERNAL, "Couldn't start SASL client");
|
294
|
+
return -1;
|
295
|
+
}
|
296
|
+
}
|
297
|
+
|
298
|
+
/**
|
299
|
+
* Given the specific mechanisms, send the auth packet to the server.
|
300
|
+
*/
|
301
|
+
static int
|
302
|
+
send_sasl_auth(mc_SESSREQ *pend, const char *sasl_data, unsigned ndata)
|
303
|
+
{
|
304
|
+
mc_pSESSINFO ctx = pend->sasl;
|
305
|
+
lcb::MemcachedRequest hdr(PROTOCOL_BINARY_CMD_SASL_AUTH);
|
306
|
+
hdr.sizes(0, ctx->mech.size(), ndata);
|
307
|
+
|
308
|
+
lcbio_ctx_put(pend->ctx, hdr.data(), hdr.size());
|
309
|
+
lcbio_ctx_put(pend->ctx, ctx->mech.c_str(), ctx->mech.size());
|
310
|
+
lcbio_ctx_put(pend->ctx, sasl_data, ndata);
|
311
|
+
lcbio_ctx_rwant(pend->ctx, 24);
|
312
|
+
return 0;
|
313
|
+
}
|
314
|
+
|
315
|
+
bool
|
316
|
+
mc_SESSREQ::send_step(const lcb::MemcachedResponse& packet)
|
317
|
+
{
|
318
|
+
cbsasl_error_t saslerr;
|
319
|
+
const char *step_data;
|
320
|
+
unsigned int ndata;
|
321
|
+
|
322
|
+
saslerr = cbsasl_client_step(sasl->sasl_client,
|
323
|
+
packet.body<const char*>(), packet.bodylen(), NULL, &step_data, &ndata);
|
324
|
+
|
325
|
+
if (saslerr != SASL_CONTINUE) {
|
326
|
+
set_error(LCB_EINTERNAL, "Unable to perform SASL STEP");
|
327
|
+
return false;
|
328
|
+
}
|
329
|
+
|
330
|
+
lcb::MemcachedRequest hdr(PROTOCOL_BINARY_CMD_SASL_STEP);
|
331
|
+
hdr.sizes(0, sasl->mech.size(), ndata);
|
332
|
+
lcbio_ctx_put(ctx, hdr.data(), hdr.size());
|
333
|
+
lcbio_ctx_put(ctx, sasl->mech.c_str(), sasl->mech.size());
|
334
|
+
lcbio_ctx_put(ctx, step_data, ndata);
|
335
|
+
lcbio_ctx_rwant(ctx, 24);
|
336
|
+
return true;
|
337
|
+
}
|
338
|
+
|
339
|
+
#define LCB_HELLO_DEFL_STRING "libcouchbase/" LCB_VERSION_STRING
|
340
|
+
#define LCB_HELLO_DEFL_LENGTH (sizeof(LCB_HELLO_DEFL_STRING)-1)
|
341
|
+
|
342
|
+
bool
|
343
|
+
mc_SESSREQ::send_hello()
|
344
|
+
{
|
345
|
+
const lcb_settings *settings = sasl->settings;
|
346
|
+
lcb_U16 features[MEMCACHED_TOTAL_HELLO_FEATURES];
|
347
|
+
|
348
|
+
unsigned nfeatures = 0;
|
349
|
+
features[nfeatures++] = PROTOCOL_BINARY_FEATURE_TLS;
|
350
|
+
if (settings->tcp_nodelay) {
|
351
|
+
features[nfeatures++] = PROTOCOL_BINARY_FEATURE_TCPNODELAY;
|
352
|
+
}
|
353
|
+
|
354
|
+
#ifndef LCB_NO_SNAPPY
|
355
|
+
if (settings->compressopts != LCB_COMPRESS_NONE) {
|
356
|
+
features[nfeatures++] = PROTOCOL_BINARY_FEATURE_DATATYPE;
|
357
|
+
}
|
358
|
+
#endif
|
359
|
+
|
360
|
+
if (settings->fetch_mutation_tokens) {
|
361
|
+
features[nfeatures++] = PROTOCOL_BINARY_FEATURE_MUTATION_SEQNO;
|
362
|
+
}
|
363
|
+
|
364
|
+
std::string client_string;
|
365
|
+
const char *clistr = LCB_HELLO_DEFL_STRING;
|
366
|
+
size_t nclistr = LCB_HELLO_DEFL_LENGTH;
|
367
|
+
|
368
|
+
if (settings->client_string) {
|
369
|
+
client_string.assign(LCB_HELLO_DEFL_STRING);
|
370
|
+
client_string += ", ";
|
371
|
+
client_string += settings->client_string;
|
372
|
+
|
373
|
+
clistr = client_string.c_str();
|
374
|
+
nclistr = client_string.size();
|
375
|
+
}
|
376
|
+
|
377
|
+
lcb::MemcachedRequest hdr(PROTOCOL_BINARY_CMD_HELLO);
|
378
|
+
hdr.sizes(0, nclistr, (sizeof features[0]) * nfeatures);
|
379
|
+
|
380
|
+
lcbio_ctx_put(ctx, hdr.data(), hdr.size());
|
381
|
+
lcbio_ctx_put(ctx, clistr, nclistr);
|
382
|
+
for (size_t ii = 0; ii < nfeatures; ii++) {
|
383
|
+
lcb_U16 tmp = htons(features[ii]);
|
384
|
+
lcbio_ctx_put(ctx, &tmp, sizeof tmp);
|
385
|
+
}
|
386
|
+
lcbio_ctx_rwant(ctx, 24);
|
387
|
+
return true;
|
388
|
+
}
|
389
|
+
|
390
|
+
bool
|
391
|
+
mc_SESSREQ::read_hello(const lcb::MemcachedResponse& resp)
|
392
|
+
{
|
393
|
+
/* some caps */
|
394
|
+
const char *cur;
|
395
|
+
const char *payload = resp.body<const char*>();
|
396
|
+
const char *limit = payload + resp.bodylen();
|
397
|
+
for (cur = payload; cur < limit; cur += 2) {
|
398
|
+
lcb_U16 tmp;
|
399
|
+
memcpy(&tmp, cur, sizeof(tmp));
|
400
|
+
tmp = ntohs(tmp);
|
401
|
+
lcb_log(LOGARGS(this, DEBUG), SESSREQ_LOGFMT "Found feature 0x%x (%s)", SESSREQ_LOGID(this), tmp, protocol_feature_2_text(tmp));
|
402
|
+
sasl->server_features.push_back(tmp);
|
403
|
+
}
|
404
|
+
return true;
|
405
|
+
}
|
406
|
+
|
407
|
+
typedef enum {
|
408
|
+
SREQ_S_WAIT,
|
409
|
+
SREQ_S_AUTHDONE,
|
410
|
+
SREQ_S_HELLODONE,
|
411
|
+
SREQ_S_ERROR
|
412
|
+
} sreq_STATE;
|
413
|
+
|
414
|
+
/**
|
415
|
+
* It's assumed the server buffers will be reset upon close(), so we must make
|
416
|
+
* sure to _not_ release the ringbuffer if that happens.
|
417
|
+
*/
|
418
|
+
static void
|
419
|
+
handle_read(lcbio_CTX *ioctx, unsigned)
|
420
|
+
{
|
421
|
+
mc_pSESSREQ sreq = mc_SESSREQ::get(lcbio_ctx_data(ioctx));
|
422
|
+
lcb::MemcachedResponse resp;
|
423
|
+
unsigned required;
|
424
|
+
sreq_STATE state = SREQ_S_WAIT;
|
425
|
+
|
426
|
+
GT_NEXT_PACKET:
|
427
|
+
|
428
|
+
if (!resp.load(ioctx, &required)) {
|
429
|
+
LCBIO_CTX_RSCHEDULE(ioctx, required);
|
430
|
+
return;
|
431
|
+
}
|
432
|
+
const uint16_t status = resp.status();
|
433
|
+
|
434
|
+
switch (resp.opcode()) {
|
435
|
+
case PROTOCOL_BINARY_CMD_SASL_LIST_MECHS: {
|
436
|
+
int mechrc;
|
437
|
+
const char *mechlist_data;
|
438
|
+
unsigned int nmechlist_data;
|
439
|
+
std::string mechs(resp.body<const char*>(), resp.bodylen());
|
440
|
+
|
441
|
+
mechrc = set_chosen_mech(sreq, mechs, &mechlist_data, &nmechlist_data);
|
442
|
+
if (mechrc == 0) {
|
443
|
+
if (0 == send_sasl_auth(sreq, mechlist_data, nmechlist_data)) {
|
444
|
+
state = SREQ_S_WAIT;
|
445
|
+
} else {
|
446
|
+
state = SREQ_S_ERROR;
|
447
|
+
}
|
448
|
+
|
449
|
+
} else if (mechrc < 0) {
|
450
|
+
state = SREQ_S_ERROR;
|
451
|
+
} else {
|
452
|
+
state = SREQ_S_HELLODONE;
|
453
|
+
}
|
454
|
+
break;
|
455
|
+
}
|
456
|
+
|
457
|
+
case PROTOCOL_BINARY_CMD_SASL_AUTH: {
|
458
|
+
if (status == PROTOCOL_BINARY_RESPONSE_SUCCESS) {
|
459
|
+
sreq->send_hello();
|
460
|
+
state = SREQ_S_AUTHDONE;
|
461
|
+
break;
|
462
|
+
}
|
463
|
+
|
464
|
+
if (status != PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE) {
|
465
|
+
sreq->set_error(LCB_AUTH_ERROR, "SASL AUTH failed");
|
466
|
+
state = SREQ_S_ERROR;
|
467
|
+
break;
|
468
|
+
}
|
469
|
+
if (sreq->send_step(resp) && sreq->send_hello()) {
|
470
|
+
state = SREQ_S_WAIT;
|
471
|
+
} else {
|
472
|
+
state = SREQ_S_ERROR;
|
473
|
+
}
|
474
|
+
break;
|
475
|
+
}
|
476
|
+
|
477
|
+
case PROTOCOL_BINARY_CMD_SASL_STEP: {
|
478
|
+
if (status != PROTOCOL_BINARY_RESPONSE_SUCCESS) {
|
479
|
+
lcb_log(LOGARGS(sreq, WARN), SESSREQ_LOGFMT "SASL auth failed with STATUS=0x%x", SESSREQ_LOGID(sreq), status);
|
480
|
+
sreq->set_error(LCB_AUTH_ERROR, "SASL Step Failed");
|
481
|
+
state = SREQ_S_ERROR;
|
482
|
+
} else {
|
483
|
+
/* Wait for pipelined HELLO response */
|
484
|
+
state = SREQ_S_AUTHDONE;
|
485
|
+
}
|
486
|
+
break;
|
487
|
+
}
|
488
|
+
|
489
|
+
case PROTOCOL_BINARY_CMD_HELLO: {
|
490
|
+
state = SREQ_S_HELLODONE;
|
491
|
+
if (status == PROTOCOL_BINARY_RESPONSE_SUCCESS) {
|
492
|
+
if (!sreq->read_hello(resp)) {
|
493
|
+
sreq->set_error(LCB_PROTOCOL_ERROR, "Couldn't parse HELLO");
|
494
|
+
}
|
495
|
+
} else if (status == PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND ||
|
496
|
+
status == PROTOCOL_BINARY_RESPONSE_NOT_SUPPORTED) {
|
497
|
+
lcb_log(LOGARGS(sreq, DEBUG), SESSREQ_LOGFMT "Server does not support HELLO", SESSREQ_LOGID(sreq));
|
498
|
+
/* nothing */
|
499
|
+
} else {
|
500
|
+
sreq->set_error(LCB_PROTOCOL_ERROR, "Hello response unexpected");
|
501
|
+
state = SREQ_S_ERROR;
|
502
|
+
}
|
503
|
+
break;
|
504
|
+
}
|
505
|
+
|
506
|
+
default: {
|
507
|
+
state = SREQ_S_ERROR;
|
508
|
+
lcb_log(LOGARGS(sreq, ERROR), SESSREQ_LOGFMT "Received unknown response. OP=0x%x. RC=0x%x", SESSREQ_LOGID(sreq), resp.opcode(), resp.status());
|
509
|
+
sreq->set_error(LCB_NOT_SUPPORTED, "Received unknown response");
|
510
|
+
break;
|
511
|
+
}
|
512
|
+
}
|
513
|
+
|
514
|
+
// We need to release the packet's buffers before actually destroying the
|
515
|
+
// underlying socket and/or buffers!
|
516
|
+
resp.release(ioctx);
|
517
|
+
|
518
|
+
// Once there is no more any dependencies on the buffers, we can succeed
|
519
|
+
// or fail the request, potentially destroying the underlying connection
|
520
|
+
if (sreq->has_error()) {
|
521
|
+
sreq->fail();
|
522
|
+
} else if (state == SREQ_S_ERROR) {
|
523
|
+
sreq->fail(LCB_ERROR, "FIXME: Error code set without description");
|
524
|
+
} else if (state == SREQ_S_HELLODONE) {
|
525
|
+
sreq->success();
|
526
|
+
} else {
|
527
|
+
goto GT_NEXT_PACKET;
|
528
|
+
}
|
529
|
+
}
|
530
|
+
|
531
|
+
static void
|
532
|
+
handle_ioerr(lcbio_CTX *ctx, lcb_error_t err)
|
533
|
+
{
|
534
|
+
mc_pSESSREQ sreq = mc_SESSREQ::get(lcbio_ctx_data(ctx));
|
535
|
+
sreq->fail(err, "IO Error");
|
536
|
+
}
|
537
|
+
|
538
|
+
static void cleanup_negotiated(mc_pSESSINFO ctx) {
|
539
|
+
delete ctx;
|
540
|
+
}
|
541
|
+
|
542
|
+
void
|
543
|
+
mc_SESSREQ::start(lcbio_SOCKET *sock, lcb_settings *settings) {
|
544
|
+
sasl = new mc_SESSINFO(settings);
|
545
|
+
|
546
|
+
lcb_error_t err = lcbio_sslify_if_needed(sock, settings);
|
547
|
+
if (err != LCB_SUCCESS) {
|
548
|
+
set_error(err, "Couldn't initialized SSL on socket");
|
549
|
+
lcbio_async_signal(timer);
|
550
|
+
return;
|
551
|
+
}
|
552
|
+
|
553
|
+
lcbio_CTXPROCS procs;
|
554
|
+
procs.cb_err = handle_ioerr;
|
555
|
+
procs.cb_read = handle_read;
|
556
|
+
ctx = lcbio_ctx_new(sock, this, &procs);
|
557
|
+
ctx->subsys = "sasl";
|
558
|
+
|
559
|
+
const lcb_host_t *curhost = lcbio_get_host(sock);
|
560
|
+
struct lcbio_NAMEINFO nistrs;
|
561
|
+
lcbio_get_nameinfo(sock, &nistrs);
|
562
|
+
|
563
|
+
if (!sasl->setup(nistrs, *curhost, *settings->auth)) {
|
564
|
+
set_error(LCB_EINTERNAL, "Couldn't start SASL client");
|
565
|
+
lcbio_async_signal(timer);
|
566
|
+
return;
|
567
|
+
}
|
568
|
+
|
569
|
+
lcb::MemcachedRequest hdr(PROTOCOL_BINARY_CMD_SASL_LIST_MECHS);
|
570
|
+
lcbio_ctx_put(ctx, hdr.data(), hdr.size());
|
571
|
+
LCBIO_CTX_RSCHEDULE(ctx, 24);
|
572
|
+
}
|
573
|
+
|
574
|
+
|
575
|
+
mc_SESSREQ::~mc_SESSREQ()
|
576
|
+
{
|
577
|
+
if (sasl) {
|
578
|
+
delete sasl;
|
579
|
+
}
|
580
|
+
if (timer) {
|
581
|
+
lcbio_timer_destroy(timer);
|
582
|
+
}
|
583
|
+
if (ctx) {
|
584
|
+
lcbio_ctx_close(ctx, NULL, NULL);
|
585
|
+
}
|
586
|
+
}
|
587
|
+
|
588
|
+
void mc_sessreq_cancel(mc_pSESSREQ sreq) {
|
589
|
+
sreq->cancel();
|
590
|
+
}
|
591
|
+
|
592
|
+
mc_pSESSREQ
|
593
|
+
mc_sessreq_start(lcbio_SOCKET *sock, lcb_settings *settings,
|
594
|
+
uint32_t tmo, lcbio_CONNDONE_cb callback, void *data)
|
595
|
+
{
|
596
|
+
mc_pSESSREQ sreq = new mc_SESSREQ(callback, data, tmo, sock->io);
|
597
|
+
sreq->start(sock, settings);
|
598
|
+
return sreq;
|
599
|
+
}
|
600
|
+
|
601
|
+
mc_pSESSINFO mc_sess_get(lcbio_SOCKET *sock) {
|
602
|
+
return static_cast<mc_pSESSINFO>(
|
603
|
+
lcbio_protoctx_get(sock, LCBIO_PROTOCTX_SESSINFO));
|
604
|
+
}
|
605
|
+
|
606
|
+
const char *mc_sess_get_saslmech(mc_pSESSINFO info) {
|
607
|
+
return info->mech.c_str();
|
608
|
+
}
|
609
|
+
|
610
|
+
int mc_sess_chkfeature(mc_pSESSINFO info, uint16_t feature) {
|
611
|
+
for (size_t ii = 0; ii < info->server_features.size(); ++ii) {
|
612
|
+
if (info->server_features[ii] == feature) {
|
613
|
+
return 1;
|
614
|
+
}
|
615
|
+
}
|
616
|
+
return 0;
|
617
|
+
}
|