1 // Copyright 2024 The gRPC Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #ifndef GRPC_SRC_CORE_LIB_EVENT_ENGINE_EXTENSIONS_SUPPORTS_FD_H 16 #define GRPC_SRC_CORE_LIB_EVENT_ENGINE_EXTENSIONS_SUPPORTS_FD_H 17 18 #include <grpc/event_engine/event_engine.h> 19 #include <grpc/support/port_platform.h> 20 21 #include "absl/functional/any_invocable.h" 22 #include "absl/status/statusor.h" 23 #include "absl/strings/string_view.h" 24 25 namespace grpc_event_engine { 26 namespace experimental { 27 28 class EndpointSupportsFdExtension { 29 public: 30 virtual ~EndpointSupportsFdExtension() = default; EndpointExtensionName()31 static absl::string_view EndpointExtensionName() { 32 return "io.grpc.event_engine.extension.endpoint_supports_fd"; 33 } 34 /// Returns the file descriptor associated with the posix endpoint. 35 virtual int GetWrappedFd() = 0; 36 37 /// Shutdown the endpoint. This function call should trigger execution of 38 /// any pending endpoint Read/Write callbacks with appropriate error 39 /// absl::Status. After this function call any subsequent endpoint 40 /// Read/Write operations until endpoint deletion should fail with an 41 /// appropriate absl::Status. 42 /// 43 /// \a on_release_fd - If specified, the callback is invoked when the 44 /// endpoint is destroyed/deleted. The underlying file descriptor is 45 /// released instead of being closed. The callback will get the released 46 /// file descriptor as its argument if the release operation is successful. 47 /// Otherwise it would get an appropriate error status as its argument. 48 virtual void Shutdown(absl::AnyInvocable<void(absl::StatusOr<int> release_fd)> 49 on_release_fd) = 0; 50 }; 51 52 class ListenerSupportsFdExtension { 53 public: 54 virtual ~ListenerSupportsFdExtension() = default; EndpointExtensionName()55 static absl::string_view EndpointExtensionName() { 56 return "io.grpc.event_engine.extension.listener_supports_fd"; 57 } 58 /// Called when a posix listener bind operation completes. A single bind 59 /// operation may trigger creation of multiple listener fds. This callback 60 /// should be invoked once on each newly created and bound fd. If the 61 /// corresponding bind operation fails for a particular fd, this callback 62 /// must be invoked with a absl::FailedPreConditionError status. 63 /// 64 /// \a listener_fd - The listening socket fd that was bound to the specified 65 /// address. 66 using OnPosixBindNewFdCallback = 67 absl::AnyInvocable<void(absl::StatusOr<int> listener_fd)>; 68 /// Bind an address/port to this Listener. 69 /// 70 /// It is expected that multiple addresses/ports can be bound to this 71 /// Listener before Listener::Start has been called. Returns either the 72 /// bound port or an appropriate error status. 73 /// \a addr - The address to listen for incoming connections. 74 /// \a on_bind_new_fd The callback is invoked once for each newly bound 75 /// listener fd that may be created by this Bind operation. 76 virtual absl::StatusOr<int> BindWithFd( 77 const EventEngine::ResolvedAddress& addr, 78 OnPosixBindNewFdCallback on_bind_new_fd) = 0; 79 80 /// Handle an externally accepted client connection. It must return an 81 /// appropriate error status in case of failure. 82 /// 83 /// This may be invoked to process a new client connection accepted by an 84 /// external listening fd. 85 /// \a listener_fd - The external listening socket fd that accepted the new 86 /// client connection. 87 /// \a fd - The socket file descriptor representing the new client 88 /// connection. 89 /// \a pending_data - If specified, it holds any pending data that may have 90 /// already been read over the externally accepted client connection. 91 /// Otherwise, it is assumed that no data has been read over the new client 92 /// connection. 93 virtual absl::Status HandleExternalConnection(int listener_fd, int fd, 94 SliceBuffer* pending_data) = 0; 95 96 /// Shutdown/stop listening on all bind Fds. 97 virtual void ShutdownListeningFds() = 0; 98 }; 99 100 class EventEngineSupportsFdExtension { 101 public: 102 virtual ~EventEngineSupportsFdExtension() = default; EndpointExtensionName()103 static absl::string_view EndpointExtensionName() { 104 return "io.grpc.event_engine.extension.event_engine_supports_fd"; 105 } 106 /// Creates a posix specific EventEngine::Endpoint from an fd which is already 107 /// assumed to be connected to a remote peer. \a fd - The connected socket 108 /// file descriptor. \a config - Additional configuration to applied to the 109 /// endpoint. \a memory_allocator - The endpoint may use the provided memory 110 /// allocator to track memory allocations. 111 virtual std::unique_ptr<EventEngine::Endpoint> CreatePosixEndpointFromFd( 112 int fd, const EndpointConfig& config, 113 MemoryAllocator memory_allocator) = 0; 114 115 /// Creates an EventEngine::Endpoint from an fd which is already assumed to be 116 /// connected to a remote peer. See \a CreatePosixEndpointFromFd for details. 117 /// This has the same behavior, but the \a memory_allocator is taken from the 118 /// EndpointConfig's resource quota. 119 virtual std::unique_ptr<EventEngine::Endpoint> CreateEndpointFromFd( 120 int fd, const EndpointConfig& config) = 0; 121 122 /// Creates an EventEngine::Endpoint from a file descriptor that is configured 123 /// and bound locally but not yet connected to a remote peer. Returns a 124 /// connection handle to cancel the connection attempt if needed. Created 125 /// endpoint will be returned through `on_connect` callback. 126 /// \a fd - The socket file descriptor. 127 /// \a on_connect - The callback to invoke once fd is connected to peer. 128 /// \a addr - The remote peer to connect to. This should be the mapped peer 129 /// address returned when creating a new socket. 130 /// \a config - Additional configuration to be applied to the endpoint. 131 /// \a memory_allocator - The endpoint may use the provided memory allocator 132 /// to track memory allocations. 133 /// \a timeout - The timeout to use for the connection attempt. 134 virtual EventEngine::ConnectionHandle CreateEndpointFromUnconnectedFd( 135 int fd, EventEngine::OnConnectCallback on_connect, 136 const EventEngine::ResolvedAddress& addr, const EndpointConfig& config, 137 MemoryAllocator memory_allocator, EventEngine::Duration timeout) = 0; 138 139 /// Called when the posix listener has accepted a new client connection. 140 /// \a listener_fd - The listening socket fd that accepted the new client 141 /// connection. 142 /// \a endpoint - The EventEngine endpoint to handle data exchange over the 143 /// new client connection. 144 /// \a is_external - A boolean indicating whether the new client connection 145 /// is accepted by an external listener_fd or by a listener_fd that is 146 /// managed by the EventEngine listener. 147 /// \a memory_allocator - The callback may use the provided memory 148 /// allocator to handle memory allocation operations. 149 /// \a pending_data - If specified, it holds any pending data that may have 150 /// already been read over the new client connection. Otherwise, it is 151 /// assumed that no data has been read over the new client connection. 152 using PosixAcceptCallback = absl::AnyInvocable<void( 153 int listener_fd, std::unique_ptr<EventEngine::Endpoint> endpoint, 154 bool is_external, MemoryAllocator memory_allocator, 155 SliceBuffer* pending_data)>; 156 157 /// Factory method to create a posix specific network listener / server with 158 /// fd support. 159 /// 160 /// Once a \a Listener is created and started, the \a on_accept callback will 161 /// be called once asynchronously for each established connection. This method 162 /// may return a non-OK status immediately if an error was encountered in any 163 /// synchronous steps required to create the Listener. In this case, 164 /// \a on_shutdown will never be called. 165 /// 166 /// If this method returns a Listener, then \a on_shutdown will be invoked 167 /// exactly once, when the Listener is shut down. The status passed to it will 168 /// indicate if there was a problem during shutdown. 169 /// 170 /// The provided \a MemoryAllocatorFactory is used to create \a 171 /// MemoryAllocators for Endpoint construction. 172 virtual absl::StatusOr<std::unique_ptr<EventEngine::Listener>> 173 CreatePosixListener( 174 PosixAcceptCallback on_accept, 175 absl::AnyInvocable<void(absl::Status)> on_shutdown, 176 const EndpointConfig& config, 177 std::unique_ptr<MemoryAllocatorFactory> memory_allocator_factory) = 0; 178 }; 179 180 } // namespace experimental 181 } // namespace grpc_event_engine 182 183 #endif // GRPC_SRC_CORE_LIB_EVENT_ENGINE_EXTENSIONS_SUPPORTS_FD_H 184