esp8266ndn
NDN Arduino library for ESP8266 and more
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
udp-unicast.hpp
Go to the documentation of this file.
1 #ifndef NDNPH_PORT_TRANSPORT_SOCKET_UDP_UNICAST_HPP
2 #define NDNPH_PORT_TRANSPORT_SOCKET_UDP_UNICAST_HPP
3 
4 #include "../../../face/transport-rxqueue.hpp"
5 #include "ipv6-endpointid.hpp"
6 
7 #include <arpa/inet.h>
8 #include <netinet/in.h>
9 #include <sys/socket.h>
10 #include <sys/types.h>
11 #include <unistd.h>
12 
13 namespace ndnph {
14 namespace port_transport_socket {
15 
18  : public virtual Transport
20 public:
21  explicit UdpUnicastTransport(size_t bufLen = DEFAULT_BUFLEN)
22  : DynamicRxQueueMixin(bufLen) {}
23 
24  ~UdpUnicastTransport() override {
25  end();
26  }
27 
33  bool beginListen(const sockaddr_in* laddr) {
34  return (createSocket(laddr->sin_family) &&
35  bindSocket(reinterpret_cast<const sockaddr*>(laddr))) ||
36  closeSocketOnError();
37  }
38 
45  bool beginListen(const sockaddr_in6* laddr, int v6only = -1) {
46  return (createSocket(laddr->sin6_family) && changeV6Only(v6only) &&
47  bindSocket(reinterpret_cast<const sockaddr*>(laddr))) ||
48  closeSocketOnError();
49  }
50 
55  bool beginListen(uint16_t localPort = 6363) {
56  sockaddr_in6 laddr{};
57  laddr.sin6_family = AF_INET6;
58  laddr.sin6_addr = in6addr_any;
59  laddr.sin6_port = htons(localPort);
60  return beginListen(&laddr, 0);
61  }
62 
68  bool beginTunnel(const sockaddr_in* raddr) {
69  return (createSocket(raddr->sin_family) &&
70  connectSocket(reinterpret_cast<const sockaddr*>(raddr))) ||
71  closeSocketOnError();
72  }
73 
80  bool beginTunnel(const sockaddr_in6* raddr, int v6only = -1) {
81  return (createSocket(raddr->sin6_family) && changeV6Only(v6only) &&
82  connectSocket(reinterpret_cast<const sockaddr*>(raddr))) ||
83  closeSocketOnError();
84  }
85 
91  bool beginTunnel(std::initializer_list<uint8_t> remoteHost, uint16_t remotePort = 6363) {
92  sockaddr_in raddr{};
93  if (remoteHost.size() != sizeof(raddr.sin_addr)) {
94  return false;
95  }
96  raddr.sin_family = AF_INET;
97  std::copy(remoteHost.begin(), remoteHost.end(), reinterpret_cast<uint8_t*>(&raddr.sin_addr));
98  raddr.sin_port = htons(remotePort);
99  return beginTunnel(&raddr);
100  }
101 
103  bool end() {
104  if (m_fd < 0) {
105  return true;
106  }
107  int ok = close(m_fd);
108  m_fd = -1;
109  return ok == 0;
110  }
111 
112 private:
113  bool doIsUp() const final {
114  return m_fd >= 0;
115  }
116 
117  void doLoop() final {
118  const auto& p = getAddressFamilyParams(m_af);
119  uint8_t raddr[std::max(sizeof(sockaddr_in), sizeof(sockaddr_in6))];
120  iovec iov{};
121  while (auto r = receiving()) {
122  iov.iov_base = r.buf();
123  iov.iov_len = r.bufLen();
124  msghdr msg{};
125  msg.msg_name = raddr;
126  msg.msg_namelen = sizeof(raddr);
127  msg.msg_iov = &iov;
128  msg.msg_iovlen = 1;
129 
130  ssize_t pktLen = recvmsg(m_fd, &msg, 0);
131  if (pktLen < 0 || (msg.msg_flags & MSG_TRUNC) != 0 || msg.msg_namelen != p.nameLen) {
132  clearSocketError();
133  break;
134  }
135 
136  in_port_t port = *reinterpret_cast<const in_port_t*>(raddr + p.portOff);
137  uint64_t endpointId = m_endpoints.encode(raddr + p.ipOff, p.ipLen, port);
138  r(pktLen, endpointId);
139  }
140 
141  loopRxQueue();
142  }
143 
144  bool doSend(const uint8_t* pkt, size_t pktLen, uint64_t endpointId) final {
145  const auto& p = getAddressFamilyParams(m_af);
146  uint8_t raddrBuf[std::max(sizeof(sockaddr_in), sizeof(sockaddr_in6))];
147  sockaddr* raddr = nullptr;
148  socklen_t raddrLen = 0;
149  if (endpointId != 0) {
150  if (m_endpoints.decode(endpointId, raddrBuf + p.ipOff,
151  reinterpret_cast<in_port_t*>(raddrBuf + p.portOff)) != p.ipLen) {
152  return false;
153  }
154  raddr = reinterpret_cast<sockaddr*>(raddrBuf);
155  raddr->sa_family = m_af;
156  raddrLen = p.nameLen;
157  }
158 
159  ssize_t sentLen = sendto(m_fd, pkt, pktLen, 0, raddr, raddrLen);
160  if (sentLen >= 0) {
161  return true;
162  }
163  clearSocketError();
164  return false;
165  }
166 
167 private:
168  struct AddressFamilyParams {
169  socklen_t nameLen;
170  ptrdiff_t ipOff;
171  socklen_t ipLen;
172  ptrdiff_t portOff;
173  const char* fmtBracketL;
174  const char* fmtBracketR;
175  };
176 
177  static const AddressFamilyParams& getAddressFamilyParams(sa_family_t family) {
178  static const AddressFamilyParams inet = {
179  .nameLen = sizeof(sockaddr_in),
180  .ipOff = offsetof(sockaddr_in, sin_addr),
181  .ipLen = sizeof(in_addr),
182  .portOff = offsetof(sockaddr_in, sin_port),
183  .fmtBracketL = "",
184  .fmtBracketR = "",
185  };
186  static const AddressFamilyParams inet6 = {
187  .nameLen = sizeof(sockaddr_in6),
188  .ipOff = offsetof(sockaddr_in6, sin6_addr),
189  .ipLen = sizeof(in6_addr),
190  .portOff = offsetof(sockaddr_in6, sin6_port),
191  .fmtBracketL = "",
192  .fmtBracketR = "",
193  };
194  switch (family) {
195  case AF_INET:
196  return inet;
197  case AF_INET6:
198  return inet6;
199  default:
200  NDNPH_ASSERT(false);
201  return inet;
202  }
203  }
204 
205  bool createSocket(sa_family_t family) {
206  end();
207  m_fd = socket(family, SOCK_DGRAM | SOCK_NONBLOCK, 0);
208  if (m_fd < 0) {
209 #ifdef NDNPH_SOCKET_DEBUG
210  perror("UdpUnicastTransport socket()");
211 #endif
212  return false;
213  }
214  m_af = family;
215 
216  const int yes = 1;
217  if (setsockopt(m_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) {
218 #ifdef NDNPH_SOCKET_DEBUG
219  perror("UdpUnicastTransport setsockopt(SO_REUSEADDR)");
220 #endif
221  return false;
222  }
223  return true;
224  }
225 
226  bool changeV6Only(int v6only) {
227  if (v6only < 0) {
228  return true;
229  }
230  int value = v6only > 0 ? 1 : 0;
231  if (setsockopt(m_fd, IPPROTO_IPV6, IPV6_V6ONLY, &value, sizeof(value)) < 0) {
232 #ifdef NDNPH_SOCKET_DEBUG
233  perror("UdpUnicastTransport setsockopt(IPV6_V6ONLY)");
234 #endif
235  return false;
236  }
237  return true;
238  }
239 
240  bool bindSocket(const sockaddr* laddr) {
241  const auto& p = getAddressFamilyParams(laddr->sa_family);
242  if (bind(m_fd, laddr, p.nameLen) < 0) {
243 #ifdef NDNPH_SOCKET_DEBUG
244  perror("UdpUnicastTransport bind()");
245 #endif
246  return false;
247  }
248 #ifdef NDNPH_SOCKET_DEBUG
249  char addrBuf[std::max(INET_ADDRSTRLEN, INET6_ADDRSTRLEN)];
250  inet_ntop(laddr->sa_family, reinterpret_cast<const uint8_t*>(laddr) + p.ipOff, addrBuf,
251  sizeof(addrBuf));
252  in_port_t port =
253  *reinterpret_cast<const in_port_t*>(reinterpret_cast<const uint8_t*>(laddr) + p.portOff);
254  fprintf(stderr, "UdpUnicastTransport bind(%s%s%s:%" PRIu16 ")\n", p.fmtBracketL, addrBuf,
255  p.fmtBracketR, ntohs(port));
256 #endif
257  return true;
258  }
259 
260  bool connectSocket(const sockaddr* raddr) {
261  const auto& p = getAddressFamilyParams(raddr->sa_family);
262  if (connect(m_fd, raddr, p.nameLen) < 0) {
263 #ifdef NDNPH_SOCKET_DEBUG
264  perror("UdpUnicastTransport connect()");
265 #endif
266  return false;
267  }
268 #ifdef NDNPH_SOCKET_DEBUG
269  char addrBuf[std::max(INET_ADDRSTRLEN, INET6_ADDRSTRLEN)];
270  inet_ntop(raddr->sa_family, reinterpret_cast<const uint8_t*>(raddr) + p.ipOff, addrBuf,
271  sizeof(addrBuf));
272  in_port_t port =
273  *reinterpret_cast<const in_port_t*>(reinterpret_cast<const uint8_t*>(raddr) + p.portOff);
274  fprintf(stderr, "UdpUnicastTransport connect(%s%s%s:%" PRIu16 ")\n", p.fmtBracketL, addrBuf,
275  p.fmtBracketR, ntohs(port));
276 #endif
277  return true;
278  }
279 
280  bool closeSocketOnError() {
281  if (m_fd >= 0) {
282  close(m_fd);
283  m_af = AF_UNSPEC;
284  m_fd = -1;
285  m_mtu = -1;
286  }
287  return false;
288  }
289 
290  void clearSocketError() {
291  int error = 0;
292  socklen_t len = sizeof(error);
293  getsockopt(m_fd, SOL_SOCKET, SO_ERROR, &error, &len);
294 #ifdef NDNPH_SOCKET_DEBUG
295  if (error != 0) {
296  errno = error;
297  perror("UdpUnicastTransport getsockopt(SO_ERROR)");
298  }
299 #endif
300  }
301 
302 private:
303  Ipv6EndpointIdHelper<15> m_endpoints;
304  int m_fd = -1;
305  ssize_t m_mtu = -1;
306  sa_family_t m_af = AF_UNSPEC;
307 };
308 
309 } // namespace port_transport_socket
310 
312 
313 } // namespace ndnph
314 
315 #endif // NDNPH_PORT_TRANSPORT_SOCKET_UDP_UNICAST_HPP
size_t decode(uint64_t endpointId, uint8_t addr[16], uint16_t *port)
Unpack IP address+port from EndpointId.
Definition: ipv6-endpointid.hpp:72
uint64_t encode(const uint8_t *addr, size_t addrLen, uint16_t port)
Pack IP address+port into EndpointId.
Definition: ipv6-endpointid.hpp:32
A transport that communicates over IPv4 unicast UDP tunnel.
Definition: udp-unicast.hpp:19
bool beginListen(const sockaddr_in6 *laddr, int v6only=-1)
Start listening on given local IPv6 address.
Definition: udp-unicast.hpp:45
bool beginTunnel(const sockaddr_in6 *raddr, int v6only=-1)
Connect to given remote IPv6 address.
Definition: udp-unicast.hpp:80
~UdpUnicastTransport() override
Definition: udp-unicast.hpp:24
bool beginListen(const sockaddr_in *laddr)
Start listening on given local IPv4 address.
Definition: udp-unicast.hpp:33
bool beginTunnel(std::initializer_list< uint8_t > remoteHost, uint16_t remotePort=6363)
Connect to given remote IP and port.
Definition: udp-unicast.hpp:91
UdpUnicastTransport(size_t bufLen=DEFAULT_BUFLEN)
Definition: udp-unicast.hpp:21
bool beginTunnel(const sockaddr_in *raddr)
Connect to given remote IPv4 address.
Definition: udp-unicast.hpp:68
bool end()
Stop listening or close connection.
Definition: udp-unicast.hpp:103
bool beginListen(uint16_t localPort=6363)
Start listening on given local port for both IPv4 and IPv6.
Definition: udp-unicast.hpp:55
Mixin of RX queue in Transport, allocating buffers from DynamicRegion.
Definition: transport-rxqueue.hpp:134
static constexpr size_t DEFAULT_BUFLEN
Definition: transport-rxqueue.hpp:136
DynamicRxQueueMixin(size_t bufLen=DEFAULT_BUFLEN)
Constructor.
Definition: transport-rxqueue.hpp:143
RxContext receiving()
Receive packets in a loop.
Definition: transport-rxqueue.hpp:103
void loopRxQueue()
Process periodical events.
Definition: transport-rxqueue.hpp:113
Base class of low-level transport.
Definition: transport.hpp:10
#define NDNPH_ASSERT(x)
Definition: common.hpp:30
Definition: fs.hpp:33
port_transport_socket::UdpUnicastTransport UdpUnicastTransport
Definition: udp-unicast.hpp:311