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