From af4104fb454cc5774aa228350f64a6f72add8d11 Mon Sep 17 00:00:00 2001 From: fpagliughi Date: Mon, 30 Jan 2023 13:55:27 -0500 Subject: [PATCH] Updated README, CHANGELOG, and CMake version for v0.8.1 release. Added forgotten 'result' source files. --- CHANGELOG.md | 15 +++++ CMakeLists.txt | 2 +- README.md | 26 +++++++-- include/sockpp/result.h | 126 ++++++++++++++++++++++++++++++++++++++++ src/result.cpp | 59 +++++++++++++++++++ 5 files changed, 221 insertions(+), 7 deletions(-) create mode 100644 include/sockpp/result.h create mode 100644 src/result.cpp diff --git a/CHANGELOG.md b/CHANGELOG.md index 7573310..0dc21c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,20 @@ # Change Log for _sockpp_ +## [Version 0.8.1](https://github.com/fpagliughi/sockpp/compare/v0.8.0..v0.8.1) + +Released: 2023-01-30 + +- Cherry picked most of the non-TLS commits in PR [#17](https://github.com/fpagliughi/sockpp/pull/17) + - Connector timeouts + - Stateless reads & writes for streaming sockets w/ functions returning `ioresult` + - Some small bug fixes + - No shutdown on invalid sockets +- [#38](https://github.com/fpagliughi/sockpp/issues/38) Made system libs public for static builds to fix Windows +- [#73](https://github.com/fpagliughi/sockpp/issue/73) Clone a datagram (UDP) socket +- [#74](https://github.com/fpagliughi/sockpp/issue/74) Added `` to properly get `timeval` in *nix builds. +- [#56](https://github.com/fpagliughi/sockpp/issue/56) handling unix paths with maximum length (no NUL term) +- Fixed outstanding build warnings on Windows when using MSVC + ## [Version 0.8.0](https://github.com/fpagliughi/sockpp/compare/v0.7.1..v0.8.0) Released: 2023-01-17 diff --git a/CMakeLists.txt b/CMakeLists.txt index b6a1b3a..6b8875d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,7 +42,7 @@ cmake_minimum_required(VERSION 3.12) # --- Project setup --- -project(sockpp VERSION "0.8.0") +project(sockpp VERSION "0.8.1") # --- Build Options --- diff --git a/README.md b/README.md index 1fd0760..a541493 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,22 @@ To keep up with the latest announcements for this project, follow me at: If you're using this library, tweet at me or send me a message, and let me know how you're using it. I'm always curious to see where it winds up! +## New in v0.8.1 + +This release attempts to fix some of the outstanding build issues on Windows with MSVC and resolv some old issues and PR commits. + +- Cherry picked most of the non-TLS commits in PR [#17](https://github.com/fpagliughi/sockpp/pull/17) + - Connector timeouts + - Stateless reads & writes for streaming sockets w/ functions returning `ioresult` + - Some small bug fixes + - No shutdown on invalid sockets +- [#38](https://github.com/fpagliughi/sockpp/issues/38) Made system libs public for static builds to fix Windows +- [#73](https://github.com/fpagliughi/sockpp/issue/73) Clone a datagram (UDP) socket +- [#74](https://github.com/fpagliughi/sockpp/issue/74) Added `` to properly get `timeval` in *nix builds. +- [#56](https://github.com/fpagliughi/sockpp/issue/56) handling unix paths with maximum length (no NUL term) +- Fixed outstanding build warnings on Windows when using MSVC + + ## New in v0.8.0 This was primarily a release of code that had been sitting in the develop branch for nearly a year. That code mostly improved CMake functionality for downstream projects. @@ -46,8 +62,6 @@ For more information, refer to: [CONTRIBUTING.md](https://github.com/fpagliughi/ ## TODO -- **Unit Tests** - The framework for unit and regression tests is in place (using _Catch2_), along with the GitHub Travis CI integration. But the library could use a lot more tests. -- **Consolidate Header Files** - The last round of refactoring left a large number of header files with a single line of code in each. This may be OK, in that it separates all the protocols and families, but seems a waste of space. - **Secure Sockets** - It would be extremely handy to have support for SSL/TLS built right into the library as an optional feature. - **SCTP** - The _SCTP_ protocol never caught on, but it seems intriguing, and might be nice to have in the library for experimentation, if not for some internal applications. @@ -183,7 +197,7 @@ The same style of connectors and acceptors can be used for TCP connections over tcp6_acceptor tcp6_socket udp6_socket - + Examples are in the [examples/tcp](https://github.com/fpagliughi/sockpp/tree/master/examples/tcp) directory. ### Unix Domain Sockets @@ -236,7 +250,7 @@ sock.recv(&frame); ## Implementation Details -The socket class hierarchy is built upon a base `socket` class. Most simple applications will probably not use `socket` directly, but rather use top-level classes defined for a specific address family like `tcp_connector` and `tcp_acceptor`. +The socket class hierarchy is built upon a base `socket` class. Most simple applications will probably not use `socket` directly, but rather use derived classes defined for a specific address family like `tcp_connector` and `tcp_acceptor`. The socket objects keep a handle to an underlying OS socket handle and a cached value for the last error that occurred for that socket. The socket handle is typically an integer file descriptor, with values >=0 for open sockets, and -1 for an unopened or invalid socket. The value used for unopened sockets is defined as a constant, `INVALID_SOCKET`, although it usually doesn't need to be tested directly, as the object itself will evaluate to _false_ if it's uninitialized or in an error state. A typical error check would be like this: @@ -273,10 +287,10 @@ It is a common patern, especially in client applications, to have one thread to The solution for this case is to use the `socket::clone()` method to make a copy of the socket. This will use the system's `dup()` function or similar create another socket with a duplicated copy of the socket handle. This has the added benefit that each copy of the socket can maintain an independent lifetime. The underlying socket will not be closed until both objects go out of scope. sockpp::tcp_connector conn({host, port}); - + auto rdSock = conn.clone(); std::thread rdThr(read_thread_func, std::move(rdSock)); -The `socket::shutdown()` method can be used to communicate the intent to close the socket from one of these objects to the other without needing another thread signaling mechanism. +The `socket::shutdown()` method can be used to communicate the intent to close the socket from one of these objects to the other without needing another thread signaling mechanism. See the [tcpechomt.cpp](https://github.com/fpagliughi/sockpp/blob/master/examples/tcp/tcpechomt.cpp) example. \ No newline at end of file diff --git a/include/sockpp/result.h b/include/sockpp/result.h new file mode 100644 index 0000000..aad5c19 --- /dev/null +++ b/include/sockpp/result.h @@ -0,0 +1,126 @@ +/// @file result.h +/// +/// Type(s) for return values that can indicate a success or failure. +/// +/// @date January 2023 + +// -------------------------------------------------------------------------- +// This file is part of the "sockpp" C++ socket library. +// +// Copyright (c) 2023 Frank Pagliughi +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// -------------------------------------------------------------------------- + +#ifndef __sockpp_result_h +#define __sockpp_result_h + +#include "sockpp/platform.h" + +namespace sockpp { + +///////////////////////////////////////////////////////////////////////////// + +/** + * Result of a thread-safe I/O operation. + * + * Most I/O operations in the OS will return >=0 on sccess and -1 on error. + * In the case of an error, the calling thread must read an `errno` variable + * immediately, before any other system calls, to get the cause of an error + * as an integer value defined by the constants ENOENT, EINTR, EBUSY, etc. + * + * Most sockpp calls retain this known behavior, but will cache this errno + * value to be read later by a call to @ref socket::last_error() or similar. + * But this makes the @ref socket classes themselves non-thread-safe since + * the cached errno variable can't be shared across threads. + * + * Several new "thread-safe" variants of I/O functions simply retrieve the + * errno immediately on a failed I/O call and instead of caching the value, + * return it immediately in this ioresult. + * See: @ref stream_socket::read_r, @ref stream_socket::read_n_r, @ref + * stream_socket::write_r, etc. + */ +class ioresult { + /** Byte count, or 0 on error or EOF */ + size_t cnt_ = 0; + /** errno value (0 if no error or EOF) */ + int err_ = 0; + + /** + * OS-specific means to retrieve the last error from an operation. + * This should be called after a failed system call to get the caue of + * the error. + */ + static int get_last_error(); + + friend class socket; + +public: + /** Creates an empty result */ + ioresult() = default; + /** + * Creates a result from the return value of a low-level I/O function. + * @param n The number of bytes read or written. If <0, then an error is + * assumed and obtained from socket::get_last_error(). + * + */ + explicit inline ioresult(ssize_t n) { + if (n < 0) + err_ = get_last_error(); + else + cnt_ = size_t(n); + } + + /** Sets the error value */ + void set_error(int e) { err_ = e; } + + /** Increments the count */ + void incr(size_t n) { cnt_ += n; } + + /** Determines if the result is OK (not an error) */ + bool is_ok() const { return err_ == 0; } + /** Determines if the result is an error */ + bool is_err() const { return err_ != 0; } + + /** Determines if the result is OK */ + explicit operator bool() const { return is_ok(); } + + /** Gets the count */ + size_t count() const { return cnt_; } + + /** Gets the error */ + int error() const { return err_; } +}; + +///////////////////////////////////////////////////////////////////////////// +// end namespace sockpp +} + +#endif // __sockpp_result_h + diff --git a/src/result.cpp b/src/result.cpp new file mode 100644 index 0000000..21c82bc --- /dev/null +++ b/src/result.cpp @@ -0,0 +1,59 @@ + +// acceptor.cpp +// +// -------------------------------------------------------------------------- +// This file is part of the "sockpp" C++ socket library. +// +// Copyright (c) 2014-2017 Frank Pagliughi +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// -------------------------------------------------------------------------- + +#include "sockpp/result.h" + +using namespace std; + +namespace sockpp { + +///////////////////////////////////////////////////////////////////////////// + +int ioresult::get_last_error() +{ + #if defined(_WIN32) + return ::WSAGetLastError(); + #else + int err = errno; + return err; + #endif +} + +///////////////////////////////////////////////////////////////////////////// +// end namespace sockpp +} +