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
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
|
+
}
|