libutil++  1.9.3
 All Classes Functions Variables
Port.cpp
1 /*
2 ** libutil++
3 ** $Id: Port.cpp 1901 2017-06-24 20:03:54Z sella $
4 ** Copyright (c) 2011-2016 Digital Genesis, LLC. All Rights Reserved.
5 ** Released under the LGPL Version 2.1 License.
6 ** http://www.digitalgenesis.com
7 */
8 
9 static const char rcsid[] __attribute__((used)) = "$Id: Port.cpp 1901 2017-06-24 20:03:54Z sella $";
10 
11 #include "Port.h"
12 #include "PortException.h"
13 #include "../util/String.h"
14 
15 #include <sys/socket.h>
16 #include <string.h>
17 #include <stdint.h>
18 #include <stdlib.h>
19 #include <netdb.h>
20 
21 #define HASH_ALGO_INT1
22 
23 union __sockaddr_union {
24  struct sockaddr_storage *ss;
25  struct sockaddr *sa;
26  struct sockaddr_in *sa_in;
27  struct sockaddr_in6 *sa_in6;
28 };
29 
30 using namespace sella::net;
31 using namespace sella::util;
32 
33 Port::Port(const std::string &service, int protocol) throw (PortException) :
34  port(0),
35  protocol(0),
36  hcache(0)
37 {
38  switch (protocol) {
39  case UDPPreferred:
40  if (this->parseUDPPreferred(this->port, this->protocol, service) == false) {
41  THROW(PortException, "unable to parse port: '%s' does not represent valid UDP or TCP port", service.c_str());
42  }
43  break;
44 
45  case UDPRequired:
46  if (this->parseUDPRequired(this->port, this->protocol, service) == false) {
47  THROW(PortException, "unable to parse port: '%s' does not represent valid UDP port", service.c_str());
48  }
49  break;
50 
51  case TCPPreferred:
52  if (this->parseTCPPreferred(this->port, this->protocol, service) == false) {
53  THROW(PortException, "unable to parse port: '%s' does not represent valid TCP or UDP port", service.c_str());
54  }
55  break;
56 
57  case TCPRequired:
58  if (this->parseTCPRequired(this->port, this->protocol, service) == false) {
59  THROW(PortException, "unable to parse port: '%s' does not represent valid TCP port", service.c_str());
60  }
61  break;
62 
63  default:
64  THROW(PortException, "unable to parse port: unknown protocol supplied for port '%s'", service.c_str());
65  }
66 }
67 
68 Port::Port(uint16_t port, int protocol) throw (PortException) :
69  port(port),
70  protocol(0)
71 {
72  switch (protocol) {
73  case UDPPreferred:
74  case UDPRequired:
75  this->protocol = UDPProtocol;
76  break;
77 
78  case TCPPreferred:
79  case TCPRequired:
80  this->protocol = TCPProtocol;
81  break;
82 
83  default:
84  THROW(PortException, "unable to parse port: unknown protocol supplied for port '%d'", protocol);
85  }
86 }
87 
88 Port::Port(const struct sockaddr_storage *ss, int protocol) throw (PortException) :
89  protocol(0),
90  hcache(0)
91 {
92  union __sockaddr_union u;
93  u.ss = (struct sockaddr_storage*) ss;
94 
95  if (ss == NULL) {
96  THROW(PortException, "passed sockaddr_storage is null");
97  }
98 
99  port = ntohs(u.sa_in->sin_port);
100 
101  switch (protocol) {
102  case UDPPreferred:
103  case UDPRequired:
104  this->protocol = UDPProtocol;
105  break;
106 
107  case TCPPreferred:
108  case TCPRequired:
109  this->protocol = TCPProtocol;
110  break;
111 
112  default:
113  THROW(PortException, "unable to parse port: unknown protocol supplied for port '%d'", protocol);
114  }
115 }
116 
117 Port::Port(const struct sockaddr *sa, int protocol) throw (PortException) :
118  protocol(0),
119  hcache(0)
120 {
121  union __sockaddr_union u;
122  u.sa = (struct sockaddr*) sa;
123 
124  if (sa == NULL) {
125  THROW(PortException, "passed sockaddr is null");
126  }
127 
128  port = ntohs(u.sa_in->sin_port);
129 
130  switch (protocol) {
131  case UDPPreferred:
132  case UDPRequired:
133  this->protocol = UDPProtocol;
134  break;
135 
136  case TCPPreferred:
137  case TCPRequired:
138  this->protocol = TCPProtocol;
139  break;
140 
141  default:
142  THROW(PortException, "unable to parse port: unknown protocol supplied for port '%d'", protocol);
143  }
144 }
145 
146 Port::Port(const Port &other) throw () :
147  port(other.port),
148  protocol(other.protocol),
149  scache(other.scache),
150  hcache(other.hcache)
151 { }
152 
153 Port::Port(const Port &&other) throw () :
154  port(other.port),
155  protocol(other.protocol),
156  scache(std::move(other.scache)),
157  hcache(other.hcache)
158 { }
159 
160 Port::~Port() throw () { }
161 
162 Port& Port::operator=(const Port &other) throw () {
163  if (this != &other) {
164  this->port = other.port;
165  this->protocol = other.protocol;
166  this->scache= other.scache;
167  this->hcache = other.hcache;
168  }
169 
170  return *this;
171 }
172 
173 Port& Port::operator=(const Port &&other) throw () {
174  if (this != &other) {
175  this->port = other.port;
176  this->protocol = other.protocol;
177  this->scache= std::move(other.scache);
178  this->hcache = other.hcache;
179  }
180 
181  return *this;
182 }
183 
184 bool Port::operator == (const Port &other) const throw () {
185  return (this->port == other.port) ? ((this->protocol == other.protocol) ? true : false) : false;
186 }
187 
188 bool Port::operator != (const Port &other) const throw () {
189  return !(*this == other);
190 }
191 
192 bool Port::operator >= (const Port &other) const throw () {
193  return (this->port < other.port) ? false : ((this->port > other.port) ? true : (this->protocol >= other.protocol) ? true : false);
194 }
195 
196 bool Port::operator <= (const Port &other) const throw () {
197  return (this->port > other.port) ? false : ((this->port < other.port) ? true : (this->protocol <= other.protocol) ? true : false);
198 }
199 
200 bool Port::operator > (const Port &other) const throw () {
201  return (this->port > other.port) ? true : ((this->port < other.port) ? false : (this->protocol > other.protocol) ? true : false);
202 }
203 
204 bool Port::operator < (const Port &other) const throw () {
205  return (this->port < other.port) ? true : ((this->port > other.port) ? false : (this->protocol < other.protocol) ? true : false);
206 }
207 
208 uint16_t Port::get(void) const throw () {
209  return this->port;
210 }
211 
212 uint16_t Port::getPort(void) const throw () {
213  return this->port;
214 }
215 
216 int Port::getProtocol(void) const throw () {
217  return this->protocol;
218 }
219 
220 const std::string& Port::str(void) const throw () {
221  if (scache.empty()) {
222  scache = String::itoa(this->port);
223  }
224 
225  return scache;
226 }
227 
228 const char* Port::c_str(void) const throw () {
229  return str().c_str();
230 }
231 
232 uint32_t Port::getU32(void) const throw () {
233  return (port | (port << 16)) ^ 0xB4B4D2D2;
234 }
235 
236 uint32_t Port::getHash(void) const throw () {
237  if (hcache != 0) {
238  return hcache;
239  }
240 
241 #if defined HASH_ALGO_INT1 /* Fast. Nibble swap. */
242  uint32_t k = getU32();
243 
244  hcache = ((k & 0xF0F0F0F0) >> 4) | ((k & 0x0F0F0F0F) << 4);
245 #elif defined HASH_ALGO_INT2
246  uint32_t k = getU32();
247 
248  hcache = (k<<16)^(k>>16)^k; /* Fast. Mix by XOR shifting.. */
249 #elif defined HASH_ALGO_INT3 /* Very fast, but not good. */
250  hcache = getU32();
251 #else
252  #error No hash algo selected.
253 #endif
254 
255  return hcache;
256 }
257 
258 bool Port::empty(void) const throw () {
259  return (port == 0);
260 }
261 
262 void Port::clear(void) throw () {
263  port = 0;
264  protocol = 0;
265  scache.clear();
266  hcache = 0;
267 }
268 
269 const Port::shared Port::shared_ptr(const std::string &service, int protocol) throw (PortException) {
270  return std::make_shared<Port>(service, protocol);
271 }
272 
273 const Port::shared Port::shared_ptr(uint16_t port, int protocol) throw (PortException) {
274  return std::make_shared<Port>(port, protocol);
275 }
276 
277 const Port::shared Port::shared_ptr(const struct sockaddr_storage *ss, int protocol) throw (PortException) {
278  return std::make_shared<Port>(ss, protocol);
279 }
280 
281 const Port::shared Port::shared_ptr(const struct sockaddr *sa, int protocol) throw (PortException) {
282  return std::make_shared<Port>(sa, protocol);
283 }
284 
285 bool Port::parseUDPRequired(uint16_t &port, int &protocol, const std::string &service) throw () {
286  struct servent entry_buf, *entry;
287  char buf[4096], *end;
288 
289  port = strtol(service.c_str(), &end, 10);
290 
291  if ((*end) != '\0') {
292  if (getservbyname_r(service.c_str(), "udp", &entry_buf, buf, sizeof(buf), &entry) == 0) {
293  protocol = UDPProtocol;
294  port = entry->s_port;
295  } else {
296  return false;
297  }
298  }
299  return true;
300 }
301 
302 bool Port::parseTCPRequired(uint16_t &port, int &protocol, const std::string &service) throw () {
303  struct servent entry_buf, *entry;
304  char buf[4096], *end;
305 
306  port = strtol(service.c_str(), &end, 10);
307 
308  if ((*end) != '\0') {
309  if (getservbyname_r(service.c_str(), "tcp", &entry_buf, buf, sizeof(buf), &entry) == 0) {
310  protocol = UDPProtocol;
311  port = entry->s_port;
312  } else {
313  return false;
314  }
315  }
316  return true;
317 }
318 
319 bool Port::parseUDPPreferred(uint16_t &port, int &protocol, const std::string &service) throw () {
320  if (this->parseUDPRequired(port, protocol, service) == false) {
321  return this->parseTCPRequired(port, protocol, service);
322  }
323  return true;
324 }
325 
326 bool Port::parseTCPPreferred(uint16_t &port, int &protocol, const std::string &service) throw () {
327  if (this->parseTCPRequired(port, protocol, service) == false) {
328  return this->parseUDPRequired(port, protocol, service);
329  }
330  return true;
331 }
332 
333 /*
334 ** vim: noet ts=3 sw=3
335 */