// ftpd is a server implementation based on the following: // - RFC 959 (https://tools.ietf.org/html/rfc959) // - RFC 3659 (https://tools.ietf.org/html/rfc3659) // - suggested implementation details from https://cr.yp.to/ftp/filesystem.html // // Copyright (C) 2024 Michael Theall // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . #pragma once #include "ioBuffer.h" #include "sockAddr.h" #include #include #ifdef __NDS__ struct pollfd { int fd; int events; int revents; }; using nfds_t = unsigned int; extern "C" int poll (pollfd *fds_, nfds_t nfds_, int timeout_); #define POLLIN (1 << 0) #define POLLPRI (1 << 1) #define POLLOUT (1 << 2) #define POLLERR (1 << 3) #define POLLHUP (1 << 4) #else #include #endif class Socket; using UniqueSocket = std::unique_ptr; using SharedSocket = std::shared_ptr; /// \brief Socket object class Socket { public: enum Type { eStream = SOCK_STREAM, ///< Stream socket eDatagram = SOCK_DGRAM, ///< Datagram socket }; /// \brief Poll info struct PollInfo { /// \brief Socket to poll std::reference_wrapper socket; /// \brief Input events int events; /// \brief Output events int revents; }; ~Socket (); /// \brief Accept connection UniqueSocket accept (); /// \brief Whether socket is at out-of-band mark int atMark (); /// \brief Bind socket to address /// \param addr_ Address to bind bool bind (SockAddr const &addr_); /// \brief Connect to a peer /// \param addr_ Peer address bool connect (SockAddr const &addr_); /// \brief Listen for connections /// \param backlog_ Queue size for incoming connections bool listen (int backlog_); /// \brief Shutdown socket /// \param how_ Type of shutdown (\sa ::shutdown) bool shutdown (int how_); /// \brief Set linger option /// \param enable_ Whether to enable linger /// \param time_ Linger timeout bool setLinger (bool enable_, std::chrono::seconds time_); /// \brief Set non-blocking /// \param nonBlocking_ Whether to set non-blocking bool setNonBlocking (bool nonBlocking_ = true); bool setWinScale (const int val); /// \brief Set reuse address in subsequent bind /// \param reuse_ Whether to reuse address bool setReuseAddress (bool reuse_ = true); /// \brief Set recv buffer size /// \param size_ Buffer size bool setRecvBufferSize (std::size_t size_); /// \brief Set send buffer size /// \param size_ Buffer size bool setSendBufferSize (std::size_t size_); #ifndef __NDS__ /// \brief Join multicast group /// \param addr_ Multicast group address /// \param iface_ Interface address bool joinMulticastGroup (SockAddr const &addr_, SockAddr const &iface_); /// \brief Drop multicast group /// \param addr_ Multicast group address /// \param iface_ Interface address bool dropMulticastGroup (SockAddr const &addr_, SockAddr const &iface_); #endif /// \brief Read data /// \param buffer_ Output buffer /// \param size_ Size to read /// \param oob_ Whether to read from out-of-band std::make_signed_t read (void *buffer_, std::size_t size_, bool oob_ = false); /// \brief Read data /// \param buffer_ Output buffer /// \param oob_ Whether to read from out-of-band std::make_signed_t read (IOBuffer &buffer_, bool oob_ = false); /// \brief Read data /// \param buffer_ Output buffer /// \param size_ Size to read /// \param[out] addr_ Source address std::make_signed_t readFrom (void *buffer_, std::size_t size_, SockAddr &addr_); /// \brief Write data /// \param buffer_ Input buffer /// \param size_ Size to write std::make_signed_t write (void const *buffer_, std::size_t size_); /// \brief Write data /// \param buffer_ Input buffer /// \param size_ Size to write std::make_signed_t write (IOBuffer &buffer_); /// \brief Write data /// \param buffer_ Input buffer /// \param size_ Size to write /// \param[out] addr_ Destination address std::make_signed_t writeTo (void const *buffer_, std::size_t size_, SockAddr const &addr_); /// \brief Local name SockAddr const &sockName () const; /// \brief Peer name SockAddr const &peerName () const; /// \brief Create socket /// \param type_ Socket type static UniqueSocket create (Type type_); /// \brief Poll sockets /// \param info_ Poll info /// \param count_ Number of poll entries /// \param timeout_ Poll timeout static int poll (PollInfo *info_, std::size_t count_, std::chrono::milliseconds timeout_); private: Socket () = delete; /// \brief Parameterized constructor /// \param fd_ Socket fd Socket (int fd_); /// \brief Parameterized constructor /// \param fd_ Socket fd /// \param sockName_ Local name /// \param peerName_ Peer name Socket (int fd_, SockAddr const &sockName_, SockAddr const &peerName_); Socket (Socket const &that_) = delete; Socket (Socket &&that_) = delete; Socket &operator= (Socket const &that_) = delete; Socket &operator= (Socket &&that_) = delete; /// \param Local name SockAddr m_sockName; /// \param Peer name SockAddr m_peerName; /// \param Socket fd int const m_fd; /// \param Whether listening bool m_listening : 1; /// \param Whether connected bool m_connected : 1; };