esp8266ndn
NDN Arduino library for ESP8266 and more
Loading...
Searching...
No Matches
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
13namespace ndnph {
14namespace port_transport_socket {
15
18 : public virtual Transport
20public:
21 explicit UdpUnicastTransport(size_t bufLen = DEFAULT_BUFLEN)
22 : DynamicRxQueueMixin(bufLen) {}
23
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
112private:
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
167private:
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
302private:
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 doSend(const uint8_t *pkt, size_t pktLen, uint64_t endpointId) final
Definition udp-unicast.hpp:144
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 doIsUp() const final
Definition udp-unicast.hpp:113
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
void doLoop() final
Definition udp-unicast.hpp:117
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