1 //===-- Socket.h ------------------------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef LLDB_HOST_SOCKET_H 10 #define LLDB_HOST_SOCKET_H 11 12 #include <memory> 13 #include <string> 14 #include <vector> 15 16 #include "lldb/Host/MainLoopBase.h" 17 #include "lldb/Utility/Timeout.h" 18 #include "lldb/lldb-private.h" 19 20 #include "lldb/Host/SocketAddress.h" 21 #include "lldb/Utility/IOObject.h" 22 #include "lldb/Utility/Status.h" 23 24 #ifdef _WIN32 25 #include "lldb/Host/Pipe.h" 26 #include "lldb/Host/windows/windows.h" 27 #include <winsock2.h> 28 #include <ws2tcpip.h> 29 #endif 30 31 namespace llvm { 32 class StringRef; 33 } 34 35 namespace lldb_private { 36 37 #if defined(_WIN32) 38 typedef SOCKET NativeSocket; 39 typedef lldb::pipe_t shared_fd_t; 40 #else 41 typedef int NativeSocket; 42 typedef NativeSocket shared_fd_t; 43 #endif 44 class Socket; 45 class TCPSocket; 46 class UDPSocket; 47 48 class SharedSocket { 49 public: 50 static const shared_fd_t kInvalidFD; 51 52 SharedSocket(const Socket *socket, Status &error); 53 GetSendableFD()54 shared_fd_t GetSendableFD() { return m_fd; } 55 56 Status CompleteSending(lldb::pid_t child_pid); 57 58 static Status GetNativeSocket(shared_fd_t fd, NativeSocket &socket); 59 60 private: 61 #ifdef _WIN32 62 Pipe m_socket_pipe; 63 NativeSocket m_socket; 64 #endif 65 shared_fd_t m_fd; 66 }; 67 68 class Socket : public IOObject { 69 public: 70 enum SocketProtocol { 71 ProtocolTcp, 72 ProtocolUdp, 73 ProtocolUnixDomain, 74 ProtocolUnixAbstract 75 }; 76 77 enum SocketMode { 78 ModeAccept, 79 ModeConnect, 80 }; 81 82 struct HostAndPort { 83 std::string hostname; 84 uint16_t port; 85 86 bool operator==(const HostAndPort &R) const { 87 return port == R.port && hostname == R.hostname; 88 } 89 }; 90 91 using ProtocolModePair = std::pair<SocketProtocol, SocketMode>; 92 static std::optional<ProtocolModePair> 93 GetProtocolAndMode(llvm::StringRef scheme); 94 95 static const NativeSocket kInvalidSocketValue; 96 97 ~Socket() override; 98 99 static const char *FindSchemeByProtocol(const SocketProtocol protocol); 100 static bool FindProtocolByScheme(const char *scheme, 101 SocketProtocol &protocol); 102 103 static llvm::Error Initialize(); 104 static void Terminate(); 105 106 static std::unique_ptr<Socket> Create(const SocketProtocol protocol, 107 Status &error); 108 109 using Pair = std::pair<std::unique_ptr<Socket>, std::unique_ptr<Socket>>; 110 static llvm::Expected<Pair> 111 CreatePair(std::optional<SocketProtocol> protocol = std::nullopt); 112 113 virtual Status Connect(llvm::StringRef name) = 0; 114 virtual Status Listen(llvm::StringRef name, int backlog) = 0; 115 116 // Use the provided main loop instance to accept new connections. The callback 117 // will be called (from MainLoop::Run) for each new connection. This function 118 // does not block. 119 virtual llvm::Expected<std::vector<MainLoopBase::ReadHandleUP>> 120 Accept(MainLoopBase &loop, 121 std::function<void(std::unique_ptr<Socket> socket)> sock_cb) = 0; 122 123 // Accept a single connection and "return" it in the pointer argument. This 124 // function blocks until the connection arrives. 125 virtual Status Accept(const Timeout<std::micro> &timeout, Socket *&socket); 126 127 // Initialize a Tcp Socket object in listening mode. listen and accept are 128 // implemented separately because the caller may wish to manipulate or query 129 // the socket after it is initialized, but before entering a blocking accept. 130 static llvm::Expected<std::unique_ptr<TCPSocket>> 131 TcpListen(llvm::StringRef host_and_port, int backlog = 5); 132 133 static llvm::Expected<std::unique_ptr<Socket>> 134 TcpConnect(llvm::StringRef host_and_port); 135 136 static llvm::Expected<std::unique_ptr<UDPSocket>> 137 UdpConnect(llvm::StringRef host_and_port); 138 139 static int GetOption(NativeSocket sockfd, int level, int option_name, 140 int &option_value); GetOption(int level,int option_name,int & option_value)141 int GetOption(int level, int option_name, int &option_value) { 142 return GetOption(m_socket, level, option_name, option_value); 143 }; 144 145 static int SetOption(NativeSocket sockfd, int level, int option_name, 146 int option_value); SetOption(int level,int option_name,int option_value)147 int SetOption(int level, int option_name, int option_value) { 148 return SetOption(m_socket, level, option_name, option_value); 149 }; 150 GetNativeSocket()151 NativeSocket GetNativeSocket() const { return m_socket; } GetSocketProtocol()152 SocketProtocol GetSocketProtocol() const { return m_protocol; } 153 154 Status Read(void *buf, size_t &num_bytes) override; 155 Status Write(const void *buf, size_t &num_bytes) override; 156 157 Status Close() override; 158 IsValid()159 bool IsValid() const override { return m_socket != kInvalidSocketValue; } 160 WaitableHandle GetWaitableHandle() override; 161 162 static llvm::Expected<HostAndPort> 163 DecodeHostAndPort(llvm::StringRef host_and_port); 164 165 // If this Socket is connected then return the URI used to connect. GetRemoteConnectionURI()166 virtual std::string GetRemoteConnectionURI() const { return ""; }; 167 168 // If the Socket is listening then return the URI for clients to connect. GetListeningConnectionURI()169 virtual std::vector<std::string> GetListeningConnectionURI() const { 170 return {}; 171 } 172 173 protected: 174 Socket(SocketProtocol protocol, bool should_close); 175 176 virtual size_t Send(const void *buf, const size_t num_bytes); 177 178 static int CloseSocket(NativeSocket sockfd); 179 static Status GetLastError(); 180 static void SetLastError(Status &error); 181 static NativeSocket CreateSocket(const int domain, const int type, 182 const int protocol, Status &error); 183 static NativeSocket AcceptSocket(NativeSocket sockfd, struct sockaddr *addr, 184 socklen_t *addrlen, Status &error); 185 186 SocketProtocol m_protocol; 187 NativeSocket m_socket; 188 bool m_should_close_fd; 189 }; 190 191 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, 192 const Socket::HostAndPort &HP); 193 194 } // namespace lldb_private 195 196 #endif // LLDB_HOST_SOCKET_H 197