RIC:1060: Change in PTL
[ric-plt/sdl.git] / src / hostandport.cpp
1 /*
2    Copyright (c) 2018-2019 Nokia.
3
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
7
8        http://www.apache.org/licenses/LICENSE-2.0
9
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.
15 */
16
17 /*
18  * This source code is part of the near-RT RIC (RAN Intelligent Controller)
19  * platform project (RICP).
20 */
21
22 #include "private/hostandport.hpp"
23 #include <sstream>
24 #include <netdb.h>
25 #include <netinet/in.h>
26 #include <arpa/inet.h>
27 #include <boost/lexical_cast.hpp>
28 #include <ostream>
29
30 using namespace shareddatalayer;
31
32 namespace
33 {
34     uint16_t stringToPort(const std::string& port)
35     {
36         if (port.empty())
37             throw HostAndPort::EmptyPort();
38         try
39         {
40             return htons(boost::lexical_cast<uint16_t>(port));
41         }
42         catch (const boost::bad_lexical_cast&)
43         {
44             char buf[1024];
45             servent resultbuf = { };
46             servent *result(nullptr);
47             getservbyname_r(port.c_str(), nullptr, &resultbuf, buf, sizeof(buf), &result);
48             if (result == nullptr)
49                 throw HostAndPort::InvalidPort(port);
50             return static_cast<uint16_t>(result->s_port);
51         }
52     }
53
54     bool isInBrackets(const std::string& str)
55     {
56         return ((!str.empty()) && (str.front() == '[') && (str.back() == ']'));
57     }
58
59     std::string removeBrackets(const std::string& str)
60     {
61         return str.substr(1U, str.size() - 2U);
62     }
63
64     bool isLiteralIPv6(const std::string& str)
65     {
66         in6_addr tmp;
67         return inet_pton(AF_INET6, str.c_str(), &tmp) == 1;
68     }
69
70     std::string buildInvalidPortError(const std::string& port)
71     {
72         std::ostringstream os;
73         os << "invalid port: " << port;
74         return os.str();
75     }
76 }
77
78 HostAndPort::InvalidPort::InvalidPort(const std::string& port):
79     Exception(buildInvalidPortError(port))
80 {
81 }
82
83 HostAndPort::EmptyPort::EmptyPort():
84     Exception("empty port")
85 {
86 }
87
88 HostAndPort::EmptyHost::EmptyHost():
89     Exception("empty host")
90 {
91 }
92
93 HostAndPort::HostAndPort(const std::string& addressAndOptionalPort, uint16_t defaultPort)
94 {
95     if (isInBrackets(addressAndOptionalPort))
96         parse(removeBrackets(addressAndOptionalPort), defaultPort);
97     else
98         parse(addressAndOptionalPort, defaultPort);
99 }
100
101 void HostAndPort::parse(const std::string& addressAndOptionalPort, uint16_t defaultPort)
102 {
103     const auto pos(addressAndOptionalPort.rfind(':'));
104     if (pos == std::string::npos)
105     {
106         host = addressAndOptionalPort;
107         port = defaultPort;
108         literalIPv6 = false;
109     }
110     else if (isLiteralIPv6(addressAndOptionalPort))
111     {
112         host = addressAndOptionalPort;
113         port = defaultPort;
114         literalIPv6 = true;
115     }
116     else
117     {
118         host = addressAndOptionalPort.substr(0, pos);
119         if (isInBrackets(host))
120             host = removeBrackets(host);
121         literalIPv6 = isLiteralIPv6(host);
122         port = stringToPort(addressAndOptionalPort.substr(pos + 1U, addressAndOptionalPort.size() - pos - 1U));
123     }
124     if (host.empty())
125         throw EmptyHost();
126 }
127
128 const std::string& HostAndPort::getHost() const
129 {
130     return host;
131 }
132
133 uint16_t HostAndPort::getPort() const
134 {
135     return port;
136 }
137
138 std::string HostAndPort::getString() const
139 {
140     std::ostringstream os;
141     if (literalIPv6)
142         os << '[' << host << "]:" << ntohs(port);
143     else
144         os << host << ':' << ntohs(port);
145     return os.str();
146 }
147
148 bool HostAndPort::operator==(const HostAndPort& hp) const
149 {
150     return this->getPort() == hp.getPort() && this->getHost() == hp.getHost();
151 }
152
153 bool HostAndPort::operator!=(const HostAndPort& hp) const
154 {
155     return !(hp == *this);
156 }
157
158 bool HostAndPort::operator<(const HostAndPort& hp) const
159 {
160     if (this->getHost() == hp.getHost())
161         return this->getPort() < hp.getPort();
162     else
163         return this->getHost() < hp.getHost();
164 }
165
166 std::ostream& shareddatalayer::operator << (std::ostream& os, const HostAndPort& hostAndPort)
167 {
168     os << hostAndPort.getHost() << ":" << hostAndPort.getPort();
169     return os;
170 }