xdrpp
RFC4506 XDR compiler and message library
socket.cc
1 #include <cstring>
2 #include <string>
3 #include <xdrpp/socket.h>
4 
5 namespace xdr {
6 
7 using std::string;
8 
9 #if 0
10 string
11 addrinfo_to_string(const addrinfo *ai)
12 {
13  std::ostringstream os;
14  bool first{true};
15  while (ai) {
16  if (first)
17  first = false;
18  else
19  os << ", ";
20  string h, p;
21  get_numinfo(ai->ai_addr, ai->ai_addrlen, &h, &p);
22  if (h.find(':') == string::npos)
23  os << h << ':' << p;
24  else
25  os << '[' << h << "]:" << p;
26  ai = ai -> ai_next;
27  }
28  return os.str();
29 }
30 #endif
31 
32 namespace{
33 struct gai_category_impl : public std::error_category {
34  const char *name() const noexcept override { return "DNS"; }
35  string message(int err) const override { return gai_strerror(err); }
36 };
37 }
38 
39 const std::error_category &
41 {
42  static gai_category_impl cat;
43  return cat;
44 }
45 
46 namespace {
47 string
48 cat_host_service(const char *host, const char *service)
49 {
50  string target;
51  if (host) {
52  if (std::strchr(host, ':')) {
53  target += "[";
54  target += host;
55  target += "]";
56  }
57  else
58  target = host;
59  }
60  else
61  target += "NULL"; // NULL should give localhost
62  if (service) {
63  target += ":";
64  target += service;
65  }
66  return target;
67 }
68 } // namespace
69 
70 unique_addrinfo get_addrinfo(const char *host, int socktype,
71  const char *service, int family)
72 {
73  addrinfo hints, *res;
74  std::memset(&hints, 0, sizeof(hints));
75  hints.ai_socktype = socktype;
76  hints.ai_family = family;
77  hints.ai_flags = AI_ADDRCONFIG;
78  int err = getaddrinfo(host, service, &hints, &res);
79  if (err)
80  throw std::system_error(err, gai_category(),
81  cat_host_service(host, service));
82  return unique_addrinfo(res);
83 }
84 
85 void get_numinfo(const sockaddr *sa, socklen_t salen,
86  string *host, string *serv)
87 {
88  char hostbuf[NI_MAXHOST];
89  char servbuf[NI_MAXSERV];
90  int err = getnameinfo(sa, salen, hostbuf, sizeof(hostbuf),
91  servbuf, sizeof(servbuf),
92  NI_NUMERICHOST|NI_NUMERICSERV);
93  if (err)
94  throw std::system_error(err, gai_category(), "getnameinfo");
95  if (host)
96  *host = hostbuf;
97  if (serv)
98  *serv = servbuf;
99 }
100 
102 tcp_connect1(const addrinfo *ai, bool ndelay)
103 {
104  unique_sock s(socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol));
105  if (!s)
106  throw_sockerr("socket");
107  if (ndelay)
108  set_nonblock(s.get());
109  if (connect(s.get().fd_, ai->ai_addr, ai->ai_addrlen) == -1
110  && errno != EINPROGRESS)
111  s.clear();
112  return s;
113 }
114 
116 tcp_connect(const addrinfo *ai)
117 {
118  unique_sock s;
119  errno = EADDRNOTAVAIL;
120  for (; ai && !s; ai = ai->ai_next)
121  if ((s = tcp_connect1(ai)))
122  return s;
123  throw_sockerr("connect");
124 }
125 
127 tcp_connect(const char *host, const char *service, int family)
128 {
129  return tcp_connect(get_addrinfo(host, SOCK_STREAM, service, family));
130 }
131 
133 tcp_listen(const char *service, int family, int backlog)
134 {
135  addrinfo hints, *res;
136  std::memset(&hints, 0, sizeof(hints));
137  hints.ai_socktype = SOCK_STREAM;
138  hints.ai_family = family;
139  hints.ai_flags = AI_ADDRCONFIG | AI_PASSIVE;
140  int err = getaddrinfo(nullptr, service ? service : "0", &hints, &res);
141  if (err)
142  throw std::system_error(err, gai_category(), "AI_PASSIVE");
143  unique_addrinfo ai{res};
144 
145  // XXX
146  //std::cerr << "listening at " << addrinfo_to_string(ai.get()) << std::endl;
147 
148  unique_sock s(sock_t(socket(ai->ai_family, ai->ai_socktype,
149  ai->ai_protocol)));
150  if (!s)
151  throw_sockerr("socket");
152  if (bind(s.get().fd_, ai->ai_addr, ai->ai_addrlen) == -1)
153  throw_sockerr("bind");
154  if (listen (s.get().fd_, backlog) == -1)
155  throw_sockerr("listen");
156  return s;
157 }
158 
159 
160 
161 
162 }
unique_sock tcp_connect(const addrinfo *ai)
Try connecting to every addrinfo in a list until one succeeds.
Definition: socket.cc:116
void throw_sockerr(const char *)
Throw a system_error exception for the last socket error.
Definition: socket_unix.cc:31
unique_sock tcp_connect1(const addrinfo *ai, bool ndelay)
Try connecting to the first addrinfo in a linked list.
Definition: socket.cc:102
Most of the xdrpp library is encapsulated in the xdr namespace.
Definition: arpc.cc:4
std::unique_ptr< addrinfo, delete_addrinfo > unique_addrinfo
Automatically garbage-collected addrinfo pointer.
Definition: socket.h:105
void set_nonblock(sock_t s)
Set the O_NONBLOCK flag on a socket.
Definition: socket_unix.cc:70
Self-closing socket.
Definition: socket.h:124
unique_addrinfo get_addrinfo(const char *host, int socktype, const char *service, int family)
Wrapper around getaddrinfo that returns a garbage-collected xdr::unique_addrinfo. ...
Definition: socket.cc:70
const std::error_category & gai_category()
Category for system errors dealing with DNS (getaddrinfo, etc.).
Definition: socket.cc:40
unique_sock tcp_listen(const char *service, int family, int backlog)
Create bind a listening TCP socket.
Definition: socket.cc:133
sock_t get() const
Return the file descriptor number, but maintain ownership.
Definition: socket.h:138
Abstract away the type of a socket (for windows).
Definition: socket.h:28
Simplified support for creating sockets.
void get_numinfo(const sockaddr *sa, socklen_t salen, string *host, string *serv)
Return printable versions of numeric host and port number.
Definition: socket.cc:85