couchbase 3.0.0.alpha.3-universal-darwin-19 → 3.0.0.alpha.4-universal-darwin-19
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/.github/workflows/tests-6.0.3.yml +4 -1
- data/.github/workflows/tests-dev-preview.yml +4 -1
- data/.github/workflows/tests.yml +4 -1
- data/README.md +1 -1
- data/bin/check-cluster +31 -0
- data/bin/init-cluster +16 -4
- data/examples/analytics.rb +221 -0
- data/examples/managing_analytics_indexes.rb +72 -0
- data/examples/managing_view_indexes.rb +54 -0
- data/examples/search_with_consistency.rb +84 -0
- data/examples/view.rb +50 -0
- data/ext/.clang-tidy +1 -0
- data/ext/build_version.hxx.in +1 -1
- data/ext/couchbase/bucket.hxx +0 -1
- data/ext/couchbase/couchbase.cxx +1421 -55
- data/ext/couchbase/io/dns_client.hxx +215 -0
- data/ext/couchbase/io/dns_codec.hxx +207 -0
- data/ext/couchbase/io/dns_config.hxx +116 -0
- data/ext/couchbase/io/dns_message.hxx +558 -0
- data/ext/couchbase/io/http_session.hxx +16 -4
- data/ext/couchbase/io/mcbp_session.hxx +2 -1
- data/ext/couchbase/mutation_token.hxx +1 -1
- data/ext/couchbase/operations.hxx +19 -0
- data/ext/couchbase/operations/analytics_dataset_create.hxx +117 -0
- data/ext/couchbase/operations/analytics_dataset_drop.hxx +103 -0
- data/ext/couchbase/operations/analytics_dataset_get_all.hxx +107 -0
- data/ext/couchbase/operations/analytics_dataverse_create.hxx +104 -0
- data/ext/couchbase/operations/analytics_dataverse_drop.hxx +104 -0
- data/ext/couchbase/operations/analytics_get_pending_mutations.hxx +91 -0
- data/ext/couchbase/operations/analytics_index_create.hxx +128 -0
- data/ext/couchbase/operations/analytics_index_drop.hxx +110 -0
- data/ext/couchbase/operations/analytics_index_get_all.hxx +106 -0
- data/ext/couchbase/operations/analytics_link_connect.hxx +102 -0
- data/ext/couchbase/operations/analytics_link_disconnect.hxx +101 -0
- data/ext/couchbase/operations/design_document.hxx +59 -0
- data/ext/couchbase/operations/document_analytics.hxx +293 -0
- data/ext/couchbase/operations/document_query.hxx +2 -2
- data/ext/couchbase/operations/document_search.hxx +19 -1
- data/ext/couchbase/operations/document_view.hxx +227 -0
- data/ext/couchbase/operations/search_index.hxx +17 -0
- data/ext/couchbase/operations/search_index_control_ingest.hxx +3 -1
- data/ext/couchbase/operations/view_index_drop.hxx +67 -0
- data/ext/couchbase/operations/view_index_get.hxx +90 -0
- data/ext/couchbase/operations/view_index_get_all.hxx +125 -0
- data/ext/couchbase/operations/view_index_upsert.hxx +87 -0
- data/ext/couchbase/service_type.hxx +38 -1
- data/ext/couchbase/timeout_defaults.hxx +3 -1
- data/ext/couchbase/utils/connection_string.hxx +231 -0
- data/ext/couchbase/version.hxx +1 -1
- data/ext/test/main.cxx +3 -12
- data/lib/couchbase/analytics_options.rb +165 -0
- data/lib/couchbase/bucket.rb +49 -0
- data/lib/couchbase/cluster.rb +46 -207
- data/lib/couchbase/management/analytics_index_manager.rb +138 -24
- data/lib/couchbase/management/view_index_manager.rb +63 -10
- data/lib/couchbase/query_options.rb +219 -0
- data/lib/couchbase/search_options.rb +6 -6
- data/lib/couchbase/version.rb +1 -1
- data/lib/couchbase/view_options.rb +155 -0
- metadata +34 -2
@@ -0,0 +1,215 @@
|
|
1
|
+
/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
2
|
+
/*
|
3
|
+
* Copyright 2020 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
|
+
#pragma once
|
19
|
+
|
20
|
+
#include <memory>
|
21
|
+
#include <sstream>
|
22
|
+
|
23
|
+
#include <io/dns_codec.hxx>
|
24
|
+
#include <io/dns_config.hxx>
|
25
|
+
|
26
|
+
#include <asio/read.hpp>
|
27
|
+
|
28
|
+
namespace couchbase::io::dns
|
29
|
+
{
|
30
|
+
class dns_client
|
31
|
+
{
|
32
|
+
public:
|
33
|
+
struct dns_srv_response {
|
34
|
+
struct address {
|
35
|
+
std::string hostname;
|
36
|
+
std::uint16_t port;
|
37
|
+
};
|
38
|
+
std::error_code ec;
|
39
|
+
std::vector<address> targets{};
|
40
|
+
};
|
41
|
+
|
42
|
+
class dns_srv_command : public std::enable_shared_from_this<dns_srv_command>
|
43
|
+
{
|
44
|
+
public:
|
45
|
+
dns_srv_command(asio::io_context& ctx,
|
46
|
+
const std::string& name,
|
47
|
+
const std::string& service,
|
48
|
+
const asio::ip::address& address,
|
49
|
+
std::uint16_t port)
|
50
|
+
: deadline_(ctx)
|
51
|
+
, udp_(ctx)
|
52
|
+
, tcp_(ctx)
|
53
|
+
, address_(address)
|
54
|
+
, port_(port)
|
55
|
+
{
|
56
|
+
static std::string protocol{ "_tcp" };
|
57
|
+
dns_message request{};
|
58
|
+
question_record qr;
|
59
|
+
qr.klass = resource_class::in;
|
60
|
+
qr.type = resource_type::srv;
|
61
|
+
qr.name.labels.push_back(service);
|
62
|
+
qr.name.labels.push_back(protocol);
|
63
|
+
std::string label;
|
64
|
+
std::istringstream name_stream(name);
|
65
|
+
while (std::getline(name_stream, label, '.')) {
|
66
|
+
qr.name.labels.push_back(label);
|
67
|
+
}
|
68
|
+
request.questions.emplace_back(qr);
|
69
|
+
send_buf_ = dns_codec::encode(request);
|
70
|
+
}
|
71
|
+
|
72
|
+
template<class Handler>
|
73
|
+
void execute(std::chrono::milliseconds timeout, Handler&& handler)
|
74
|
+
{
|
75
|
+
asio::ip::udp::endpoint endpoint(address_, port_);
|
76
|
+
udp_.open(endpoint.protocol());
|
77
|
+
udp_.async_send_to(
|
78
|
+
asio::buffer(send_buf_),
|
79
|
+
endpoint,
|
80
|
+
[self = shared_from_this(), handler = std::forward<Handler>(handler)](std::error_code ec1,
|
81
|
+
std::size_t /* bytes_transferred */) mutable {
|
82
|
+
if (ec1 == asio::error::operation_aborted) {
|
83
|
+
self->deadline_.cancel();
|
84
|
+
return handler({ std::make_error_code(error::common_errc::ambiguous_timeout) });
|
85
|
+
}
|
86
|
+
if (ec1) {
|
87
|
+
self->deadline_.cancel();
|
88
|
+
return handler({ ec1 });
|
89
|
+
}
|
90
|
+
|
91
|
+
asio::ip::udp::endpoint sender_endpoint;
|
92
|
+
self->recv_buf_.resize(512);
|
93
|
+
self->udp_.async_receive_from(
|
94
|
+
asio::buffer(self->recv_buf_),
|
95
|
+
sender_endpoint,
|
96
|
+
[self, handler = std::forward<Handler>(handler)](std::error_code ec2, std::size_t bytes_transferred) mutable {
|
97
|
+
self->deadline_.cancel();
|
98
|
+
if (ec2) {
|
99
|
+
return handler({ ec2 });
|
100
|
+
}
|
101
|
+
self->recv_buf_.resize(bytes_transferred);
|
102
|
+
dns_message message = dns_codec::decode(self->recv_buf_);
|
103
|
+
if (message.header.flags.tc == truncation::yes) {
|
104
|
+
self->udp_.close();
|
105
|
+
return self->retry_with_tcp(std::forward<Handler>(handler));
|
106
|
+
}
|
107
|
+
dns_srv_response resp{ ec2 };
|
108
|
+
resp.targets.reserve(message.answers.size());
|
109
|
+
for (const auto& answer : message.answers) {
|
110
|
+
resp.targets.emplace_back(
|
111
|
+
dns_srv_response::address{ fmt::format("{}", fmt::join(answer.target.labels, ".")), answer.port });
|
112
|
+
}
|
113
|
+
return handler(resp);
|
114
|
+
});
|
115
|
+
});
|
116
|
+
deadline_.expires_after(timeout);
|
117
|
+
deadline_.async_wait([self = shared_from_this()](std::error_code ec) {
|
118
|
+
if (ec == asio::error::operation_aborted) {
|
119
|
+
return;
|
120
|
+
}
|
121
|
+
self->udp_.cancel();
|
122
|
+
self->tcp_.cancel();
|
123
|
+
});
|
124
|
+
}
|
125
|
+
|
126
|
+
private:
|
127
|
+
template<class Handler>
|
128
|
+
void retry_with_tcp(Handler&& handler)
|
129
|
+
{
|
130
|
+
asio::ip::tcp::no_delay no_delay(true);
|
131
|
+
std::error_code ignore_ec;
|
132
|
+
tcp_.set_option(no_delay, ignore_ec);
|
133
|
+
asio::ip::tcp::endpoint endpoint(address_, port_);
|
134
|
+
tcp_.async_connect(
|
135
|
+
endpoint, [self = shared_from_this(), handler = std::forward<Handler>(handler)](std::error_code ec1) mutable {
|
136
|
+
if (ec1) {
|
137
|
+
self->deadline_.cancel();
|
138
|
+
return handler({ ec1 });
|
139
|
+
}
|
140
|
+
auto send_size = static_cast<uint16_t>(self->send_buf_.size());
|
141
|
+
self->send_buf_.insert(self->send_buf_.begin(), std::uint8_t(send_size & 0xffU));
|
142
|
+
self->send_buf_.insert(self->send_buf_.begin(), std::uint8_t(send_size >> 8U));
|
143
|
+
asio::async_write(
|
144
|
+
self->tcp_,
|
145
|
+
asio::buffer(self->send_buf_),
|
146
|
+
[self, handler = std::forward<Handler>(handler)](std::error_code ec2, std::size_t /* bytes_transferred */) mutable {
|
147
|
+
if (ec2) {
|
148
|
+
self->deadline_.cancel();
|
149
|
+
if (ec2 == asio::error::operation_aborted) {
|
150
|
+
ec2 = std::make_error_code(error::common_errc::ambiguous_timeout);
|
151
|
+
}
|
152
|
+
return handler({ ec2 });
|
153
|
+
}
|
154
|
+
asio::async_read(self->tcp_,
|
155
|
+
asio::buffer(&self->recv_buf_size_, sizeof(self->recv_buf_size_)),
|
156
|
+
[self, handler = std::forward<Handler>(handler)](std::error_code ec3,
|
157
|
+
std::size_t /* bytes_transferred */) mutable {
|
158
|
+
if (ec3) {
|
159
|
+
self->deadline_.cancel();
|
160
|
+
return handler({ ec3 });
|
161
|
+
}
|
162
|
+
self->recv_buf_size_ = ntohs(self->recv_buf_size_);
|
163
|
+
self->recv_buf_.resize(self->recv_buf_size_);
|
164
|
+
asio::async_read(
|
165
|
+
self->tcp_,
|
166
|
+
asio::buffer(self->recv_buf_),
|
167
|
+
[self, handler = std::forward<Handler>(handler)](std::error_code ec4,
|
168
|
+
std::size_t bytes_transferred) mutable {
|
169
|
+
self->deadline_.cancel();
|
170
|
+
if (ec4) {
|
171
|
+
return handler({ ec4 });
|
172
|
+
}
|
173
|
+
self->recv_buf_.resize(bytes_transferred);
|
174
|
+
dns_message message = dns_codec::decode(self->recv_buf_);
|
175
|
+
dns_srv_response resp{ ec4 };
|
176
|
+
resp.targets.reserve(message.answers.size());
|
177
|
+
for (const auto& answer : message.answers) {
|
178
|
+
resp.targets.emplace_back(dns_srv_response::address{
|
179
|
+
fmt::format("{}", fmt::join(answer.target.labels, ".")), answer.port });
|
180
|
+
}
|
181
|
+
return handler(resp);
|
182
|
+
});
|
183
|
+
});
|
184
|
+
});
|
185
|
+
});
|
186
|
+
}
|
187
|
+
|
188
|
+
asio::steady_timer deadline_;
|
189
|
+
asio::ip::udp::socket udp_;
|
190
|
+
asio::ip::tcp::socket tcp_;
|
191
|
+
|
192
|
+
asio::ip::address address_;
|
193
|
+
std::uint16_t port_;
|
194
|
+
|
195
|
+
std::vector<uint8_t> send_buf_;
|
196
|
+
std::uint16_t recv_buf_size_{ 0 };
|
197
|
+
std::vector<uint8_t> recv_buf_;
|
198
|
+
};
|
199
|
+
|
200
|
+
explicit dns_client(asio::io_context& ctx)
|
201
|
+
: ctx_(ctx)
|
202
|
+
{
|
203
|
+
}
|
204
|
+
|
205
|
+
template<class Handler>
|
206
|
+
void query_srv(const std::string& name, const std::string& service, Handler&& handler)
|
207
|
+
{
|
208
|
+
dns_config& config = dns_config::get();
|
209
|
+
auto cmd = std::make_shared<dns_srv_command>(ctx_, name, service, config.address(), config.port());
|
210
|
+
cmd->execute(config.timeout(), std::forward<Handler>(handler));
|
211
|
+
}
|
212
|
+
|
213
|
+
asio::io_context& ctx_;
|
214
|
+
};
|
215
|
+
} // namespace couchbase::io::dns
|
@@ -0,0 +1,207 @@
|
|
1
|
+
/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
2
|
+
/*
|
3
|
+
* Copyright 2020 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
|
+
#pragma once
|
19
|
+
|
20
|
+
#include <cstring>
|
21
|
+
|
22
|
+
#include <arpa/inet.h>
|
23
|
+
|
24
|
+
#include <io/dns_message.hxx>
|
25
|
+
|
26
|
+
namespace couchbase::io::dns
|
27
|
+
{
|
28
|
+
class dns_codec
|
29
|
+
{
|
30
|
+
public:
|
31
|
+
static dns_message decode(const std::vector<uint8_t>& payload)
|
32
|
+
{
|
33
|
+
dns_message message{};
|
34
|
+
std::size_t offset = 0;
|
35
|
+
|
36
|
+
std::memcpy(&message.header.id, payload.data() + offset, sizeof(std::uint16_t));
|
37
|
+
offset += sizeof(std::uint16_t);
|
38
|
+
message.header.id = ntohs(message.header.id);
|
39
|
+
|
40
|
+
uint16_t flags = 0;
|
41
|
+
std::memcpy(&flags, payload.data() + offset, sizeof(std::uint16_t));
|
42
|
+
offset += sizeof(std::uint16_t);
|
43
|
+
message.header.flags.decode(ntohs(flags));
|
44
|
+
|
45
|
+
std::memcpy(&message.header.question_records, payload.data() + offset, sizeof(std::uint16_t));
|
46
|
+
offset += sizeof(std::uint16_t);
|
47
|
+
message.header.question_records = ntohs(message.header.question_records);
|
48
|
+
|
49
|
+
std::memcpy(&message.header.answer_records, payload.data() + offset, sizeof(std::uint16_t));
|
50
|
+
offset += sizeof(std::uint16_t);
|
51
|
+
message.header.answer_records = ntohs(message.header.answer_records);
|
52
|
+
|
53
|
+
std::memcpy(&message.header.authority_records, payload.data() + offset, sizeof(std::uint16_t));
|
54
|
+
offset += sizeof(std::uint16_t);
|
55
|
+
message.header.authority_records = ntohs(message.header.authority_records);
|
56
|
+
|
57
|
+
std::memcpy(&message.header.additional_records, payload.data() + offset, sizeof(std::uint16_t));
|
58
|
+
offset += sizeof(std::uint16_t);
|
59
|
+
message.header.additional_records = ntohs(message.header.additional_records);
|
60
|
+
|
61
|
+
for (std::uint16_t idx = 0; idx < message.header.question_records; ++idx) {
|
62
|
+
question_record qr;
|
63
|
+
qr.name = get_name(payload, offset);
|
64
|
+
|
65
|
+
std::uint16_t val = 0;
|
66
|
+
std::memcpy(&val, payload.data() + offset, sizeof(std::uint16_t));
|
67
|
+
offset += sizeof(std::uint16_t);
|
68
|
+
val = ntohs(val);
|
69
|
+
qr.type = static_cast<resource_type>(val);
|
70
|
+
|
71
|
+
std::memcpy(&val, payload.data() + offset, sizeof(std::uint16_t));
|
72
|
+
offset += sizeof(std::uint16_t);
|
73
|
+
val = ntohs(val);
|
74
|
+
qr.klass = static_cast<resource_class>(val);
|
75
|
+
|
76
|
+
message.questions.emplace_back(qr);
|
77
|
+
}
|
78
|
+
|
79
|
+
message.answers.reserve(message.header.answer_records);
|
80
|
+
for (std::uint16_t idx = 0; idx < message.header.answer_records; ++idx) {
|
81
|
+
srv_record ar;
|
82
|
+
ar.name = get_name(payload, offset);
|
83
|
+
|
84
|
+
std::uint16_t val = 0;
|
85
|
+
std::memcpy(&val, payload.data() + offset, sizeof(std::uint16_t));
|
86
|
+
offset += sizeof(std::uint16_t);
|
87
|
+
val = ntohs(val);
|
88
|
+
ar.type = static_cast<resource_type>(val);
|
89
|
+
|
90
|
+
std::memcpy(&val, payload.data() + offset, sizeof(std::uint16_t));
|
91
|
+
offset += sizeof(std::uint16_t);
|
92
|
+
val = ntohs(val);
|
93
|
+
ar.klass = static_cast<resource_class>(val);
|
94
|
+
|
95
|
+
std::memcpy(&ar.ttl, payload.data() + offset, sizeof(std::uint32_t));
|
96
|
+
offset += static_cast<std::uint16_t>(4U);
|
97
|
+
ar.ttl = ntohl(ar.ttl);
|
98
|
+
|
99
|
+
std::uint16_t size = 0;
|
100
|
+
std::memcpy(&size, payload.data() + offset, sizeof(std::uint16_t));
|
101
|
+
offset += sizeof(std::uint16_t);
|
102
|
+
size = ntohs(size);
|
103
|
+
|
104
|
+
if (ar.klass != resource_class::in || ar.type != resource_type::srv) {
|
105
|
+
// ignore everything except SRV answers
|
106
|
+
offset += size;
|
107
|
+
continue;
|
108
|
+
}
|
109
|
+
|
110
|
+
std::memcpy(&val, payload.data() + offset, sizeof(std::uint16_t));
|
111
|
+
offset += sizeof(std::uint16_t);
|
112
|
+
ar.priority = ntohs(val);
|
113
|
+
|
114
|
+
std::memcpy(&val, payload.data() + offset, sizeof(std::uint16_t));
|
115
|
+
offset += sizeof(std::uint16_t);
|
116
|
+
ar.weight = ntohs(val);
|
117
|
+
|
118
|
+
std::memcpy(&val, payload.data() + offset, sizeof(std::uint16_t));
|
119
|
+
offset += sizeof(std::uint16_t);
|
120
|
+
ar.port = ntohs(val);
|
121
|
+
|
122
|
+
ar.target = get_name(payload, offset);
|
123
|
+
|
124
|
+
message.answers.emplace_back(ar);
|
125
|
+
}
|
126
|
+
return message;
|
127
|
+
}
|
128
|
+
|
129
|
+
static std::vector<uint8_t> encode(const dns_message& message)
|
130
|
+
{
|
131
|
+
std::vector<std::uint8_t> payload;
|
132
|
+
payload.resize(message.request_size(), 0);
|
133
|
+
std::size_t offset = 0;
|
134
|
+
|
135
|
+
// write header
|
136
|
+
{
|
137
|
+
uint16_t val;
|
138
|
+
|
139
|
+
val = htons(message.header.id);
|
140
|
+
std::memcpy(payload.data() + offset, &val, sizeof(std::uint16_t));
|
141
|
+
offset += sizeof(std::uint16_t);
|
142
|
+
|
143
|
+
val = htons(message.header.flags.encode());
|
144
|
+
std::memcpy(payload.data() + offset, &val, sizeof(std::uint16_t));
|
145
|
+
offset += sizeof(std::uint16_t);
|
146
|
+
|
147
|
+
val = htons(static_cast<std::uint16_t>(message.questions.size()));
|
148
|
+
std::memcpy(payload.data() + offset, &val, sizeof(std::uint16_t));
|
149
|
+
offset += sizeof(std::uint16_t) + 3 * sizeof(std::uint16_t); // answer, authority, additional are all zeros
|
150
|
+
}
|
151
|
+
|
152
|
+
// write body
|
153
|
+
for (const auto& question : message.questions) {
|
154
|
+
for (const auto& label : question.name.labels) {
|
155
|
+
payload[offset] = static_cast<std::uint8_t>(label.size());
|
156
|
+
++offset;
|
157
|
+
std::memcpy(payload.data() + offset, label.data(), label.size());
|
158
|
+
offset += label.size();
|
159
|
+
}
|
160
|
+
payload[offset] = '\0';
|
161
|
+
++offset;
|
162
|
+
|
163
|
+
uint16_t val;
|
164
|
+
|
165
|
+
val = htons(static_cast<std::uint16_t>(question.type));
|
166
|
+
std::memcpy(payload.data() + offset, &val, sizeof(std::uint16_t));
|
167
|
+
offset += sizeof(std::uint16_t);
|
168
|
+
|
169
|
+
val = htons(static_cast<std::uint16_t>(question.klass));
|
170
|
+
std::memcpy(payload.data() + offset, &val, sizeof(std::uint16_t));
|
171
|
+
offset += sizeof(std::uint16_t);
|
172
|
+
}
|
173
|
+
return payload;
|
174
|
+
}
|
175
|
+
|
176
|
+
private:
|
177
|
+
static resource_name get_name(const std::vector<std::uint8_t>& payload, std::size_t& offset)
|
178
|
+
{
|
179
|
+
resource_name name{};
|
180
|
+
std::optional<std::size_t> save_offset{};
|
181
|
+
while (true) {
|
182
|
+
std::uint8_t len = payload[offset];
|
183
|
+
if (len == 0) {
|
184
|
+
offset += 1;
|
185
|
+
if (save_offset) {
|
186
|
+
// restore offset after pointer jump
|
187
|
+
offset = *save_offset;
|
188
|
+
}
|
189
|
+
return name;
|
190
|
+
}
|
191
|
+
if ((len & 0b1100'0000U) != 0) {
|
192
|
+
std::uint16_t ptr = 0;
|
193
|
+
std::memcpy(&ptr, payload.data() + offset, sizeof(std::uint16_t));
|
194
|
+
ptr = ntohs(ptr);
|
195
|
+
ptr &= 0b0011'1111'1111'1111U;
|
196
|
+
// store old offset and jump to pointer
|
197
|
+
save_offset = offset + sizeof(std::uint16_t);
|
198
|
+
offset = ptr;
|
199
|
+
} else {
|
200
|
+
std::string label(payload.data() + offset + 1, payload.data() + offset + 1 + len);
|
201
|
+
name.labels.emplace_back(label);
|
202
|
+
offset += static_cast<std::uint16_t>(1U + len);
|
203
|
+
}
|
204
|
+
}
|
205
|
+
}
|
206
|
+
};
|
207
|
+
} // namespace couchbase::io::dns
|
@@ -0,0 +1,116 @@
|
|
1
|
+
/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
2
|
+
/*
|
3
|
+
* Copyright 2020 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
|
+
#pragma once
|
19
|
+
|
20
|
+
#include <unistd.h>
|
21
|
+
|
22
|
+
#include <string>
|
23
|
+
#include <fstream>
|
24
|
+
|
25
|
+
#include <asio/ip/address.hpp>
|
26
|
+
|
27
|
+
#include <timeout_defaults.hxx>
|
28
|
+
|
29
|
+
namespace couchbase::io::dns
|
30
|
+
{
|
31
|
+
class dns_config
|
32
|
+
{
|
33
|
+
public:
|
34
|
+
static inline constexpr auto default_resolv_conf_path = "/etc/resolv.conf";
|
35
|
+
static inline constexpr auto default_host = "8.8.8.8";
|
36
|
+
static inline constexpr std::uint16_t default_port = 53;
|
37
|
+
|
38
|
+
[[nodiscard]] const asio::ip::address& address() const
|
39
|
+
{
|
40
|
+
return address_;
|
41
|
+
}
|
42
|
+
|
43
|
+
[[nodiscard]] std::uint16_t port() const
|
44
|
+
{
|
45
|
+
return port_;
|
46
|
+
}
|
47
|
+
|
48
|
+
[[nodiscard]] std::chrono::milliseconds timeout() const
|
49
|
+
{
|
50
|
+
return timeout_;
|
51
|
+
}
|
52
|
+
|
53
|
+
static dns_config& get()
|
54
|
+
{
|
55
|
+
static dns_config instance{};
|
56
|
+
|
57
|
+
instance.initialize();
|
58
|
+
|
59
|
+
return instance;
|
60
|
+
}
|
61
|
+
|
62
|
+
private:
|
63
|
+
void initialize()
|
64
|
+
{
|
65
|
+
if (!initialized_) {
|
66
|
+
load_resolv_conf(default_resolv_conf_path);
|
67
|
+
std::error_code ec;
|
68
|
+
address_ = asio::ip::address::from_string(host_, ec);
|
69
|
+
if (ec) {
|
70
|
+
host_ = default_host;
|
71
|
+
address_ = asio::ip::address::from_string(host_, ec);
|
72
|
+
}
|
73
|
+
initialized_ = true;
|
74
|
+
}
|
75
|
+
}
|
76
|
+
|
77
|
+
void load_resolv_conf(const char* conf_path)
|
78
|
+
{
|
79
|
+
if (access(conf_path, R_OK) == 0) {
|
80
|
+
std::ifstream conf(conf_path);
|
81
|
+
while (conf.good()) {
|
82
|
+
std::string line;
|
83
|
+
std::getline(conf, line);
|
84
|
+
if (line.empty()) {
|
85
|
+
continue;
|
86
|
+
}
|
87
|
+
std::size_t offset = 0;
|
88
|
+
while (line[offset] == ' ') {
|
89
|
+
++offset;
|
90
|
+
}
|
91
|
+
if (line[offset] == '#') {
|
92
|
+
continue;
|
93
|
+
}
|
94
|
+
std::size_t space = line.find(' ', offset);
|
95
|
+
if (space == std::string::npos || space == offset || line.size() < space + 2) {
|
96
|
+
continue;
|
97
|
+
}
|
98
|
+
std::string keyword = line.substr(offset, space);
|
99
|
+
if (keyword != "nameserver") {
|
100
|
+
continue;
|
101
|
+
}
|
102
|
+
offset = space + 1;
|
103
|
+
space = line.find(' ', offset);
|
104
|
+
host_ = line.substr(offset, space);
|
105
|
+
break;
|
106
|
+
}
|
107
|
+
}
|
108
|
+
}
|
109
|
+
|
110
|
+
std::atomic_bool initialized_{ false };
|
111
|
+
std::string host_{ default_host };
|
112
|
+
asio::ip::address address_{};
|
113
|
+
std::uint16_t port_{ default_port };
|
114
|
+
std::chrono::milliseconds timeout_{ timeout_defaults::dns_srv_timeout };
|
115
|
+
};
|
116
|
+
} // namespace couchbase::io::dns
|