1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
|
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "socket_spec.h"
#include <vespa/vespalib/util/stringfmt.h>
namespace vespalib {
namespace {
const vespalib::string tcp_prefix("tcp/");
const vespalib::string ipc_path_prefix("ipc/file:");
const vespalib::string ipc_name_prefix("ipc/name:");
const vespalib::string fallback_host("localhost");
SocketAddress make_address(const char *node, int port, bool server) {
if (server) {
return SocketAddress::select_local(port, node);
} else {
return SocketAddress::select_remote(port, node);
}
}
SocketAddress make_address(int port, bool server) {
const char *node = server ? nullptr : fallback_host.c_str();
return make_address(node, port, server);
}
} // namespace vespalib::<unnamed>
const vespalib::string SocketSpec::_empty;
SocketAddress
SocketSpec::address(bool server) const
{
switch (_type) {
case Type::PATH: return SocketAddress::from_path(_node);
case Type::NAME: return SocketAddress::from_name(_node);
case Type::HOST_PORT: return make_address(_node.c_str(), _port, server);
case Type::PORT: return make_address(_port, server);
case Type::INVALID: ;
}
return SocketAddress();
}
const SocketSpec SocketSpec::invalid;
SocketSpec::SocketSpec(const vespalib::string &spec)
: SocketSpec()
{
if (starts_with(spec, ipc_path_prefix)) {
_node = spec.substr(ipc_path_prefix.size());
_type = Type::PATH;
} else if (starts_with(spec, ipc_name_prefix)) {
_node = spec.substr(ipc_name_prefix.size());
_type = Type::NAME;
} else if (starts_with(spec, tcp_prefix)) {
bool with_host = (spec.find(':') != spec.npos);
const char *port_str = spec.c_str() + (with_host
? (spec.rfind(':') + 1)
: tcp_prefix.size());
int port = atoi(port_str);
if ((port > 0) || (strcmp(port_str, "0") == 0)) {
_port = port;
if (with_host) {
const char *host_str = spec.c_str() + tcp_prefix.size();
size_t host_str_len = (port_str - host_str) - 1;
if ((host_str_len >= 2)
&& (host_str[0] == '[')
&& (host_str[host_str_len - 1] == ']'))
{
++host_str;
host_str_len -= 2;
}
_node.assign(host_str, host_str_len);
_type = Type::HOST_PORT;
} else {
_type = Type::PORT;
}
}
}
if ((_type != Type::PORT) && _node.empty()) {
_type = Type::INVALID;
_port = -1;
}
}
vespalib::string
SocketSpec::spec() const
{
switch (_type) {
case Type::PATH: return make_string("ipc/file:%s", _node.c_str());
case Type::NAME: return make_string("ipc/name:%s", _node.c_str());
case Type::HOST_PORT:
if (_node.find(':') != _node.npos) {
return make_string("tcp/[%s]:%d", _node.c_str(), _port);
} else {
return make_string("tcp/%s:%d", _node.c_str(), _port);
}
case Type::PORT: return make_string("tcp/%d", _port);
case Type::INVALID: ;
}
return "invalid";
}
SocketSpec
SocketSpec::replace_host(const vespalib::string &new_host) const
{
if ((_type == Type::HOST_PORT) && !new_host.empty()) {
return from_host_port(new_host, _port);
}
return SocketSpec();
}
const vespalib::string &
SocketSpec::host_with_fallback() const
{
return (_type == Type::PORT) ? fallback_host : host();
}
} // namespace vespalib
|