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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 15b9827bbd26ee170b40f83be4fa35578ef0a56f
4
- data.tar.gz: 531475c5c64ddb29d3358c531b653ab9def8aa7f
3
+ metadata.gz: f0c53dfe8623cf0faa99de16e9045f53fc67b218
4
+ data.tar.gz: 501f00181489330d8f2e13d6e5eaa252d0d52297
5
5
  SHA512:
6
- metadata.gz: c39feb21629a9313571375e2f26586547a0786c0c097a737058926df9e6525697103118fb342c05b2af5dc41a919ebc3a8ac7926a573b3baa7f128eed2ff5bb7
7
- data.tar.gz: e8b00748522a53cfcbc18ad6d8cae6f6c18bf8a220fe2096ce4e0f823b93f6af891b51acd96cede8d88fbbb02171cb90bc1eb508fb9b1c20f7804b932245b836
6
+ metadata.gz: 891511712ed931c40defe204d5604764af650e42224f8abd6c3992a87ab44482c66de3c863b313c92feeb3ccd85dc1df4a61b6fdc96270ebb7d9f3c534ee1bb4
7
+ data.tar.gz: 72ac448fffbd391bab23f7bbea809f3ecf8517e90b66282cf90e9f322df84e1402f2788ed40a1d5ffde95997321f38e616808cdf846f340841b191297dc58f62
@@ -63,6 +63,7 @@ list2args(LCB_GNUC_CXX_WARNINGS)
63
63
 
64
64
  #MSVC-specific flags for C/C++
65
65
  LIST(APPEND LCB_CL_CPPFLAGS /nologo /W3 /MP /EHsc)
66
+ LIST(APPEND LCB_CL_CPPFLAGS /wd4800 /wd4244 /wd4267)
66
67
  list2args(LCB_CL_CPPFLAGS)
67
68
 
68
69
  # Common flags for DEBUG
@@ -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. Abort.\n", entry->ktype);
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 NULL; }
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
- #include "config.h"
22
- #include "hashset.h"
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
- hashset_t items[LCB_PENDTYPE_MAX];
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 = hostlist_create();
384
- obj->mc_nodes = hostlist_create();
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(hostlist_destroy, ht_nodes);
450
- DESTROY(hostlist_destroy, mc_nodes);
451
- if ((hs = lcb_aspend_get(po, LCB_PENDTYPE_TIMER))) {
452
- for (ii = 0; ii < hs->capacity; ++ii) {
453
- if (hs->items[ii] > 1) {
454
- lcb__timer_destroy_nowarn(instance, (lcb_timer_t)hs->items[ii]);
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 ((hs = lcb_aspend_get(po, LCB_PENDTYPE_DURABILITY))) {
460
- struct lcb_DURSET_st **dset_list;
461
- lcb_size_t nitems = hashset_num_items(hs);
462
- dset_list = (struct lcb_DURSET_st **)hashset_get_items(hs, NULL);
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 ((hs = lcb_aspend_get(po, LCB_PENDTYPE_HTTP))) {
477
- for (ii = 0; ii < hs->capacity; ++ii) {
478
- if (hs->items[ii] > 1) {
479
- lcb_http_request_t htreq = (lcb_http_request_t)hs->items[ii];
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] = hashset_create();
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
- hashset_add(ops->items[type], (void *)item);
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 (hashset_remove(ops->items[type], (void *)item)) {
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
- hashset_destroy(ops->items[ii]);
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
+ }