/* * Copyright (c) 2021 Cisco and/or its affiliates. */ #pragma once #include #include #include #include namespace std { template <> struct hash { size_t operator()(const asio::ip::udp::endpoint &endpoint) const; }; } // namespace std namespace transport { namespace core { class UdpTunnelListener : public std::enable_shared_from_this { using PacketReceivedCallback = Connector::PacketReceivedCallback; using EndpointId = std::pair; static constexpr uint16_t default_port = 5004; public: using Ptr = std::shared_ptr; template UdpTunnelListener(asio::io_service &io_service, ReceiveCallback &&receive_callback, asio::ip::udp::endpoint endpoint = asio::ip::udp::endpoint( asio::ip::udp::v4(), default_port)) : io_service_(io_service), strand_(std::make_shared(io_service_)), socket_(std::make_shared(io_service_, endpoint.protocol())), local_endpoint_(endpoint), receive_callback_(std::forward(receive_callback)), #ifndef LINUX read_msg_(nullptr, 0) #else iovecs_{}, msgs_{}, current_position_(0) #endif { if (endpoint.protocol() == asio::ip::udp::v6()) { std::error_code ec; socket_->set_option(asio::ip::v6_only(false), ec); // Call succeeds only on dual stack systems. } socket_->bind(local_endpoint_); io_service_.post(std::bind(&UdpTunnelListener::doRecvPacket, this)); } ~UdpTunnelListener(); void close(); int deleteConnector(Connector *connector) { return (int)connectors_.erase(connector->getConnectorId()); } template void setReceiveCallback(ReceiveCallback &&callback) { receive_callback_ = std::forward(callback); } Connector *findConnector(Connector::Id connId) { auto it = connectors_.find(connId); if (it != connectors_.end()) { return it->second.get(); } return nullptr; } private: void doRecvPacket(); void readHandler(const std::error_code &ec); asio::io_service &io_service_; std::shared_ptr strand_; std::shared_ptr socket_; asio::ip::udp::endpoint local_endpoint_; asio::ip::udp::endpoint remote_endpoint_; std::unordered_map> connectors_; PacketReceivedCallback receive_callback_; #ifdef LINUX struct iovec iovecs_[Connector::max_burst][8]; struct mmsghdr msgs_[Connector::max_burst]; struct sockaddr_storage remote_endpoints_[Connector::max_burst]; std::uint8_t current_position_; #else std::pair read_msg_; #endif }; } // namespace core } // namespace transport