pw_stream: SocketStream closing and cleanup

Provide member function to close and cleanup socket fds in SocketStream.
Additionally cleans up and closes fds during destruction.

Change-Id: Ia271f944a4630b223707f7c6bf340df8843323ca
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/31260
Reviewed-by: Keir Mierle <keir@google.com>
Reviewed-by: Alexei Frolov <frolv@google.com>
Commit-Queue: Jason Graffius <jgraff@google.com>
diff --git a/pw_stream/public/pw_stream/socket_stream.h b/pw_stream/public/pw_stream/socket_stream.h
index b7079e6..c9d3e0f 100644
--- a/pw_stream/public/pw_stream/socket_stream.h
+++ b/pw_stream/public/pw_stream/socket_stream.h
@@ -34,10 +34,14 @@
 class SocketStream : public Writer, public Reader {
  public:
   explicit SocketStream() {}
+  ~SocketStream();
 
   // Listen to the port and return after a client is connected
   Status Init(uint16_t port);
 
+  // Close the socket stream and release all resources
+  void Close();
+
  private:
   Status DoWrite(std::span<const std::byte> data) override;
 
diff --git a/pw_stream/socket_stream.cc b/pw_stream/socket_stream.cc
index 5599307..f81ef05 100644
--- a/pw_stream/socket_stream.cc
+++ b/pw_stream/socket_stream.cc
@@ -17,6 +17,8 @@
 
 static constexpr uint32_t kMaxConcurrentUser = 1;
 
+SocketStream::~SocketStream() { Close(); }
+
 // Listen to the port and return after a client is connected
 Status SocketStream::Init(uint16_t port) {
   listen_port_ = port;
@@ -51,6 +53,18 @@
   return OkStatus();
 }
 
+void SocketStream::Close() {
+  if (socket_fd_ != kInvalidFd) {
+    close(socket_fd_);
+    socket_fd_ = kInvalidFd;
+  }
+
+  if (conn_fd_ != kInvalidFd) {
+    close(conn_fd_);
+    conn_fd_ = kInvalidFd;
+  }
+}
+
 Status SocketStream::DoWrite(std::span<const std::byte> data) {
   ssize_t bytes_sent = send(conn_fd_, data.data(), data.size_bytes(), 0);