xref: /freebsd/contrib/llvm-project/lldb/include/lldb/Host/Socket.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
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