1 /* 2 * Copyright (C) 2019 Savoir-faire Linux Inc. 3 * Author(s) : Adrien Béraud <adrien.beraud@savoirfairelinux.com> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 3 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <https://www.gnu.org/licenses/>. 17 */ 18 #pragma once 19 20 #include "def.h" 21 22 #include "sockaddr.h" 23 #include "utils.h" 24 #include "log_enable.h" 25 26 #ifdef _WIN32 27 #include <ws2tcpip.h> 28 #include <winsock2.h> 29 #else 30 #include <sys/socket.h> 31 #include <netinet/in.h> 32 #include <unistd.h> 33 #endif 34 35 #include <functional> 36 #include <thread> 37 #include <atomic> 38 #include <iostream> 39 40 namespace dht { 41 namespace net { 42 43 static const constexpr in_port_t DHT_DEFAULT_PORT = 4222; 44 45 int bindSocket(const SockAddr& addr, SockAddr& bound); 46 47 bool setNonblocking(int fd, bool nonblocking = true); 48 49 #ifdef _WIN32 50 void udpPipe(int fds[2]); 51 #endif 52 struct ReceivedPacket { 53 Blob data; 54 SockAddr from; 55 time_point received; 56 }; 57 58 class OPENDHT_PUBLIC DatagramSocket { 59 public: 60 using OnReceive = std::function<void(std::unique_ptr<ReceivedPacket>&& packet)>; ~DatagramSocket()61 virtual ~DatagramSocket() {}; 62 63 virtual int sendTo(const SockAddr& dest, const uint8_t* data, size_t size, bool replied) = 0; 64 setOnReceive(OnReceive && cb)65 inline void setOnReceive(OnReceive&& cb) { 66 rx_callback = std::move(cb); 67 } 68 69 virtual const SockAddr& getBound(sa_family_t family = AF_UNSPEC) const = 0; 70 virtual bool hasIPv4() const = 0; 71 virtual bool hasIPv6() const = 0; 72 73 in_port_t getPort(sa_family_t family = AF_UNSPEC) const { 74 return getBound(family).getPort(); 75 } 76 77 virtual void stop() = 0; 78 protected: 79 onReceived(std::unique_ptr<ReceivedPacket> && packet)80 inline void onReceived(std::unique_ptr<ReceivedPacket>&& packet) { 81 if (rx_callback) 82 rx_callback(std::move(packet)); 83 } 84 private: 85 OnReceive rx_callback; 86 }; 87 88 class OPENDHT_PUBLIC UdpSocket : public DatagramSocket { 89 public: 90 UdpSocket(in_port_t port, const Logger& l = {}); 91 UdpSocket(const SockAddr& bind4, const SockAddr& bind6, const Logger& l = {}); 92 ~UdpSocket(); 93 94 int sendTo(const SockAddr& dest, const uint8_t* data, size_t size, bool replied) override; 95 96 const SockAddr& getBound(sa_family_t family = AF_UNSPEC) const override { 97 return (family == AF_INET6) ? bound6 : bound4; 98 } 99 hasIPv4()100 bool hasIPv4() const override { return s4 != -1; } hasIPv6()101 bool hasIPv6() const override { return s6 != -1; } 102 103 void stop() override; 104 private: 105 Logger logger; 106 int s4 {-1}; 107 int s6 {-1}; 108 int stopfd {-1}; 109 SockAddr bound4, bound6; 110 std::thread rcv_thread {}; 111 std::atomic_bool running {false}; 112 113 void openSockets(const SockAddr& bind4, const SockAddr& bind6); 114 }; 115 116 } 117 } 118