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 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 struct HostAndPort { 78 std::string hostname; 79 uint16_t port; 80 81 bool operator==(const HostAndPort &R) const { 82 return port == R.port && hostname == R.hostname; 83 } 84 }; 85 86 static const NativeSocket kInvalidSocketValue; 87 88 ~Socket() override; 89 90 static const char *FindSchemeByProtocol(const SocketProtocol protocol); 91 static bool FindProtocolByScheme(const char *scheme, 92 SocketProtocol &protocol); 93 94 static llvm::Error Initialize(); 95 static void Terminate(); 96 97 static std::unique_ptr<Socket> Create(const SocketProtocol protocol, 98 Status &error); 99 100 virtual Status Connect(llvm::StringRef name) = 0; 101 virtual Status Listen(llvm::StringRef name, int backlog) = 0; 102 103 // Use the provided main loop instance to accept new connections. The callback 104 // will be called (from MainLoop::Run) for each new connection. This function 105 // does not block. 106 virtual llvm::Expected<std::vector<MainLoopBase::ReadHandleUP>> 107 Accept(MainLoopBase &loop, 108 std::function<void(std::unique_ptr<Socket> socket)> sock_cb) = 0; 109 110 // Accept a single connection and "return" it in the pointer argument. This 111 // function blocks until the connection arrives. 112 virtual Status Accept(const Timeout<std::micro> &timeout, Socket *&socket); 113 114 // Initialize a Tcp Socket object in listening mode. listen and accept are 115 // implemented separately because the caller may wish to manipulate or query 116 // the socket after it is initialized, but before entering a blocking accept. 117 static llvm::Expected<std::unique_ptr<TCPSocket>> 118 TcpListen(llvm::StringRef host_and_port, int backlog = 5); 119 120 static llvm::Expected<std::unique_ptr<Socket>> 121 TcpConnect(llvm::StringRef host_and_port); 122 123 static llvm::Expected<std::unique_ptr<UDPSocket>> 124 UdpConnect(llvm::StringRef host_and_port); 125 126 static int GetOption(NativeSocket sockfd, int level, int option_name, 127 int &option_value); 128 int GetOption(int level, int option_name, int &option_value) { 129 return GetOption(m_socket, level, option_name, option_value); 130 }; 131 132 static int SetOption(NativeSocket sockfd, int level, int option_name, 133 int option_value); 134 int SetOption(int level, int option_name, int option_value) { 135 return SetOption(m_socket, level, option_name, option_value); 136 }; 137 138 NativeSocket GetNativeSocket() const { return m_socket; } 139 SocketProtocol GetSocketProtocol() const { return m_protocol; } 140 141 Status Read(void *buf, size_t &num_bytes) override; 142 Status Write(const void *buf, size_t &num_bytes) override; 143 144 Status Close() override; 145 146 bool IsValid() const override { return m_socket != kInvalidSocketValue; } 147 WaitableHandle GetWaitableHandle() override; 148 149 static llvm::Expected<HostAndPort> 150 DecodeHostAndPort(llvm::StringRef host_and_port); 151 152 // If this Socket is connected then return the URI used to connect. 153 virtual std::string GetRemoteConnectionURI() const { return ""; }; 154 155 // If the Socket is listening then return the URI for clients to connect. 156 virtual std::vector<std::string> GetListeningConnectionURI() const { 157 return {}; 158 } 159 160 protected: 161 Socket(SocketProtocol protocol, bool should_close); 162 163 virtual size_t Send(const void *buf, const size_t num_bytes); 164 165 static int CloseSocket(NativeSocket sockfd); 166 static Status GetLastError(); 167 static void SetLastError(Status &error); 168 static NativeSocket CreateSocket(const int domain, const int type, 169 const int protocol, Status &error); 170 static NativeSocket AcceptSocket(NativeSocket sockfd, struct sockaddr *addr, 171 socklen_t *addrlen, Status &error); 172 173 SocketProtocol m_protocol; 174 NativeSocket m_socket; 175 bool m_should_close_fd; 176 }; 177 178 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, 179 const Socket::HostAndPort &HP); 180 181 } // namespace lldb_private 182 183 #endif // LLDB_HOST_SOCKET_H 184