Evo C++ Library v0.5.1
iosock.h
Go to the documentation of this file.
1 // Evo C++ Library
2 /* Copyright 2019 Justin Crowell
3 Distributed under the BSD 2-Clause License -- see included file LICENSE.txt for details.
4 */
6 
7 #pragma once
8 #ifndef INCL_evo_iosock_h
9 #define INCL_evo_iosock_h
10 
11 #include "io.h"
12 #include "impl/sysio_sock.h"
13 #include "substring.h"
14 #include "strscan.h"
15 #if !defined(_WIN32)
16  #include <net/if.h>
17  #include <sys/select.h>
18 #endif
19 
20 namespace evo {
23 
25 
30  static const uint MAX_INET4_STRLEN = 22;
31  static const uint MAX_INET6_STRLEN = 65;
32 
33  static const socklen_t MAX_SIZE = sizeof(sockaddr_in6);
34 
35  union {
36  struct sockaddr addr;
37  struct sockaddr_in addr_ip4;
38  struct sockaddr_in6 addr_ip6;
39  };
40 
43  { clear(); }
44 
49  memcpy(&addr_ip6, &src.addr_ip6, sizeof(sockaddr_in6));
50  addrlen = src.addrlen;
51  }
52 
56  SocketAddressIp(struct sockaddr_in* ptr) {
57  if (ptr == NULL)
58  clear();
59  else
60  memcpy(&addr, ptr, (addrlen=sizeof(sockaddr)));
61  }
62 
66  SocketAddressIp(struct sockaddr_in6* ptr) {
67  if (ptr == NULL)
68  clear();
69  else
70  memcpy(&addr_ip6, ptr, (addrlen=sizeof(sockaddr_in6)));
71  }
72 
77  SocketAddressIp(ushort port, bool ip6=false) {
78  clear();
79  if (ip6) {
80  addr_ip6.sin6_family = AF_INET6;
81  addr_ip6.sin6_addr = in6addr_any;
82  addr_ip6.sin6_port = htons(port);
83  } else {
84  addr_ip4.sin_family = AF_INET;
85  addr_ip4.sin_addr.s_addr = INADDR_ANY;
86  addr_ip4.sin_port = htons(port);
87  }
88  }
89 
93  SocketAddressIp(struct addrinfo* ptr)
94  { set(ptr); }
95 
101  SocketAddressIp(struct sockaddr* ptr) {
102  clear();
103  if (ptr != NULL) {
104  switch (ptr->sa_family) {
105  case AF_INET: set((struct sockaddr_in*)ptr); break;
106  case AF_INET6: set((struct sockaddr_in6*)ptr); break;
107  }
108  }
109  }
110 
111  // Documented by parent
112  void set_maxsize()
113  { addrlen = MAX_SIZE; }
114 
118  bool valid() const
119  { return (addr.sa_family != 0); }
120 
125  memset(&addr, 0, (addrlen=sizeof(MAX_SIZE)));
126  return *this;
127  }
128 
133  SocketAddressIp& set(const SocketAddressIp& src) {
134  memcpy(&addr_ip6, &src.addr_ip6, sizeof(struct sockaddr_in6));
135  addrlen = src.addrlen;
136  return *this;
137  }
138 
143  SocketAddressIp& set(struct sockaddr_in* ptr) {
144  if (ptr == NULL)
145  clear();
146  else
147  memcpy(&addr_ip4, ptr, (addrlen=sizeof(struct sockaddr_in)));
148  return *this;
149  }
150 
155  SocketAddressIp& set(struct sockaddr_in6* ptr) {
156  if (ptr == NULL)
157  clear();
158  else
159  memcpy(&addr_ip6, ptr, (addrlen=sizeof(struct sockaddr_in6)));
160  return *this;
161  }
162 
167  SocketAddressIp& set(struct addrinfo* ptr) {
168  clear();
169  if (ptr != NULL && ptr->ai_addr != NULL && ptr->ai_addrlen > 0) {
170  switch (ptr->ai_family) {
171  case AF_INET: memcpy(&addr_ip4, ptr->ai_addr, (addrlen=sizeof(struct sockaddr_in))); break;
172  case AF_INET6: memcpy(&addr_ip6, ptr->ai_addr, (addrlen=sizeof(struct sockaddr_in6))); break;
173  }
174  }
175  return *this;
176  }
177 
184  SocketAddressIp& setport(ushort port) {
185  switch (addr.sa_family) {
186  case AF_INET: addr_ip4.sin_port = htons(port); break;
187  case AF_INET6: addr_ip6.sin6_port = htons(port); break;
188  }
189  return *this;
190  }
191 
196  SocketAddressIp& setany4(ushort port=0) {
197  clear();
198  addr_ip4.sin_family = AF_INET;
199  addr_ip4.sin_addr.s_addr = INADDR_ANY;
200  addr_ip4.sin_port = htons(port);
201  return *this;
202  }
203 
208  SocketAddressIp& setany6(ushort port=0) {
209  clear();
210  addr_ip6.sin6_family = AF_INET6;
211  addr_ip6.sin6_addr = in6addr_any;
212  addr_ip6.sin6_port = htons(port);
213  return *this;
214  }
215 
216  bool parse(const SubString& str, ushort port=0, int family=AF_UNSPEC) {
217  clear();
218  if (str.size() == 0)
219  return false;
220  const char* pstr = str.data();
221  const char* pend = pstr + str.size();
222 
223  if (family == AF_UNSPEC) {
224  // Auto-detect: Check first few chars for IPv4 syntax, fallback to IPv6
225  int i = 0;
226  for (const char* p=pstr; p < pend; ++p, ++i) {
227  if (*p == '.') {
228  --i;
229  break;
230  }
231  if (*p < '0' || *p > '9') {
232  i = -1;
233  break;
234  }
235  }
236  family = (i < 0 ? AF_INET6 : AF_INET);
237  }
238 
239  switch (family) {
240  case AF_INET: {
241  if (str.size() >= MAX_INET4_STRLEN)
242  return false;
243  uint32 ip = 0;
244  ushort num, shift = 32;
245  const char* p = pstr;
246  for (uint i=0; i < 4; ++i) {
247  num = 0;
248  p = str_scan_decimal(num, p, pend);
249  if (p == NULL)
250  return false;
251  if (i < 3) {
252  if (p == pend || *p != '.')
253  return false;
254  ++p;
255  }
256  if (num > 0xFF)
257  return false;
258  shift -= 8;
259  ip |= (num << shift);
260  }
261  addr_ip4.sin_addr.s_addr = htonl(ip);
262  if (p != pend) {
263  if (*p != ':')
264  return false;
265  num = 0;
266  p = str_scan_decimal(num, p+1, pend);
267  if (p != pend)
268  return false;
269  addr_ip4.sin_port = htons(num);
270  }
271  if (port > 0)
272  addr_ip4.sin_port = htons(port);
273  addrlen = sizeof(struct sockaddr_in);
274  break;
275  }
276  case AF_INET6: {
277  if (str.size() >= MAX_INET6_STRLEN)
278  return false; // too long
279  const char* p = pstr;
280 
281  bool brackets = false;
282  if (*p == '[') {
283  brackets = true;
284  if (++p == pend)
285  return false; // bad syntax
286  }
287 
288  const uint MAX_NUMS = 8;
289  const uint MAX_IPLEN = MAX_NUMS * 2;
290  uint head_len = MAX_IPLEN;
291  uint i = 1;
292  if (*p == ':') {
293  if (++p == pend || *p != ':')
294  return false; // bad syntax
295  if (++p < pend && *p == ']') {
296  if (!brackets)
297  return false; // unexpected ']'
298  i = MAX_NUMS; // stop parse loop
299  }
300  head_len = 0;
301  }
302 
303  // Parsing from first token
304  const char* tokp;
305  uchar* ip = addr_ip6.sin6_addr.s6_addr;
306  uchar* p_ip = ip;
307  ushort num;
308  for (; p < pend && i <= MAX_NUMS; ++i) {
309  if (*p == ':') {
310  if (head_len < MAX_IPLEN)
311  return false; // only 1 "::" allowed
312  head_len = (uint)(p_ip - ip);
313  if (++p == pend)
314  break; // ended with "::"
315  }
316 
317  tokp = p;
318  num = 0;
319  if ((p = str_scan_hex(num, p, pend)) == NULL)
320  return false; // bad num
321 
322  if (p == pend) {
323  if (i < MAX_NUMS && head_len == MAX_IPLEN)
324  return false; // too short, no "::"
325  } else if (*p == '%') {
326  i = MAX_NUMS;
327  } else if (i < MAX_NUMS) {
328  // Not last token, check delim
329  if (*p == '.') {
330  // IPv4 mapped, re-parse from current token
331  p = tokp;
332  if ((uint)(pend - p) > MAX_INET4_STRLEN + 1) // +1 for possible end bracket
333  return false; // too long
334  const uint MAX_IP4LEN = 4;
335  for (uint j=1; j <= MAX_IP4LEN; ++j) {
336  num = 0;
337  if ((p = str_scan_decimal(num, p, pend)) == NULL)
338  return false;
339  if (j < MAX_IP4LEN) {
340  if (p == pend || *p != '.')
341  return false; // too short or bad delim
342  ++p;
343  }
344  if (num > 0xFF)
345  return false; // num out of range
346  *p_ip = (uchar)num;
347  ++p_ip;
348  }
349  break;
350  } else if (*p == ']') {
351  if (!brackets)
352  return false; // unexpected ']'
353  *p_ip = (uchar)((num >> 8) & 0xFF);
354  *++p_ip = (uchar)(num & 0xFF);
355  ++p_ip;
356  break;
357  } else if (*p != ':')
358  return false; // bad delim
359  ++p;
360  }
361  *p_ip = (uchar)((num >> 8) & 0xFF);
362  *++p_ip = (uchar)(num & 0xFF);
363  ++p_ip;
364  }
365 
366  // Adjust for 0-compression
367  if (head_len < MAX_IPLEN) {
368  uint ip_mov_len = (uint)(p_ip - ip);
369  if (ip_mov_len >= MAX_IPLEN)
370  return false; // can't use "::" on full IP
371  ip_mov_len -= head_len;
372  if (ip_mov_len > 0)
373  memmove(ip + MAX_IPLEN - ip_mov_len, ip + head_len, ip_mov_len);
374  memset(ip + head_len, 0, MAX_IPLEN - ip_mov_len - head_len);
375  }
376 
377  // Zone/Scope ID
378  if (p < pend && *p == '%') {
379  if (++p == pend)
380  return false; // missing scope ID after delim
381  #if !defined(_WIN32)
382  // Linux/Unix: Map interface name to ID
383  if (*p < '0' || *p > '9') {
384  const char* p0 = str_scan_to(IF_NAMESIZE-1, p, pend, ']', ':');
385  if (p0 == NULL || p0 == pend)
386  return false; // interface name too long, or missing delim
387  const uint len = p0 - p;
388  char buf[IF_NAMESIZE];
389  memcpy(buf, p, len);
390  if ((i = if_nametoindex(buf)) != 0)
391  return false; // bad interface name
392  addr_ip6.sin6_scope_id = i;
393  p = p0;
394  } else
395  #endif
396  if ((p = str_scan_decimal(addr_ip6.sin6_scope_id, p, pend)) == NULL)
397  return false; // bad scope ID
398  }
399 
400  // End bracket
401  if (brackets) {
402  if (p == pend || *p != ']')
403  return false; // missing end ']'
404  ++p;
405  }
406 
407  // Port number
408  if (p < pend) {
409  if (*p != ':' || ++p == pend)
410  return false;
411  num = 0;
412  if ((p = str_scan_decimal(num, p, pend)) != pend)
413  return false;
414  addr_ip6.sin6_port = htons(num);
415  }
416  if (port > 0)
417  addr_ip6.sin6_port = htons(port);
418 
419  addrlen = sizeof(struct sockaddr_in6);
420  break;
421  }
422  default:
423  return false;
424  }
425  addr.sa_family = (ushort)family;
426  return true;
427  }
428 
433  bool format(String& str) const
434  { return SocketAddressIp::format_addr(str, this); }
435 
441  static bool format_addr(String& str, const SocketAddressBase* address) {
442  if (address != NULL) {
443  const SocketAddress* address_base = (SocketAddress*)address;
444  switch (address_base->addr.sa_family) {
445  case AF_INET: {
446  struct sockaddr_in* sock_addr = (struct sockaddr_in*)&address_base->addr;
447  if (sock_addr->sin_port > 0) {
448  const ushort port = ntohs(sock_addr->sin_port);
449  char* buf = str.advWrite(MAX_INET4_STRLEN); // Add port and delims: addr:port
450  if (inet_ntop(AF_INET, (void*)&sock_addr->sin_addr, buf, MAX_INET4_STRLEN) != NULL) {
451  String::Size addrlen = (String::Size)strlen(buf);
452  buf[addrlen++] = ':';
453  addrlen += impl::fnum(buf + addrlen + IntegerT<ushort>::digits(port, 10), port, 10);
454  str.advWriteDone(addrlen);
455  return true;
456  }
457  } else {
458  char* buf = str.advWrite(MAX_INET4_STRLEN);
459  if (inet_ntop(AF_INET, (void*)&sock_addr->sin_addr, buf, MAX_INET4_STRLEN) != NULL) {
460  str.advWriteDone((String::Size)strlen(buf));
461  return true;
462  }
463  }
464  break; // cov: can't mock error
465  }
466  case AF_INET6: {
467  struct sockaddr_in6* sock_addr = (struct sockaddr_in6*)&address_base->addr;
468  if (sock_addr->sin6_port > 0) {
469  const ushort port = ntohs(sock_addr->sin6_port);
470  char* buf = str.advWrite(MAX_INET6_STRLEN); // Add port and delims: [addr]:port
471  *buf = '[';
472  if (inet_ntop(AF_INET6, (void*)&sock_addr->sin6_addr, buf+1, MAX_INET6_STRLEN-1) != NULL) {
473  String::Size addrlen = (String::Size)strlen(buf+1) + 1; // includes '['
474  buf[addrlen++] = ']';
475  buf[addrlen++] = ':';
476  addrlen += impl::fnum(buf + addrlen + IntegerT<ushort>::digits(port, 10), port, 10);
477  str.advWriteDone(addrlen);
478  return true;
479  }
480  } else {
481  char* buf = str.advWrite(MAX_INET6_STRLEN);
482  if (inet_ntop(AF_INET6, (void*)&sock_addr->sin6_addr, buf, MAX_INET6_STRLEN) != NULL) {
483  str.advWriteDone((String::Size)strlen(buf));
484  return true;
485  }
486  }
487  break; // cov: can't mock error
488  }
489  }
490  }
491  return false;
492  }
493 
498  static bool check(struct sockaddr* addr) {
499  if (addr != NULL) {
500  switch (addr->sa_family) {
501  case AF_INET: return true;
502  case AF_INET6: return true;
503  }
504  }
505  return false;
506  }
507 };
508 
510 
511 #if !defined(_WIN32)
512 
516  static const socklen_t MAX_SIZE = sizeof(sockaddr_un);
517 
518  union {
519  struct sockaddr addr;
520  struct sockaddr_un addr_unix;
521  };
522 
525  { clear(); }
526 
531  memcpy(&addr_unix, &src.addr_unix, sizeof(sockaddr_un));
532  addrlen = src.addrlen;
533  }
534 
538  SocketAddressUnix(struct sockaddr_un* ptr)
539  { set(ptr); }
540 
546  SocketAddressUnix(struct sockaddr* ptr) {
547  clear();
548  if (ptr != NULL && ptr->sa_family == AF_UNIX)
549  set((struct sockaddr_un*)ptr);
550  }
551 
552  // Documented by parent
553  void set_maxsize()
554  { addrlen = MAX_SIZE; }
555 
559  bool valid() const
560  { return (addr.sa_family != 0); }
561 
566  memset(&addr, 0, (addrlen=sizeof(MAX_SIZE)));
567  return *this;
568  }
569 
575  memcpy(&addr_unix, &src.addr_unix, (addrlen=src.addrlen));
576  return *this;
577  }
578 
583  SocketAddressUnix& set(struct sockaddr_un* ptr) {
584  if (ptr == NULL || ptr->sun_family != AF_UNIX)
585  clear();
586  else
587  memcpy(&addr_unix, ptr, (addrlen=offsetof(struct sockaddr_un, sun_path) + strlen(ptr->sun_path)));
588  return *this;
589  }
590 
597  bool parse(const SubString& path) {
598  const SubString::Size pathlen = path.size();
599  if (pathlen+1 < sizeof(addr_unix.sun_path)) {
600  bzero((char*)&addr_unix, sizeof(addr_unix));
601  addr_unix.sun_family = AF_UNIX;
602 
603  memcpy(addr_unix.sun_path, path.data(), pathlen);
604  addr_unix.sun_path[pathlen] = '\0';
605 
606  addrlen = pathlen + offsetof(struct sockaddr_un, sun_path);
607  return true;
608  }
609  return false;
610  }
611 
618  bool format(String& str) const
619  { return SocketAddressUnix::format_addr(str, this); }
620 
628  static bool format_addr(String& str, const SocketAddressBase* address) {
629  if (address != NULL) {
630  const SocketAddress* address_base = (SocketAddress*)address;
631  if (address_base->addr.sa_family == AF_UNIX) {
632  const struct sockaddr_un* address_unix = (struct sockaddr_un*)&address_base->addr;
633  str.copy(address_unix->sun_path, address_base->addrlen - offsetof(struct sockaddr_un, sun_path));
634  return true;
635  }
636  }
637  return false;
638  }
639 
644  static bool check(struct sockaddr* addr) {
645  if (addr != NULL && addr->sa_family == AF_UNIX)
646  return true;
647  return false;
648  }
649 };
650 #endif
651 
653 
734 class Socket : public Stream<IoSocket> {
735 public:
737 
738  static const int BACKLOG_DEFAULT = 5;
739 
748  Socket(Newline nl=NL_SYS, bool exceptions=EVO_EXCEPTIONS) : Base(nl), resolve_enable_(true)
749  { excep(exceptions); }
750 
758  Socket(bool exceptions) : Base(NL_SYS), resolve_enable_(true)
759  { excep(exceptions); }
760 
765  { return device_; }
766 
772  ulong get_timeout() const
773  { return device_.timeout_ms; }
774 
781  Socket& set_timeout(ulong timeout_ms)
782  { device_.timeout_ms = timeout_ms; return *this; }
783 
792  bool get_resolve() const
793  { return resolve_enable_; }
794 
804  Socket& set_resolve(bool enable) {
805  resolve_enable_ = enable;
806  return *this;
807  }
808 
820  template<class T>
821  T* get_opt(int level, int optname, T* buf) {
822  uint size = sizeof(T);
823  error_ = device_.getopt(level, optname, buf, size);
824  if (error_ == ENone)
825  return buf;
826  EVO_THROW_ERR_CHECK(ExceptionSocketConfig, "Socket getopt() failed", error_, excep_);
827  return NULL;
828  }
829 
841  Long get_opt_num(int level, int optname) {
842  IoSocket::OptNum num = 0;
843  uint size = sizeof(num);
844  error_ = device_.getopt(level, optname, &num, size);
845 
846  Long result;
847  if (error_ == ENone)
848  result = (long)num;
849  else
850  { EVO_THROW_ERR_CHECK(ExceptionSocketConfig, "Socket getopt() failed", error_, excep_); }
851  return result;
852  }
853 
865  template<class T>
866  bool set_opt(int level, int optname, const T& val) {
867  error_ = device_.setopt(level, optname, (T*)&val, sizeof(T));
868  if (error_ != ENone) {
869  EVO_THROW_ERR_CHECK(ExceptionSocketConfig, "Socket setopt() failed", error_, excep_);
870  return false;
871  }
872  return true;
873  }
874 
886  bool set_opt_num(int level, int optname, long val) {
888  return set_opt(level, optname, num);
889  }
890 
900  bool listen_ip(const SubString& host, ushort port, int family=AF_INET, int backlog=BACKLOG_DEFAULT) {
901  SocketAddressInfo address_info(family);
902  if (resolve_enable_)
903  error_ = address_info.resolve(host, port);
904  else
905  error_ = address_info.convert(host, port);
906  if (error_ == ENone && device_.listen(error_, address_info.ptr, backlog)) {
907  owned_ = true;
908  return true;
909  }
910  errno = address_info.code;
911  EVO_THROW_ERR_CHECK(ExceptionSocketOpen, "Socket listen_ip() failed", error_, excep_);
912  return false;
913  }
914 
921  bool listen_ip(ushort port, int family=AF_INET, int backlog=BACKLOG_DEFAULT) {
922  SocketAddressInfo address_info(family);
923  error_ = address_info.resolve(NULL, port, AI_PASSIVE | AI_NUMERICSERV);
924  if (error_ == ENone && device_.listen(error_, address_info.ptr, backlog)) {
925  owned_ = true;
926  return true;
927  }
928  errno = address_info.code;
929  EVO_THROW_ERR_CHECK(ExceptionSocketOpen, "Socket listen_ip() failed", error_, excep_);
930  return false;
931  }
932 
944  bool listen_ud(const SubString& path, int backlog=BACKLOG_DEFAULT) {
945  assert( path.size_ > 0 );
946  #if defined(_WIN32)
947  (void)path; // prevent compiler warnings
948  (void)backlog;
949  errno = EINVAL;
950  error_ = ENotImpl;
951  #else
952  SocketAddressUnix address;
953  if (address.parse(path)) {
954  if (device_.listen(error_, &address.addr, address.addrlen, backlog))
955  return true;
956  } else {
957  errno = ENAMETOOLONG;
958  error_ = ESize;
959  }
960  #endif
961  EVO_THROW_ERR_CHECK(ExceptionSocketOpen, "Socket listen_ud() failed", error_, excep_);
962  return false;
963  }
964 
974  bool accept(Socket& client_socket, SocketAddressBase* client_address=NULL) {
975  client_socket.close();
976  if (client_address != NULL) {
977  ((SocketAddress*)client_address)->addr.sa_family = 0;
978  client_address->set_maxsize();
979  }
980  if (device_.accept(error_, client_socket.device_, client_address)) {
981  client_socket.owned_ = true;
982  return true;
983  }
984  EVO_THROW_ERR_CHECK(ExceptionSocketOpen, "Socket accept() failed", error_, excep_);
985  return false;
986  }
987 
997  bool connect_ip(const char* host, ushort port, int family=AF_INET) {
998  close();
999  SocketAddressInfo address_info(family);
1000  if (resolve_enable_)
1001  error_ = address_info.resolve(host, port);
1002  else
1003  error_ = address_info.convert(host, port);
1004  if (error_ == ENone && device_.connect(error_, address_info.ptr)) {
1005  owned_ = true;
1006  return true;
1007  }
1008  errno = address_info.code;
1009  EVO_THROW_ERR_CHECK(ExceptionSocketOpen, "Socket connect_ip() failed", error_, excep_);
1010  return false;
1011  }
1012 
1022  bool connect_ip(const SubString& host, ushort port, int family=AF_INET) {
1023  close();
1024  SocketAddressInfo address_info(family);
1025  if (resolve_enable_)
1026  error_ = address_info.resolve(host, port);
1027  else
1028  error_ = address_info.convert(host, port);
1029  if (error_ == ENone && device_.connect(error_, address_info.ptr)) {
1030  owned_ = true;
1031  return true;
1032  }
1033  errno = address_info.code;
1034  EVO_THROW_ERR_CHECK(ExceptionSocketOpen, "Socket connect_ip() failed", error_, excep_);
1035  return false;
1036  }
1037 
1047  bool connect_ud(const SubString& path) {
1048  assert( path.size_ > 0 );
1049  close();
1050  #if defined(_WIN32)
1051  (void)path; // prevent compiler warning
1052  errno = EINVAL;
1053  error_ = ENotImpl;
1054  #else
1055  SocketAddressUnix address;
1056  if (address.parse(path)) {
1057  if (device_.connect(error_, &address.addr, address.addrlen))
1058  return true;
1059  } else {
1060  errno = ENAMETOOLONG;
1061  error_ = ESize;
1062  }
1063  #endif
1064  EVO_THROW_ERR_CHECK(ExceptionSocketOpen, "Socket connect_ud() failed", error_, excep_);
1065  return false;
1066  }
1067 
1076  bool finish()
1077  { return device_.shutdown(); }
1078 
1087  bool finish_in()
1088  { return device_.shutdown(IoSocket::sIN); }
1089 
1097  bool finish_out()
1098  { return device_.shutdown(IoSocket::sOUT); }
1099 
1107  template<class TOut>
1108  TOut& errormsg_out(TOut& out)
1109  { return IoSocket::errormsg_out<>(out, error_); }
1110 
1115  static void sysinit()
1116  { IoSocket::init(); }
1117 
1118 private:
1119  bool resolve_enable_;
1120 
1121  // Disable copying
1122  Socket(const Socket&);
1123  Socket& operator=(const Socket&);
1124 };
1125 
1127 
1155 class SocketCast : public IoBase {
1156 public:
1160  SocketCast(bool exceptions=EVO_EXCEPTIONS) : target_address_(NULL)
1161  { excep(exceptions); }
1162 
1167  SocketCast(SocketAddressBase* address, bool exceptions=EVO_EXCEPTIONS) : target_address_(address)
1168  { excep(exceptions); }
1169 
1172  { close(); }
1173 
1179  ulong get_timeout() const
1180  { return device_.timeout_ms; }
1181 
1188  SocketCast& set_timeout(ulong timeout_ms)
1189  { device_.timeout_ms = timeout_ms; return *this; }
1190 
1202  template<class T>
1203  T* get_opt(int level, int optname, T* buf) {
1204  uint size = sizeof(T);
1205  error_ = device_.getopt(level, optname, buf, size);
1206  if (error_ == ENone)
1207  return buf;
1208  else
1209  { EVO_THROW_ERR_CHECK(ExceptionSocketConfig, "SocketCast getopt() failed", error_, excep_); }
1210  return NULL;
1211  }
1212 
1224  Long get_opt_num(int level, int optname) {
1225  IoSocket::OptNum num = 0;
1226  uint size = sizeof(num);
1227  error_ = device_.getopt(level, optname, &num, size);
1228 
1229  Long result;
1230  if (error_ == ENone)
1231  result = (long)num;
1232  else
1233  { EVO_THROW_ERR_CHECK(ExceptionSocketConfig, "SocketCast getopt() failed", error_, excep_); }
1234  return result;
1235  }
1236 
1248  template<class T>
1249  bool set_opt(int level, int optname, const T& val) {
1250  error_ = device_.setopt(level, optname, (T*)&val, sizeof(T));
1251  if (error_ != ENone) {
1252  EVO_THROW_ERR_CHECK(ExceptionSocketConfig, "SocketCast setopt() failed", error_, excep_);
1253  return false;
1254  }
1255  return true;
1256  }
1257 
1269  bool set_opt_num(int level, int optname, long val) {
1271  return set_opt(level, optname, num);
1272  }
1273 
1280  bool bind(const SocketAddressBase& address, int socktype=SOCK_DGRAM, int protocol=0) {
1281  if (!device_.bind(error_, &((SocketAddress&)address).addr, address.addrlen, socktype, protocol)) {
1282  EVO_THROW_ERR_CHECK(ExceptionSocketOpen, "SocketCast bind failed", error_, excep_);
1283  return false;
1284  }
1285  return true;
1286  }
1287 
1298  bool cast(const SocketAddressBase* address=NULL, int family=AF_UNSPEC, int socktype=SOCK_DGRAM, int protocol=0) {
1299  if (family == AF_UNSPEC) {
1300  if (address != NULL)
1301  family = ((SocketAddress*)address)->addr.sa_family;
1302  else
1303  family = AF_INET;
1304  }
1305  target_address_ = address;
1306  if (!device_.cast(error_, family, socktype, protocol)) {
1307  EVO_THROW_ERR_CHECK(ExceptionSocketOpen, "SocketCast create failed", error_, excep_);
1308  return false;
1309  }
1310  return true;
1311  }
1312 
1314  void close()
1315  { device_.close(); }
1316 
1324  ulong read(void* buf, ulong size, int flags=0, SocketAddressBase* address=NULL) {
1325  if (address == NULL)
1326  return device_.readfrom(error_, buf, size, NULL, 0, flags);
1327  address->set_maxsize();
1328  const ulong result = device_.readfrom(error_, buf, size, &((SocketAddress*)address)->addr, &address->addrlen, flags);
1329  EVO_THROW_ERR_CHECK(ExceptionSocketIn, "SocketCast read failed", error_, (excep_ && result == 0 && error_ != ENone));
1330  return result;
1331  }
1332 
1333  // Documented by parent
1334  ulong readbin(void* buf, ulong size)
1335  { return read(buf, size); }
1336 
1344  ulong write(const void* buf, ulong size, int flags=0, const SocketAddressBase* address=NULL) {
1345  if (address == NULL) {
1346  if (target_address_ == NULL) {
1347  error_ = EInval;
1348  errno = EINVAL;
1349  return 0;
1350  }
1351  address = target_address_;
1352  }
1353  const ulong result = device_.writeto(error_, buf, size, &((SocketAddress*)address)->addr, address->addrlen, flags);
1354  EVO_THROW_ERR_CHECK(ExceptionSocketOut, "SocketCast write failed", error_, (excep_ && result == 0 && error_ != ENone));
1355  return result;
1356  }
1357 
1358  // Documented by parent
1359  ulong writebin(const void* buf, ulong size)
1360  { return write(buf, size); }
1361 
1369  template<class TOut>
1370  TOut& errormsg_out(TOut& out)
1371  { return IoSocket::errormsg_out<>(out, error_); }
1372 
1373 private:
1374  const SocketAddressBase* target_address_;
1375  IoSocket device_;
1376 };
1377 
1379 
1380 }
1381 #endif
struct sockaddr addr
Generic address structure.
Definition: iosock.h:519
Error convert(const char *host)
Convert host address to one or more socket addresses.
Definition: sysio_sock.h:258
SocketAddressIp(struct sockaddr *ptr)
Constructor to copy IP address from sockaddr structure.
Definition: iosock.h:101
TOut & errormsg_out(TOut &out)
Write detailed error message with errno to output stream/string.
Definition: iosock.h:1370
bool bind(const SocketAddressBase &address, int socktype=SOCK_DGRAM, int protocol=0)
Create and bind datagram socket to address (read/write).
Definition: iosock.h:1280
T * advWrite(Size addsize)
Advanced: Get buffer pointer to write/append (modifier).
Definition: list.h:2768
struct sockaddr addr
Generic address structure.
Definition: sysio_sock.h:114
Socket for I/O casting (datagram/UDP).
Definition: iosock.h:1155
bool connect_ud(const SubString &path)
Connect to Unix Domain socket at file path (linux/unix).
Definition: iosock.h:1047
Shutdown input (reads) on socket.
Definition: sysio_sock.h:688
String & copy(const ListType &str)
Set as full (unshared) copy of another string (modifier).
Definition: string.h:2705
TOut & errormsg_out(TOut &out)
Write detailed error message with errno to output stream/string.
Definition: iosock.h:1108
bool cast(const SocketAddressBase *address=NULL, int family=AF_UNSPEC, int socktype=SOCK_DGRAM, int protocol=0)
Create unbound datagram socket for casting (write only).
Definition: iosock.h:1298
SocketAddressIp(struct addrinfo *ptr)
Constructor to copy from addrinfo structure.
Definition: iosock.h:93
Evo SubString container.
Socket config exception for getopt() or setopt() errors, see Exception.
Definition: sysio_sock.h:73
Evo string scanning helpers with SSE optimized code.
Invalid argument or data.
Definition: sys.h:1123
SocketCast & set_timeout(ulong timeout_ms)
Set timeout for socket operations.
Definition: iosock.h:1188
SocketAddressIp & setany4(ushort port=0)
Set as wildcard IPv4 address.
Definition: iosock.h:196
bool listen_ud(const SubString &path, int backlog=BACKLOG_DEFAULT)
Create and bind Unix Domain socket to file path and listen for connections (linux/unix).
Definition: iosock.h:944
socklen_t addrlen
Address length.
Definition: sysio_sock.h:96
bool valid() const
Get whether valid.
Definition: iosock.h:118
Long get_opt_num(int level, int optname)
Get socket option flag or numeric value.
Definition: iosock.h:841
Socket open exception for socket connect/bind/listen errors, see Exception.
Definition: sysio_sock.h:77
SocketCast(bool exceptions=1)
Constructor.
Definition: iosock.h:1160
static bool format_addr(String &str, const SocketAddressBase *address)
Format Unix Domain socket address to given string (appended).
Definition: iosock.h:628
ulong write(const void *buf, ulong size, int flags=0, const SocketAddressBase *address=NULL)
Write message to socket.
Definition: iosock.h:1344
SocketAddressIp & setany6(ushort port=0)
Set as wildcard IPv6 address.
Definition: iosock.h:208
Stream< IoSocket > Base
Base class alias (used internally)
Definition: iosock.h:736
void set_maxsize()
Set addrlen to max size for socket address.
Definition: iosock.h:112
bool set_opt(int level, int optname, const T &val)
Set socket option value.
Definition: iosock.h:1249
bool finish()
Finish (shutdown) socket input and output (reads and writes).
Definition: iosock.h:1076
Newline
Newline type.
Definition: sys.h:748
SocketAddressUnix()
Default constructor sets as empty/invalid.
Definition: iosock.h:524
static const uint MAX_INET6_STRLEN
Max IPv6 string length with IPv4 tunneling, brackets, zone/scope ID, and port num + terminator...
Definition: iosock.h:31
#define EVO_THROW_ERR_CHECK(TYPE, MSG, ERROR, COND)
Throw an Evo exception with error code if COND is true.
Definition: sys.h:1513
T device_
I/O device.
Definition: iobase.h:1687
bool parse(const SubString &path)
Parse Unix Domain socket address.
Definition: iosock.h:597
SocketAddressIp(ushort port, bool ip6=false)
Constructor for wildcard address.
Definition: iosock.h:77
Evo I/O streams and Console I/O.
ulong get_timeout() const
Get timeout for socket operations.
Definition: iosock.h:772
Socket input stream exception for socket read errors, see Exception.
Definition: sysio_sock.h:81
void advWriteDone(Size addsize)
Advanced: Update size added after writing directly to buffer.
Definition: list.h:2784
static const socklen_t MAX_SIZE
Max socket address size used here.
Definition: iosock.h:33
Basic integer type.
Definition: type.h:980
SocketAddressUnix(struct sockaddr *ptr)
Constructor to copy Unix Domain socket address from sockaddr structure.
Definition: iosock.h:546
struct sockaddr_un addr_unix
Unix Domain address structure (union with addr)
Definition: iosock.h:520
Long get_opt_num(int level, int optname)
Get socket option flag or numeric value.
Definition: iosock.h:1224
SocketAddressIp & setport(ushort port)
Set port on current address.
Definition: iosock.h:184
StrSizeT Size
List size integer type
Definition: list.h:247
bool connect_ip(const SubString &host, ushort port, int family=AF_INET)
Connect TCP socket to host address.
Definition: iosock.h:1022
Size size() const
Get size.
~SocketCast()
Destructor.
Definition: iosock.h:1171
struct addrinfo * ptr
Pointer to first address in resolve results.
Definition: sysio_sock.h:127
Size limit exceeded.
Definition: sys.h:1139
No error.
Definition: sys.h:1115
SocketAddressUnix(const SocketAddressUnix &src)
Copy constructor.
Definition: iosock.h:530
#define EVO_EXCEPTIONS
Whether to throw exceptions on error by default.
Definition: evo_config.h:35
static const Init & init()
Initialize socket library.
Definition: sysio_sock.h:1360
bool connect_ip(const char *host, ushort port, int family=AF_INET)
Connect TCP socket to host address.
Definition: iosock.h:997
int OptNum
General number type for socket options.
Definition: sysio_sock.h:698
bool close()
Close stream.
Definition: iobase.h:888
struct sockaddr_in addr_ip4
IPv4 address structure (union with addr)
Definition: iosock.h:37
Socket output stream exception for socket write errors, see Exception.
Definition: sysio_sock.h:85
StrSizeT Size
List size integer type.
Definition: sublist.h:150
String container.
Definition: string.h:674
Socket I/O device (used internally).
Definition: sysio_sock.h:307
bool accept(Socket &client_socket, SocketAddressBase *client_address=NULL)
Accept connection from listening socket.
Definition: iosock.h:974
SocketAddressIp()
Default constructor sets as empty/invalid.
Definition: iosock.h:42
ulong get_timeout() const
Get timeout for socket operations.
Definition: iosock.h:1179
Socket I/O stream.
Definition: iosock.h:734
Base binary stream interface.
Definition: iobase.h:30
int code
Internal return code from resolve()
Definition: sysio_sock.h:128
bool set_opt_num(int level, int optname, long val)
Set socket option flag or numeric value.
Definition: iosock.h:1269
const char * str_scan_to(uint maxlen, const char *str, const char *end, char ch)
Scan string pointer for char and return stop pointer.
Definition: strscan.h:1775
Socket & set_resolve(bool enable)
Set whether full resolver is used when resolving addresses.
Definition: iosock.h:804
SocketAddressIp(struct sockaddr_in6 *ptr)
Constructor to copy from an IPv6 address.
Definition: iosock.h:66
bool set_opt_num(int level, int optname, long val)
Set socket option flag or numeric value.
Definition: iosock.h:886
void close()
Close socket.
Definition: iosock.h:1314
static bool format_addr(String &str, const SocketAddressBase *address)
Format IP address to given string (appended).
Definition: iosock.h:441
SocketAddressIp & clear()
Clear current address.
Definition: iosock.h:124
bool set_opt(int level, int optname, const T &val)
Set socket option value.
Definition: iosock.h:866
Evo C++ Library namespace.
Definition: alg.h:11
const char * str_scan_decimal(T &num, const char *str, const char *end)
Scan string pointer for decimal number and return stop pointer.
Definition: strscan.h:1826
bool format(String &str) const
Format Unix Domain socket address to given string (appended).
Definition: iosock.h:618
Error resolve(const char *host, const char *port=NULL, int flags=AI_NUMERICSERV)
Resolve or convert host name/address and port to one or more socket addresses.
Definition: sysio_sock.h:185
bool valid() const
Get whether valid.
Definition: iosock.h:559
Input/Output stream implementation.
Definition: iobase.h:791
static const uint MAX_INET4_STRLEN
Max IPv4 string length with port num + terminator.
Definition: iosock.h:30
Resolves socket name/address to socket address info.
Definition: sysio_sock.h:125
SocketAddressIp(struct sockaddr_in *ptr)
Constructor to copy from an IPv4 address.
Definition: iosock.h:56
static bool check(struct sockaddr *addr)
Check if address struct holds a supported Unix Domain socket address type.
Definition: iosock.h:644
void set_maxsize()
Set addrlen to max size for socket address.
Definition: iosock.h:553
TCP/IP socket address.
Definition: iosock.h:29
struct sockaddr_in6 addr_ip6
IPv6 address structure (union with addr)
Definition: iosock.h:38
static const Newline NL_SYS
Current system newline type.
Definition: sys.h:763
T * get_opt(int level, int optname, T *buf)
Get socket option value.
Definition: iosock.h:821
ulong readbin(void *buf, ulong size)
Read binary input from stream.
Definition: iosock.h:1334
bool owned_
Whether handle is owned (to be closed here)
Definition: iobase.h:1688
bool finish_out()
Finish (shutdown) socket output (writes).
Definition: iosock.h:1097
Evo system I/O socket implementation.
bool get_resolve() const
Get whether full resolver is used when resolving addresses.
Definition: iosock.h:792
TSize size_
Data size as item count, 0 if empty or null.
Definition: sys.h:980
const char * str_scan_hex(T &num, const char *str, const char *end)
Scan string pointer for hex number and return stop pointer.
Definition: strscan.h:1856
bool finish_in()
Finish (shutdown) socket input (reads).
Definition: iosock.h:1087
SocketAddressUnix & clear()
Clear current address.
Definition: iosock.h:565
IoSocket & device()
Access low-level I/O device for socket.
Definition: iosock.h:764
Socket(bool exceptions)
Constructor.
Definition: iosock.h:758
T * get_opt(int level, int optname, T *buf)
Get socket option value.
Definition: iosock.h:1203
bool listen_ip(const SubString &host, ushort port, int family=AF_INET, int backlog=BACKLOG_DEFAULT)
Create and bind TCP socket on host interface and listen for connections.
Definition: iosock.h:900
SocketCast(SocketAddressBase *address, bool exceptions=1)
Constructor.
Definition: iosock.h:1167
SocketAddressIp(const SocketAddressIp &src)
Copy constructor.
Definition: iosock.h:48
Reference and access existing string data.
Definition: substring.h:229
ulong writebin(const void *buf, ulong size)
Write binary output to stream.
Definition: iosock.h:1359
struct sockaddr addr
Generic address structure.
Definition: iosock.h:36
Base socket address.
Definition: sysio_sock.h:95
Shutdown output (writes) on socket.
Definition: sysio_sock.h:689
Function not supported/implemented.
Definition: sys.h:1121
Socket(Newline nl=NL_SYS, bool exceptions=1)
Constructor.
Definition: iosock.h:748
bool parse(const SubString &str, ushort port=0, int family=AF_UNSPEC)
Definition: iosock.h:216
bool listen_ip(ushort port, int family=AF_INET, int backlog=BACKLOG_DEFAULT)
Create and bind TCP socket on all interfaces and listen for connections.
Definition: iosock.h:921
SocketAddressUnix(struct sockaddr_un *ptr)
Constructor to copy from address.
Definition: iosock.h:538
const char * data() const
Get data pointer.
Generic socket address (used internally).
Definition: sysio_sock.h:113
Socket & set_timeout(ulong timeout_ms)
Set timeout for socket operations.
Definition: iosock.h:781
Unix Domain socket address (linux/unix).
Definition: iosock.h:515
static bool check(struct sockaddr *addr)
Check if address struct holds a supported IP address type.
Definition: iosock.h:498
ulong read(void *buf, ulong size, int flags=0, SocketAddressBase *address=NULL)
Read message from socket.
Definition: iosock.h:1324
bool format(String &str) const
Format IP address to given string (appended).
Definition: iosock.h:433
static void sysinit()
Initialize socket library.
Definition: iosock.h:1115