1 #ifndef NDNPH_PORT_TRANSPORT_SOCKET_UDP_UNICAST_HPP
2 #define NDNPH_PORT_TRANSPORT_SOCKET_UDP_UNICAST_HPP
4 #include "../../../face/transport-rxqueue.hpp"
8 #include <netinet/in.h>
9 #include <sys/socket.h>
10 #include <sys/types.h>
14 namespace port_transport_socket {
34 return (createSocket(laddr->sin_family) &&
35 bindSocket(
reinterpret_cast<const sockaddr*
>(laddr))) ||
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))) ||
57 laddr.sin6_family = AF_INET6;
58 laddr.sin6_addr = in6addr_any;
59 laddr.sin6_port = htons(localPort);
69 return (createSocket(raddr->sin_family) &&
70 connectSocket(
reinterpret_cast<const sockaddr*
>(raddr))) ||
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))) ||
91 bool beginTunnel(std::initializer_list<uint8_t> remoteHost, uint16_t remotePort = 6363) {
93 if (remoteHost.size() !=
sizeof(raddr.sin_addr)) {
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);
107 int ok = close(m_fd);
113 bool doIsUp() const final {
117 void doLoop() final {
118 const auto& p = getAddressFamilyParams(m_af);
119 uint8_t raddr[std::max(
sizeof(sockaddr_in),
sizeof(sockaddr_in6))];
122 iov.iov_base = r.buf();
123 iov.iov_len = r.bufLen();
125 msg.msg_name = raddr;
126 msg.msg_namelen =
sizeof(raddr);
130 ssize_t pktLen = recvmsg(m_fd, &msg, 0);
131 if (pktLen < 0 || (msg.msg_flags & MSG_TRUNC) != 0 || msg.msg_namelen != p.nameLen) {
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);
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) {
154 raddr =
reinterpret_cast<sockaddr*
>(raddrBuf);
155 raddr->sa_family = m_af;
156 raddrLen = p.nameLen;
159 ssize_t sentLen = sendto(m_fd, pkt, pktLen, 0, raddr, raddrLen);
168 struct AddressFamilyParams {
173 const char* fmtBracketL;
174 const char* fmtBracketR;
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),
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),
205 bool createSocket(sa_family_t family) {
207 m_fd = socket(family, SOCK_DGRAM | SOCK_NONBLOCK, 0);
209 #ifdef NDNPH_SOCKET_DEBUG
210 perror(
"UdpUnicastTransport socket()");
217 if (setsockopt(m_fd, SOL_SOCKET, SO_REUSEADDR, &yes,
sizeof(yes)) < 0) {
218 #ifdef NDNPH_SOCKET_DEBUG
219 perror(
"UdpUnicastTransport setsockopt(SO_REUSEADDR)");
226 bool changeV6Only(
int v6only) {
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)");
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()");
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,
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));
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()");
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,
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));
280 bool closeSocketOnError() {
290 void clearSocketError() {
292 socklen_t len =
sizeof(error);
293 getsockopt(m_fd, SOL_SOCKET, SO_ERROR, &error, &len);
294 #ifdef NDNPH_SOCKET_DEBUG
297 perror(
"UdpUnicastTransport getsockopt(SO_ERROR)");
303 Ipv6EndpointIdHelper<15> m_endpoints;
306 sa_family_t m_af = AF_UNSPEC;
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
port_transport_socket::UdpUnicastTransport UdpUnicastTransport
Definition: udp-unicast.hpp:311