C/C++ API Reference
Loading...
Searching...
No Matches
socket_stream.h
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 <cstdint>
17
18#include "pw_result/result.h"
19#include "pw_span/span.h"
20#include "pw_stream/stream.h"
21#include "pw_sync/lock_annotations.h"
22#include "pw_sync/mutex.h"
23
24namespace pw::stream {
25
27
33 public:
34 SocketStream() = default;
35 // Construct a SocketStream directly from a file descriptor.
36 explicit SocketStream(int connection_fd) : connection_fd_(connection_fd) {
37 // Mark as ready and take ownership of the connection by this object.
38 ready_ = true;
39 TakeConnection();
40 }
41
42 // SocketStream objects are moveable but not copyable.
43 SocketStream& operator=(SocketStream&& other) {
44 MoveFrom(std::move(other));
45 return *this;
46 }
47 SocketStream(SocketStream&& other) noexcept { MoveFrom(std::move(other)); }
48 SocketStream(const SocketStream&) = delete;
49 SocketStream& operator=(const SocketStream&) = delete;
50
51 ~SocketStream() override { Close(); }
52
53 // Connect to a local or remote endpoint. Host may be either an IPv4 or IPv6
54 // address. If host is nullptr then the IPv4 localhost address is used
55 // instead.
56 Status Connect(const char* host, uint16_t port);
57
58 // Configures socket options.
59 int SetSockOpt(int level,
60 int optname,
61 const void* optval,
62 unsigned int optlen);
63
64 // Get the connection ready state (true if ready, false otherwise).
65 bool IsReady();
66
67 // Close the socket stream and release all resources
68 void Close();
69
70 private:
71 static constexpr int kInvalidFd = -1;
72
73 class ConnectionOwnership {
74 public:
75 explicit ConnectionOwnership(SocketStream* socket_stream)
76 : socket_stream_(socket_stream) {
77 fd_ = socket_stream_->TakeConnection();
78 std::lock_guard lock(socket_stream_->connection_mutex_);
79 pipe_r_fd_ = socket_stream->connection_pipe_r_fd_;
80 }
81
82 ~ConnectionOwnership() { socket_stream_->ReleaseConnection(); }
83
84 int fd() { return fd_; }
85
86 int pipe_r_fd() { return pipe_r_fd_; }
87
88 private:
89 SocketStream* socket_stream_;
90 int fd_;
91 int pipe_r_fd_;
92 };
93
94 Status DoWrite(span<const std::byte> data) override;
95
97
98 // Take ownership of the connection. There may be multiple owners. Each time
99 // TakeConnection is called, ReleaseConnection must be called to release
100 // ownership, even if the connection is not valid.
101 //
102 // Returns the connection fd or kInvalidFd if the connection is not valid.
103 int TakeConnection();
104 int TakeConnectionWithLockHeld()
105 PW_EXCLUSIVE_LOCKS_REQUIRED(connection_mutex_);
106
107 // Release ownership of the connection. If no owners remain, close and clear
108 // the connection fds.
109 void ReleaseConnection();
110 void ReleaseConnectionWithLockHeld()
111 PW_EXCLUSIVE_LOCKS_REQUIRED(connection_mutex_);
112
113 // Moves other to this.
114 void MoveFrom(SocketStream&& other) {
115 std::lock_guard lock(connection_mutex_);
116 std::lock_guard other_lock(other.connection_mutex_);
117
118 connection_own_count_ = other.connection_own_count_;
119 other.connection_own_count_ = 0;
120 ready_ = other.ready_;
121 other.ready_ = false;
122 connection_fd_ = other.connection_fd_;
123 other.connection_fd_ = kInvalidFd;
124 connection_pipe_r_fd_ = other.connection_pipe_r_fd_;
125 other.connection_pipe_r_fd_ = kInvalidFd;
126 connection_pipe_w_fd_ = other.connection_pipe_w_fd_;
127 other.connection_pipe_w_fd_ = kInvalidFd;
128 }
129
130 sync::Mutex connection_mutex_;
131 int connection_own_count_ PW_GUARDED_BY(connection_mutex_) = 0;
132 bool ready_ PW_GUARDED_BY(connection_mutex_) = false;
133 int connection_fd_ PW_GUARDED_BY(connection_mutex_) = kInvalidFd;
134 int connection_pipe_r_fd_ PW_GUARDED_BY(connection_mutex_) = kInvalidFd;
135 int connection_pipe_w_fd_ PW_GUARDED_BY(connection_mutex_) = kInvalidFd;
136};
137
144 public:
145 ServerSocket() = default;
146 ~ServerSocket() { Close(); }
147
148 ServerSocket(const ServerSocket& other) = delete;
149 ServerSocket& operator=(const ServerSocket& other) = delete;
150
151 // Listen for connections on the given port.
152 // If port is 0, a random unused port is chosen and can be retrieved with
153 // port().
154 Status Listen(uint16_t port = 0);
155
156 // Accept a connection. Blocks until after a client is connected.
157 // On success, returns a SocketStream connected to the new client.
158 Result<SocketStream> Accept();
159
160 // Close the server socket, preventing further connections.
161 void Close();
162
163 // Returns the port this socket is listening on.
164 uint16_t port() const { return port_; }
165
166 private:
167 static constexpr int kInvalidFd = -1;
168
169 class SocketOwnership {
170 public:
171 explicit SocketOwnership(ServerSocket* server_socket)
172 : server_socket_(server_socket) {
173 fd_ = server_socket_->TakeSocket();
174 std::lock_guard lock(server_socket->socket_mutex_);
175 pipe_r_fd_ = server_socket->socket_pipe_r_fd_;
176 }
177
178 ~SocketOwnership() { server_socket_->ReleaseSocket(); }
179
180 int fd() { return fd_; }
181
182 int pipe_r_fd() { return pipe_r_fd_; }
183
184 private:
185 ServerSocket* server_socket_;
186 int fd_;
187 int pipe_r_fd_;
188 };
189
190 // Take ownership of the socket. There may be multiple owners. Each time
191 // TakeSocket is called, ReleaseSocket must be called to release ownership,
192 // even if the socket is not invalid.
193 //
194 // Returns the socket fd or kInvalidFd if the socket is not valid.
195 int TakeSocket();
196 int TakeSocketWithLockHeld() PW_EXCLUSIVE_LOCKS_REQUIRED(socket_mutex_);
197
198 // Release ownership of the socket. If no owners remain, close and clear the
199 // socket fds.
200 void ReleaseSocket();
201 void ReleaseSocketWithLockHeld() PW_EXCLUSIVE_LOCKS_REQUIRED(socket_mutex_);
202
203 uint16_t port_ = 0;
204 sync::Mutex socket_mutex_;
205 int socket_own_count_ PW_GUARDED_BY(socket_mutex_) = 0;
206 bool ready_ PW_GUARDED_BY(socket_mutex_) = false;
207 int socket_fd_ PW_GUARDED_BY(socket_mutex_) = kInvalidFd;
208 int socket_pipe_r_fd_ PW_GUARDED_BY(socket_mutex_) = kInvalidFd;
209 int socket_pipe_w_fd_ PW_GUARDED_BY(socket_mutex_) = kInvalidFd;
210};
211
213
214} // namespace pw::stream
Definition: poll.h:25
Definition: status.h:109
Definition: status_with_size.h:51
Definition: span_impl.h:235
Definition: stream.h:650
Definition: socket_stream.h:143
Definition: socket_stream.h:32
StatusWithSize DoRead(ByteSpan dest) override
Virtual Read() function implemented by derived classes.
Definition: mutex.h:40
#define PW_GUARDED_BY(x)
Definition: lock_annotations.h:60
#define PW_EXCLUSIVE_LOCKS_REQUIRED(...)
Definition: lock_annotations.h:146