1 // Copyright 2020 The Pigweed Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not 4 // use this file except in compliance with the License. You may obtain a copy of 5 // the License at 6 // 7 // https://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, WITHOUT 11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 // License for the specific language governing permissions and limitations under 13 // the License. 14 #pragma once 15 16 #include <netinet/in.h> 17 18 #include <cstdint> 19 20 #include "pw_result/result.h" 21 #include "pw_span/span.h" 22 #include "pw_stream/stream.h" 23 24 namespace pw::stream { 25 26 class SocketStream : public NonSeekableReaderWriter { 27 public: 28 constexpr SocketStream() = default; 29 30 // SocketStream objects are moveable but not copyable. 31 SocketStream& operator=(SocketStream&& other) { 32 listen_port_ = other.listen_port_; 33 socket_fd_ = other.socket_fd_; 34 other.socket_fd_ = kInvalidFd; 35 connection_fd_ = other.connection_fd_; 36 other.connection_fd_ = kInvalidFd; 37 sockaddr_client_ = other.sockaddr_client_; 38 return *this; 39 } SocketStream(SocketStream && other)40 SocketStream(SocketStream&& other) noexcept 41 : listen_port_(other.listen_port_), 42 socket_fd_(other.socket_fd_), 43 connection_fd_(other.connection_fd_), 44 sockaddr_client_(other.sockaddr_client_) { 45 other.socket_fd_ = kInvalidFd; 46 other.connection_fd_ = kInvalidFd; 47 } 48 SocketStream(const SocketStream&) = delete; 49 SocketStream& operator=(const SocketStream&) = delete; 50 ~SocketStream()51 ~SocketStream() override { Close(); } 52 53 // Listen to the port and return after a client is connected 54 // 55 // DEPRECATED: Use the ServerSocket class instead. 56 // TODO(b/271323032): Remove when this method is no longer used. 57 Status Serve(uint16_t port); 58 59 // Connect to a local or remote endpoint. Host may be either an IPv4 or IPv6 60 // address. If host is nullptr then the IPv4 localhost address is used 61 // instead. 62 Status Connect(const char* host, uint16_t port); 63 64 // Close the socket stream and release all resources 65 void Close(); 66 67 // Exposes the file descriptor for the active connection. This is exposed to 68 // allow configuration and introspection of this socket's current 69 // configuration using setsockopt() and getsockopt(). 70 // 71 // Returns -1 if there is no active connection. connection_fd()72 int connection_fd() { return connection_fd_; } 73 74 private: 75 friend class ServerSocket; 76 77 static constexpr int kInvalidFd = -1; 78 79 Status DoWrite(span<const std::byte> data) override; 80 81 StatusWithSize DoRead(ByteSpan dest) override; 82 83 uint16_t listen_port_ = 0; 84 int socket_fd_ = kInvalidFd; 85 int connection_fd_ = kInvalidFd; 86 struct sockaddr_in sockaddr_client_ = {}; 87 }; 88 89 /// `ServerSocket` wraps a POSIX-style server socket, producing a `SocketStream` 90 /// for each accepted client connection. 91 /// 92 /// Call `Listen` to create the socket and start listening for connections. 93 /// Then call `Accept` any number of times to accept client connections. 94 class ServerSocket { 95 public: 96 ServerSocket() = default; ~ServerSocket()97 ~ServerSocket() { Close(); } 98 99 ServerSocket(const ServerSocket& other) = delete; 100 ServerSocket& operator=(const ServerSocket& other) = delete; 101 102 // Listen for connections on the given port. 103 // If port is 0, a random unused port is chosen and can be retrieved with 104 // port(). 105 Status Listen(uint16_t port = 0); 106 107 // Accept a connection. Blocks until after a client is connected. 108 // On success, returns a SocketStream connected to the new client. 109 Result<SocketStream> Accept(); 110 111 // Close the server socket, preventing further connections. 112 void Close(); 113 114 // Returns the port this socket is listening on. port()115 uint16_t port() const { return port_; } 116 117 private: 118 static constexpr int kInvalidFd = -1; 119 120 uint16_t port_ = -1; 121 int socket_fd_ = kInvalidFd; 122 }; 123 124 } // namespace pw::stream 125