couchbase 3.0.0.alpha.3-universal-darwin-19 → 3.0.0.alpha.4-universal-darwin-19
Sign up to get free protection for your applications and to get access to all the features.
- 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
|