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>
24 using namespace shareddatalayer;
28 uint16_t stringToPort(const std::string& port)
31 throw HostAndPort::EmptyPort();
34 return htons(boost::lexical_cast<uint16_t>(port));
36 catch (const boost::bad_lexical_cast&)
39 servent resultbuf = { };
40 servent *result(nullptr);
41 getservbyname_r(port.c_str(), nullptr, &resultbuf, buf, sizeof(buf), &result);
42 if (result == nullptr)
43 throw HostAndPort::InvalidPort(port);
44 return static_cast<uint16_t>(result->s_port);
48 bool isInBrackets(const std::string& str)
50 return ((!str.empty()) && (str.front() == '[') && (str.back() == ']'));
53 std::string removeBrackets(const std::string& str)
55 return str.substr(1U, str.size() - 2U);
58 bool isLiteralIPv6(const std::string& str)
61 return inet_pton(AF_INET6, str.c_str(), &tmp) == 1;
64 std::string buildInvalidPortError(const std::string& port)
66 std::ostringstream os;
67 os << "invalid port: " << port;
72 HostAndPort::InvalidPort::InvalidPort(const std::string& port):
73 Exception(buildInvalidPortError(port))
77 HostAndPort::EmptyPort::EmptyPort():
78 Exception("empty port")
82 HostAndPort::EmptyHost::EmptyHost():
83 Exception("empty host")
87 HostAndPort::HostAndPort(const std::string& addressAndOptionalPort, uint16_t defaultPort)
89 if (isInBrackets(addressAndOptionalPort))
90 parse(removeBrackets(addressAndOptionalPort), defaultPort);
92 parse(addressAndOptionalPort, defaultPort);
95 void HostAndPort::parse(const std::string& addressAndOptionalPort, uint16_t defaultPort)
97 const auto pos(addressAndOptionalPort.rfind(':'));
98 if (pos == std::string::npos)
100 host = addressAndOptionalPort;
104 else if (isLiteralIPv6(addressAndOptionalPort))
106 host = addressAndOptionalPort;
112 host = addressAndOptionalPort.substr(0, pos);
113 if (isInBrackets(host))
114 host = removeBrackets(host);
115 literalIPv6 = isLiteralIPv6(host);
116 port = stringToPort(addressAndOptionalPort.substr(pos + 1U, addressAndOptionalPort.size() - pos - 1U));
122 const std::string& HostAndPort::getHost() const
127 uint16_t HostAndPort::getPort() const
132 std::string HostAndPort::getString() const
134 std::ostringstream os;
136 os << '[' << host << "]:" << ntohs(port);
138 os << host << ':' << ntohs(port);
142 bool HostAndPort::operator==(const HostAndPort& hp) const
144 return this->getPort() == hp.getPort() && this->getHost() == hp.getHost();
147 bool HostAndPort::operator!=(const HostAndPort& hp) const
149 return !(hp == *this);
152 bool HostAndPort::operator<(const HostAndPort& hp) const
154 if (this->getHost() == hp.getHost())
155 return this->getPort() < hp.getPort();
157 return this->getHost() < hp.getHost();