1 //===-- llvm/Support/raw_socket_stream.h - Socket streams --*- 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 // This file contains raw_ostream implementations for streams to communicate 10 // via UNIX sockets 11 // 12 //===----------------------------------------------------------------------===// 13 14 #ifndef LLVM_SUPPORT_RAW_SOCKET_STREAM_H 15 #define LLVM_SUPPORT_RAW_SOCKET_STREAM_H 16 17 #include "llvm/Support/Threading.h" 18 #include "llvm/Support/raw_ostream.h" 19 20 #include <atomic> 21 #include <chrono> 22 23 namespace llvm { 24 25 class raw_socket_stream; 26 27 #ifdef _WIN32 28 /// Ensures proper initialization and cleanup of winsock resources 29 /// 30 /// Make sure that calls to WSAStartup and WSACleanup are balanced. 31 class WSABalancer { 32 public: 33 WSABalancer(); 34 ~WSABalancer(); 35 }; 36 #endif // _WIN32 37 38 /// Manages a passive (i.e., listening) UNIX domain socket 39 /// 40 /// The ListeningSocket class encapsulates a UNIX domain socket that can listen 41 /// and accept incoming connections. ListeningSocket is portable and supports 42 /// Windows builds begining with Insider Build 17063. ListeningSocket is 43 /// designed for server-side operations, working alongside \p raw_socket_streams 44 /// that function as client connections. 45 /// 46 /// Usage example: 47 /// \code{.cpp} 48 /// std::string Path = "/path/to/socket" 49 /// Expected<ListeningSocket> S = ListeningSocket::createUnix(Path); 50 /// 51 /// if (S) { 52 /// Expected<std::unique_ptr<raw_socket_stream>> connection = S->accept(); 53 /// if (connection) { 54 /// // Use the accepted raw_socket_stream for communication. 55 /// } 56 /// } 57 /// \endcode 58 /// 59 class ListeningSocket { 60 61 std::atomic<int> FD; 62 std::string SocketPath; // Not modified after construction 63 64 /// If a seperate thread calls ListeningSocket::shutdown, the ListeningSocket 65 /// file descriptor (FD) could be closed while ::poll is waiting for it to be 66 /// ready to perform a I/O operations. ::poll will continue to block even 67 /// after FD is closed so use a self-pipe mechanism to get ::poll to return 68 int PipeFD[2]; // Not modified after construction other then move constructor 69 70 ListeningSocket(int SocketFD, StringRef SocketPath, int PipeFD[2]); 71 72 #ifdef _WIN32 73 WSABalancer _; 74 #endif // _WIN32 75 76 public: 77 ~ListeningSocket(); 78 ListeningSocket(ListeningSocket &&LS); 79 ListeningSocket(const ListeningSocket &LS) = delete; 80 ListeningSocket &operator=(const ListeningSocket &) = delete; 81 82 /// Closes the FD, unlinks the socket file, and writes to PipeFD. 83 /// 84 /// After the construction of the ListeningSocket, shutdown is signal safe if 85 /// it is called during the lifetime of the object. shutdown can be called 86 /// concurrently with ListeningSocket::accept as writing to PipeFD will cause 87 /// a blocking call to ::poll to return. 88 /// 89 /// Once shutdown is called there is no way to reinitialize ListeningSocket. 90 void shutdown(); 91 92 /// Accepts an incoming connection on the listening socket. This method can 93 /// optionally either block until a connection is available or timeout after a 94 /// specified amount of time has passed. By default the method will block 95 /// until the socket has recieved a connection. 96 /// 97 /// \param Timeout An optional timeout duration in milliseconds. Setting 98 /// Timeout to -1 causes accept to block indefinitely 99 /// 100 Expected<std::unique_ptr<raw_socket_stream>> 101 accept(std::chrono::milliseconds Timeout = std::chrono::milliseconds(-1)); 102 103 /// Creates a listening socket bound to the specified file system path. 104 /// Handles the socket creation, binding, and immediately starts listening for 105 /// incoming connections. 106 /// 107 /// \param SocketPath The file system path where the socket will be created 108 /// \param MaxBacklog The max number of connections in a socket's backlog 109 /// 110 static Expected<ListeningSocket> createUnix( 111 StringRef SocketPath, 112 int MaxBacklog = llvm::hardware_concurrency().compute_thread_count()); 113 }; 114 115 //===----------------------------------------------------------------------===// 116 // raw_socket_stream 117 //===----------------------------------------------------------------------===// 118 119 class raw_socket_stream : public raw_fd_stream { current_pos()120 uint64_t current_pos() const override { return 0; } 121 #ifdef _WIN32 122 WSABalancer _; 123 #endif // _WIN32 124 125 public: 126 raw_socket_stream(int SocketFD); 127 /// Create a \p raw_socket_stream connected to the UNIX domain socket at \p 128 /// SocketPath. 129 static Expected<std::unique_ptr<raw_socket_stream>> 130 createConnectedUnix(StringRef SocketPath); 131 ~raw_socket_stream(); 132 }; 133 134 } // end namespace llvm 135 136 #endif 137