2 Copyright (c) 2018-2019 Nokia.
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
8 http://www.apache.org/licenses/LICENSE-2.0
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
17 #include "private/hostandport.hpp"
20 #include <netinet/in.h>
21 #include <arpa/inet.h>
22 #include <boost/lexical_cast.hpp>
25 using namespace shareddatalayer;
29 uint16_t stringToPort(const std::string& port)
32 throw HostAndPort::EmptyPort();
35 return htons(boost::lexical_cast<uint16_t>(port));
37 catch (const boost::bad_lexical_cast&)
40 servent resultbuf = { };
41 servent *result(nullptr);
42 getservbyname_r(port.c_str(), nullptr, &resultbuf, buf, sizeof(buf), &result);
43 if (result == nullptr)
44 throw HostAndPort::InvalidPort(port);
45 return static_cast<uint16_t>(result->s_port);
49 bool isInBrackets(const std::string& str)
51 return ((!str.empty()) && (str.front() == '[') && (str.back() == ']'));
54 std::string removeBrackets(const std::string& str)
56 return str.substr(1U, str.size() - 2U);
59 bool isLiteralIPv6(const std::string& str)
62 return inet_pton(AF_INET6, str.c_str(), &tmp) == 1;
65 std::string buildInvalidPortError(const std::string& port)
67 std::ostringstream os;
68 os << "invalid port: " << port;
73 HostAndPort::InvalidPort::InvalidPort(const std::string& port):
74 Exception(buildInvalidPortError(port))
78 HostAndPort::EmptyPort::EmptyPort():
79 Exception("empty port")
83 HostAndPort::EmptyHost::EmptyHost():
84 Exception("empty host")
88 HostAndPort::HostAndPort(const std::string& addressAndOptionalPort, uint16_t defaultPort)
90 if (isInBrackets(addressAndOptionalPort))
91 parse(removeBrackets(addressAndOptionalPort), defaultPort);
93 parse(addressAndOptionalPort, defaultPort);
96 void HostAndPort::parse(const std::string& addressAndOptionalPort, uint16_t defaultPort)
98 const auto pos(addressAndOptionalPort.rfind(':'));
99 if (pos == std::string::npos)
101 host = addressAndOptionalPort;
105 else if (isLiteralIPv6(addressAndOptionalPort))
107 host = addressAndOptionalPort;
113 host = addressAndOptionalPort.substr(0, pos);
114 if (isInBrackets(host))
115 host = removeBrackets(host);
116 literalIPv6 = isLiteralIPv6(host);
117 port = stringToPort(addressAndOptionalPort.substr(pos + 1U, addressAndOptionalPort.size() - pos - 1U));
123 const std::string& HostAndPort::getHost() const
128 uint16_t HostAndPort::getPort() const
133 std::string HostAndPort::getString() const
135 std::ostringstream os;
137 os << '[' << host << "]:" << ntohs(port);
139 os << host << ':' << ntohs(port);
143 bool HostAndPort::operator==(const HostAndPort& hp) const
145 return this->getPort() == hp.getPort() && this->getHost() == hp.getHost();
148 bool HostAndPort::operator!=(const HostAndPort& hp) const
150 return !(hp == *this);
153 bool HostAndPort::operator<(const HostAndPort& hp) const
155 if (this->getHost() == hp.getHost())
156 return this->getPort() < hp.getPort();
158 return this->getHost() < hp.getHost();
161 std::ostream& shareddatalayer::operator << (std::ostream& os, const HostAndPort& hostAndPort)
163 os << hostAndPort.getHost() << ":" << hostAndPort.getPort();