Commit 48b4c725c9739b3959576d5f9043d2fa1338445a

Authored by Peter M. Groen
0 parents

Setting up Socket-pp

Showing 68 changed files with 7940 additions and 0 deletions
CMakeLists.txt 0 โ†’ 100644
  1 +++ a/CMakeLists.txt
  1 +cmake_minmum_required(VERSION 3.20)
  2 +project(osdev-socket-cpp)
  3 +
  4 +LIST(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)
  5 +
  6 +# ===========================================================================
  7 +# == Include build information
  8 +include(osdevversion)
  9 +include(projectheader)
  10 +
  11 +project_header(osdev-socket-cpp)
  12 +
  13 +include(compiler)
  14 +
  15 +add_subdirectory(src)
  16 +add_subdirectory(examples)
  17 +add_subdirectory(tests)
examples/linux/canrecv.cpp 0 โ†’ 100644
  1 +++ a/examples/linux/canrecv.cpp
  1 +// canrecv.cpp
  2 +//
  3 +// Linux SoxketCAN reader example.
  4 +//
  5 +//
  6 +// --------------------------------------------------------------------------
  7 +// This file is part of the "sockpp" C++ socket library.
  8 +//
  9 +// Copyright (c) 2021 Frank Pagliughi
  10 +// All rights reserved.
  11 +//
  12 +// Redistribution and use in source and binary forms, with or without
  13 +// modification, are permitted provided that the following conditions are
  14 +// met:
  15 +//
  16 +// 1. Redistributions of source code must retain the above copyright notice,
  17 +// this list of conditions and the following disclaimer.
  18 +//
  19 +// 2. Redistributions in binary form must reproduce the above copyright
  20 +// notice, this list of conditions and the following disclaimer in the
  21 +// documentation and/or other materials provided with the distribution.
  22 +//
  23 +// 3. Neither the name of the copyright holder nor the names of its
  24 +// contributors may be used to endorse or promote products derived from this
  25 +// software without specific prior written permission.
  26 +//
  27 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  28 +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  29 +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  30 +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  31 +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  32 +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  33 +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  34 +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  35 +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  36 +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  37 +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  38 +// --------------------------------------------------------------------------
  39 +
  40 +#include <iostream>
  41 +#include <iomanip>
  42 +#include <string>
  43 +#include <chrono>
  44 +#include <thread>
  45 +#include "sockpp/can_socket.h"
  46 +#include "sockpp/can_frame.h"
  47 +#include "sockpp/version.h"
  48 +
  49 +#include <net/if.h>
  50 +#include <sys/ioctl.h>
  51 +
  52 +using namespace std;
  53 +
  54 +// The clock to use to get time and pace the app.
  55 +using sysclock = chrono::system_clock;
  56 +
  57 +// --------------------------------------------------------------------------
  58 +
  59 +int main(int argc, char* argv[])
  60 +{
  61 + cout << "Sample SocketCAN writer for 'sockpp' "
  62 + << sockpp::SOCKPP_VERSION << endl;
  63 +
  64 + string canIface = (argc > 1) ? argv[1] : "can0";
  65 + canid_t canID = (argc > 2) ? atoi(argv[2]) : 0x20;
  66 +
  67 + sockpp::socket_initializer sockInit;
  68 +
  69 + sockpp::can_address addr(canIface);
  70 + sockpp::can_socket sock(addr);
  71 +
  72 + if (!sock) {
  73 + cerr << "Error binding to the CAN interface " << canIface << "\n\t"
  74 + << sock.last_error_str() << endl;
  75 + return 1;
  76 + }
  77 +
  78 + cout << "Created CAN socket on " << sock.address() << endl;
  79 + time_t t = sysclock::to_time_t(sysclock::now());
  80 +
  81 + cout.setf(ios::fixed, ios::floatfield);
  82 + cout << setfill('0');
  83 +
  84 + while (true) {
  85 + sockpp::can_frame frame;
  86 + sock.recv(&frame);
  87 + auto t = sock.last_frame_timestamp();
  88 +
  89 + cout << t << " ";
  90 + for (uint8_t i=0; i<frame.can_dlc; ++i)
  91 + cout << hex << uppercase << setw(2) << unsigned(frame.data[i]) << " ";
  92 + cout << endl;
  93 + }
  94 +
  95 + return (!sock) ? 1 : 0;
  96 +}
examples/linux/cantime.cpp 0 โ†’ 100644
  1 +++ a/examples/linux/cantime.cpp
  1 +// cantime.cpp
  2 +//
  3 +// Linux SoxketCAN writer example.
  4 +//
  5 +// This writes the 1-sec, 32-bit, Linux time_t value to the CAN bus each
  6 +// time it ticks. This is a simple (though not overly precise) way to
  7 +// synchronize the time for nodes on the bus
  8 +//
  9 +// --------------------------------------------------------------------------
  10 +// This file is part of the "sockpp" C++ socket library.
  11 +//
  12 +// Copyright (c) 2021 Frank Pagliughi
  13 +// All rights reserved.
  14 +//
  15 +// Redistribution and use in source and binary forms, with or without
  16 +// modification, are permitted provided that the following conditions are
  17 +// met:
  18 +//
  19 +// 1. Redistributions of source code must retain the above copyright notice,
  20 +// this list of conditions and the following disclaimer.
  21 +//
  22 +// 2. Redistributions in binary form must reproduce the above copyright
  23 +// notice, this list of conditions and the following disclaimer in the
  24 +// documentation and/or other materials provided with the distribution.
  25 +//
  26 +// 3. Neither the name of the copyright holder nor the names of its
  27 +// contributors may be used to endorse or promote products derived from this
  28 +// software without specific prior written permission.
  29 +//
  30 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  31 +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  32 +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  33 +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  34 +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  35 +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  36 +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  37 +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  38 +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  39 +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  40 +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  41 +// --------------------------------------------------------------------------
  42 +
  43 +#include <iostream>
  44 +#include <string>
  45 +#include <chrono>
  46 +#include <thread>
  47 +#include "sockpp/can_socket.h"
  48 +#include "sockpp/can_frame.h"
  49 +#include "sockpp/version.h"
  50 +
  51 +#include <net/if.h>
  52 +#include <sys/ioctl.h>
  53 +
  54 +using namespace std;
  55 +
  56 +// The clock to use to get time and pace the app.
  57 +using sysclock = chrono::system_clock;
  58 +
  59 +// --------------------------------------------------------------------------
  60 +
  61 +int main(int argc, char* argv[])
  62 +{
  63 + cout << "Sample SocketCAN writer for 'sockpp' "
  64 + << sockpp::SOCKPP_VERSION << endl;
  65 +
  66 + string canIface = (argc > 1) ? argv[1] : "can0";
  67 + canid_t canID = (argc > 2) ? atoi(argv[2]) : 0x20;
  68 +
  69 + sockpp::socket_initializer sockInit;
  70 +
  71 + sockpp::can_address addr(canIface);
  72 + sockpp::can_socket sock(addr);
  73 +
  74 + if (!sock) {
  75 + cerr << "Error binding to the CAN interface " << canIface << "\n\t"
  76 + << sock.last_error_str() << endl;
  77 + return 1;
  78 + }
  79 +
  80 + cout << "Created CAN socket on " << sock.address() << endl;
  81 + time_t t = sysclock::to_time_t(sysclock::now());
  82 +
  83 + while (true) {
  84 + // Sleep until the clock ticks to the next second
  85 + this_thread::sleep_until(sysclock::from_time_t(t+1));
  86 +
  87 + // Re-read the time in case we fell behind
  88 + t = sysclock::to_time_t(sysclock::now());
  89 +
  90 + // Write the time to the CAN bus as a 32-bit int
  91 + auto nt = uint32_t(t);
  92 +
  93 + sockpp::can_frame frame { canID, &nt, sizeof(nt) };
  94 + sock.send(frame);
  95 + }
  96 +
  97 + return (!sock) ? 1 : 0;
  98 +}
examples/tcp/tcp6echo.cpp 0 โ†’ 100644
  1 +++ a/examples/tcp/tcp6echo.cpp
  1 +// tcpecho.cpp
  2 +//
  3 +// Simple TCP echo client
  4 +//
  5 +// --------------------------------------------------------------------------
  6 +// This file is part of the "sockpp" C++ socket library.
  7 +//
  8 +// Copyright (c) 2014-2017 Frank Pagliughi
  9 +// All rights reserved.
  10 +//
  11 +// Redistribution and use in source and binary forms, with or without
  12 +// modification, are permitted provided that the following conditions are
  13 +// met:
  14 +//
  15 +// 1. Redistributions of source code must retain the above copyright notice,
  16 +// this list of conditions and the following disclaimer.
  17 +//
  18 +// 2. Redistributions in binary form must reproduce the above copyright
  19 +// notice, this list of conditions and the following disclaimer in the
  20 +// documentation and/or other materials provided with the distribution.
  21 +//
  22 +// 3. Neither the name of the copyright holder nor the names of its
  23 +// contributors may be used to endorse or promote products derived from this
  24 +// software without specific prior written permission.
  25 +//
  26 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  27 +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  28 +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  29 +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  30 +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  31 +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  32 +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  33 +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  34 +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  35 +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  36 +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  37 +// --------------------------------------------------------------------------
  38 +
  39 +#include <iostream>
  40 +#include <string>
  41 +#include "sockpp/tcp6_connector.h"
  42 +#include "sockpp/version.h"
  43 +
  44 +using namespace std;
  45 +using namespace std::chrono;
  46 +
  47 +// --------------------------------------------------------------------------
  48 +
  49 +int main(int argc, char* argv[])
  50 +{
  51 + cout << "Sample IPv6 TCP echo client for 'sockpp' "
  52 + << sockpp::SOCKPP_VERSION << '\n' << endl;
  53 +
  54 + std::string host = (argc > 1) ? argv[1] : "::1";
  55 + in_port_t port = (argc > 2) ? atoi(argv[2]) : 12345;
  56 +
  57 + sockpp::socket_initializer sockInit;
  58 +
  59 + // Implicitly creates an inet6_address from {host,port}
  60 + // and then tries the connection.
  61 +
  62 + sockpp::tcp6_connector conn({host, port});
  63 + if (!conn) {
  64 + cerr << "Error connecting to server at "
  65 + << sockpp::inet6_address(host, port)
  66 + << "\n\t" << conn.last_error_str() << endl;
  67 + return 1;
  68 + }
  69 +
  70 + cout << "Created a connection from " << conn.address() << endl;
  71 +
  72 + // Set a timeout for the responses
  73 + if (!conn.read_timeout(seconds(5))) {
  74 + cerr << "Error setting timeout on TCP stream: "
  75 + << conn.last_error_str() << endl;
  76 + }
  77 +
  78 + string s, sret;
  79 + while (getline(cin, s) && !s.empty()) {
  80 + if (conn.write(s) != ssize_t(s.length())) {
  81 + cerr << "Error writing to the TCP stream: "
  82 + << conn.last_error_str() << endl;
  83 + break;
  84 + }
  85 +
  86 + sret.resize(s.length());
  87 + ssize_t n = conn.read_n(&sret[0], s.length());
  88 +
  89 + if (n != ssize_t(s.length())) {
  90 + cerr << "Error reading from TCP stream: "
  91 + << conn.last_error_str() << endl;
  92 + break;
  93 + }
  94 +
  95 + cout << sret << endl;
  96 + }
  97 +
  98 + return (!conn) ? 1 : 0;
  99 +}
examples/tcp/tcp6echosvr.cpp 0 โ†’ 100644
  1 +++ a/examples/tcp/tcp6echosvr.cpp
  1 +// tcp6echosvr.cpp
  2 +//
  3 +// A multi-threaded TCP v6 echo server for sockpp library.
  4 +// This is a simple thread-per-connection TCP server for IPv6.
  5 +//
  6 +// USAGE:
  7 +// tcp6echosvr [port]
  8 +//
  9 +// --------------------------------------------------------------------------
  10 +// This file is part of the "sockpp" C++ socket library.
  11 +//
  12 +// Copyright (c) 2019 Frank Pagliughi
  13 +// All rights reserved.
  14 +//
  15 +// Redistribution and use in source and binary forms, with or without
  16 +// modification, are permitted provided that the following conditions are
  17 +// met:
  18 +//
  19 +// 1. Redistributions of source code must retain the above copyright notice,
  20 +// this list of conditions and the following disclaimer.
  21 +//
  22 +// 2. Redistributions in binary form must reproduce the above copyright
  23 +// notice, this list of conditions and the following disclaimer in the
  24 +// documentation and/or other materials provided with the distribution.
  25 +//
  26 +// 3. Neither the name of the copyright holder nor the names of its
  27 +// contributors may be used to endorse or promote products derived from this
  28 +// software without specific prior written permission.
  29 +//
  30 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  31 +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  32 +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  33 +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  34 +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  35 +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  36 +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  37 +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  38 +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  39 +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  40 +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  41 +// --------------------------------------------------------------------------
  42 +
  43 +#include <iostream>
  44 +#include <thread>
  45 +#include "sockpp/tcp6_acceptor.h"
  46 +#include "sockpp/version.h"
  47 +
  48 +using namespace std;
  49 +
  50 +// --------------------------------------------------------------------------
  51 +// The thread function. This is run in a separate thread for each socket.
  52 +// Ownership of the socket object is transferred to the thread, so when this
  53 +// function exits, the socket is automatically closed.
  54 +
  55 +void run_echo(sockpp::tcp6_socket sock)
  56 +{
  57 + ssize_t n;
  58 + char buf[512];
  59 +
  60 + while ((n = sock.read(buf, sizeof(buf))) > 0)
  61 + sock.write_n(buf, n);
  62 +
  63 + cout << "Connection closed from " << sock.peer_address() << endl;
  64 +}
  65 +
  66 +// --------------------------------------------------------------------------
  67 +// The main thread runs the TCP port acceptor. Each time a connection is
  68 +// made, a new thread is spawned to handle it, leaving this main thread to
  69 +// immediately wait for the next connection.
  70 +
  71 +int main(int argc, char* argv[])
  72 +{
  73 + cout << "Sample IPv6 TCP echo server for 'sockpp' "
  74 + << sockpp::SOCKPP_VERSION << '\n' << endl;
  75 +
  76 + in_port_t port = (argc > 1) ? atoi(argv[1]) : 12345;
  77 +
  78 + sockpp::socket_initializer sockInit;
  79 + sockpp::tcp6_acceptor acc(port);
  80 +
  81 + if (!acc) {
  82 + cerr << "Error creating the acceptor: " << acc.last_error_str() << endl;
  83 + return 1;
  84 + }
  85 + cout << "Awaiting connections on port " << port << "..." << endl;
  86 +
  87 + while (true) {
  88 + sockpp::inet6_address peer;
  89 +
  90 + // Accept a new client connection
  91 + sockpp::tcp6_socket sock = acc.accept(&peer);
  92 + cout << "Received a connection request from " << peer << endl;
  93 +
  94 + if (!sock) {
  95 + cerr << "Error accepting incoming connection: "
  96 + << acc.last_error_str() << endl;
  97 + }
  98 + else {
  99 + // Create a thread and transfer the new stream to it.
  100 + thread thr(run_echo, std::move(sock));
  101 + thr.detach();
  102 + }
  103 + }
  104 +
  105 + return 0;
  106 +}
  107 +
  108 +
  109 +
examples/tcp/tcpecho.cpp 0 โ†’ 100644
  1 +++ a/examples/tcp/tcpecho.cpp
  1 +// tcpecho.cpp
  2 +//
  3 +// Simple TCP echo client
  4 +//
  5 +// --------------------------------------------------------------------------
  6 +// This file is part of the "sockpp" C++ socket library.
  7 +//
  8 +// Copyright (c) 2014-2017 Frank Pagliughi
  9 +// All rights reserved.
  10 +//
  11 +// Redistribution and use in source and binary forms, with or without
  12 +// modification, are permitted provided that the following conditions are
  13 +// met:
  14 +//
  15 +// 1. Redistributions of source code must retain the above copyright notice,
  16 +// this list of conditions and the following disclaimer.
  17 +//
  18 +// 2. Redistributions in binary form must reproduce the above copyright
  19 +// notice, this list of conditions and the following disclaimer in the
  20 +// documentation and/or other materials provided with the distribution.
  21 +//
  22 +// 3. Neither the name of the copyright holder nor the names of its
  23 +// contributors may be used to endorse or promote products derived from this
  24 +// software without specific prior written permission.
  25 +//
  26 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  27 +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  28 +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  29 +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  30 +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  31 +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  32 +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  33 +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  34 +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  35 +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  36 +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  37 +// --------------------------------------------------------------------------
  38 +
  39 +#include <iostream>
  40 +#include <string>
  41 +#include "sockpp/tcp_connector.h"
  42 +#include "sockpp/version.h"
  43 +
  44 +using namespace std;
  45 +using namespace std::chrono;
  46 +
  47 +int main(int argc, char* argv[])
  48 +{
  49 + cout << "Sample TCP echo client for 'sockpp' "
  50 + << sockpp::SOCKPP_VERSION << '\n' << endl;
  51 +
  52 + string host = (argc > 1) ? argv[1] : "localhost";
  53 + in_port_t port = (argc > 2) ? atoi(argv[2]) : 12345;
  54 +
  55 + sockpp::socket_initializer sockInit;
  56 +
  57 + // Implicitly creates an inet_address from {host,port}
  58 + // and then tries the connection.
  59 +
  60 + sockpp::tcp_connector conn({host, port});
  61 + if (!conn) {
  62 + cerr << "Error connecting to server at "
  63 + << sockpp::inet_address(host, port)
  64 + << "\n\t" << conn.last_error_str() << endl;
  65 + return 1;
  66 + }
  67 +
  68 + cout << "Created a connection from " << conn.address() << endl;
  69 +
  70 + // Set a timeout for the responses
  71 + if (!conn.read_timeout(seconds(5))) {
  72 + cerr << "Error setting timeout on TCP stream: "
  73 + << conn.last_error_str() << endl;
  74 + }
  75 +
  76 + string s, sret;
  77 + while (getline(cin, s) && !s.empty()) {
  78 + if (conn.write(s) != ssize_t(s.length())) {
  79 + cerr << "Error writing to the TCP stream: "
  80 + << conn.last_error_str() << endl;
  81 + break;
  82 + }
  83 +
  84 + sret.resize(s.length());
  85 + ssize_t n = conn.read_n(&sret[0], s.length());
  86 +
  87 + if (n != ssize_t(s.length())) {
  88 + cerr << "Error reading from TCP stream: "
  89 + << conn.last_error_str() << endl;
  90 + break;
  91 + }
  92 +
  93 + cout << sret << endl;
  94 + }
  95 +
  96 + return (!conn) ? 1 : 0;
  97 +}
examples/tcp/tcpechomt.cpp 0 โ†’ 100644
  1 +++ a/examples/tcp/tcpechomt.cpp
  1 +// tcpechomt.cpp
  2 +//
  3 +// TCP echo client that uses separate read and write threads.
  4 +//
  5 +// --------------------------------------------------------------------------
  6 +// This file is part of the "sockpp" C++ socket library.
  7 +//
  8 +// Copyright (c) 2014-2017 Frank Pagliughi
  9 +// All rights reserved.
  10 +//
  11 +// Redistribution and use in source and binary forms, with or without
  12 +// modification, are permitted provided that the following conditions are
  13 +// met:
  14 +//
  15 +// 1. Redistributions of source code must retain the above copyright notice,
  16 +// this list of conditions and the following disclaimer.
  17 +//
  18 +// 2. Redistributions in binary form must reproduce the above copyright
  19 +// notice, this list of conditions and the following disclaimer in the
  20 +// documentation and/or other materials provided with the distribution.
  21 +//
  22 +// 3. Neither the name of the copyright holder nor the names of its
  23 +// contributors may be used to endorse or promote products derived from this
  24 +// software without specific prior written permission.
  25 +//
  26 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  27 +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  28 +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  29 +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  30 +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  31 +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  32 +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  33 +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  34 +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  35 +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  36 +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  37 +// --------------------------------------------------------------------------
  38 +
  39 +#include <iostream>
  40 +#include <string>
  41 +#include <thread>
  42 +#include "sockpp/tcp_connector.h"
  43 +#include "sockpp/version.h"
  44 +
  45 +using namespace std;
  46 +
  47 +// --------------------------------------------------------------------------
  48 +// The read thread will run independently, retrieving packets from the
  49 +// server and writing them to the console. When the main (write) thread
  50 +// shuts down the socket, we exit.
  51 +
  52 +void read_thr(sockpp::tcp_socket rdSock)
  53 +{
  54 + char buf[512];
  55 + ssize_t n;
  56 +
  57 + while ((n = rdSock.read(buf, sizeof(buf))) > 0) {
  58 + cout.write(buf, n);
  59 + cout << endl;
  60 + }
  61 +
  62 + if (n < 0) {
  63 + cout << "Read error [" << rdSock.last_error() << "]: "
  64 + << rdSock.last_error_str() << endl;
  65 + }
  66 + rdSock.shutdown();
  67 +}
  68 +
  69 +// --------------------------------------------------------------------------
  70 +
  71 +int main(int argc, char* argv[])
  72 +{
  73 + cout << "Sample multi-threaded TCP echo client for 'sockpp' "
  74 + << sockpp::SOCKPP_VERSION << '\n' << endl;
  75 +
  76 + string host = (argc > 1) ? argv[1] : "localhost";
  77 + in_port_t port = (argc > 2) ? atoi(argv[2]) : 12345;
  78 +
  79 + sockpp::socket_initializer sockInit;
  80 +
  81 + // Implicitly creates an inet_address from {host,port}
  82 + // and then tries the connection.
  83 +
  84 + sockpp::tcp_connector conn({host, port});
  85 + if (!conn) {
  86 + cerr << "Error connecting to server at "
  87 + << sockpp::inet_address(host, port)
  88 + << "\n\t" << conn.last_error_str() << endl;
  89 + return 1;
  90 + }
  91 +
  92 + cout << "Created a connection from " << conn.address() << endl;
  93 +
  94 + // We create a read thread and send it a clone (dup) of the
  95 + // connector socket.
  96 +
  97 + std::thread rdThr(read_thr, std::move(conn.clone()));
  98 +
  99 + // The write loop get user input and writes it to the socket.
  100 +
  101 + string s, sret;
  102 + while (getline(cin, s) && !s.empty()) {
  103 + if (conn.write(s) != (int) s.length()) {
  104 + if (conn.last_error() == EPIPE) {
  105 + cerr << "It appears that the socket was closed." << endl;
  106 + }
  107 + else {
  108 + cerr << "Error writing to the TCP stream ["
  109 + << conn.last_error() << "]: "
  110 + << conn.last_error_str() << endl;
  111 + }
  112 + break;
  113 + }
  114 + }
  115 + int ret = !conn ? 1 : 0;
  116 +
  117 + // Shutting down the socket will cause the read thread to exit.
  118 + // We wait for it to exit before we leave the app.
  119 +
  120 + conn.shutdown(SHUT_WR);
  121 + rdThr.join();
  122 +
  123 + return ret;
  124 +}
examples/tcp/tcpechosvr.cpp 0 โ†’ 100644
  1 +++ a/examples/tcp/tcpechosvr.cpp
  1 +// tcpechosvr.cpp
  2 +//
  3 +// A multi-threaded TCP echo server for sockpp library.
  4 +// This is a simple thread-per-connection TCP server.
  5 +//
  6 +// USAGE:
  7 +// tcpechosvr [port]
  8 +//
  9 +// --------------------------------------------------------------------------
  10 +// This file is part of the "sockpp" C++ socket library.
  11 +//
  12 +// Copyright (c) 2014-2017 Frank Pagliughi
  13 +// All rights reserved.
  14 +//
  15 +// Redistribution and use in source and binary forms, with or without
  16 +// modification, are permitted provided that the following conditions are
  17 +// met:
  18 +//
  19 +// 1. Redistributions of source code must retain the above copyright notice,
  20 +// this list of conditions and the following disclaimer.
  21 +//
  22 +// 2. Redistributions in binary form must reproduce the above copyright
  23 +// notice, this list of conditions and the following disclaimer in the
  24 +// documentation and/or other materials provided with the distribution.
  25 +//
  26 +// 3. Neither the name of the copyright holder nor the names of its
  27 +// contributors may be used to endorse or promote products derived from this
  28 +// software without specific prior written permission.
  29 +//
  30 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  31 +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  32 +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  33 +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  34 +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  35 +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  36 +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  37 +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  38 +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  39 +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  40 +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  41 +// --------------------------------------------------------------------------
  42 +
  43 +#include <iostream>
  44 +#include <thread>
  45 +#include "sockpp/tcp_acceptor.h"
  46 +#include "sockpp/version.h"
  47 +
  48 +using namespace std;
  49 +
  50 +// --------------------------------------------------------------------------
  51 +// The thread function. This is run in a separate thread for each socket.
  52 +// Ownership of the socket object is transferred to the thread, so when this
  53 +// function exits, the socket is automatically closed.
  54 +
  55 +void run_echo(sockpp::tcp_socket sock)
  56 +{
  57 + ssize_t n;
  58 + char buf[512];
  59 +
  60 + while ((n = sock.read(buf, sizeof(buf))) > 0)
  61 + sock.write_n(buf, n);
  62 +
  63 + cout << "Connection closed from " << sock.peer_address() << endl;
  64 +}
  65 +
  66 +// --------------------------------------------------------------------------
  67 +// The main thread runs the TCP port acceptor. Each time a connection is
  68 +// made, a new thread is spawned to handle it, leaving this main thread to
  69 +// immediately wait for the next connection.
  70 +
  71 +int main(int argc, char* argv[])
  72 +{
  73 + cout << "Sample TCP echo server for 'sockpp' "
  74 + << sockpp::SOCKPP_VERSION << '\n' << endl;
  75 +
  76 + in_port_t port = (argc > 1) ? atoi(argv[1]) : 12345;
  77 +
  78 + sockpp::socket_initializer sockInit;
  79 +
  80 + sockpp::tcp_acceptor acc(port);
  81 +
  82 + if (!acc) {
  83 + cerr << "Error creating the acceptor: " << acc.last_error_str() << endl;
  84 + return 1;
  85 + }
  86 + //cout << "Acceptor bound to address: " << acc.address() << endl;
  87 + cout << "Awaiting connections on port " << port << "..." << endl;
  88 +
  89 + while (true) {
  90 + sockpp::inet_address peer;
  91 +
  92 + // Accept a new client connection
  93 + sockpp::tcp_socket sock = acc.accept(&peer);
  94 + cout << "Received a connection request from " << peer << endl;
  95 +
  96 + if (!sock) {
  97 + cerr << "Error accepting incoming connection: "
  98 + << acc.last_error_str() << endl;
  99 + }
  100 + else {
  101 + // Create a thread and transfer the new stream to it.
  102 + thread thr(run_echo, std::move(sock));
  103 + thr.detach();
  104 + }
  105 + }
  106 +
  107 + return 0;
  108 +}
  109 +
  110 +
  111 +
examples/tcp/tcpechotest.cpp 0 โ†’ 100644
  1 +++ a/examples/tcp/tcpechotest.cpp
  1 +// tcpechotest.cpp
  2 +//
  3 +// TCP echo timing client.
  4 +//
  5 +// --------------------------------------------------------------------------
  6 +// This file is part of the "sockpp" C++ socket library.
  7 +//
  8 +// Copyright (c) 2020 Frank Pagliughi
  9 +// All rights reserved.
  10 +//
  11 +// Redistribution and use in source and binary forms, with or without
  12 +// modification, are permitted provided that the following conditions are
  13 +// met:
  14 +//
  15 +// 1. Redistributions of source code must retain the above copyright notice,
  16 +// this list of conditions and the following disclaimer.
  17 +//
  18 +// 2. Redistributions in binary form must reproduce the above copyright
  19 +// notice, this list of conditions and the following disclaimer in the
  20 +// documentation and/or other materials provided with the distribution.
  21 +//
  22 +// 3. Neither the name of the copyright holder nor the names of its
  23 +// contributors may be used to endorse or promote products derived from this
  24 +// software without specific prior written permission.
  25 +//
  26 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  27 +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  28 +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  29 +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  30 +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  31 +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  32 +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  33 +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  34 +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  35 +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  36 +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  37 +// --------------------------------------------------------------------------
  38 +
  39 +#include <iostream>
  40 +#include <string>
  41 +#include <chrono>
  42 +#include <random>
  43 +#include "sockpp/tcp_connector.h"
  44 +#include "sockpp/version.h"
  45 +
  46 +using namespace std;
  47 +using namespace std::chrono;
  48 +
  49 +const size_t DFLT_N = 100000;
  50 +const size_t DFLT_SZ = 512;
  51 +
  52 +using fpsec = std::chrono::duration<double, std::chrono::seconds::period>;
  53 +
  54 +// --------------------------------------------------------------------------
  55 +
  56 +int main(int argc, char* argv[])
  57 +{
  58 + cout << "Unix-domain echo timing test client for 'sockpp' "
  59 + << sockpp::SOCKPP_VERSION << '\n' << endl;
  60 +
  61 + string host = (argc > 1) ? argv[1] : "localhost";
  62 + in_port_t port = (argc > 2) ? atoi(argv[2]) : 12345;
  63 +
  64 + size_t n = (argc > 3) ? size_t(atoll(argv[3])) : DFLT_N;
  65 + size_t sz = (argc > 4) ? size_t(atoll(argv[4])) : DFLT_SZ;
  66 +
  67 + sockpp::socket_initializer sockInit;
  68 +
  69 + auto t_start = high_resolution_clock::now();
  70 +
  71 +
  72 + sockpp::tcp_connector conn({host, port});
  73 + if (!conn) {
  74 + cerr << "Error connecting to server at "
  75 + << sockpp::inet_address(host, port)
  76 + << "\n\t" << conn.last_error_str() << endl;
  77 + return 1;
  78 + }
  79 +
  80 + cout << "Created a connection from " << conn.address() << endl;
  81 + cout << "Created a connection to " << conn.peer_address() << endl;
  82 +
  83 + // Set a timeout for the responses
  84 + if (!conn.read_timeout(seconds(2))) {
  85 + cerr << "Error setting timeout on TCP stream: "
  86 + << conn.last_error_str() << endl;
  87 + }
  88 + string s, sret;
  89 +
  90 + random_device rd;
  91 + mt19937 reng(rd());
  92 + uniform_int_distribution<int> dist(0, 25);
  93 +
  94 + for (size_t i=0; i<sz; ++i)
  95 + s.push_back('a' + static_cast<char>(dist(reng)));
  96 +
  97 + auto t_start_tx = high_resolution_clock::now();
  98 +
  99 + for (size_t i=0; i<n; ++i) {
  100 + if (conn.write(s) != (ssize_t) s.length()) {
  101 + cerr << "Error writing to the UNIX stream" << endl;
  102 + break;
  103 + }
  104 +
  105 + sret.resize(s.length());
  106 + int n = conn.read_n(&sret[0], s.length());
  107 +
  108 + if (n != (int) s.length()) {
  109 + cerr << "Error reading from UNIX stream" << endl;
  110 + break;
  111 + }
  112 + }
  113 +
  114 + auto t_end = high_resolution_clock::now();
  115 + cout << "Total time: " << fpsec(t_end - t_start).count() << "s" << endl;
  116 +
  117 + auto t_tx = fpsec(t_end - t_start_tx).count();
  118 + auto rate = size_t(n / t_tx);
  119 + cout << "Transfer time: " << t_tx << "s\n "
  120 + << rate << " msg/s" << endl;
  121 +
  122 + return (!conn) ? 1 : 0;
  123 +}
examples/udp/udp6echo.cpp 0 โ†’ 100644
  1 +++ a/examples/udp/udp6echo.cpp
  1 +// udp6echo.cpp
  2 +//
  3 +// Simple UDP v6 echo client
  4 +//
  5 +// --------------------------------------------------------------------------
  6 +// This file is part of the "sockpp" C++ socket library.
  7 +//
  8 +// Copyright (c) 2019 Frank Pagliughi
  9 +// All rights reserved.
  10 +//
  11 +// Redistribution and use in source and binary forms, with or without
  12 +// modification, are permitted provided that the following conditions are
  13 +// met:
  14 +//
  15 +// 1. Redistributions of source code must retain the above copyright notice,
  16 +// this list of conditions and the following disclaimer.
  17 +//
  18 +// 2. Redistributions in binary form must reproduce the above copyright
  19 +// notice, this list of conditions and the following disclaimer in the
  20 +// documentation and/or other materials provided with the distribution.
  21 +//
  22 +// 3. Neither the name of the copyright holder nor the names of its
  23 +// contributors may be used to endorse or promote products derived from this
  24 +// software without specific prior written permission.
  25 +//
  26 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  27 +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  28 +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  29 +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  30 +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  31 +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  32 +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  33 +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  34 +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  35 +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  36 +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  37 +// --------------------------------------------------------------------------
  38 +
  39 +#include <iostream>
  40 +#include <string>
  41 +#include "sockpp/udp6_socket.h"
  42 +#include "sockpp/version.h"
  43 +
  44 +using namespace std;
  45 +
  46 +// --------------------------------------------------------------------------
  47 +
  48 +int main(int argc, char* argv[])
  49 +{
  50 + cout << "Sample IPv6 UDP echo client for 'sockpp' "
  51 + << sockpp::SOCKPP_VERSION << '\n' << endl;
  52 +
  53 + string host = (argc > 1) ? argv[1] : "localhost";
  54 + in_port_t port = (argc > 2) ? atoi(argv[2]) : 12345;
  55 +
  56 + sockpp::socket_initializer sockInit;
  57 +
  58 + sockpp::udp6_socket sock;
  59 +
  60 + if (!sock.connect(sockpp::inet6_address(host, port))) {
  61 + cerr << "Error connecting to server at " << host << ":" << port
  62 + << "\n\t" << sock.last_error_str() << endl;
  63 + return 1;
  64 + }
  65 +
  66 + cout << "Created UDP socket at: " << sock.address() << endl;
  67 +
  68 + string s, sret;
  69 + while (getline(cin, s) && !s.empty()) {
  70 + if (sock.send(s) != ssize_t(s.length())) {
  71 + cerr << "Error writing to the UDP socket: "
  72 + << sock.last_error_str() << endl;
  73 + break;
  74 + }
  75 +
  76 + sret.resize(s.length());
  77 + ssize_t n = sock.recv(&sret[0], s.length());
  78 +
  79 + if (n != ssize_t(s.length())) {
  80 + cerr << "Error reading from UDP socket: "
  81 + << sock.last_error_str() << endl;
  82 + break;
  83 + }
  84 +
  85 + cout << sret << endl;
  86 + }
  87 +
  88 + return (!sock) ? 1 : 0;
  89 +}
examples/udp/udpecho.cpp 0 โ†’ 100644
  1 +++ a/examples/udp/udpecho.cpp
  1 +// udpecho.cpp
  2 +//
  3 +// Simple UDP v4 echo client
  4 +//
  5 +// --------------------------------------------------------------------------
  6 +// This file is part of the "sockpp" C++ socket library.
  7 +//
  8 +// Copyright (c) 2019 Frank Pagliughi
  9 +// All rights reserved.
  10 +//
  11 +// Redistribution and use in source and binary forms, with or without
  12 +// modification, are permitted provided that the following conditions are
  13 +// met:
  14 +//
  15 +// 1. Redistributions of source code must retain the above copyright notice,
  16 +// this list of conditions and the following disclaimer.
  17 +//
  18 +// 2. Redistributions in binary form must reproduce the above copyright
  19 +// notice, this list of conditions and the following disclaimer in the
  20 +// documentation and/or other materials provided with the distribution.
  21 +//
  22 +// 3. Neither the name of the copyright holder nor the names of its
  23 +// contributors may be used to endorse or promote products derived from this
  24 +// software without specific prior written permission.
  25 +//
  26 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  27 +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  28 +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  29 +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  30 +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  31 +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  32 +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  33 +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  34 +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  35 +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  36 +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  37 +// --------------------------------------------------------------------------
  38 +
  39 +#include <iostream>
  40 +#include <string>
  41 +#include "sockpp/udp_socket.h"
  42 +#include "sockpp/version.h"
  43 +
  44 +using namespace std;
  45 +
  46 +// --------------------------------------------------------------------------
  47 +
  48 +int main(int argc, char* argv[])
  49 +{
  50 + cout << "Sample UDP echo client for 'sockpp' "
  51 + << sockpp::SOCKPP_VERSION << '\n' << endl;
  52 +
  53 + string host = (argc > 1) ? argv[1] : "localhost";
  54 + in_port_t port = (argc > 2) ? atoi(argv[2]) : 12345;
  55 +
  56 + sockpp::socket_initializer sockInit;
  57 +
  58 + sockpp::udp_socket sock;
  59 +
  60 + if (!sock.connect(sockpp::inet_address(host, port))) {
  61 + cerr << "Error connecting to server at " << host << ":" << port
  62 + << "\n\t" << sock.last_error_str() << endl;
  63 + return 1;
  64 + }
  65 +
  66 + cout << "Created UDP socket at: " << sock.address() << endl;
  67 +
  68 + string s, sret;
  69 + while (getline(cin, s) && !s.empty()) {
  70 + if (sock.send(s) != ssize_t(s.length())) {
  71 + cerr << "Error writing to the UDP socket: "
  72 + << sock.last_error_str() << endl;
  73 + break;
  74 + }
  75 +
  76 + sret.resize(s.length());
  77 + ssize_t n = sock.recv(&sret[0], s.length());
  78 +
  79 + if (n != ssize_t(s.length())) {
  80 + cerr << "Error reading from UDP socket: "
  81 + << sock.last_error_str() << endl;
  82 + break;
  83 + }
  84 +
  85 + cout << sret << endl;
  86 + }
  87 +
  88 + return (!sock) ? 1 : 0;
  89 +}
examples/udp/udpechosvr.cpp 0 โ†’ 100644
  1 +++ a/examples/udp/udpechosvr.cpp
  1 +// udpechosvr.cpp
  2 +//
  3 +// A simple multi-threaded TCP/IP UDP echo server for sockpp library.
  4 +//
  5 +// This runs a UDP echo server for both IPv4 and IPv6, each in a separate
  6 +// thread. They both use the same port number, either as provided by the user
  7 +// on the command line, or defaulting to 12345.
  8 +//
  9 +// USAGE:
  10 +// uspechosvr [port]
  11 +//
  12 +// You can test with a netcat client, like:
  13 +// $ nc -u localhost 12345 # IPv4
  14 +// $ nc -6u localhost 12345 # IPv6
  15 +//
  16 +// --------------------------------------------------------------------------
  17 +// This file is part of the "sockpp" C++ socket library.
  18 +//
  19 +// Copyright (c) 2019 Frank Pagliughi
  20 +// All rights reserved.
  21 +//
  22 +// Redistribution and use in source and binary forms, with or without
  23 +// modification, are permitted provided that the following conditions are
  24 +// met:
  25 +//
  26 +// 1. Redistributions of source code must retain the above copyright notice,
  27 +// this list of conditions and the following disclaimer.
  28 +//
  29 +// 2. Redistributions in binary form must reproduce the above copyright
  30 +// notice, this list of conditions and the following disclaimer in the
  31 +// documentation and/or other materials provided with the distribution.
  32 +//
  33 +// 3. Neither the name of the copyright holder nor the names of its
  34 +// contributors may be used to endorse or promote products derived from this
  35 +// software without specific prior written permission.
  36 +//
  37 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  38 +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  39 +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  40 +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  41 +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  42 +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  43 +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  44 +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  45 +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  46 +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  47 +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  48 +// --------------------------------------------------------------------------
  49 +
  50 +#include <iostream>
  51 +#include <thread>
  52 +#include "sockpp/udp_socket.h"
  53 +#include "sockpp/udp6_socket.h"
  54 +#include "sockpp/version.h"
  55 +
  56 +using namespace std;
  57 +
  58 +// --------------------------------------------------------------------------
  59 +// The thread function. This is run in a separate thread for each socket.
  60 +// Ownership of the socket object is transferred to the thread, so when this
  61 +// function exits, the socket is automatically closed.
  62 +
  63 +template <typename UDPSOCK>
  64 +void run_echo(UDPSOCK sock)
  65 +{
  66 + ssize_t n;
  67 + char buf[512];
  68 +
  69 + // Each UDP socket type knows its address type as `addr_t`
  70 + typename UDPSOCK::addr_t srcAddr;
  71 +
  72 + // Read some data, also getting the address of the sender,
  73 + // then just send it back.
  74 + while ((n = sock.recv_from(buf, sizeof(buf), &srcAddr)) > 0)
  75 + sock.send_to(buf, n, srcAddr);
  76 +}
  77 +
  78 +// --------------------------------------------------------------------------
  79 +// The main thread creates the two UDP sockets (one each for IPv4 and IPv6),
  80 +// and then starts them running the echo function each in a separate thread.
  81 +
  82 +int main(int argc, char* argv[])
  83 +{
  84 + cout << "Sample UDP echo server for 'sockpp' "
  85 + << sockpp::SOCKPP_VERSION << '\n' << endl;
  86 +
  87 + in_port_t port = (argc > 1) ? atoi(argv[1]) : 12345;
  88 +
  89 + sockpp::socket_initializer sockInit;
  90 +
  91 + sockpp::udp_socket udpsock;
  92 + if (!udpsock) {
  93 + cerr << "Error creating the UDP v4 socket: " << udpsock.last_error_str() << endl;
  94 + return 1;
  95 + }
  96 +
  97 + if (!udpsock.bind(sockpp::inet_address("localhost", port))) {
  98 + cerr << "Error binding the UDP v4 socket: " << udpsock.last_error_str() << endl;
  99 + return 1;
  100 + }
  101 +
  102 + sockpp::udp6_socket udp6sock;
  103 + if (!udp6sock) {
  104 + cerr << "Error creating the UDP v6 socket: " << udp6sock.last_error_str() << endl;
  105 + return 1;
  106 + }
  107 +
  108 + if (!udp6sock.bind(sockpp::inet6_address("localhost", port))) {
  109 + cerr << "Error binding the UDP v6 socket: " << udp6sock.last_error_str() << endl;
  110 + return 1;
  111 + }
  112 +
  113 + // Spin up a thread to run the IPv4 socket.
  114 + thread thr(run_echo<sockpp::udp_socket>, std::move(udpsock));
  115 + thr.detach();
  116 +
  117 + // Run the IPv6 socket in this thread. (Call doesn't return)
  118 + run_echo(std::move(udp6sock));
  119 + return 0;
  120 +}
  121 +
examples/unix/undgramecho.cpp 0 โ†’ 100644
  1 +++ a/examples/unix/undgramecho.cpp
  1 +// udpecho.cpp
  2 +//
  3 +// Simple Unix-domain UDP echo client
  4 +//
  5 +// --------------------------------------------------------------------------
  6 +// This file is part of the "sockpp" C++ socket library.
  7 +//
  8 +// Copyright (c) 2019 Frank Pagliughi
  9 +// All rights reserved.
  10 +//
  11 +// Redistribution and use in source and binary forms, with or without
  12 +// modification, are permitted provided that the following conditions are
  13 +// met:
  14 +//
  15 +// 1. Redistributions of source code must retain the above copyright notice,
  16 +// this list of conditions and the following disclaimer.
  17 +//
  18 +// 2. Redistributions in binary form must reproduce the above copyright
  19 +// notice, this list of conditions and the following disclaimer in the
  20 +// documentation and/or other materials provided with the distribution.
  21 +//
  22 +// 3. Neither the name of the copyright holder nor the names of its
  23 +// contributors may be used to endorse or promote products derived from this
  24 +// software without specific prior written permission.
  25 +//
  26 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  27 +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  28 +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  29 +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  30 +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  31 +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  32 +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  33 +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  34 +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  35 +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  36 +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  37 +// --------------------------------------------------------------------------
  38 +
  39 +#include <iostream>
  40 +#include <string>
  41 +#include "sockpp/unix_dgram_socket.h"
  42 +
  43 +using namespace std;
  44 +
  45 +// --------------------------------------------------------------------------
  46 +
  47 +int main(int argc, char* argv[])
  48 +{
  49 + sockpp::socket_initializer sockInit;
  50 +
  51 + string cliAddr { "/tmp/undgramecho.sock" },
  52 + svrAddr { "/tmp/undgramechosvr.sock" };
  53 +
  54 + sockpp::unix_dgram_socket sock;
  55 +
  56 + // A Unix-domain UDP client needs to bind to its own address
  57 + // before it can send or receive packets
  58 +
  59 + if (!sock.bind(sockpp::unix_address(cliAddr))) {
  60 + cerr << "Error connecting to client address at '" << cliAddr << "'"
  61 + << "\n\t" << sock.last_error_str() << endl;
  62 + return 1;
  63 + }
  64 +
  65 + // "Connect" to the server address. This is a convenience to set the
  66 + // default 'send_to' address, as there is no real connection.
  67 +
  68 + if (!sock.connect(sockpp::unix_address(svrAddr))) {
  69 + cerr << "Error connecting to server at '" << svrAddr << "'"
  70 + << "\n\t" << sock.last_error_str() << endl;
  71 + return 1;
  72 + }
  73 +
  74 + cout << "Created UDP socket at: " << sock.address() << endl;
  75 +
  76 + string s, sret;
  77 + while (getline(cin, s) && !s.empty()) {
  78 + if (sock.send(s) != ssize_t(s.length())) {
  79 + cerr << "Error writing to the UDP socket: "
  80 + << sock.last_error_str() << endl;
  81 + break;
  82 + }
  83 +
  84 + sret.resize(s.length());
  85 + ssize_t n = sock.recv(&sret[0], s.length());
  86 +
  87 + if (n != ssize_t(s.length())) {
  88 + cerr << "Error reading from UDP socket: "
  89 + << sock.last_error_str() << endl;
  90 + break;
  91 + }
  92 +
  93 + cout << sret << endl;
  94 + }
  95 +
  96 + return (!sock) ? 1 : 0;
  97 +}
examples/unix/undgramechosvr.cpp 0 โ†’ 100644
  1 +++ a/examples/unix/undgramechosvr.cpp
  1 +// undgramechosvr.cpp
  2 +//
  3 +// A simple multi-threaded TCP/IP UDP echo server for sockpp library.
  4 +//
  5 +// This runs a UDP echo server for both IPv4 and IPv6, each in a separate
  6 +// thread. They both use the same port number, either as provided by the user
  7 +// on the command line, or defaulting to 12345.
  8 +//
  9 +// USAGE:
  10 +// undgramechosvr [port]
  11 +//
  12 +// You can test with a netcat client, like:
  13 +// $ nc -u localhost 12345 # IPv4
  14 +// $ nc -6u localhost 12345 # IPv6
  15 +//
  16 +// --------------------------------------------------------------------------
  17 +// This file is part of the "sockpp" C++ socket library.
  18 +//
  19 +// Copyright (c) 2019 Frank Pagliughi
  20 +// All rights reserved.
  21 +//
  22 +// Redistribution and use in source and binary forms, with or without
  23 +// modification, are permitted provided that the following conditions are
  24 +// met:
  25 +//
  26 +// 1. Redistributions of source code must retain the above copyright notice,
  27 +// this list of conditions and the following disclaimer.
  28 +//
  29 +// 2. Redistributions in binary form must reproduce the above copyright
  30 +// notice, this list of conditions and the following disclaimer in the
  31 +// documentation and/or other materials provided with the distribution.
  32 +//
  33 +// 3. Neither the name of the copyright holder nor the names of its
  34 +// contributors may be used to endorse or promote products derived from this
  35 +// software without specific prior written permission.
  36 +//
  37 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  38 +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  39 +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  40 +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  41 +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  42 +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  43 +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  44 +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  45 +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  46 +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  47 +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  48 +// --------------------------------------------------------------------------
  49 +
  50 +#include <iostream>
  51 +#include "sockpp/unix_dgram_socket.h"
  52 +#include "sockpp/version.h"
  53 +
  54 +using namespace std;
  55 +
  56 +// --------------------------------------------------------------------------
  57 +// The main thread creates the UDP socket, and then starts them running the
  58 +// echo service in a loop.
  59 +
  60 +int main(int argc, char* argv[])
  61 +{
  62 + cout << "Sample Unix-domain datagram echo server for 'sockpp' "
  63 + << sockpp::SOCKPP_VERSION << '\n' << endl;
  64 +
  65 + sockpp::socket_initializer sockInit;
  66 +
  67 + sockpp::unix_dgram_socket sock;
  68 + if (!sock) {
  69 + cerr << "Error creating the socket: " << sock.last_error_str() << endl;
  70 + return 1;
  71 + }
  72 +
  73 + if (!sock.bind(sockpp::unix_address("/tmp/undgramechosvr.sock"))) {
  74 + cerr << "Error binding the socket: " << sock.last_error_str() << endl;
  75 + return 1;
  76 + }
  77 +
  78 + // Run the socket in this thread.
  79 + ssize_t n;
  80 + char buf[512];
  81 +
  82 + sockpp::unix_address srcAddr;
  83 +
  84 + cout << "Awaiting packets on: '" << sock.address() << "'" << endl;
  85 +
  86 + // Read some data, also getting the address of the sender,
  87 + // then just send it back.
  88 + while ((n = sock.recv_from(buf, sizeof(buf), &srcAddr)) > 0)
  89 + sock.send_to(buf, n, srcAddr);
  90 +
  91 + return 0;
  92 +}
  93 +
examples/unix/unecho.cpp 0 โ†’ 100644
  1 +++ a/examples/unix/unecho.cpp
  1 +// unecho.cpp
  2 +//
  3 +// Simple Unix-domain echo client
  4 +//
  5 +// --------------------------------------------------------------------------
  6 +// This file is part of the "sockpp" C++ socket library.
  7 +//
  8 +// Copyright (c) 2014-2017 Frank Pagliughi
  9 +// All rights reserved.
  10 +//
  11 +// Redistribution and use in source and binary forms, with or without
  12 +// modification, are permitted provided that the following conditions are
  13 +// met:
  14 +//
  15 +// 1. Redistributions of source code must retain the above copyright notice,
  16 +// this list of conditions and the following disclaimer.
  17 +//
  18 +// 2. Redistributions in binary form must reproduce the above copyright
  19 +// notice, this list of conditions and the following disclaimer in the
  20 +// documentation and/or other materials provided with the distribution.
  21 +//
  22 +// 3. Neither the name of the copyright holder nor the names of its
  23 +// contributors may be used to endorse or promote products derived from this
  24 +// software without specific prior written permission.
  25 +//
  26 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  27 +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  28 +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  29 +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  30 +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  31 +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  32 +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  33 +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  34 +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  35 +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  36 +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  37 +// --------------------------------------------------------------------------
  38 +
  39 +#include <iostream>
  40 +#include <string>
  41 +#include "sockpp/unix_connector.h"
  42 +#include "sockpp/version.h"
  43 +
  44 +using namespace std;
  45 +
  46 +// --------------------------------------------------------------------------
  47 +
  48 +int main(int argc, char* argv[])
  49 +{
  50 + cout << "Sample Unix-domain echo client for 'sockpp' "
  51 + << sockpp::SOCKPP_VERSION << '\n' << endl;
  52 +
  53 + string path = (argc > 1) ? argv[1] : "/tmp/unechosvr.sock";
  54 +
  55 + sockpp::socket_initializer sockInit;
  56 +
  57 + sockpp::unix_connector conn;
  58 +
  59 + bool ok = conn.connect(sockpp::unix_address(path));
  60 + if (!ok) {
  61 + cerr << "Error connecting to UNIX socket at " << path
  62 + << "\n\t" << conn.last_error_str() << endl;
  63 + return 1;
  64 + }
  65 +
  66 + cout << "Created a connection to '" << conn.peer_address() << "'" << endl;
  67 +
  68 + string s, sret;
  69 + while (getline(cin, s) && !s.empty()) {
  70 + if (conn.write(s) != (int) s.length()) {
  71 + cerr << "Error writing to the UNIX stream" << endl;
  72 + break;
  73 + }
  74 +
  75 + sret.resize(s.length());
  76 + int n = conn.read_n(&sret[0], s.length());
  77 +
  78 + if (n != (int) s.length()) {
  79 + cerr << "Error reading from UNIX stream" << endl;
  80 + break;
  81 + }
  82 +
  83 + cout << sret << endl;
  84 + }
  85 +
  86 + return (!conn) ? 1 : 0;
  87 +}
examples/unix/unechosvr.cpp 0 โ†’ 100644
  1 +++ a/examples/unix/unechosvr.cpp
  1 +// unechosvr.cpp
  2 +//
  3 +// A multi-threaded UNIX-domain echo server for sockpp library.
  4 +// This is a simple thread-per-connection UNIX server.
  5 +//
  6 +// USAGE:
  7 +// unechosvr [path]
  8 +//
  9 +// --------------------------------------------------------------------------
  10 +// This file is part of the "sockpp" C++ socket library.
  11 +//
  12 +// Copyright (c) 2014-2017 Frank Pagliughi
  13 +// All rights reserved.
  14 +//
  15 +// Redistribution and use in source and binary forms, with or without
  16 +// modification, are permitted provided that the following conditions are
  17 +// met:
  18 +//
  19 +// 1. Redistributions of source code must retain the above copyright notice,
  20 +// this list of conditions and the following disclaimer.
  21 +//
  22 +// 2. Redistributions in binary form must reproduce the above copyright
  23 +// notice, this list of conditions and the following disclaimer in the
  24 +// documentation and/or other materials provided with the distribution.
  25 +//
  26 +// 3. Neither the name of the copyright holder nor the names of its
  27 +// contributors may be used to endorse or promote products derived from this
  28 +// software without specific prior written permission.
  29 +//
  30 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  31 +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  32 +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  33 +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  34 +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  35 +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  36 +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  37 +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  38 +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  39 +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  40 +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  41 +// --------------------------------------------------------------------------
  42 +
  43 +#include <iostream>
  44 +#include <thread>
  45 +#include "sockpp/unix_acceptor.h"
  46 +#include "sockpp/version.h"
  47 +
  48 +using namespace std;
  49 +
  50 +// --------------------------------------------------------------------------
  51 +// The thread function. This is run in a separate thread for each socket.
  52 +// Ownership of the socket object is transferred to the thread, so when this
  53 +// function exits, the socket is automatically closed.
  54 +
  55 +void run_echo(sockpp::unix_socket sock)
  56 +{
  57 + int n;
  58 + char buf[512];
  59 +
  60 + while ((n = sock.read(buf, sizeof(buf))) > 0)
  61 + sock.write_n(buf, n);
  62 +
  63 + cout << "Connection closed" << endl;
  64 +}
  65 +
  66 +// --------------------------------------------------------------------------
  67 +// The main thread runs the UNIX acceptor.
  68 +// Each time a connection is made, a new thread is spawned to handle it,
  69 +// leaving this main thread to immediately wait for the next connection.
  70 +
  71 +int main(int argc, char* argv[])
  72 +{
  73 + cout << "Sample Unix-domain echo server for 'sockpp' "
  74 + << sockpp::SOCKPP_VERSION << '\n' << endl;
  75 +
  76 + string path = "/tmp/unechosvr.sock";
  77 +
  78 + if (argc > 1) {
  79 + path = argv[1];
  80 + }
  81 +
  82 + sockpp::socket_initializer sockInit;
  83 + sockpp::unix_acceptor acc;
  84 +
  85 + bool ok = acc.open(sockpp::unix_address(path));
  86 +
  87 + if (!ok) {
  88 + cerr << "Error creating the acceptor: " << acc.last_error_str() << endl;
  89 + return 1;
  90 + }
  91 + cout << "Acceptor bound to address: '" << acc.address() << "'..." << endl;
  92 +
  93 + while (true) {
  94 + // Accept a new client connection
  95 + auto sock = acc.accept();
  96 + cout << "Received a connection" << endl;
  97 +
  98 + if (!sock) {
  99 + cerr << "Error accepting incoming connection: "
  100 + << acc.last_error_str() << endl;
  101 + }
  102 + else {
  103 + // Create a thread and transfer the new stream to it.
  104 + thread thr(run_echo, std::move(sock));
  105 + thr.detach();
  106 + }
  107 + }
  108 +
  109 + return 0;
  110 +}
  111 +
examples/unix/unechotest.cpp 0 โ†’ 100644
  1 +++ a/examples/unix/unechotest.cpp
  1 +// unechotest.cpp
  2 +//
  3 +// Unix-domain echo timing test client
  4 +//
  5 +// --------------------------------------------------------------------------
  6 +// This file is part of the "sockpp" C++ socket library.
  7 +//
  8 +// Copyright (c) 2020 Frank Pagliughi
  9 +// All rights reserved.
  10 +//
  11 +// Redistribution and use in source and binary forms, with or without
  12 +// modification, are permitted provided that the following conditions are
  13 +// met:
  14 +//
  15 +// 1. Redistributions of source code must retain the above copyright notice,
  16 +// this list of conditions and the following disclaimer.
  17 +//
  18 +// 2. Redistributions in binary form must reproduce the above copyright
  19 +// notice, this list of conditions and the following disclaimer in the
  20 +// documentation and/or other materials provided with the distribution.
  21 +//
  22 +// 3. Neither the name of the copyright holder nor the names of its
  23 +// contributors may be used to endorse or promote products derived from this
  24 +// software without specific prior written permission.
  25 +//
  26 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  27 +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  28 +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  29 +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  30 +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  31 +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  32 +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  33 +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  34 +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  35 +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  36 +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  37 +// --------------------------------------------------------------------------
  38 +
  39 +#include <iostream>
  40 +#include <string>
  41 +#include <chrono>
  42 +#include <random>
  43 +#include "sockpp/unix_connector.h"
  44 +#include "sockpp/version.h"
  45 +
  46 +using namespace std;
  47 +using namespace std::chrono;
  48 +
  49 +const size_t DFLT_N = 100000;
  50 +const size_t DFLT_SZ = 512;
  51 +
  52 +using fpsec = std::chrono::duration<double, std::chrono::seconds::period>;
  53 +
  54 +// --------------------------------------------------------------------------
  55 +
  56 +int main(int argc, char* argv[])
  57 +{
  58 + cout << "Unix-domain echo timing test client for 'sockpp' "
  59 + << sockpp::SOCKPP_VERSION << '\n' << endl;
  60 +
  61 + string path = (argc > 1) ? argv[1] : "/tmp/unechosvr.sock";
  62 + size_t n = (argc > 2) ? size_t(atoll(argv[2])) : DFLT_N;
  63 + size_t sz = (argc > 3) ? size_t(atoll(argv[3])) : DFLT_SZ;
  64 +
  65 + sockpp::socket_initializer sockInit;
  66 +
  67 + auto t_start = high_resolution_clock::now();
  68 + sockpp::unix_connector conn;
  69 +
  70 + bool ok = conn.connect(sockpp::unix_address(path));
  71 + if (!ok) {
  72 + cerr << "Error connecting to UNIX socket at " << path
  73 + << "\n\t" << conn.last_error_str() << endl;
  74 + return 1;
  75 + }
  76 +
  77 + cout << "Created a connection to '" << conn.peer_address() << "'" << endl;
  78 +
  79 + string s, sret;
  80 +
  81 + random_device rd;
  82 + mt19937 reng(rd());
  83 + uniform_int_distribution<char> dist(0, 25);
  84 +
  85 + for (size_t i=0; i<sz; ++i)
  86 + s.push_back('a' + dist(reng));
  87 +
  88 + auto t_start_tx = high_resolution_clock::now();
  89 +
  90 + for (size_t i=0; i<n; ++i) {
  91 + if (conn.write(s) != (ssize_t) s.length()) {
  92 + cerr << "Error writing to the UNIX stream" << endl;
  93 + break;
  94 + }
  95 +
  96 + sret.resize(s.length());
  97 + int n = conn.read_n(&sret[0], s.length());
  98 +
  99 + if (n != (int) s.length()) {
  100 + cerr << "Error reading from UNIX stream" << endl;
  101 + break;
  102 + }
  103 + }
  104 +
  105 + auto t_end = high_resolution_clock::now();
  106 + cout << "Total time: " << fpsec(t_end - t_start).count() << "s" << endl;
  107 +
  108 + auto t_tx = fpsec(t_end - t_start_tx).count();
  109 + auto rate = size_t(n / t_tx);
  110 + cout << "Transfer time: " << t_tx << "s\n "
  111 + << rate << " msg/s" << endl;
  112 +
  113 + return (!conn) ? 1 : 0;
  114 +}
include/socket-cpp/acceptor.h 0 โ†’ 100644
  1 +++ a/include/socket-cpp/acceptor.h
  1 +#pragma once
  2 +
  3 +#include "socket-cpp/inet_address.h"
  4 +#include "socket-cpp/stream_socket.h"
  5 +
  6 +namespace osdev {
  7 +namespace components {
  8 +namespace socket-cpp {
  9 +
  10 +/**
  11 + * Class for creating a streaming server.
  12 + * Objects of this class bind and listen on streaming ports for incoming
  13 + * connections. Normally, a server thread creates one of these and blocks on
  14 + * the call to accept incoming connections. The call to accept creates and
  15 + * returns a @ref stream_socket which can then be used for the actual
  16 + * communications.
  17 + */
  18 +class acceptor : public socket
  19 +{
  20 + /** The base class */
  21 + using base = socket;
  22 +
  23 + // Non-copyable
  24 + acceptor(const acceptor&) = delete;
  25 + acceptor& operator=(const acceptor&) = delete;
  26 +
  27 +protected:
  28 + /** The default listener queue size. */
  29 + static const int DFLT_QUE_SIZE = 4;
  30 +
  31 + /**
  32 + * Creates an underlying acceptor socket.
  33 + * The acceptor uses a stream socket type, but for our purposes is not
  34 + * classified (derived from) a streaming socket, since it doesn't
  35 + * support read and write to the socket.
  36 + * @param domain The communications domain (address family).
  37 + * @return An OS handle to a stream socket.
  38 + */
  39 + static socket_t create_handle(int domain) {
  40 + return stream_socket::create_handle(domain);
  41 + }
  42 +
  43 +public:
  44 + /**
  45 + * Creates an unconnected acceptor.
  46 + */
  47 + acceptor() {}
  48 + /**
  49 + * Creates an acceptor from an existing OS socket
  50 + * handle and claims ownership of the handle.
  51 + * @param handle A socket handle from the operating system.
  52 + */
  53 + explicit acceptor(socket_t handle) : base(handle) {}
  54 + /**
  55 + * Creates an acceptor socket and starts it listening to the specified
  56 + * address.
  57 + * @param addr The address to which this server should be bound.
  58 + * @param queSize The listener queue size.
  59 + */
  60 + acceptor(const sock_address& addr, int queSize=DFLT_QUE_SIZE) {
  61 + open(addr, queSize);
  62 + }
  63 + /**
  64 + * Move constructor.
  65 + * Creates an acceptor by moving the other acceptor to this one.
  66 + * @param acc Another acceptor
  67 + */
  68 + acceptor(acceptor&& acc) : base(std::move(acc)) {}
  69 + /**
  70 + * Creates an unbound acceptor socket with an open OS socket handle.
  71 + * An application would need to manually bind and listen to this
  72 + * acceptor to get incoming connections.
  73 + * @param domain The communications domain (address family).
  74 + * @return An open, but unbound acceptor socket.
  75 + */
  76 + static acceptor create(int domain);
  77 + /**
  78 + * Move assignment.
  79 + * @param rhs The other socket to move into this one.
  80 + * @return A reference to this object.
  81 + */
  82 + acceptor& operator=(acceptor&& rhs) {
  83 + base::operator=(std::move(rhs));
  84 + return *this;
  85 + }
  86 + /**
  87 + * Sets the socket listening on the address to which it is bound.
  88 + * @param queSize The listener queue size.
  89 + * @return @em true on success, @em false on error
  90 + */
  91 + bool listen(int queSize=DFLT_QUE_SIZE) {
  92 + return check_ret_bool(::listen(handle(), queSize));
  93 + };
  94 + /**
  95 + * Opens the acceptor socket, binds it to the specified address, and starts
  96 + * listening.
  97 + * @param addr The address to which this server should be bound.
  98 + * @param queSize The listener queue size.
  99 + * @param reuseSock Whether the SO_REUSEPORT (or SO_REUSEADDR on Win32)
  100 + * socket option should be used before binding and
  101 + * listening.
  102 + * @return @em true on success, @em false on error
  103 + */
  104 + bool open(const sock_address& addr, int queSize=DFLT_QUE_SIZE, bool reuseSock=true);
  105 + /**
  106 + * Accepts an incoming TCP connection and gets the address of the client.
  107 + * @param clientAddr Pointer to the variable that will get the
  108 + * address of a client when it connects.
  109 + * @return A socket to the remote client.
  110 + */
  111 + stream_socket accept(sock_address* clientAddr=nullptr);
  112 +};
  113 +
  114 +
  115 +/**
  116 + * Base template class for streaming servers of specific address families.
  117 + * This is a base for creating socket acceptor classes for an individual
  118 + * family. In most cases, all that is needed is a type definition specifying
  119 + * which addresses type should be used to receive incoming connections,
  120 + * like:
  121 + * using tcp_acceptor = acceptor_tmpl<tcp_socket>;
  122 + */
  123 +template <typename STREAM_SOCK, typename ADDR=typename STREAM_SOCK::addr_t>
  124 +class acceptor_tmpl : public acceptor
  125 +{
  126 + /** The base class */
  127 + using base = acceptor;
  128 +
  129 + // Non-copyable
  130 + acceptor_tmpl(const acceptor_tmpl&) =delete;
  131 + acceptor_tmpl& operator=(const acceptor_tmpl&) =delete;
  132 +
  133 +public:
  134 + /** The type of streaming socket from the acceptor. */
  135 + using stream_sock_t = STREAM_SOCK;
  136 + /** The type of address for the acceptor and streams. */
  137 + using addr_t = ADDR;
  138 +
  139 + /**
  140 + * Creates an unconnected acceptor.
  141 + */
  142 + acceptor_tmpl() {}
  143 + /**
  144 + * Creates a acceptor and starts it listening on the specified address.
  145 + * @param addr The TCP address on which to listen.
  146 + * @param queSize The listener queue size.
  147 + */
  148 + acceptor_tmpl(const addr_t& addr, int queSize=DFLT_QUE_SIZE) {
  149 + open(addr, queSize);
  150 + }
  151 + /**
  152 + * Creates a acceptor and starts it listening on the specified port.
  153 + * The acceptor binds to the specified port for any address on the local
  154 + * host.
  155 + * @param port The TCP port on which to listen.
  156 + * @param queSize The listener queue size.
  157 + */
  158 + acceptor_tmpl(in_port_t port, int queSize=DFLT_QUE_SIZE) {
  159 + open(port, queSize);
  160 + }
  161 + /**
  162 + * Move constructor.
  163 + * Creates an acceptor by moving the other acceptor to this one.
  164 + * @param acc Another acceptor
  165 + */
  166 + acceptor_tmpl(acceptor_tmpl&& acc) : base(std::move(acc)) {}
  167 + /**
  168 + * Creates an unbound acceptor socket with an open OS socket handle.
  169 + * An application would need to manually bind and listen to this
  170 + * acceptor to get incoming connections.
  171 + * @return An open, but unbound acceptor socket.
  172 + */
  173 + static acceptor_tmpl create() {
  174 + return base::create(addr_t::ADDRESS_FAMILY);
  175 + }
  176 + /**
  177 + * Move assignment.
  178 + * @param rhs The other socket to move into this one.
  179 + * @return A reference to this object.
  180 + */
  181 + acceptor_tmpl& operator=(acceptor_tmpl&& rhs) {
  182 + base::operator=(std::move(rhs));
  183 + return *this;
  184 + }
  185 + /**
  186 + * Gets the local address to which we are bound.
  187 + * @return The local address to which we are bound.
  188 + */
  189 + addr_t address() const { return addr_t(base::address()); }
  190 + /**
  191 + * Binds the socket to the specified address.
  192 + * @param addr The address to which we get bound.
  193 + * @return @em true on success, @em false on error
  194 + */
  195 + bool bind(const addr_t& addr) { return base::bind(addr); }
  196 + /**
  197 + * Opens the acceptor socket, binds it to the specified address, and starts
  198 + * listening.
  199 + * @param addr The address to which this server should be bound.
  200 + * @param queSize The listener queue size.
  201 + * @return @em true on success, @em false on error
  202 + */
  203 + bool open(const addr_t& addr, int queSize=DFLT_QUE_SIZE) {
  204 + return base::open(addr, queSize);
  205 + }
  206 + /**
  207 + * Opens the acceptor socket, binds the socket to all adapters and starts it
  208 + * listening.
  209 + * @param port The TCP port on which to listen.
  210 + * @param queSize The listener queue size.
  211 + * @return @em true on success, @em false on error
  212 + */
  213 + bool open(in_port_t port, int queSize=DFLT_QUE_SIZE) {
  214 + return open(addr_t(port), queSize);
  215 + }
  216 + /**
  217 + * Accepts an incoming connection and gets the address of the client.
  218 + * @param clientAddr Pointer to the variable that will get the
  219 + * address of a client when it connects.
  220 + * @return A tcp_socket to the remote client.
  221 + */
  222 + stream_sock_t accept(addr_t* clientAddr=nullptr) {
  223 + return stream_sock_t(base::accept(clientAddr));
  224 + }
  225 +};
  226 +
  227 +} // End namespace socket-cpp
  228 +} // End namespace components
  229 +} // End namespace osdev
  230 +
include/socket-cpp/can_address.h 0 โ†’ 100644
  1 +++ a/include/socket-cpp/can_address.h
  1 +#pragma once
  2 +
  3 +#include "socket-cpp/platform.h"
  4 +#include "socket-cpp/sock_address.h"
  5 +#include <iostream>
  6 +#include <string>
  7 +#include <cstring>
  8 +#include <sys/un.h>
  9 +
  10 +#include <linux/can.h>
  11 +
  12 +namespace osdev {
  13 +namespace components {
  14 +namespace socket-cpp {
  15 +
  16 +/**
  17 + * Class that represents a Linux SocketCAN address.
  18 + * This inherits from the CAN form of a socket address, @em sockaddr_can.
  19 + */
  20 +class can_address : public sock_address
  21 +{
  22 + /** The underlying C struct for SocketCAN addresses */
  23 + sockaddr_can addr_;
  24 +
  25 + /** The size of the underlying address struct, in bytes */
  26 + static constexpr size_t SZ = sizeof(sockaddr_can);
  27 +
  28 +public:
  29 + /** The address family for this type of address */
  30 + static constexpr sa_family_t ADDRESS_FAMILY = AF_CAN;
  31 +
  32 + /** Iface to use to indicate binding to all interfaces */
  33 + static const unsigned ALL_IFACE = 0;
  34 +
  35 + /**
  36 + * Constructs an empty address.
  37 + * The address is initialized to all zeroes.
  38 + */
  39 + can_address() : addr_() {}
  40 + /**
  41 + * Creates an address for binding to a specific CAN interface
  42 + * @param ifindex The interface index to use. This must, obviously, be
  43 + * an index to a CAN interface.
  44 + */
  45 + explicit can_address(unsigned ifindex);
  46 + /**
  47 + * Constructs an address for the specified CAN interface.
  48 + * The interface might be "can0", "can1", "vcan0", etc.
  49 + * @param iface The name of the CAN interface
  50 + */
  51 + can_address(const std::string& iface);
  52 + /**
  53 + * Constructs the address by copying the specified structure.
  54 + * @param addr The generic address
  55 + * @throws std::invalid_argument if the address is not a SocketCAN
  56 + * address (i.e. family is not AF_CAN)
  57 + */
  58 + explicit can_address(const sockaddr& addr);
  59 + /**
  60 + * Constructs the address by copying the specified structure.
  61 + * @param addr The other address
  62 + */
  63 + can_address(const sock_address& addr) {
  64 + std::memcpy(&addr_, addr.sockaddr_ptr(), SZ);
  65 + }
  66 + /**
  67 + * Constructs the address by copying the specified structure.
  68 + * @param addr The other address
  69 + * @throws std::invalid_argument if the address is not properly
  70 + * initialized as a SocketCAN address (i.e. family is not
  71 + * AF_CAN)
  72 + */
  73 + can_address(const sockaddr_can& addr) : addr_(addr) {}
  74 + /**
  75 + * Constructs the address by copying the specified address.
  76 + * @param addr The other address
  77 + */
  78 + can_address(const can_address& addr) : addr_(addr.addr_) {}
  79 + /**
  80 + * Checks if the address is set to some value.
  81 + * This doesn't attempt to determine if the address is valid, simply
  82 + * that it's not all zero.
  83 + * @return @em true if the address has been set, @em false otherwise.
  84 + */
  85 + bool is_set() const { return family() != AF_UNSPEC; }
  86 + /**
  87 + * Gets the name of the CAN interface to which this address refers.
  88 + * @return The name of the CAN interface to which this address refers.
  89 + */
  90 + std::string iface() const;
  91 + /**
  92 + * Gets the size of the address structure.
  93 + * Note: In this implementation, this should return sizeof(this) but
  94 + * more convenient in some places, and the implementation might change
  95 + * in the future, so it might be more compatible with future revisions
  96 + * to use this call.
  97 + * @return The size of the address structure.
  98 + */
  99 + socklen_t size() const override { return socklen_t(SZ); }
  100 +
  101 + // TODO: Do we need a:
  102 + // create(iface)
  103 + // to mimic the inet_address behavior?
  104 +
  105 + /**
  106 + * Gets a pointer to this object cast to a const @em sockaddr.
  107 + * @return A pointer to this object cast to a const @em sockaddr.
  108 + */
  109 + const sockaddr* sockaddr_ptr() const override {
  110 + return reinterpret_cast<const sockaddr*>(&addr_);
  111 + }
  112 + /**
  113 + * Gets a pointer to this object cast to a @em sockaddr.
  114 + * @return A pointer to this object cast to a @em sockaddr.
  115 + */
  116 + sockaddr* sockaddr_ptr() override {
  117 + return reinterpret_cast<sockaddr*>(&addr_);
  118 + }
  119 + /**
  120 + * Gets a const pointer to this object cast to a @em sockaddr_can.
  121 + * @return const sockaddr_can pointer to this object.
  122 + */
  123 + const sockaddr_can* sockaddr_can_ptr() const { return &addr_; }
  124 + /**
  125 + * Gets a pointer to this object cast to a @em sockaddr_can.
  126 + * @return sockaddr_can pointer to this object.
  127 + */
  128 + sockaddr_can* sockaddr_can_ptr() { return &addr_; }
  129 + /**
  130 + * Gets a printable string for the address.
  131 + * @return A string representation of the address in the form
  132 + * "unix:<path>"
  133 + */
  134 + std::string to_string() const {
  135 + return std::string("can:") + iface();
  136 + }
  137 +};
  138 +
  139 +// --------------------------------------------------------------------------
  140 +
  141 +/**
  142 + * Stream inserter for the address.
  143 + * @param os The output stream
  144 + * @param addr The address
  145 + * @return A reference to the output stream.
  146 + */
  147 +std::ostream& operator<<(std::ostream& os, const can_address& addr);
  148 +
  149 +} // End namespace socket-cpp
  150 +} // End namespace components
  151 +} // End namespace osdev
include/socket-cpp/can_frame.h 0 โ†’ 100644
  1 +++ a/include/socket-cpp/can_frame.h
  1 +#pragma once
  2 +
  3 +#include "socket-cpp/platform.h"
  4 +#include <string>
  5 +#include <cstring>
  6 +//#include <sys/un.h>
  7 +#include <linux/can.h>
  8 +
  9 +namespace osdev {
  10 +namespace components {
  11 +namespace socket-cpp {
  12 +
  13 +/**
  14 + * Class that represents a Linux SocketCAN frame.
  15 + * This inherits from the Linux CAN frame struct, just providing easier
  16 + construction.
  17 + */
  18 +class can_frame : public ::can_frame
  19 +{
  20 + using base = ::can_frame;
  21 +
  22 + /** The size of the underlying address struct, in bytes */
  23 + static constexpr size_t SZ = sizeof(::can_frame);
  24 +
  25 +public:
  26 + /**
  27 + * Constructs an empty frame.
  28 + * The frame is initialized to all zeroes.
  29 + */
  30 + can_frame() : base{} {}
  31 + /**
  32 + * Constructs a frame with the specified ID and data.
  33 + * @param canID The CAN identifier for the frame
  34 + * @param data The data field for the frame
  35 + */
  36 + can_frame(canid_t canID, const std::string& data)
  37 + : can_frame{ canID, data.data(), data.length() } {}
  38 + /**
  39 + * Constructs a frame with the specified ID and data.
  40 + * @param canID The CAN identifier for the frame
  41 + * @param data The data field for the frame
  42 + * @param n The number of bytes in the data field
  43 + */
  44 + can_frame(canid_t canID, const void* data, size_t n) : base{} {
  45 + this->can_id = canID;
  46 + this->can_dlc = n;
  47 + ::memcpy(&this->data, data, n);
  48 + }
  49 +};
  50 +
  51 +} // End namespace socket-cpp
  52 +} // End namespace components
  53 +} // End namespace osdev
include/socket-cpp/can_socket.h 0 โ†’ 100644
  1 +++ a/include/socket-cpp/can_socket.h
  1 +#pragma once
  2 +
  3 +#include "socket-cpp/datagram_socket.h"
  4 +#include "socket-cpp/can_address.h"
  5 +#include "socket-cpp/can_frame.h"
  6 +
  7 +namespace osdev {
  8 +namespace components {
  9 +namespace socket-cpp {
  10 +
  11 +/**
  12 + * Socket type for Linux SocketCAN.
  13 + *
  14 + * Note that technically these are RAW sockets, not DGRAM. We can/should
  15 + * organize the underlying hierarch to properly indicate this, but for
  16 + * practical usge, it doesn't matter too MUCH.
  17 + * The BCM CAN sockets are DGRAM sockets, but those aren't implemented yet.
  18 + * It wouldn't take too much to add them, though.
  19 + */
  20 +class can_socket : public datagram_socket
  21 +{
  22 + /** The base class */
  23 + using base = datagram_socket;
  24 +
  25 + // Non-copyable
  26 + can_socket(const can_socket&) =delete;
  27 + can_socket& operator=(const can_socket&) =delete;
  28 +
  29 + /**
  30 + * We can't connect to a raw CAN socket;
  31 + * we can only bind the address/iface.
  32 + */
  33 + bool connect(const sock_address&) =delete;
  34 +
  35 +protected:
  36 + static socket_t create_handle(int type, int protocol) {
  37 + return socket_t(::socket(PROTOCOL_FAMILY, type, protocol));
  38 + }
  39 +
  40 +public:
  41 + /**
  42 + * The SocketCAN protocol family.
  43 + * Note that AF_CAN == PF_CAN, which is used in many of the CAN
  44 + * examples.
  45 + */
  46 + static const int PROTOCOL_FAMILY = AF_CAN;
  47 +
  48 + /** The socket 'type' for communications semantics. */
  49 + static constexpr int COMM_TYPE = SOCK_RAW;
  50 +
  51 + /**
  52 + * Creates an uninitialized CAN socket.
  53 + */
  54 + can_socket() {}
  55 + /**
  56 + * Creates a CAN socket from an existing OS socket handle and
  57 + * claims ownership of the handle.
  58 + * @param handle A socket handle from the operating system.
  59 + */
  60 + explicit can_socket(socket_t handle) : base(handle) {}
  61 + /**
  62 + * Creates a CAN socket and binds it to the address.
  63 + * @param addr The address to bind.
  64 + */
  65 + explicit can_socket(const can_address& addr);
  66 + /**
  67 + * Move constructor.
  68 + * @param other The other socket to move to this one
  69 + */
  70 + can_socket(can_socket&& other) : base(std::move(other)) {}
  71 + /**
  72 + * Move assignment.
  73 + * @param rhs The other socket to move into this one.
  74 + * @return A reference to this object.
  75 + */
  76 + can_socket& operator=(can_socket&& rhs) {
  77 + base::operator=(std::move(rhs));
  78 + return *this;
  79 + }
  80 +
  81 + /**
  82 + * Gets the system time of the last frame read from the socket.
  83 + * @return The system time of the last frame read from the socket with
  84 + * microsecond precision.
  85 + */
  86 + std::chrono::system_clock::time_point last_frame_time();
  87 + /**
  88 + * Gets a floating point timestamp of the last frame read from the
  89 + * socket.
  90 + * This is the number of seconds since the Unix epoch (time_t), with
  91 + * floating-point, microsecond precision.
  92 + * @return A floating-point timestamp with microsecond precision.
  93 + */
  94 + double last_frame_timestamp();
  95 +
  96 + // ----- I/O -----
  97 +
  98 + /**
  99 + * Sends a frame to the CAN interfacce at the specified address.
  100 + * @param frame The CAN frame to send.
  101 + * @param flags The flags. See send(2).
  102 + * @param addr The remote destination of the data.
  103 + * @return the number of bytes sent on success or, @em -1 on failure.
  104 + */
  105 + ssize_t send_to(const can_frame& frame, int flags, const can_address& addr) {
  106 + return check_ret(
  107 + ::sendto(handle(), &frame, sizeof(can_frame), flags,
  108 + addr.sockaddr_ptr(), addr.size())
  109 + );
  110 + }
  111 +
  112 + /**
  113 + * Sends a frame to the CAN interface at the specified address.
  114 + * @param frame The CAN frame to send.
  115 + * @param addr The remote destination of the data.
  116 + * @return the number of bytes sent on success or, @em -1 on failure.
  117 + */
  118 + ssize_t send_to(const can_frame& frame, const can_address& addr) {
  119 + return check_ret(
  120 + ::sendto(handle(), &frame, sizeof(can_frame), 0,
  121 + addr.sockaddr_ptr(), addr.size())
  122 + );
  123 + }
  124 + /**
  125 + * Sends a frame to the CAN bus.
  126 + * The socket should be bound before calling this.
  127 + * @param frame The CAN frame to send.
  128 + * @param flags The option bit flags. See send(2).
  129 + * @return @em zero on success, @em -1 on failure.
  130 + */
  131 + ssize_t send(const can_frame& frame, int flags=0) {
  132 + return check_ret(::send(handle(), &frame, sizeof(can_frame), flags));
  133 + }
  134 + /**
  135 + * Receives a message from the CAN interface at the specified address.
  136 + * @param frame CAN frame to get the incoming data.
  137 + * @param flags The option bit flags. See send(2).
  138 + * @param srcAddr Receives the address of the peer that sent the
  139 + * message
  140 + * @return The number of bytes read or @em -1 on error.
  141 + */
  142 + ssize_t recv_from(can_frame* frame, int flags, can_address* srcAddr=nullptr);
  143 + /**
  144 + * Receives a message on the socket.
  145 + * @param frame CAN frame to get the incoming data.
  146 + * @param flags The option bit flags. See send(2).
  147 + * @return The number of bytes read or @em -1 on error.
  148 + */
  149 + ssize_t recv(can_frame* frame, int flags=0) {
  150 + return check_ret(::recv(handle(), frame, sizeof(can_frame), flags));
  151 + }
  152 +};
  153 +
  154 +} // End namespace socket-cpp
  155 +} // End namespace components
  156 +} // End namespace osdev
include/socket-cpp/connector.h 0 โ†’ 100644
  1 +++ a/include/socket-cpp/connector.h
  1 +#pragma once
  2 +
  3 +#include "socket-cpp/stream_socket.h"
  4 +#include "socket-cpp/sock_address.h"
  5 +
  6 +namespace osdev {
  7 +namespace components {
  8 +namespace socket-cpp {
  9 +
  10 +/**
  11 + * Class to create a client stream connection.
  12 + * This is a base class for creating active, streaming sockets that initiate
  13 + * connections to a server. It can be used to derive classes that implement
  14 + * TCP on IPv4 or IPv6.
  15 + */
  16 +class connector : public stream_socket
  17 +{
  18 + /** The base class */
  19 + using base = stream_socket;
  20 +
  21 + // Non-copyable
  22 + connector(const connector&) =delete;
  23 + connector& operator=(const connector&) =delete;
  24 +
  25 +public:
  26 + /**
  27 + * Creates an unconnected connector.
  28 + */
  29 + connector() {}
  30 + /**
  31 + * Creates the connector and attempts to connect to the specified
  32 + * address.
  33 + * @param addr The remote server address.
  34 + */
  35 + connector(const sock_address& addr) { connect(addr); }
  36 + /**
  37 + * Move constructor.
  38 + * Creates a connector by moving the other connector to this one.
  39 + * @param conn Another connector.
  40 + */
  41 + connector(connector&& conn) : base(std::move(conn)) {}
  42 + /**
  43 + * Move assignment.
  44 + * @param rhs The other connector to move into this one.
  45 + * @return A reference to this object.
  46 + */
  47 + connector& operator=(connector&& rhs) {
  48 + base::operator=(std::move(rhs));
  49 + return *this;
  50 + }
  51 + /**
  52 + * Determines if the socket connected to a remote host.
  53 + * Note that this is not a reliable determination if the socket is
  54 + * currently connected, but rather that an initial connection was
  55 + * established.
  56 + * @return @em true If the socket connected to a remote host,
  57 + * @em false if not.
  58 + */
  59 + bool is_connected() const { return is_open(); }
  60 + /**
  61 + * Attempts to connect to the specified server.
  62 + * If the socket is currently connected, this will close the current
  63 + * connection and open the new one.
  64 + * @param addr The remote server address.
  65 + * @return @em true on success, @em false on error
  66 + */
  67 + bool connect(const sock_address& addr);
  68 +};
  69 +
  70 +/**
  71 + * Class to create a client TCP connection.
  72 + */
  73 +template <typename STREAM_SOCK, typename ADDR=typename STREAM_SOCK::addr_t>
  74 +class connector_tmpl : public connector
  75 +{
  76 + /** The base class */
  77 + using base = connector;
  78 +
  79 + // Non-copyable
  80 + connector_tmpl(const connector_tmpl&) =delete;
  81 + connector_tmpl& operator=(const connector_tmpl&) =delete;
  82 +
  83 +public:
  84 + /** The type of streaming socket from the acceptor. */
  85 + using stream_sock_t = STREAM_SOCK;
  86 + /** The type of address for the connector. */
  87 + using addr_t = ADDR;
  88 +
  89 + /**
  90 + * Creates an unconnected connector.
  91 + */
  92 + connector_tmpl() {}
  93 + /**
  94 + * Creates the connector and attempts to connect to the specified
  95 + * address.
  96 + * @param addr The remote server address.
  97 + */
  98 + connector_tmpl(const addr_t& addr) : base(addr) {}
  99 + /**
  100 + * Move constructor.
  101 + * Creates a connector by moving the other connector to this one.
  102 + * @param conn Another connector.
  103 + */
  104 + connector_tmpl(connector_tmpl&& rhs) : base(std::move(rhs)) {}
  105 + /**
  106 + * Move assignment.
  107 + * @param rhs The other connector to move into this one.
  108 + * @return A reference to this object.
  109 + */
  110 + connector_tmpl& operator=(connector_tmpl&& rhs) {
  111 + base::operator=(std::move(rhs));
  112 + return *this;
  113 + }
  114 + /**
  115 + * Gets the local address to which the socket is bound.
  116 + * @return The local address to which the socket is bound.
  117 + * @throw sys_error on error
  118 + */
  119 + addr_t address() const { return addr_t(base::address()); }
  120 + /**
  121 + * Gets the address of the remote peer, if this socket is connected.
  122 + * @return The address of the remote peer, if this socket is connected.
  123 + * @throw sys_error on error
  124 + */
  125 + addr_t peer_address() const { return addr_t(base::peer_address()); }
  126 + /**
  127 + * Binds the socket to the specified address.
  128 + * This call is optional for a client connector, though it is rarely
  129 + * used.
  130 + * @param addr The address to which we get bound.
  131 + * @return @em true on success, @em false on error
  132 + */
  133 + bool bind(const addr_t& addr) { return base::bind(addr); }
  134 + /**
  135 + * Attempts to connects to the specified server.
  136 + * If the socket is currently connected, this will close the current
  137 + * connection and open the new one.
  138 + * @param addr The remote server address.
  139 + * @return @em true on success, @em false on error
  140 + */
  141 + bool connect(const addr_t& addr) { return base::connect(addr); }
  142 +};
  143 +
  144 +} // End namespace socket-cpp
  145 +} // End namespace components
  146 +} // End namespace osdev
  147 +
include/socket-cpp/datagram_socket.h 0 โ†’ 100644
  1 +++ a/include/socket-cpp/datagram_socket.h
  1 +#pragma once
  2 +
  3 +#include "socket-cpp/socket.h"
  4 +
  5 +namespace osdev {
  6 +namespace components {
  7 +namespace socket-cpp {
  8 +
  9 +/**
  10 + * Base class for datagram sockets.
  11 + *
  12 + * Datagram sockets are normally connectionless, where each packet is
  13 + * individually routed and delivered.
  14 + */
  15 +class datagram_socket : public socket
  16 +{
  17 + /** The base class */
  18 + using base = socket;
  19 +
  20 + // Non-copyable
  21 + datagram_socket(const datagram_socket&) =delete;
  22 + datagram_socket& operator=(const datagram_socket&) =delete;
  23 +
  24 +protected:
  25 + static socket_t create_handle(int domain, int protocol=0) {
  26 + return socket_t(::socket(domain, COMM_TYPE, protocol));
  27 + }
  28 +
  29 + static socket_t create_handle(int domain, int type, int protocol) {
  30 + return socket_t(::socket(domain, type, protocol));
  31 + }
  32 +
  33 +public:
  34 + /** The socket 'type' for communications semantics. */
  35 + static constexpr int COMM_TYPE = SOCK_DGRAM;
  36 +
  37 + /**
  38 + * Creates an uninitialized datagram socket.
  39 + */
  40 + datagram_socket() {}
  41 + /**
  42 + * Creates a datagram socket from an existing OS socket handle and
  43 + * claims ownership of the handle.
  44 + * @param handle A socket handle from the operating system.
  45 + */
  46 + explicit datagram_socket(socket_t handle) : base(handle) {}
  47 + /**
  48 + * Creates a UDP socket and binds it to the address.
  49 + * @param addr The address to bind.
  50 + */
  51 + explicit datagram_socket(const sock_address& addr);
  52 + /**
  53 + * Move constructor.
  54 + * @param other The other socket to move to this one
  55 + */
  56 + datagram_socket(datagram_socket&& other)
  57 + : base(std::move(other)) {}
  58 + /**
  59 + * Move assignment.
  60 + * @param rhs The other socket to move into this one.
  61 + * @return A reference to this object.
  62 + */
  63 + datagram_socket& operator=(datagram_socket&& rhs) {
  64 + base::operator=(std::move(rhs));
  65 + return *this;
  66 + }
  67 + /**
  68 + * Connects the socket to the remote address.
  69 + * In the case of datagram sockets, this does not create an actual
  70 + * connection, but rather specifies the address to which datagrams are
  71 + * sent by default and the only address from which packets are
  72 + * received.
  73 + * @param addr The address on which to "connect".
  74 + * @return @em true on success, @em false on failure
  75 + */
  76 + bool connect(const sock_address& addr) {
  77 + return check_ret_bool(::connect(handle(), addr.sockaddr_ptr(),
  78 + addr.size()));
  79 + }
  80 +
  81 + // ----- I/O -----
  82 +
  83 + /**
  84 + * Sends a message to the socket at the specified address.
  85 + * @param buf The data to send.
  86 + * @param n The number of bytes in the data buffer.
  87 + * @param flags The flags. See send(2).
  88 + * @param addr The remote destination of the data.
  89 + * @return the number of bytes sent on success or, @em -1 on failure.
  90 + */
  91 + ssize_t send_to(const void* buf, size_t n, int flags, const sock_address& addr) {
  92 + #if defined(_WIN32)
  93 + return check_ret(::sendto(handle(), reinterpret_cast<const char*>(buf), int(n),
  94 + flags, addr.sockaddr_ptr(), addr.size()));
  95 + #else
  96 + return check_ret(::sendto(handle(), buf, n, flags,
  97 + addr.sockaddr_ptr(), addr.size()));
  98 + #endif
  99 + }
  100 + /**
  101 + * Sends a string to the socket at the specified address.
  102 + * @param s The string to send.
  103 + * @param flags The flags. See send(2).
  104 + * @param addr The remote destination of the data.
  105 + * @return the number of bytes sent on success or, @em -1 on failure.
  106 + */
  107 + ssize_t send_to(const std::string& s, int flags, const sock_address& addr) {
  108 + return send_to(s.data(), s.length(), flags, addr);
  109 + }
  110 + /**
  111 + * Sends a message to another socket.
  112 + * @param buf The data to send.
  113 + * @param n The number of bytes in the data buffer.
  114 + * @param addr The remote destination of the data.
  115 + * @return the number of bytes sent on success or, @em -1 on failure.
  116 + */
  117 + ssize_t send_to(const void* buf, size_t n, const sock_address& addr) {
  118 + return send_to(buf, n, 0, addr);
  119 + }
  120 + /**
  121 + * Sends a string to another socket.
  122 + * @param s The string to send.
  123 + * @param addr The remote destination of the data.
  124 + * @return the number of bytes sent on success or, @em -1 on failure.
  125 + */
  126 + ssize_t send_to(const std::string& s, const sock_address& addr) {
  127 + return send_to(s.data(), s.length(), 0, addr);
  128 + }
  129 + /**
  130 + * Sends a message to the socket at the default address.
  131 + * The socket should be connected before calling this.
  132 + * @param buf The date to send.
  133 + * @param n The number of bytes in the data buffer.
  134 + * @param flags The option bit flags. See send(2).
  135 + * @return @em zero on success, @em -1 on failure.
  136 + */
  137 + ssize_t send(const void* buf, size_t n, int flags=0) {
  138 + #if defined(_WIN32)
  139 + return check_ret(::send(handle(), reinterpret_cast<const char*>(buf),
  140 + int(n), flags));
  141 + #else
  142 + return check_ret(::send(handle(), buf, n, flags));
  143 + #endif
  144 + }
  145 + /**
  146 + * Sends a string to the socket at the default address.
  147 + * The socket should be connected before calling this
  148 + * @param s The string to send.
  149 + * @param flags The option bit flags. See send(2).
  150 + * @return @em zero on success, @em -1 on failure.
  151 + */
  152 + ssize_t send(const std::string& s, int flags=0) {
  153 + return send(s.data(), s.length(), flags);
  154 + }
  155 + /**
  156 + * Receives a message on the socket.
  157 + * @param buf Buffer to get the incoming data.
  158 + * @param n The number of bytes to read.
  159 + * @param flags The option bit flags. See send(2).
  160 + * @param srcAddr Receives the address of the peer that sent the
  161 + * message
  162 + * @return The number of bytes read or @em -1 on error.
  163 + */
  164 + ssize_t recv_from(void* buf, size_t n, int flags, sock_address* srcAddr=nullptr);
  165 + /**
  166 + * Receives a message on the socket.
  167 + * @param buf Buffer to get the incoming data.
  168 + * @param n The number of bytes to read.
  169 + * @param srcAddr Receives the address of the peer that sent the
  170 + * message
  171 + * @return The number of bytes read or @em -1 on error.
  172 + */
  173 + ssize_t recv_from(void* buf, size_t n, sock_address* srcAddr=nullptr) {
  174 + return recv_from(buf, n, 0, srcAddr);
  175 + }
  176 + /**
  177 + * Receives a message on the socket.
  178 + * @param buf Buffer to get the incoming data.
  179 + * @param n The number of bytes to read.
  180 + * @param flags The option bit flags. See send(2).
  181 + * @return The number of bytes read or @em -1 on error.
  182 + */
  183 + ssize_t recv(void* buf, size_t n, int flags=0) {
  184 + #if defined(_WIN32)
  185 + return check_ret(::recv(handle(), reinterpret_cast<char*>(buf),
  186 + int(n), flags));
  187 + #else
  188 + return check_ret(::recv(handle(), buf, n, flags));
  189 + #endif
  190 + }
  191 +};
  192 +
  193 +/**
  194 + * Base class for datagram sockets.
  195 + *
  196 + * Datagram sockets are normally connectionless, where each packet is
  197 + * individually routed and delivered.
  198 + */
  199 +template <typename ADDR>
  200 +class datagram_socket_tmpl : public datagram_socket
  201 +{
  202 + /** The base class */
  203 + using base = datagram_socket;
  204 +
  205 +public:
  206 + /** The address family for this type of address */
  207 + static constexpr sa_family_t ADDRESS_FAMILY = ADDR::ADDRESS_FAMILY;
  208 + /** The type of address for the socket. */
  209 + using addr_t = ADDR;
  210 +
  211 + /**
  212 + * Creates an unbound datagram socket.
  213 + * This can be used as a client or later bound as a server socket.
  214 + */
  215 + datagram_socket_tmpl() : base(create_handle(ADDRESS_FAMILY)) {}
  216 + /**
  217 + * Creates a datagram socket from an existing OS socket handle and
  218 + * claims ownership of the handle.
  219 + * @param handle A socket handle from the operating system.
  220 + */
  221 + datagram_socket_tmpl(socket_t handle) : base(handle) {}
  222 + /**
  223 + * Creates a datagram socket and binds it to the address.
  224 + * @param addr The address to bind.
  225 + */
  226 + datagram_socket_tmpl(const ADDR& addr) : base(addr) {}
  227 + /**
  228 + * Move constructor.
  229 + * @param other The other socket to move to this one
  230 + */
  231 + datagram_socket_tmpl(datagram_socket_tmpl&& other)
  232 + : base(std::move(other)) {}
  233 + /**
  234 + * Move assignment.
  235 + * @param rhs The other socket to move into this one.
  236 + * @return A reference to this object.
  237 + */
  238 + datagram_socket_tmpl& operator=(datagram_socket_tmpl&& rhs) {
  239 + base::operator=(std::move(rhs));
  240 + return *this;
  241 + }
  242 +
  243 + /**
  244 + * Creates a pair of connected stream sockets.
  245 + *
  246 + * Whether this will work at all is highly system and domain dependent.
  247 + * Currently it is only known to work for Unix-domain sockets on *nix
  248 + * systems.
  249 + *
  250 + * @param protocol The protocol to be used with the socket. (Normally 0)
  251 + *
  252 + * @return A std::tuple of stream sockets. On error both sockets will be
  253 + * in an error state with the last error set.
  254 + */
  255 + static std::tuple<datagram_socket_tmpl, datagram_socket_tmpl> pair(int protocol=0) {
  256 + auto pr = base::pair(addr_t::ADDRESS_FAMILY, COMM_TYPE, protocol);
  257 + return std::make_tuple<datagram_socket_tmpl, datagram_socket_tmpl>(
  258 + datagram_socket_tmpl{std::get<0>(pr).release()},
  259 + datagram_socket_tmpl{std::get<1>(pr).release()});
  260 + }
  261 + /**
  262 + * Binds the socket to the local address.
  263 + * Datagram sockets can bind to a local address/adapter to filter which
  264 + * incoming packets to receive.
  265 + * @param addr The address on which to bind.
  266 + * @return @em true on success, @em false on failure
  267 + */
  268 + bool bind(const ADDR& addr) { return base::bind(addr); }
  269 + /**
  270 + * Connects the socket to the remote address.
  271 + * In the case of datagram sockets, this does not create an actual
  272 + * connection, but rather specifies the address to which datagrams are
  273 + * sent by default and the only address from which packets are
  274 + * received.
  275 + * @param addr The address on which to "connect".
  276 + * @return @em true on success, @em false on failure
  277 + */
  278 + bool connect(const ADDR& addr) { return base::connect(addr); }
  279 +
  280 + // ----- I/O -----
  281 +
  282 + /**
  283 + * Sends a message to the socket at the specified address.
  284 + * @param buf The data to send.
  285 + * @param n The number of bytes in the data buffer.
  286 + * @param flags The option bit flags. See send(2).
  287 + * @param addr The remote destination of the data.
  288 + * @return the number of bytes sent on success or, @em -1 on failure.
  289 + */
  290 + ssize_t send_to(const void* buf, size_t n, int flags, const ADDR& addr) {
  291 + return base::send_to(buf, n, flags, addr);
  292 + }
  293 + /**
  294 + * Sends a string to the socket at the specified address.
  295 + * @param s The string to send.
  296 + * @param flags The flags. See send(2).
  297 + * @param addr The remote destination of the data.
  298 + * @return the number of bytes sent on success or, @em -1 on failure.
  299 + */
  300 + ssize_t send_to(const std::string& s, int flags, const ADDR& addr) {
  301 + return base::send_to(s, flags, addr);
  302 + }
  303 + /**
  304 + * Sends a message to another socket.
  305 + * @param buf The data to send.
  306 + * @param n The number of bytes in the data buffer.
  307 + * @param addr The remote destination of the data.
  308 + * @return the number of bytes sent on success or, @em -1 on failure.
  309 + */
  310 + ssize_t send_to(const void* buf, size_t n, const ADDR& addr) {
  311 + return base::send_to(buf, n, 0, addr);
  312 + }
  313 + /**
  314 + * Sends a string to another socket.
  315 + * @param s The string to send.
  316 + * @param addr The remote destination of the data.
  317 + * @return the number of bytes sent on success or, @em -1 on failure.
  318 + */
  319 + ssize_t send_to(const std::string& s, const ADDR& addr) {
  320 + return base::send_to(s, addr);
  321 + }
  322 + /**
  323 + * Receives a message on the socket.
  324 + * @param buf Buffer to get the incoming data.
  325 + * @param n The number of bytes to read.
  326 + * @param flags The option bit flags. See send(2).
  327 + * @param srcAddr Receives the address of the peer that sent
  328 + * the message
  329 + * @return The number of bytes read or @em -1 on error.
  330 + */
  331 + ssize_t recv_from(void* buf, size_t n, int flags, ADDR* srcAddr) {
  332 + return base::recv_from(buf, n, flags, srcAddr);
  333 + }
  334 + /**
  335 + * Receives a message on the socket.
  336 + * @param buf Buffer to get the incoming data.
  337 + * @param n The number of bytes to read.
  338 + * @param srcAddr Receives the address of the peer that sent
  339 + * the message
  340 + * @return The number of bytes read or @em -1 on error.
  341 + */
  342 + ssize_t recv_from(void* buf, size_t n, ADDR* srcAddr=nullptr) {
  343 + return base::recv_from(buf, n, srcAddr);
  344 + }
  345 +};
  346 +
  347 +} // End namespace socket-cpp
  348 +} // End namespace components
  349 +} // End namespace osdev
  350 +
include/socket-cpp/exception.h 0 โ†’ 100644
  1 +++ a/include/socket-cpp/exception.h
  1 +#pragma once
  2 +
  3 +#include <cerrno>
  4 +#include <stdexcept>
  5 +#include <string>
  6 +
  7 +namespace osdev {
  8 +namespace components {
  9 +namespace socket-cpp {
  10 +
  11 +/**
  12 + * System error.
  13 + * These are errors that are resulted from system socket calls. The error
  14 + * codes are platform 'errno' values (or similar), and the messages are
  15 + * typically derived from the system.
  16 + */
  17 +class sys_error : public std::runtime_error
  18 +{
  19 + /** The system error number (errno) */
  20 + int errno_;
  21 +
  22 +public:
  23 + /**
  24 + * Creates an error using the current system 'errno' value.
  25 + */
  26 + sys_error() : sys_error(errno) {}
  27 + /**
  28 + * Constructs an error with the specified system errno.
  29 + * @param err The error number. This is the system errno value.
  30 + */
  31 + explicit sys_error(int err);
  32 + /**
  33 + * Get the error number.
  34 + * @return The system error number.
  35 + */
  36 + int error() const { return errno_; }
  37 + /**
  38 + * Gets a string describing the specified error.
  39 + * This is typically the returned message from the system strerror().
  40 + * @param err The system error number.
  41 + * @return A string describing the specified error.
  42 + */
  43 + static std::string error_str(int err);
  44 +};
  45 +
  46 +/**
  47 + * Errors from getaddrinfo.
  48 + * These are errors relating to DNS lookup, returned from the getaddrinfo system call.
  49 + * Their codes are declared in <netdb.h>.
  50 + */
  51 +class getaddrinfo_error : public std::runtime_error
  52 +{
  53 + /** The error number, as returned by getaddrinfo. */
  54 + int error_;
  55 + /** The hostname being resolved. */
  56 + std::string hostname_;
  57 +
  58 +public:
  59 + /**
  60 + * Constructs an error with the specified getaddrinfo error code.
  61 + * @param err The error number, as returned by getaddrinfo.
  62 + * @param hostname The DNS name being resolved that triggered the error.
  63 + */
  64 + getaddrinfo_error(int err, const std::string &hostname);
  65 + /**
  66 + * Get the error number.
  67 + * @return The error number returned by getaddrinfo.
  68 + */
  69 + int error() const { return error_; }
  70 + /**
  71 + * Get the hostname that triggered the error.
  72 + * @return The hostname that getaddrinfo failed to resolve.
  73 + */
  74 + const std::string &hostname() const { return hostname_; }
  75 +};
  76 +
  77 +} // End namespace socket-cpp
  78 +} // End namespace components
  79 +} // End namespace osdev
  80 +
include/socket-cpp/inet6_address.h 0 โ†’ 100644
  1 +++ a/include/socket-cpp/inet6_address.h
  1 +#pragma once
  2 +
  3 +#include "socket-cpp/platform.h"
  4 +#include "socket-cpp/sock_address.h"
  5 +#include <iostream>
  6 +#include <string>
  7 +#include <cstring>
  8 +
  9 +namespace osdev {
  10 +namespace components {
  11 +namespace socket-cpp {
  12 +
  13 +/**
  14 + * Class that represents an internet (IPv6) address. This inherits from the
  15 + * IP-specific form of a socket address, @em sockaddr_in.
  16 + */
  17 +class inet6_address : public sock_address
  18 +{
  19 + /** The underlying C IPv6 struct */
  20 + sockaddr_in6 addr_;
  21 +
  22 + /** The size of the underlying address struct, in bytes */
  23 + static constexpr size_t SZ = sizeof(sockaddr_in6);
  24 +
  25 +public:
  26 + /** The address family for this type of address */
  27 + static constexpr sa_family_t ADDRESS_FAMILY = AF_INET6;
  28 +
  29 + /**
  30 + * Constructs an empty address.
  31 + * The address is initialized to all zeroes.
  32 + */
  33 + inet6_address() : addr_() {}
  34 + /**
  35 + * Constructs an address for any iface using the specified port.
  36 + * This is a convenient way for a server to specify an address that will
  37 + * bind to all interfaces.
  38 + * @param port The port number in native/host byte order.
  39 + */
  40 + explicit inet6_address(in_port_t port) {
  41 + const in6_addr ANY IN6ADDR_ANY_INIT;
  42 + create(ANY, port);
  43 + }
  44 + /**
  45 + * Constructs an address using the name of the host and the specified
  46 + * port. This attempts to resolve the host name to an address.
  47 + *
  48 + * @param saddr The name of the host.
  49 + * @param port The port number in native/host byte order.
  50 + */
  51 + inet6_address(const std::string& saddr, in_port_t port) {
  52 + create(saddr, port);
  53 + }
  54 + /**
  55 + * Constructs the address by copying the specified structure.
  56 + * TODO: Do we actually need a conversion from something that's
  57 + * cast to a sockaddr, but is really a sockaddr_in6?
  58 + * @param addr The other address
  59 + */
  60 + inet6_address(const sockaddr_storage& addr) {
  61 + std::memcpy(&addr_, &addr, SZ);
  62 + }
  63 + /**
  64 + * Constructs the address by copying the specified structure.
  65 + * @param addr The other address
  66 + */
  67 + inet6_address(const sock_address& addr) {
  68 + std::memcpy(&addr_, addr.sockaddr_ptr(), SZ);
  69 + }
  70 + /**
  71 + * Constructs the address by copying the specified structure.
  72 + * @param addr The other address
  73 + */
  74 + inet6_address(const sockaddr_in6& addr) {
  75 + std::memcpy(&addr_, &addr, SZ);
  76 + }
  77 + /**
  78 + * Constructs the address by copying the specified address.
  79 + * @param addr The other address
  80 + */
  81 + inet6_address(const inet6_address& addr) : addr_(addr.addr_) {}
  82 + /**
  83 + * Creates an address on the loopback (localhost) interface.
  84 + * @param port The port number (in native/host byte order).
  85 + * @return The full address on the loopback interface.
  86 + */
  87 + static inet6_address loopback(in_port_t port) {
  88 + const in6_addr LOOPBACK IN6ADDR_LOOPBACK_INIT;
  89 + inet6_address addr;
  90 + addr.create(LOOPBACK, port);
  91 + return addr;
  92 + }
  93 + /**
  94 + * Checks if the address is set to some value.
  95 + * This doesn't attempt to determine if the address is valid, simply
  96 + * that it's not all zero.
  97 + * @return bool
  98 + */
  99 + bool is_set() const;
  100 + /**
  101 + * Attempts to resolve the host name into a 32-bit internet address.
  102 + * @param saddr The string host name.
  103 + * @return The internet address in network byte order.
  104 + */
  105 + static in6_addr resolve_name(const std::string& saddr);
  106 + /**
  107 + * Creates the socket address using the specified host address and port
  108 + * number.
  109 + * @param addr The host address (16-byte IPv6 address).
  110 + * @param port The host port number.
  111 + */
  112 + void create(const in6_addr& addr, in_port_t port);
  113 + /**
  114 + * Creates the socket address using the specified host name and port
  115 + * number.
  116 + * @param saddr The string host name.
  117 + * @param port The port number in native/host byte order.
  118 + */
  119 + void create(const std::string& saddr, in_port_t port);
  120 + /**
  121 + * Gets 128-bit IPv6 address.
  122 + * The address is usually stored in network byte order.
  123 + * @return The IPv6 address.
  124 + */
  125 + in6_addr address() const { return addr_.sin6_addr; }
  126 + /**
  127 + * Gets a byte of the 128-bit IPv6 Address.
  128 + * Note that the address is normally stored in network byte
  129 + * order.
  130 + * @param i The byte to read (0-7)
  131 +{
  132 + return addr_ != sockaddr_in6{};
  133 + * @return The specified byte in the 128-bit IPv6 Address
  134 + */
  135 + uint8_t operator[](int i) const {
  136 + return addr_.sin6_addr.s6_addr[i];
  137 + }
  138 + /**
  139 + * Gets the port number.
  140 + * @return The port number in native/host byte order.
  141 + */
  142 + in_port_t port() const { return ntohs(addr_.sin6_port); }
  143 + /**
  144 + * Gets the size of this structure.
  145 + * This is equivalent to sizeof(this) but more convenient in some
  146 + * places.
  147 + * @return The size of this structure.
  148 + */
  149 + socklen_t size() const override { return socklen_t(SZ); }
  150 + /**
  151 + * Gets a pointer to this object cast to a @em sockaddr.
  152 + * @return A pointer to this object cast to a @em sockaddr.
  153 + */
  154 + const sockaddr* sockaddr_ptr() const override {
  155 + return reinterpret_cast<const sockaddr*>(&addr_);
  156 + }
  157 + /**
  158 + * Gets a pointer to this object cast to a @em sockaddr.
  159 + * @return A pointer to this object cast to a @em sockaddr.
  160 + */
  161 + sockaddr* sockaddr_ptr() override {
  162 + return reinterpret_cast<sockaddr*>(&addr_);
  163 + }
  164 + /**
  165 + * Gets a const pointer to this object cast to a @em
  166 + * sockaddr_in6.
  167 + * @return const sockaddr_in6 pointer to this object.
  168 + */
  169 + const sockaddr_in6* sockaddr_in6_ptr() const { return &addr_; }
  170 + /**
  171 + * Gets a pointer to this object cast to a @em sockaddr_in6.
  172 + * @return sockaddr_in6 pointer to this object.
  173 + */
  174 + sockaddr_in6* sockaddr_in6_ptr() { return &addr_; }
  175 + /**
  176 + * Gets a printable string for the address.
  177 + * This gets the address in the printable form "[addr]:port"
  178 + * using inet_ntop(). It does not attempt to find the host name
  179 + * using a lookup.
  180 + * @return A string representation of the address in the form
  181 + * '[address]:port'
  182 + */
  183 + std::string to_string() const;
  184 +};
  185 +
  186 +// --------------------------------------------------------------------------
  187 +
  188 +/**
  189 + * Stream inserter for the address.
  190 + * This uses the simple dot notation of the address as returned from
  191 + * inet_ntop(). It does not attempt a host lookup.
  192 + * @param os The output stream
  193 + * @param addr The address
  194 + * @return A reference to the output stream.
  195 + */
  196 +std::ostream& operator<<(std::ostream& os, const inet6_address& addr);
  197 +
  198 +} // End namespace socket-cpp
  199 +} // End namespace components
  200 +} // End namespace osdev
include/socket-cpp/inet_address.h 0 โ†’ 100644
  1 +++ a/include/socket-cpp/inet_address.h
  1 +#pragma once
  2 +
  3 +#include "socket-cpp/sock_address.h"
  4 +#include <iostream>
  5 +#include <string>
  6 +#include <cstring>
  7 +#include <algorithm>
  8 +
  9 +namespace osdev {
  10 +namespace components {
  11 +namespace socket-cpp {
  12 +
  13 +/**
  14 + * Class that represents an internet (IPv4) address.
  15 + * This inherits from the IP-specific form of a socket address,
  16 + * @em sockaddr_in.
  17 + */
  18 +class inet_address : public sock_address
  19 +{
  20 + /** The underlying C struct for IPv4 addresses */
  21 + sockaddr_in addr_;
  22 +
  23 + /** The size of the underlying address struct, in bytes */
  24 + static constexpr size_t SZ = sizeof(sockaddr_in);
  25 +
  26 +public:
  27 + /** The address family for this type of address */
  28 + static constexpr sa_family_t ADDRESS_FAMILY = AF_INET;
  29 +
  30 + /**
  31 + * Constructs an empty address.
  32 + * The address is initialized to all zeroes.
  33 + */
  34 + inet_address() : addr_() {}
  35 + /**
  36 + * Constructs an address for any iface using the specified port.
  37 + * This is a convenient way for a server to specify an address that will
  38 + * bind to all interfaces.
  39 + * @param port The port number in native/host byte order.
  40 + */
  41 + explicit inet_address(in_port_t port) {
  42 + create(in_addr_t(INADDR_ANY), port);
  43 + }
  44 + /**
  45 + * Constructs an address for the specified host using the specified
  46 + * port.
  47 + * @param addr The 32-bit host address in native/host byte order.
  48 + * @param port The port number in native/host byte order.
  49 + */
  50 + inet_address(uint32_t addr, in_port_t port) { create(addr, port); }
  51 + /**
  52 + * Constructs an address using the name of the host and the specified
  53 + * port. This attempts to resolve the host name to an address.
  54 + *
  55 + * @param saddr The name of the host.
  56 + * @param port The port number in native/host byte order.
  57 + */
  58 + inet_address(const std::string& saddr, in_port_t port) {
  59 + create(saddr, port);
  60 + }
  61 + /**
  62 + * Constructs the address by copying the specified structure.
  63 + * @param addr The other address
  64 + */
  65 + inet_address(const sockaddr& addr) {
  66 + std::memcpy(&addr_, &addr, SZ);
  67 + }
  68 + /**
  69 + * Constructs the address by copying the specified structure.
  70 + * @param addr The other address
  71 + */
  72 + inet_address(const sock_address& addr) {
  73 + std::memcpy(&addr_, addr.sockaddr_ptr(), SZ);
  74 + }
  75 + /**
  76 + * Constructs the address by copying the specified structure.
  77 + * @param addr The other address
  78 + */
  79 + inet_address(const sockaddr_in& addr) : addr_(addr) {}
  80 + /**
  81 + * Constructs the address by copying the specified address.
  82 + * @param addr The other address
  83 + */
  84 + inet_address(const inet_address& addr) : addr_(addr.addr_) {}
  85 + /**
  86 + * Checks if the address is set to some value.
  87 + * This doesn't attempt to determine if the address is valid, simply
  88 + * that it's not all zero.
  89 + * @return bool
  90 + */
  91 + bool is_set() const;
  92 + /**
  93 + * Attempts to resolve the host name into a 32-bit internet address.
  94 + * @param saddr The string host name.
  95 + * @return The internet address in network byte order.
  96 + * @throw sys_error, getaddrinfo_error
  97 + */
  98 + static in_addr_t resolve_name(const std::string& saddr);
  99 + /**
  100 + * Creates the socket address using the specified host address and port
  101 + * number.
  102 + * @param addr The host address.
  103 + * @param port The host port number.
  104 + */
  105 + void create(in_addr_t addr, in_port_t port);
  106 + /**
  107 + * Creates the socket address using the specified host name and port
  108 + * number.
  109 + * @param saddr The string host name.
  110 + * @param port The port number in native/host byte order.
  111 + * @throw sys_error, getaddrinfo_error
  112 + */
  113 + void create(const std::string& saddr, in_port_t port);
  114 + /**
  115 + * Gets the 32-bit internet address.
  116 + * @return The internet address in the local host's byte order.
  117 + */
  118 + in_addr_t address() const { return ntohl(addr_.sin_addr.s_addr); }
  119 + /**
  120 + * Gets a byte of the 32-bit Internet Address
  121 + * @param i The byte to read (0-3)
  122 + * @return The specified byte in the 32-bit Internet Address
  123 + */
  124 + uint8_t operator[](int i) const {
  125 + in_addr_t addr = address();
  126 + return ((const uint8_t*)&addr)[i];
  127 + }
  128 + /**
  129 + * Gets the port number.
  130 + * @return The port number in native/host byte order.
  131 + */
  132 + in_port_t port() const { return ntohs(addr_.sin_port); }
  133 + /**
  134 + * Gets the size of this structure.
  135 + * This is equivalent to sizeof(this) but more convenient in some
  136 + * places.
  137 + * @return The size of this structure.
  138 + */
  139 + socklen_t size() const override { return socklen_t(SZ); }
  140 + /**
  141 + * Gets a pointer to this object cast to a @em sockaddr.
  142 + * @return A pointer to this object cast to a @em sockaddr.
  143 + */
  144 + const sockaddr* sockaddr_ptr() const override {
  145 + return reinterpret_cast<const sockaddr*>(&addr_);
  146 + }
  147 + /**
  148 + * Gets a pointer to this object cast to a @em sockaddr.
  149 + * @return A pointer to this object cast to a @em sockaddr.
  150 + */
  151 + sockaddr* sockaddr_ptr() override {
  152 + return reinterpret_cast<sockaddr*>(&addr_);
  153 + }
  154 + /**
  155 + * Gets a const pointer to this object cast to a @em sockaddr_in.
  156 + * @return const sockaddr_in pointer to this object.
  157 + */
  158 + const sockaddr_in* sockaddr_in_ptr() const {
  159 + return static_cast<const sockaddr_in*>(&addr_);
  160 + }
  161 + /**
  162 + * Gets a pointer to this object cast to a @em sockaddr_in.
  163 + * @return sockaddr_in pointer to this object.
  164 + */
  165 + sockaddr_in* sockaddr_in_ptr() {
  166 + return static_cast<sockaddr_in*>(&addr_);
  167 + }
  168 + /**
  169 + * Gets a printable string for the address.
  170 + * This gets the simple dot notation of the address as returned from
  171 + * inet_ntop(). It does not attempt a host lookup.
  172 + * @return A string representation of the address in the form
  173 + * 'address:port'
  174 + */
  175 + std::string to_string() const;
  176 +};
  177 +
  178 +// --------------------------------------------------------------------------
  179 +
  180 +/**
  181 + * Stream inserter for the address.
  182 + * This uses the simple dot notation of the address as returned from
  183 + * inet_ntop(). It does not attempt a host lookup.
  184 + * @param os The output stream
  185 + * @param addr The address
  186 + * @return A reference to the output stream.
  187 + */
  188 +std::ostream& operator<<(std::ostream& os, const inet_address& addr);
  189 +
  190 +} // End namespace socket-cpp
  191 +} // End namespace components
  192 +} // End namespace osdev
include/socket-cpp/platform.h 0 โ†’ 100644
  1 +++ a/include/socket-cpp/platform.h
  1 +#pragma once
  2 +
  3 +namespace osdev {
  4 +namespace components {
  5 +namespace socket-cpp {
  6 +
  7 +#include <cstdint>
  8 +
  9 +#if defined(_WIN32)
  10 + //#pragma warning(4 : 4996) // Deprecated functions (CRT & all)
  11 + //#pragma warning(4 : 4250) // Inheritance via dominance
  12 +
  13 + #if !defined(WIN32_LEAN_AND_MEAN)
  14 + #define WIN32_LEAN_AND_MEAN
  15 + #endif
  16 +
  17 + #if !defined(_CRT_SECURE_NO_DEPRECATE)
  18 + #define _CRT_SECURE_NO_DEPRECATE
  19 + #endif
  20 +
  21 + //#include <cstddef>
  22 + //#include <windows.h>
  23 + #include <winsock2.h>
  24 + #include <ws2tcpip.h>
  25 +
  26 + #define SOCKPP_SOCKET_T_DEFINED
  27 + using socket_t = SOCKET;
  28 +
  29 + using socklen_t = int;
  30 + using in_port_t = uint16_t;
  31 + using in_addr_t = uint32_t;
  32 +
  33 + using sa_family_t = u_short;
  34 +
  35 + #ifndef _SSIZE_T_DEFINED
  36 + #define _SSIZE_T_DEFINED
  37 + #undef ssize_t
  38 + using ssize_t = SSIZE_T;
  39 + #endif // _SSIZE_T_DEFINED
  40 +
  41 + #ifndef _SUSECONDS_T
  42 + #define _SUSECONDS_T
  43 + typedef long suseconds_t; // signed # of microseconds in timeval
  44 + #endif // _SUSECONDS_T
  45 +
  46 + #define SHUT_RD SD_RECEIVE
  47 + #define SHUT_WR SD_SEND
  48 + #define SHUT_RDWR SD_BOTH
  49 +
  50 + struct iovec
  51 + {
  52 + void* iov_base;
  53 + size_t iov_len;
  54 + };
  55 +
  56 +#else
  57 + #include <unistd.h>
  58 + #include <sys/socket.h>
  59 + #include <sys/uio.h>
  60 + #include <arpa/inet.h>
  61 + #ifdef __FreeBSD__
  62 + #include <netinet/in.h>
  63 + #endif
  64 + #include <netdb.h>
  65 + #include <signal.h>
  66 + #include <cerrno>
  67 +#endif
  68 +
  69 +} // End namespace socket-cpp
  70 +} // End namespace components
  71 +} // End namespace osdev
  72 +
include/socket-cpp/sock_address.h 0 โ†’ 100644
  1 +++ a/include/socket-cpp/sock_address.h
  1 +#pragma once
  2 +
  3 +#include "socket-cpp/platform.h"
  4 +#include <cstring>
  5 +#include <stdexcept>
  6 +
  7 +namespace osdev {
  8 +namespace components {
  9 +namespace socket-cpp {
  10 +
  11 +/**
  12 + * Generic socket address.
  13 + * Abstract base class for socket addresses. The underlying C socket
  14 + * functions typically take or return an address as a `sockaddr` pointer and
  15 + * length. So derived classes that wrap the
  16 + */
  17 +class sock_address
  18 +{
  19 +public:
  20 + /**
  21 + * Virtual destructor.
  22 + */
  23 + virtual ~sock_address() {}
  24 + /**
  25 + * Gets the size of this structure.
  26 + * This is equivalent to sizeof(this) but more convenient in some
  27 + * places.
  28 + * @return The size of this structure.
  29 + */
  30 + virtual socklen_t size() const =0;
  31 + /**
  32 + * Gets a pointer to this object cast to a @em sockaddr.
  33 + * @return A pointer to this object cast to a @em sockaddr.
  34 + */
  35 + virtual sockaddr* sockaddr_ptr() =0;
  36 + /**
  37 + * Gets a pointer to this object cast to a @em sockaddr.
  38 + * @return A pointer to this object cast to a @em sockaddr.
  39 + */
  40 + virtual const sockaddr* sockaddr_ptr() const =0;
  41 + /**
  42 + * Gets the network family of the address.
  43 + * @return The network family of the address (AF_INET, etc). If the
  44 + * address is not known, returns AF_UNSPEC.
  45 + */
  46 + virtual sa_family_t family() const {
  47 + auto p = sockaddr_ptr();
  48 + return p ? p->sa_family : AF_UNSPEC;
  49 + }
  50 +};
  51 +
  52 +/**
  53 + * Generic socket address.
  54 + *
  55 + * This is a wrapper around `sockaddr_storage` which can hold any family
  56 + * address. This should have enough memory to contain any address struct for
  57 + * the system on which it is compiled.
  58 + */
  59 +class sock_address_any : public sock_address
  60 +{
  61 + /** Storage for any kind of socket address */
  62 + sockaddr_storage addr_;
  63 + /** Length of the address (in bytes) */
  64 + socklen_t sz_;
  65 +
  66 + /** The maximum size of an address, in bytes */
  67 + static constexpr size_t MAX_SZ = sizeof(sockaddr_storage);
  68 +
  69 +public:
  70 + /**
  71 + * Constructs an empty address.
  72 + * The address is initialized to all zeroes.
  73 + */
  74 + sock_address_any() : addr_{}, sz_{MAX_SZ} {}
  75 + /**
  76 + * Constructs an address.
  77 + * @param addr Pointer to a buffer holding the address.
  78 + * @param n The number of valid bytes in the address
  79 + * @throws std::length_error if `n` is greater than the maximum size of
  80 + * an address.
  81 + */
  82 + sock_address_any(const sockaddr* addr, socklen_t n) {
  83 + if (n > MAX_SZ)
  84 + throw std::length_error("Address length out of range");
  85 + std::memcpy(&addr_, addr, sz_ = n);
  86 + }
  87 + /**
  88 + * Constructs an address.
  89 + * @param addr The buffer holding the address.
  90 + * @param n The number of valid bytes in the address
  91 + * @throws std::length_error if `n` is greater than the maximum size of
  92 + * an address.
  93 + */
  94 + sock_address_any(const sockaddr_storage& addr, socklen_t n) {
  95 + if (n > MAX_SZ)
  96 + throw std::length_error("Address length out of range");
  97 + std::memcpy(&addr_, &addr, sz_ = n);
  98 + }
  99 + /**
  100 + * Copies another address to this one.
  101 + * @param addr The other address to copy into this one.
  102 + */
  103 + sock_address_any(const sock_address& addr)
  104 + : sock_address_any(addr.sockaddr_ptr(), addr.size()) {}
  105 + /**
  106 + * Gets the size of the address.
  107 + * @return The size of the address. This is the number of bytes that are a
  108 + * valid part of the address.
  109 + */
  110 + socklen_t size() const override { return sz_; }
  111 + /**
  112 + * Gets a pointer to this object cast to a @em sockaddr.
  113 + * @return A pointer to this object cast to a @em sockaddr.
  114 + */
  115 + const sockaddr* sockaddr_ptr() const override {
  116 + return reinterpret_cast<const sockaddr*>(&addr_);
  117 + }
  118 + /**
  119 + * Gets a pointer to this object cast to a @em sockaddr.
  120 + * @return A pointer to this object cast to a @em sockaddr.
  121 + */
  122 + sockaddr* sockaddr_ptr() override {
  123 + return reinterpret_cast<sockaddr*>(&addr_);
  124 + }
  125 +};
  126 +
  127 +/**
  128 + * Determines if the two objects refer to the same address.
  129 + * @param lhs A socket address
  130 + * @param rhs A socket address
  131 + * @return @em true if `lhs` and `rhs` refer to the same address, @em false
  132 + * otherwise.
  133 + */
  134 +inline bool operator==(const sock_address& lhs, const sock_address& rhs) {
  135 + return lhs.size() == rhs.size() &&
  136 + std::memcmp(lhs.sockaddr_ptr(), rhs.sockaddr_ptr(), lhs.size()) == 0;
  137 +}
  138 +
  139 +/**
  140 + * Determines if the two objects refer to the different address.
  141 + * @param lhs A socket address
  142 + * @param rhs A socket address
  143 + * @return @em true if `lhs` and `rhs` refer to different address, @em false
  144 + * if they refer to the same address.
  145 + */
  146 +inline bool operator!=(const sock_address& lhs, const sock_address& rhs) {
  147 + return !operator==(lhs, rhs);
  148 +}
  149 +
  150 +} // End namespace socket-cpp
  151 +} // End namespace components
  152 +} // End namespace osdev
  153 +
include/socket-cpp/socket.h 0 โ†’ 100644
  1 +++ a/include/socket-cpp/socket.h
  1 +/**
  2 + * @file socket.h
  3 + *
  4 + * Classes for TCP & UDP socket.
  5 + *
  6 + * @author Frank Pagliughi
  7 + * @author SoRo Systems, Inc.
  8 + * @author www.sorosys.com
  9 + *
  10 + * @date December 2014
  11 + */
  12 +
  13 +// --------------------------------------------------------------------------
  14 +// This file is part of the "sockpp" C++ socket library.
  15 +//
  16 +// Copyright (c) 2014-2019 Frank Pagliughi
  17 +// All rights reserved.
  18 +//
  19 +// Redistribution and use in source and binary forms, with or without
  20 +// modification, are permitted provided that the following conditions are
  21 +// met:
  22 +//
  23 +// 1. Redistributions of source code must retain the above copyright notice,
  24 +// this list of conditions and the following disclaimer.
  25 +//
  26 +// 2. Redistributions in binary form must reproduce the above copyright
  27 +// notice, this list of conditions and the following disclaimer in the
  28 +// documentation and/or other materials provided with the distribution.
  29 +//
  30 +// 3. Neither the name of the copyright holder nor the names of its
  31 +// contributors may be used to endorse or promote products derived from this
  32 +// software without specific prior written permission.
  33 +//
  34 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  35 +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  36 +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  37 +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  38 +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  39 +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  40 +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  41 +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  42 +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  43 +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  44 +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  45 +// --------------------------------------------------------------------------
  46 +
  47 +#ifndef __sockpp_socket_h
  48 +#define __sockpp_socket_h
  49 +
  50 +#include "sockpp/sock_address.h"
  51 +#include <chrono>
  52 +#include <string>
  53 +#include <tuple>
  54 +
  55 +namespace sockpp {
  56 +
  57 +/////////////////////////////////////////////////////////////////////////////
  58 +
  59 +#if !defined(SOCKPP_SOCKET_T_DEFINED)
  60 + typedef int socket_t; ///< The OS socket handle
  61 + const socket_t INVALID_SOCKET = -1; ///< Invalid socket descriptor
  62 + #define SOCKPP_SOCKET_T_DEFINED
  63 +#endif
  64 +
  65 +/**
  66 + * Converts a number of microseconds to a relative timeval.
  67 + * @param dur A chrono duration of microseconds.
  68 + * @return A timeval
  69 + */
  70 +timeval to_timeval(const std::chrono::microseconds& dur);
  71 +
  72 +/**
  73 + * Converts a chrono duration to a relative timeval.
  74 + * @param dur A chrono duration.
  75 + * @return A timeval.
  76 + */
  77 +template<class Rep, class Period>
  78 +timeval to_timeval(const std::chrono::duration<Rep,Period>& dur) {
  79 + return to_timeval(std::chrono::duration_cast<std::chrono::microseconds>(dur));
  80 +}
  81 +
  82 +/**
  83 + * Converts a relative timeval to a chrono duration.
  84 + * @param tv A timeval.
  85 + * @return A chrono duration.
  86 + */
  87 +inline std::chrono::microseconds to_duration(const timeval& tv)
  88 +{
  89 + auto dur = std::chrono::seconds{tv.tv_sec}
  90 + + std::chrono::microseconds{tv.tv_usec};
  91 + return std::chrono::duration_cast<std::chrono::microseconds>(dur);
  92 +}
  93 +
  94 +/**
  95 + * Converts an absolute timeval to a chrono time_point.
  96 + * @param tv A timeval.
  97 + * @return A chrono time_point.
  98 + */
  99 +inline std::chrono::system_clock::time_point to_timepoint(const timeval& tv)
  100 +{
  101 + return std::chrono::system_clock::time_point {
  102 + std::chrono::duration_cast<std::chrono::system_clock::duration>(to_duration(tv))
  103 + };
  104 +}
  105 +
  106 +/////////////////////////////////////////////////////////////////////////////
  107 +
  108 +/**
  109 + * Base class for socket objects.
  110 + *
  111 + * This class wraps an OS socket handle and maintains strict ownership
  112 + * semantics. If a socket object has a valid, open socket, then it owns the
  113 + * handle and will close it when the object is destroyed.
  114 + *
  115 + * Objects of this class are not copyable, but they are moveable.
  116 + */
  117 +class socket
  118 +{
  119 + /** The OS integer socket handle */
  120 + socket_t handle_;
  121 + /** Cache of the last error (errno) */
  122 + mutable int lastErr_;
  123 + /**
  124 + * The OS-specific function to close a socket handle/
  125 + * @param h The OS socket handle.
  126 + * @return @em true if the sock is closed, @em false on error.
  127 + */
  128 + bool close(socket_t h);
  129 +
  130 + // Non-copyable.
  131 + socket(const socket&) =delete;
  132 + socket& operator=(const socket&) =delete;
  133 +
  134 +protected:
  135 + /**
  136 + * Closes the socket without checking for errors or updating the last
  137 + * error.
  138 + * This is used in internal open/connect type functions that fail after
  139 + * creating the socket, but want to preserve the previous failure
  140 + * condition.
  141 + * Assumes that the socket handle is valid.
  142 + * @return Always returns @em false.
  143 + */
  144 + bool close_on_err() {
  145 + close(release());
  146 + return false;
  147 + }
  148 + /**
  149 + * OS-specific means to retrieve the last error from an operation.
  150 + * This should be called after a failed system call to set the
  151 + * lastErr_ member variable. Normally this would be called from
  152 + * @ref check_ret.
  153 + */
  154 + static int get_last_error();
  155 + /**
  156 + * Cache the last system error code into this object.
  157 + * This should be called after a failed system call to store the error
  158 + * value.
  159 + */
  160 + void set_last_error() {
  161 + lastErr_ = get_last_error();
  162 + }
  163 + /**
  164 + * Checks the value and if less than zero, sets last error.
  165 + * @tparam T A signed integer type of any size
  166 + * @param ret The return value from a library or system call.
  167 + * @return Returns the value sent to it, `ret`.
  168 + */
  169 + template <typename T>
  170 + T check_ret(T ret) const{
  171 + lastErr_ = (ret < 0) ? get_last_error() : 0;
  172 + return ret;
  173 + }
  174 + /**
  175 + * Checks the value and if less than zero, sets last error.
  176 + * @tparam T A signed integer type of any size
  177 + * @param ret The return value from a library or system call.
  178 + * @return @em true if the value is a typical system success value (>=0)
  179 + * or @em false is is an error (<0)
  180 + */
  181 + template <typename T>
  182 + bool check_ret_bool(T ret) const{
  183 + lastErr_ = (ret < 0) ? get_last_error() : 0;
  184 + return ret >= 0;
  185 + }
  186 + /**
  187 + * Checks the value and if it is not a valid socket, sets last error.
  188 + * This is specifically required for Windows which uses an unsigned type
  189 + * for its SOCKET.
  190 + * @param ret The return value from a library or system call that returns
  191 + * a socket, such as socket() or accept().
  192 + * @return Returns the value sent to it, `ret`.
  193 + */
  194 + socket_t check_socket(socket_t ret) const {
  195 + lastErr_ = (ret == INVALID_SOCKET) ? get_last_error() : 0;
  196 + return ret;
  197 + }
  198 + /**
  199 + * Checks the value and if it is INVALID_SOCKET, sets last error.
  200 + * This is specifically required for Windows which uses an unsigned type
  201 + * for its SOCKET.
  202 + * @param ret The return value from a library or system call that returns
  203 + * a socket such as socket() or accept().
  204 + * @return @em true if the value is a valid socket (not INVALID_SOCKET)
  205 + * or @em false is is an error (INVALID_SOCKET)
  206 + */
  207 + bool check_socket_bool(socket_t ret) const{
  208 + lastErr_ = (ret == INVALID_SOCKET) ? get_last_error() : 0;
  209 + return ret != INVALID_SOCKET;
  210 + }
  211 +
  212 +public:
  213 + /**
  214 + * Creates an unconnected (invalid) socket
  215 + */
  216 + socket() : handle_(INVALID_SOCKET), lastErr_(0) {}
  217 + /**
  218 + * Creates a socket from an existing OS socket handle.
  219 + * The object takes ownership of the handle and will close it when
  220 + * destroyed.
  221 + * @param h An OS socket handle.
  222 + */
  223 + explicit socket(socket_t h) : handle_(h), lastErr_(0) {}
  224 + /**
  225 + * Move constructor.
  226 + * This takes ownership of the underlying handle in sock.
  227 + * @param sock An rvalue reference to a socket object.
  228 + */
  229 + socket(socket&& sock) noexcept
  230 + : handle_(sock.handle_), lastErr_(sock.lastErr_) {
  231 + sock.handle_ = INVALID_SOCKET;
  232 + }
  233 + /**
  234 + * Destructor closes the socket.
  235 + */
  236 + virtual ~socket() { close(); }
  237 + /**
  238 + * Initializes the socket (sockpp) library.
  239 + * This is only required for Win32. On platforms that use a standard
  240 + * socket implementation this is an empty call.
  241 + */
  242 + static void initialize();
  243 + /**
  244 + * Shuts down the socket library.
  245 + * This is only required for Win32. On platforms that use a standard
  246 + * socket implementation this is an empty call.
  247 + */
  248 + static void destroy();
  249 + /**
  250 + * Creates a socket with the specified communications characterics.
  251 + * Not that this is not normally how a socket is creates in the sockpp
  252 + * library. Applications would typically create a connector (client) or
  253 + * acceptor (server) socket which would take care of the details.
  254 + *
  255 + * This is included for completeness or for creating different types of
  256 + * sockets than are supported by the library.
  257 + *
  258 + * @param domain The communications domain for the sockets (i.e. the
  259 + * address family)
  260 + * @param type The communication semantics for the sockets (SOCK_STREAM,
  261 + * SOCK_DGRAM, etc).
  262 + * @param protocol The particular protocol to be used with the sockets
  263 + *
  264 + * @return A socket with the requested communications characteristics.
  265 + */
  266 + static socket create(int domain, int type, int protocol=0);
  267 + /**
  268 + * Determines if the socket is open (valid).
  269 + * @return @em true if the socket is open, @em false otherwise.
  270 + */
  271 + bool is_open() const { return handle_ != INVALID_SOCKET; }
  272 + /**
  273 + * Determines if the socket is closed or in an error state.
  274 + * @return @em true if the socket is closed or in an error state, @em
  275 + * false otherwise.
  276 + */
  277 + bool operator!() const {
  278 + return handle_ == INVALID_SOCKET || lastErr_ != 0;
  279 + }
  280 + /**
  281 + * Determines if the socket is open and in an error-free state.
  282 + * @return @em true if the socket is open and in an error-free state,
  283 + * @em false otherwise.
  284 + */
  285 + explicit operator bool() const {
  286 + return handle_ != INVALID_SOCKET && lastErr_ == 0;
  287 + }
  288 + /**
  289 + * Get the underlying OS socket handle.
  290 + * @return The underlying OS socket handle.
  291 + */
  292 + socket_t handle() const { return handle_; }
  293 + /**
  294 + * Gets the network family of the address to which the socket is bound.
  295 + * @return The network family of the address (AF_INET, etc) to which the
  296 + * socket is bound. If the socket is not bound, or the address
  297 + * is not known, returns AF_UNSPEC.
  298 + */
  299 + virtual sa_family_t family() const {
  300 + return address().family();
  301 + }
  302 + /**
  303 + * Creates a new socket that refers to this one.
  304 + * This creates a new object with an independent lifetime, but refers
  305 + * back to this same socket. On most systems, this duplicates the file
  306 + * handle using the dup() call.
  307 + * A typical use of this is to have separate threads for reading and
  308 + * writing the socket. One thread would get the original socket and the
  309 + * other would get the cloned one.
  310 + * @return A new socket object that refers to the same socket as this
  311 + * one.
  312 + */
  313 + socket clone() const;
  314 + /**
  315 + * Creates a pair of connected sockets.
  316 + *
  317 + * Whether this will work at all is highly system and domain dependent.
  318 + * Currently it is only known to work for Unix-domain sockets on *nix
  319 + * systems.
  320 + *
  321 + * Note that applications would normally call this from a derived socket
  322 + * class which would return the properly type-cast sockets to match the
  323 + * `domain` and `type`.
  324 + *
  325 + * @param domain The communications domain for the sockets (i.e. the
  326 + * address family)
  327 + * @param type The communication semantics for the sockets (SOCK_STREAM,
  328 + * SOCK_DGRAM, etc).
  329 + * @param protocol The particular protocol to be used with the sockets
  330 + *
  331 + * @return A std::tuple of sockets. On error both sockets will be in an
  332 + * error state with the
  333 + */
  334 + static std::tuple<socket, socket> pair(int domain, int type, int protocol=0);
  335 + /**
  336 + * Clears the error flag for the object.
  337 + * @param val The value to set the flag, normally zero.
  338 + */
  339 + void clear(int val=0) { lastErr_ = val; }
  340 + /**
  341 + * Releases ownership of the underlying socket object.
  342 + * @return The OS socket handle.
  343 + */
  344 + socket_t release() {
  345 + socket_t h = handle_;
  346 + handle_ = INVALID_SOCKET;
  347 + return h;
  348 + }
  349 + /**
  350 + * Replaces the underlying managed socket object.
  351 + * @param h The new socket handle to manage.
  352 + */
  353 + void reset(socket_t h=INVALID_SOCKET);
  354 + /**
  355 + * Move assignment.
  356 + * This assigns ownership of the socket from the other object to this
  357 + * one.
  358 + * @return A reference to this object.
  359 + */
  360 + socket& operator=(socket&& sock) noexcept {
  361 + // Give our handle to the other to close.
  362 + std::swap(handle_, sock.handle_);
  363 + lastErr_ = sock.lastErr_;
  364 + return *this;
  365 + }
  366 + /**
  367 + * Binds the socket to the specified address.
  368 + * @param addr The address to which we get bound.
  369 + * @return @em true on success, @em false on error
  370 + */
  371 + bool bind(const sock_address& addr);
  372 + /**
  373 + * Gets the local address to which the socket is bound.
  374 + * @return The local address to which the socket is bound.
  375 + */
  376 + sock_address_any address() const;
  377 + /**
  378 + * Gets the address of the remote peer, if this socket is connected.
  379 + * @return The address of the remote peer, if this socket is connected.
  380 + */
  381 + sock_address_any peer_address() const;
  382 + /**
  383 + * Gets the value of a socket option.
  384 + *
  385 + * This is a thin wrapper for the system `getsockopt`.
  386 + *
  387 + * @param level The protocol level at which the option resides, such as
  388 + * SOL_SOCKET.
  389 + * @param optname The option passed directly to the protocol module.
  390 + * @param optval The buffer for the value to retrieve
  391 + * @param optlen Initially contains the lenth of the buffer, and on return
  392 + * contains the length of the value retrieved.
  393 + *
  394 + * @return bool @em true if the value was retrieved, @em false if an error
  395 + * occurred.
  396 + */
  397 + bool get_option(int level, int optname, void* optval, socklen_t* optlen) const;
  398 + /**
  399 + * Gets the value of a socket option.
  400 + *
  401 + * @param level The protocol level at which the option resides, such as
  402 + * SOL_SOCKET.
  403 + * @param optname The option passed directly to the protocol module.
  404 + * @param val The value to retrieve
  405 + * @return bool @em true if the value was retrieved, @em false if an error
  406 + * occurred.
  407 + */
  408 + template <typename T>
  409 + bool get_option(int level, int optname, T* val) const {
  410 + socklen_t len = sizeof(T);
  411 + return get_option(level, optname, (void*) val, &len);
  412 + }
  413 + /**
  414 + * Sets the value of a socket option.
  415 + *
  416 + * This is a thin wrapper for the system `setsockopt`.
  417 + *
  418 + * @param level The protocol level at which the option resides, such as
  419 + * SOL_SOCKET.
  420 + * @param optname The option passed directly to the protocol module.
  421 + * @param optval The buffer with the value to set.
  422 + * @param optlen Contains the lenth of the value buffer.
  423 + *
  424 + * @return bool @em true if the value was set, @em false if an error
  425 + * occurred.
  426 + */
  427 + bool set_option(int level, int optname, const void* optval, socklen_t optlen);
  428 + /**
  429 + * Sets the value of a socket option.
  430 + *
  431 + * @param level The protocol level at which the option resides, such as
  432 + * SOL_SOCKET.
  433 + * @param optname The option passed directly to the protocol module.
  434 + * @param val The value to set.
  435 + *
  436 + * @return bool @em true if the value was set, @em false if an error
  437 + * occurred.
  438 + */
  439 + template <typename T>
  440 + bool set_option(int level, int optname, const T& val) {
  441 + return set_option(level, optname, (void*) &val, sizeof(T));
  442 + }
  443 + /**
  444 + * Places the socket into or out of non-blocking mode.
  445 + * When in non-blocking mode, a call that is not immediately ready to
  446 + * complete (read, write, accept, etc) will return immediately with the
  447 + * error EWOULDBLOCK.
  448 + * @param on Whether to turn non-blocking mode on or off.
  449 + * @return @em true on success, @em false on failure.
  450 + */
  451 + bool set_non_blocking(bool on=true);
  452 + /**
  453 + * Gets a string describing the specified error.
  454 + * This is typically the returned message from the system strerror().
  455 + * @param errNum The error number.
  456 + * @return A string describing the specified error.
  457 + */
  458 + static std::string error_str(int errNum);
  459 + /**
  460 + * Gets the code for the last errror.
  461 + * This is typically the code from the underlying OS operation.
  462 + * @return The code for the last errror.
  463 + */
  464 + int last_error() const { return lastErr_; }
  465 + /**
  466 + * Gets a string describing the last errror.
  467 + * This is typically the returned message from the system strerror().
  468 + * @return A string describing the last errror.
  469 + */
  470 + std::string last_error_str() const {
  471 + return error_str(lastErr_);
  472 + }
  473 + /**
  474 + * Shuts down all or part of the full-duplex connection.
  475 + * @param how Which part of the connection should be shut:
  476 + * @li SHUT_RD (0) Further reads disallowed.
  477 + * @li SHUT_WR (1) Further writes disallowed
  478 + * @li SHUT_RDWR (2) Further reads and writes disallowed.
  479 + * @return @em true on success, @em false on error.
  480 + */
  481 + bool shutdown(int how=SHUT_RDWR);
  482 + /**
  483 + * Closes the socket.
  484 + * After closing the socket, the handle is @em invalid, and can not be
  485 + * used again until reassigned.
  486 + * @return @em true if the sock is closed, @em false on error.
  487 + */
  488 + bool close();
  489 +};
  490 +
  491 +/////////////////////////////////////////////////////////////////////////////
  492 +
  493 +/**
  494 + * RAII class to initialize and then shut down the library.
  495 + * A single object of this class can be declared before any other classes in
  496 + * the library are used. The lifetime of the object should span the use of
  497 + * the other classes in the library, so declaring an object at the top of
  498 + * main() is usually the best choice.
  499 + * This is only required on some platforms, particularly Windows, but is
  500 + * harmless on other platforms. On some, such as POSIX, the initializer sets
  501 + * optional parameters for the library, and the destructor does nothing.
  502 + */
  503 +class socket_initializer
  504 +{
  505 +public:
  506 + socket_initializer() { socket::initialize(); }
  507 + ~socket_initializer() { socket::destroy(); }
  508 +};
  509 +
  510 +/////////////////////////////////////////////////////////////////////////////
  511 +// end namespace sockpp
  512 +}
  513 +
  514 +#endif // __sockpp_socket_h
  515 +
include/socket-cpp/stream_socket.h 0 โ†’ 100644
  1 +++ a/include/socket-cpp/stream_socket.h
  1 +/**
  2 + * @file stream_socket.h
  3 + *
  4 + * Classes for stream sockets.
  5 + *
  6 + * @author Frank Pagliughi
  7 + * @author SoRo Systems, Inc.
  8 + * @author www.sorosys.com
  9 + *
  10 + * @date December 2014
  11 + */
  12 +
  13 +// --------------------------------------------------------------------------
  14 +// This file is part of the "sockpp" C++ socket library.
  15 +//
  16 +// Copyright (c) 2014-2017 Frank Pagliughi
  17 +// All rights reserved.
  18 +//
  19 +// Redistribution and use in source and binary forms, with or without
  20 +// modification, are permitted provided that the following conditions are
  21 +// met:
  22 +//
  23 +// 1. Redistributions of source code must retain the above copyright notice,
  24 +// this list of conditions and the following disclaimer.
  25 +//
  26 +// 2. Redistributions in binary form must reproduce the above copyright
  27 +// notice, this list of conditions and the following disclaimer in the
  28 +// documentation and/or other materials provided with the distribution.
  29 +//
  30 +// 3. Neither the name of the copyright holder nor the names of its
  31 +// contributors may be used to endorse or promote products derived from this
  32 +// software without specific prior written permission.
  33 +//
  34 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  35 +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  36 +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  37 +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  38 +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  39 +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  40 +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  41 +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  42 +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  43 +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  44 +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  45 +// --------------------------------------------------------------------------
  46 +
  47 +#ifndef __sockpp_stream_socket_h
  48 +#define __sockpp_stream_socket_h
  49 +
  50 +#include "sockpp/socket.h"
  51 +#include <vector>
  52 +
  53 +namespace sockpp {
  54 +
  55 +/////////////////////////////////////////////////////////////////////////////
  56 +
  57 +/**
  58 + * Base class for streaming sockets, such as TCP and Unix Domain.
  59 + * This is the streaming connection between two peers. It looks like a
  60 + * readable/writeable device.
  61 + */
  62 +class stream_socket : public socket
  63 +{
  64 + /** The base class */
  65 + using base = socket;
  66 +
  67 +protected:
  68 + /** Acceptor can create stream sockets. */
  69 + friend class acceptor;
  70 +
  71 + /**
  72 + * Creates a streaming socket.
  73 + * @return An OS handle to a stream socket.
  74 + */
  75 + static socket_t create_handle(int domain) {
  76 + return (socket_t) ::socket(domain, COMM_TYPE, 0);
  77 + }
  78 +
  79 +public:
  80 + /** The socket 'type' for communications semantics. */
  81 + static constexpr int COMM_TYPE = SOCK_STREAM;
  82 + /**
  83 + * Creates an unconnected streaming socket.
  84 + */
  85 + stream_socket() {}
  86 + /**
  87 + * Creates a streaming socket from an existing OS socket handle and
  88 + * claims ownership of the handle.
  89 + * @param handle A socket handle from the operating system.
  90 + */
  91 + explicit stream_socket(socket_t handle) : base(handle) {}
  92 + /**
  93 + * Creates a stream socket by copying the socket handle from the
  94 + * specified socket object and transfers ownership of the socket.
  95 + */
  96 + stream_socket(stream_socket&& sock) : base(std::move(sock)) {}
  97 +
  98 +
  99 + /**
  100 + * Creates a socket with the specified communications characterics.
  101 + * Not that this is not normally how a socket is creates in the sockpp
  102 + * library. Applications would typically create a connector (client) or
  103 + * acceptor (server) socket which would take care of the details.
  104 + *
  105 + * This is included for completeness or for creating different types of
  106 + * sockets than are supported by the library.
  107 + *
  108 + * @param domain The communications domain for the sockets (i.e. the
  109 + * address family)
  110 + * @param protocol The particular protocol to be used with the sockets
  111 + *
  112 + * @return A stream socket with the requested communications
  113 + * characteristics.
  114 + */
  115 + static stream_socket create(int domain, int protocol=0);
  116 +
  117 + /**
  118 + * Move assignment.
  119 + * @param rhs The other socket to move into this one.
  120 + * @return A reference to this object.
  121 + */
  122 + stream_socket& operator=(stream_socket&& rhs) {
  123 + base::operator=(std::move(rhs));
  124 + return *this;
  125 + }
  126 + /**
  127 + * Creates a new stream_socket that refers to this one.
  128 + * This creates a new object with an independent lifetime, but refers
  129 + * back to this same socket. On most systems, this duplicates the file
  130 + * handle using the dup() call.
  131 + * A typical use of this is to have separate threads for reading and
  132 + * writing the socket. One thread would get the original socket and the
  133 + * other would get the cloned one.
  134 + * @return A new stream socket object that refers to the same socket as
  135 + * this one.
  136 + */
  137 + stream_socket clone() const {
  138 + auto h = base::clone().release();
  139 + return stream_socket(h);
  140 + }
  141 + /**
  142 + * Reads from the port
  143 + * @param buf Buffer to get the incoming data.
  144 + * @param n The number of bytes to try to read.
  145 + * @return The number of bytes read on success, or @em -1 on error.
  146 + */
  147 + virtual ssize_t read(void *buf, size_t n);
  148 + /**
  149 + * Best effort attempts to read the specified number of bytes.
  150 + * This will make repeated read attempts until all the bytes are read in
  151 + * or until an error occurs.
  152 + * @param buf Buffer to get the incoming data.
  153 + * @param n The number of bytes to try to read.
  154 + * @return The number of bytes read on success, or @em -1 on error. If
  155 + * successful, the number of bytes read should always be 'n'.
  156 + */
  157 + virtual ssize_t read_n(void *buf, size_t n);
  158 + /**
  159 + * Reads discontiguous memory ranges from the socket.
  160 + * @param ranges The vector of memory ranges to fill
  161 + * @return The number of bytes read, or @em -1 on error.
  162 + */
  163 + ssize_t read(const std::vector<iovec>& ranges);
  164 + /**
  165 + * Set a timeout for read operations.
  166 + * Sets the timeout that the device uses for read operations. Not all
  167 + * devices support timeouts, so the caller should prepare for failure.
  168 + * @param to The amount of time to wait for the operation to complete.
  169 + * @return @em true on success, @em false on failure.
  170 + */
  171 + virtual bool read_timeout(const std::chrono::microseconds& to);
  172 + /**
  173 + * Set a timeout for read operations.
  174 + * Sets the timout that the device uses for read operations. Not all
  175 + * devices support timouts, so the caller should prepare for failure.
  176 + * @param to The amount of time to wait for the operation to complete.
  177 + * @return @em true on success, @em false on failure.
  178 + */
  179 + template<class Rep, class Period>
  180 + bool read_timeout(const std::chrono::duration<Rep,Period>& to) {
  181 + return read_timeout(std::chrono::duration_cast<std::chrono::microseconds>(to));
  182 + }
  183 + /**
  184 + * Writes the buffer to the socket.
  185 + * @param buf The buffer to write
  186 + * @param n The number of bytes in the buffer.
  187 + * @return The number of bytes written, or @em -1 on error.
  188 + */
  189 + virtual ssize_t write(const void *buf, size_t n);
  190 + /**
  191 + * Best effort attempt to write the whole buffer to the socket.
  192 + * @param buf The buffer to write
  193 + * @param n The number of bytes in the buffer.
  194 + * @return The number of bytes written, or @em -1 on error. If
  195 + * successful, the number of bytes written should always be 'n'.
  196 + */
  197 + virtual ssize_t write_n(const void *buf, size_t n);
  198 + /**
  199 + * Best effort attempt to write a string to the socket.
  200 + * @param s The string to write.
  201 + * @return The number of bytes written, or @em -1 on error. On success,
  202 + * the number of bytes written should always be the length of
  203 + * the string.
  204 + */
  205 + virtual ssize_t write(const std::string& s) {
  206 + return write_n(s.data(), s.size());
  207 + }
  208 + /**
  209 + * Writes discontiguous memory ranges to the socket.
  210 + * @param ranges The vector of memory ranges to write
  211 + * @return The number of bytes written, or @em -1 on error.
  212 + */
  213 + virtual ssize_t write(const std::vector<iovec> &ranges);
  214 + /**
  215 + * Set a timeout for write operations.
  216 + * Sets the timout that the device uses for write operations. Not all
  217 + * devices support timouts, so the caller should prepare for failure.
  218 + * @param to The amount of time to wait for the operation to complete.
  219 + * @return @em true on success, @em false on failure.
  220 + */
  221 + virtual bool write_timeout(const std::chrono::microseconds& to);
  222 + /**
  223 + * Set a timeout for write operations.
  224 + * Sets the timout that the device uses for write operations. Not all
  225 + * devices support timouts, so the caller should prepare for failure.
  226 + * @param to The amount of time to wait for the operation to complete.
  227 + * @return @em true on success, @em false on failure.
  228 + */
  229 + template<class Rep, class Period>
  230 + bool write_timeout(const std::chrono::duration<Rep,Period>& to) {
  231 + return write_timeout(std::chrono::duration_cast<std::chrono::microseconds>(to));
  232 + }
  233 +};
  234 +
  235 +/////////////////////////////////////////////////////////////////////////////
  236 +
  237 +/**
  238 + * Template for creating specific stream types (IPv4, IPv6, etc).
  239 + * This just overrides methods that take a generic address and replace them
  240 + * with the address type for a specific family. This doesn't add any
  241 + * runtime functionality, but has compile-time checks that address types
  242 + * aren't accidentally being mixed for an object.
  243 + */
  244 +template <typename ADDR>
  245 +class stream_socket_tmpl : public stream_socket
  246 +{
  247 + /** The base class */
  248 + using base = stream_socket;
  249 +
  250 +public:
  251 + /** The address family for this type of address */
  252 + static constexpr sa_family_t ADDRESS_FAMILY = ADDR::ADDRESS_FAMILY;
  253 + /** The type of network address used with this socket. */
  254 + using addr_t = ADDR;
  255 + /**
  256 + * Creates an unconnected streaming socket.
  257 + */
  258 + stream_socket_tmpl() {}
  259 + /**
  260 + * Creates a streaming socket from an existing OS socket handle and
  261 + * claims ownership of the handle.
  262 + * @param handle A socket handle from the operating system.
  263 + */
  264 + explicit stream_socket_tmpl(socket_t handle) : base(handle) {}
  265 + /**
  266 + * Move constructor.
  267 + * Creates a stream socket by moving the other socket to this one.
  268 + * @param sock Another stream socket.
  269 + */
  270 + stream_socket_tmpl(stream_socket&& sock)
  271 + : base(std::move(sock)) {}
  272 + /**
  273 + * Creates a stream socket by copying the socket handle from the
  274 + * specified socket object and transfers ownership of the socket.
  275 + */
  276 + stream_socket_tmpl(stream_socket_tmpl&& sock)
  277 + : base(std::move(sock)) {}
  278 + /**
  279 + * Move assignment.
  280 + * @param rhs The other socket to move into this one.
  281 + * @return A reference to this object.
  282 + */
  283 + stream_socket_tmpl& operator=(stream_socket_tmpl&& rhs) {
  284 + base::operator=(std::move(rhs));
  285 + return *this;
  286 + }
  287 + /**
  288 + * Cretates a stream socket.
  289 + * @param protocol The particular protocol to be used with the sockets
  290 + * @return A stream socket
  291 + */
  292 + stream_socket_tmpl create(int protocol=0) {
  293 + return stream_socket_tmpl(std::move(base::create(ADDRESS_FAMILY, protocol)));
  294 + }
  295 + /**
  296 + * Creates a pair of connected stream sockets.
  297 + *
  298 + * Whether this will work at all is highly system and domain dependent.
  299 + * Currently it is only known to work for Unix-domain sockets on *nix
  300 + * systems.
  301 + *
  302 + * @param protocol The protocol to be used with the socket. (Normally 0)
  303 + *
  304 + * @return A std::tuple of stream sockets. On error both sockets will be
  305 + * in an error state with the last error set.
  306 + */
  307 + static std::tuple<stream_socket_tmpl, stream_socket_tmpl> pair(int protocol=0) {
  308 + auto pr = base::pair(ADDRESS_FAMILY, COMM_TYPE, protocol);
  309 + return std::make_tuple<stream_socket_tmpl, stream_socket_tmpl>(
  310 + stream_socket_tmpl{std::get<0>(pr).release()},
  311 + stream_socket_tmpl{std::get<1>(pr).release()});
  312 + }
  313 + /**
  314 + * Gets the local address to which the socket is bound.
  315 + * @return The local address to which the socket is bound.
  316 + * @throw sys_error on error
  317 + */
  318 + addr_t address() const { return addr_t(socket::address()); }
  319 + /**
  320 + * Gets the address of the remote peer, if this socket is connected.
  321 + * @return The address of the remote peer, if this socket is connected.
  322 + * @throw sys_error on error
  323 + */
  324 + addr_t peer_address() const { return addr_t(socket::peer_address()); }
  325 +};
  326 +
  327 +/////////////////////////////////////////////////////////////////////////////
  328 +// end namespace sockpp
  329 +}
  330 +
  331 +#endif // __sockpp_socket_h
  332 +
include/socket-cpp/tcp6_acceptor.h 0 โ†’ 100644
  1 +++ a/include/socket-cpp/tcp6_acceptor.h
  1 +/// @file tcp6_acceptor.h
  2 +///
  3 +/// Class for a TCP v6 server to accept incoming connections.
  4 +///
  5 +/// @author Frank Pagliughi
  6 +/// @author SoRo Systems, Inc.
  7 +/// @author www.sorosys.com
  8 +///
  9 +/// @date May 2019
  10 +
  11 +// --------------------------------------------------------------------------
  12 +// This file is part of the "sockpp" C++ socket library.
  13 +//
  14 +// Copyright (c) 2019 Frank Pagliughi
  15 +// All rights reserved.
  16 +//
  17 +// Redistribution and use in source and binary forms, with or without
  18 +// modification, are permitted provided that the following conditions are
  19 +// met:
  20 +//
  21 +// 1. Redistributions of source code must retain the above copyright notice,
  22 +// this list of conditions and the following disclaimer.
  23 +//
  24 +// 2. Redistributions in binary form must reproduce the above copyright
  25 +// notice, this list of conditions and the following disclaimer in the
  26 +// documentation and/or other materials provided with the distribution.
  27 +//
  28 +// 3. Neither the name of the copyright holder nor the names of its
  29 +// contributors may be used to endorse or promote products derived from this
  30 +// software without specific prior written permission.
  31 +//
  32 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  33 +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  34 +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  35 +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  36 +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  37 +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  38 +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  39 +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  40 +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  41 +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  42 +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  43 +// --------------------------------------------------------------------------
  44 +
  45 +#ifndef __sockpp_tcp6_acceptor_h
  46 +#define __sockpp_tcp6_acceptor_h
  47 +
  48 +#include "sockpp/acceptor.h"
  49 +#include "sockpp/tcp6_socket.h"
  50 +
  51 +namespace sockpp {
  52 +
  53 +/////////////////////////////////////////////////////////////////////////////
  54 +
  55 +/// Class for creating a TCP v6 server.
  56 +/// Objects of this class bind and listen on TCP ports for incoming
  57 +/// connections. Normally, a server thread creates one of these and blocks
  58 +/// on the call to accept incoming connections. The call to accept creates
  59 +/// and returns a @ref tcp6_socket which can then be used for the actual
  60 +/// communications.
  61 +
  62 +using tcp6_acceptor = acceptor_tmpl<tcp6_socket>;
  63 +
  64 +/////////////////////////////////////////////////////////////////////////////
  65 +// end namespace sockpp
  66 +};
  67 +
  68 +#endif // __sockpp_tcp_acceptor_h
  69 +
include/socket-cpp/tcp6_connector.h 0 โ†’ 100644
  1 +++ a/include/socket-cpp/tcp6_connector.h
  1 +/**
  2 + * @file tcp6_connector.h
  3 + *
  4 + * Class for creating client-side TCP connections
  5 + *
  6 + * @author Frank Pagliughi
  7 + * @author SoRo Systems, Inc.
  8 + * @author www.sorosys.com
  9 + *
  10 + * @date May 2019
  11 + */
  12 +
  13 +// --------------------------------------------------------------------------
  14 +// This file is part of the "sockpp" C++ socket library.
  15 +//
  16 +// Copyright (c) 2014-2019 Frank Pagliughi
  17 +// All rights reserved.
  18 +//
  19 +// Redistribution and use in source and binary forms, with or without
  20 +// modification, are permitted provided that the following conditions are
  21 +// met:
  22 +//
  23 +// 1. Redistributions of source code must retain the above copyright notice,
  24 +// this list of conditions and the following disclaimer.
  25 +//
  26 +// 2. Redistributions in binary form must reproduce the above copyright
  27 +// notice, this list of conditions and the following disclaimer in the
  28 +// documentation and/or other materials provided with the distribution.
  29 +//
  30 +// 3. Neither the name of the copyright holder nor the names of its
  31 +// contributors may be used to endorse or promote products derived from this
  32 +// software without specific prior written permission.
  33 +//
  34 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  35 +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  36 +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  37 +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  38 +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  39 +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  40 +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  41 +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  42 +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  43 +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  44 +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  45 +// --------------------------------------------------------------------------
  46 +
  47 +
  48 +#ifndef __sockpp_tcp6_connector_h
  49 +#define __sockpp_tcp6_connector_h
  50 +
  51 +#include "sockpp/connector.h"
  52 +#include "sockpp/tcp6_socket.h"
  53 +
  54 +namespace sockpp {
  55 +
  56 +/////////////////////////////////////////////////////////////////////////////
  57 +
  58 +/** IPv6 active, connector (client) socket. */
  59 +using tcp6_connector = connector_tmpl<tcp6_socket>;
  60 +
  61 +/////////////////////////////////////////////////////////////////////////////
  62 +// end namespace sockpp
  63 +}
  64 +
  65 +#endif // __sockpp_tcp6_connector_h
  66 +
include/socket-cpp/tcp6_socket.h 0 โ†’ 100644
  1 +++ a/include/socket-cpp/tcp6_socket.h
  1 +/**
  2 + * @file tcp6_socket.h
  3 + *
  4 + * Class (typedef) for IPv6 TCP socket.
  5 + *
  6 + * @author Frank Pagliughi
  7 + * @author SoRo Systems, Inc.
  8 + * @author www.sorosys.com
  9 + *
  10 + * @date August 2019
  11 + */
  12 +
  13 +// --------------------------------------------------------------------------
  14 +// This file is part of the "sockpp" C++ socket library.
  15 +//
  16 +// Copyright (c) 2019 Frank Pagliughi
  17 +// All rights reserved.
  18 +//
  19 +// Redistribution and use in source and binary forms, with or without
  20 +// modification, are permitted provided that the following conditions are
  21 +// met:
  22 +//
  23 +// 1. Redistributions of source code must retain the above copyright notice,
  24 +// this list of conditions and the following disclaimer.
  25 +//
  26 +// 2. Redistributions in binary form must reproduce the above copyright
  27 +// notice, this list of conditions and the following disclaimer in the
  28 +// documentation and/or other materials provided with the distribution.
  29 +//
  30 +// 3. Neither the name of the copyright holder nor the names of its
  31 +// contributors may be used to endorse or promote products derived from this
  32 +// software without specific prior written permission.
  33 +//
  34 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  35 +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  36 +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  37 +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  38 +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  39 +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  40 +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  41 +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  42 +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  43 +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  44 +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  45 +// --------------------------------------------------------------------------
  46 +
  47 +#ifndef __sockpp_tcp6_socket_h
  48 +#define __sockpp_tcp6_socket_h
  49 +
  50 +#include "sockpp/stream_socket.h"
  51 +#include "sockpp/inet6_address.h"
  52 +
  53 +namespace sockpp {
  54 +
  55 +/////////////////////////////////////////////////////////////////////////////
  56 +
  57 +/** IPv6 streaming TCP socket */
  58 +using tcp6_socket = stream_socket_tmpl<inet6_address>;
  59 +
  60 +/////////////////////////////////////////////////////////////////////////////
  61 +// end namespace sockpp
  62 +}
  63 +
  64 +#endif // __sockpp_tcp6_socket_h
  65 +
include/socket-cpp/tcp_acceptor.h 0 โ†’ 100644
  1 +++ a/include/socket-cpp/tcp_acceptor.h
  1 +/// @file tcp_acceptor.h
  2 +///
  3 +/// Class for a TCP server to accept incoming connections.
  4 +///
  5 +/// @author Frank Pagliughi
  6 +/// @author SoRo Systems, Inc.
  7 +/// @author www.sorosys.com
  8 +///
  9 +/// @date December 2014
  10 +
  11 +// --------------------------------------------------------------------------
  12 +// This file is part of the "sockpp" C++ socket library.
  13 +//
  14 +// Copyright (c) 2014-2019 Frank Pagliughi
  15 +// All rights reserved.
  16 +//
  17 +// Redistribution and use in source and binary forms, with or without
  18 +// modification, are permitted provided that the following conditions are
  19 +// met:
  20 +//
  21 +// 1. Redistributions of source code must retain the above copyright notice,
  22 +// this list of conditions and the following disclaimer.
  23 +//
  24 +// 2. Redistributions in binary form must reproduce the above copyright
  25 +// notice, this list of conditions and the following disclaimer in the
  26 +// documentation and/or other materials provided with the distribution.
  27 +//
  28 +// 3. Neither the name of the copyright holder nor the names of its
  29 +// contributors may be used to endorse or promote products derived from this
  30 +// software without specific prior written permission.
  31 +//
  32 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  33 +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  34 +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  35 +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  36 +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  37 +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  38 +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  39 +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  40 +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  41 +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  42 +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  43 +// --------------------------------------------------------------------------
  44 +
  45 +#ifndef __sockpp_tcp_acceptor_h
  46 +#define __sockpp_tcp_acceptor_h
  47 +
  48 +#include "sockpp/acceptor.h"
  49 +#include "sockpp/tcp_socket.h"
  50 +
  51 +namespace sockpp {
  52 +
  53 +/////////////////////////////////////////////////////////////////////////////
  54 +
  55 +/// Class for creating a TCP server.
  56 +/// Objects of this class bind and listen on TCP ports for incoming
  57 +/// connections. Normally, a server thread creates one of these and blocks
  58 +/// on the call to accept incoming connections. The call to accept creates
  59 +/// and returns a @ref tcp_socket which can then be used for the actual
  60 +/// communications.
  61 +
  62 +using tcp_acceptor = acceptor_tmpl<tcp_socket>;
  63 +
  64 +/////////////////////////////////////////////////////////////////////////////
  65 +// end namespace sockpp
  66 +};
  67 +
  68 +#endif // __sockpp_tcp_acceptor_h
  69 +
include/socket-cpp/tcp_connector.h 0 โ†’ 100644
  1 +++ a/include/socket-cpp/tcp_connector.h
  1 +/**
  2 + * @file tcp_connector.h
  3 + *
  4 + * Class for creating client-side TCP connections
  5 + *
  6 + * @author Frank Pagliughi
  7 + * @author SoRo Systems, Inc.
  8 + * @author www.sorosys.com
  9 + *
  10 + * @date December 2014
  11 + */
  12 +
  13 +// --------------------------------------------------------------------------
  14 +// This file is part of the "sockpp" C++ socket library.
  15 +//
  16 +// Copyright (c) 2014-2019 Frank Pagliughi
  17 +// All rights reserved.
  18 +//
  19 +// Redistribution and use in source and binary forms, with or without
  20 +// modification, are permitted provided that the following conditions are
  21 +// met:
  22 +//
  23 +// 1. Redistributions of source code must retain the above copyright notice,
  24 +// this list of conditions and the following disclaimer.
  25 +//
  26 +// 2. Redistributions in binary form must reproduce the above copyright
  27 +// notice, this list of conditions and the following disclaimer in the
  28 +// documentation and/or other materials provided with the distribution.
  29 +//
  30 +// 3. Neither the name of the copyright holder nor the names of its
  31 +// contributors may be used to endorse or promote products derived from this
  32 +// software without specific prior written permission.
  33 +//
  34 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  35 +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  36 +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  37 +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  38 +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  39 +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  40 +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  41 +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  42 +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  43 +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  44 +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  45 +// --------------------------------------------------------------------------
  46 +
  47 +
  48 +#ifndef __sockpp_tcp_connector_h
  49 +#define __sockpp_tcp_connector_h
  50 +
  51 +#include "sockpp/connector.h"
  52 +#include "sockpp/tcp_socket.h"
  53 +
  54 +namespace sockpp {
  55 +
  56 +/////////////////////////////////////////////////////////////////////////////
  57 +
  58 +/** IPv4 active, connector (client) socket. */
  59 +using tcp_connector = connector_tmpl<tcp_socket>;
  60 +
  61 +/////////////////////////////////////////////////////////////////////////////
  62 +// end namespace sockpp
  63 +};
  64 +
  65 +#endif // __sockpp_tcp_connector_h
include/socket-cpp/tcp_socket.h 0 โ†’ 100644
  1 +++ a/include/socket-cpp/tcp_socket.h
  1 +/**
  2 + * @file tcp_socket.h
  3 + *
  4 + * Class (typedef) for IPv4 TCP socket.
  5 + *
  6 + * @author Frank Pagliughi
  7 + * @author SoRo Systems, Inc.
  8 + * @author www.sorosys.com
  9 + *
  10 + * @date August 2019
  11 + */
  12 +
  13 +// --------------------------------------------------------------------------
  14 +// This file is part of the "sockpp" C++ socket library.
  15 +//
  16 +// Copyright (c) 2019 Frank Pagliughi
  17 +// All rights reserved.
  18 +//
  19 +// Redistribution and use in source and binary forms, with or without
  20 +// modification, are permitted provided that the following conditions are
  21 +// met:
  22 +//
  23 +// 1. Redistributions of source code must retain the above copyright notice,
  24 +// this list of conditions and the following disclaimer.
  25 +//
  26 +// 2. Redistributions in binary form must reproduce the above copyright
  27 +// notice, this list of conditions and the following disclaimer in the
  28 +// documentation and/or other materials provided with the distribution.
  29 +//
  30 +// 3. Neither the name of the copyright holder nor the names of its
  31 +// contributors may be used to endorse or promote products derived from this
  32 +// software without specific prior written permission.
  33 +//
  34 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  35 +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  36 +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  37 +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  38 +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  39 +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  40 +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  41 +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  42 +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  43 +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  44 +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  45 +// --------------------------------------------------------------------------
  46 +
  47 +#ifndef __sockpp_tcp_socket_h
  48 +#define __sockpp_tcp_socket_h
  49 +
  50 +#include "sockpp/stream_socket.h"
  51 +#include "sockpp/inet_address.h"
  52 +
  53 +namespace sockpp {
  54 +
  55 +/////////////////////////////////////////////////////////////////////////////
  56 +
  57 +/** IPv4 streaming TCP socket */
  58 +using tcp_socket = stream_socket_tmpl<inet_address>;
  59 +
  60 +/////////////////////////////////////////////////////////////////////////////
  61 +// end namespace sockpp
  62 +}
  63 +
  64 +#endif // __sockpp_tcp_socket_h
  65 +
include/socket-cpp/udp6_socket.h 0 โ†’ 100644
  1 +++ a/include/socket-cpp/udp6_socket.h
  1 +/**
  2 + * @file udp6_socket.h
  3 + *
  4 + * Class (typedef) for UDP v6 socket.
  5 + *
  6 + * @author Frank Pagliughi
  7 + * @author SoRo Systems, Inc.
  8 + * @author www.sorosys.com
  9 + *
  10 + * @date August 2019
  11 + */
  12 +
  13 +// --------------------------------------------------------------------------
  14 +// This file is part of the "sockpp" C++ socket library.
  15 +//
  16 +// Copyright (c) 2019 Frank Pagliughi
  17 +// All rights reserved.
  18 +//
  19 +// Redistribution and use in source and binary forms, with or without
  20 +// modification, are permitted provided that the following conditions are
  21 +// met:
  22 +//
  23 +// 1. Redistributions of source code must retain the above copyright notice,
  24 +// this list of conditions and the following disclaimer.
  25 +//
  26 +// 2. Redistributions in binary form must reproduce the above copyright
  27 +// notice, this list of conditions and the following disclaimer in the
  28 +// documentation and/or other materials provided with the distribution.
  29 +//
  30 +// 3. Neither the name of the copyright holder nor the names of its
  31 +// contributors may be used to endorse or promote products derived from this
  32 +// software without specific prior written permission.
  33 +//
  34 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  35 +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  36 +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  37 +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  38 +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  39 +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  40 +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  41 +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  42 +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  43 +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  44 +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  45 +// --------------------------------------------------------------------------
  46 +
  47 +#ifndef __sockpp_udp6_socket_h
  48 +#define __sockpp_udp6_socket_h
  49 +
  50 +#include "sockpp/datagram_socket.h"
  51 +#include "sockpp/inet6_address.h"
  52 +
  53 +namespace sockpp {
  54 +
  55 +/////////////////////////////////////////////////////////////////////////////
  56 +
  57 +/** UDP datagram socket type for IPv6 */
  58 +using udp6_socket = datagram_socket_tmpl<inet6_address>;
  59 +
  60 +/////////////////////////////////////////////////////////////////////////////
  61 +// end namespace sockpp
  62 +}
  63 +
  64 +#endif // __sockpp_udp6_socket_h
  65 +
include/socket-cpp/udp_socket.h 0 โ†’ 100644
  1 +++ a/include/socket-cpp/udp_socket.h
  1 +/**
  2 + * @file udp_socket.h
  3 + *
  4 + * Class (typedef) for UDP v4 socket.
  5 + *
  6 + * @author Frank Pagliughi
  7 + * @author SoRo Systems, Inc.
  8 + * @author www.sorosys.com
  9 + *
  10 + * @date August 2019
  11 + */
  12 +
  13 +// --------------------------------------------------------------------------
  14 +// This file is part of the "sockpp" C++ socket library.
  15 +//
  16 +// Copyright (c) 2019 Frank Pagliughi
  17 +// All rights reserved.
  18 +//
  19 +// Redistribution and use in source and binary forms, with or without
  20 +// modification, are permitted provided that the following conditions are
  21 +// met:
  22 +//
  23 +// 1. Redistributions of source code must retain the above copyright notice,
  24 +// this list of conditions and the following disclaimer.
  25 +//
  26 +// 2. Redistributions in binary form must reproduce the above copyright
  27 +// notice, this list of conditions and the following disclaimer in the
  28 +// documentation and/or other materials provided with the distribution.
  29 +//
  30 +// 3. Neither the name of the copyright holder nor the names of its
  31 +// contributors may be used to endorse or promote products derived from this
  32 +// software without specific prior written permission.
  33 +//
  34 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  35 +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  36 +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  37 +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  38 +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  39 +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  40 +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  41 +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  42 +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  43 +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  44 +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  45 +// --------------------------------------------------------------------------
  46 +
  47 +#ifndef __sockpp_udp_socket_h
  48 +#define __sockpp_udp_socket_h
  49 +
  50 +#include "sockpp/datagram_socket.h"
  51 +#include "sockpp/inet_address.h"
  52 +
  53 +namespace sockpp {
  54 +
  55 +/////////////////////////////////////////////////////////////////////////////
  56 +
  57 +/** UDP datagram socket type for IPv4 */
  58 +using udp_socket = datagram_socket_tmpl<inet_address>;
  59 +
  60 +/////////////////////////////////////////////////////////////////////////////
  61 +// end namespace sockpp
  62 +}
  63 +
  64 +#endif // __sockpp_udp_socket_h
  65 +
include/socket-cpp/unix_acceptor.h 0 โ†’ 100644
  1 +++ a/include/socket-cpp/unix_acceptor.h
  1 +/// @file unix_acceptor.h
  2 +///
  3 +/// Class for a TCP server to accept incoming connections.
  4 +///
  5 +/// @author Frank Pagliughi
  6 +/// @author SoRo Systems, Inc.
  7 +/// @author www.sorosys.com
  8 +///
  9 +/// @date December 2014
  10 +
  11 +// --------------------------------------------------------------------------
  12 +// This file is part of the "sockpp" C++ socket library.
  13 +//
  14 +// Copyright (c) 2014-2017 Frank Pagliughi
  15 +// All rights reserved.
  16 +//
  17 +// Redistribution and use in source and binary forms, with or without
  18 +// modification, are permitted provided that the following conditions are
  19 +// met:
  20 +//
  21 +// 1. Redistributions of source code must retain the above copyright notice,
  22 +// this list of conditions and the following disclaimer.
  23 +//
  24 +// 2. Redistributions in binary form must reproduce the above copyright
  25 +// notice, this list of conditions and the following disclaimer in the
  26 +// documentation and/or other materials provided with the distribution.
  27 +//
  28 +// 3. Neither the name of the copyright holder nor the names of its
  29 +// contributors may be used to endorse or promote products derived from this
  30 +// software without specific prior written permission.
  31 +//
  32 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  33 +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  34 +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  35 +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  36 +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  37 +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  38 +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  39 +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  40 +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  41 +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  42 +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  43 +// --------------------------------------------------------------------------
  44 +
  45 +#ifndef __sockpp_unix_acceptor_h
  46 +#define __sockpp_unix_acceptor_h
  47 +
  48 +#include "sockpp/acceptor.h"
  49 +#include "sockpp/unix_stream_socket.h"
  50 +
  51 +namespace sockpp {
  52 +
  53 +/////////////////////////////////////////////////////////////////////////////
  54 +
  55 +/// Class for creating a Unix-domain server.
  56 +/// Objects of this class bind and listen on Unix-domain ports for
  57 +/// connections. Normally, a server thread creates one of these and blocks
  58 +/// on the call to accept incoming connections. The call to accept creates
  59 +/// and returns a @ref unix_stream_socket which can then be used for the
  60 +/// actual communications.
  61 +
  62 +class unix_acceptor : public acceptor
  63 +{
  64 + /** The base class */
  65 + using base = acceptor;
  66 +
  67 + // Non-copyable
  68 + unix_acceptor(const unix_acceptor&) =delete;
  69 + unix_acceptor& operator=(const unix_acceptor&) =delete;
  70 +
  71 +public:
  72 + /**
  73 + * Creates an unconnected acceptor.
  74 + */
  75 + unix_acceptor() {}
  76 + /**
  77 + * Creates a acceptor and starts it listening on the specified address.
  78 + * @param addr The TCP address on which to listen.
  79 + * @param queSize The listener queue size.
  80 + */
  81 + unix_acceptor(const unix_address& addr, int queSize=DFLT_QUE_SIZE) {
  82 + open(addr, queSize);
  83 + }
  84 + /**
  85 + * Gets the local address to which we are bound.
  86 + * @return The local address to which we are bound.
  87 + */
  88 + unix_address address() const { return unix_address(base::address()); }
  89 + /**
  90 + * Base open call also work.
  91 + */
  92 + using base::open;
  93 + /**
  94 + * Opens the acceptor socket and binds it to the specified address.
  95 + * @param addr The address to which this server should be bound.
  96 + * @param queSize The listener queue size.
  97 + * @return @em true on success, @em false on error
  98 + */
  99 + bool open(const unix_address& addr, int queSize=DFLT_QUE_SIZE) {
  100 + return base::open(addr, queSize);
  101 + }
  102 + /**
  103 + * Accepts an incoming UNIX connection and gets the address of the
  104 + * client.
  105 + * @return A unix_socket to the client.
  106 + */
  107 + unix_socket accept() { return unix_socket(base::accept()); }
  108 +};
  109 +
  110 +/////////////////////////////////////////////////////////////////////////////
  111 +// end namespace sockpp
  112 +};
  113 +
  114 +#endif // __sockpp_unix_acceptor_h
  115 +
include/socket-cpp/unix_address.h 0 โ†’ 100644
  1 +++ a/include/socket-cpp/unix_address.h
  1 +/**
  2 + * @file unix_address.h
  3 + *
  4 + * Class for a UNIX-domain socket address.
  5 + *
  6 + * @author Frank Pagliughi
  7 + * @author SoRo Systems, Inc.
  8 + * @author www.sorosys.com
  9 + *
  10 + * @date February 2014
  11 + */
  12 +
  13 +// --------------------------------------------------------------------------
  14 +// This file is part of the "sockpp" C++ socket library.
  15 +//
  16 +// Copyright (c) 2014-2017 Frank Pagliughi
  17 +// All rights reserved.
  18 +//
  19 +// Redistribution and use in source and binary forms, with or without
  20 +// modification, are permitted provided that the following conditions are
  21 +// met:
  22 +//
  23 +// 1. Redistributions of source code must retain the above copyright notice,
  24 +// this list of conditions and the following disclaimer.
  25 +//
  26 +// 2. Redistributions in binary form must reproduce the above copyright
  27 +// notice, this list of conditions and the following disclaimer in the
  28 +// documentation and/or other materials provided with the distribution.
  29 +//
  30 +// 3. Neither the name of the copyright holder nor the names of its
  31 +// contributors may be used to endorse or promote products derived from this
  32 +// software without specific prior written permission.
  33 +//
  34 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  35 +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  36 +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  37 +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  38 +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  39 +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  40 +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  41 +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  42 +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  43 +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  44 +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  45 +// --------------------------------------------------------------------------
  46 +
  47 +#ifndef __sockpp_unix_addr_h
  48 +#define __sockpp_unix_addr_h
  49 +
  50 +#include "sockpp/platform.h"
  51 +#include "sockpp/sock_address.h"
  52 +#include <iostream>
  53 +#include <string>
  54 +#include <cstring>
  55 +#include <sys/un.h>
  56 +
  57 +namespace sockpp {
  58 +
  59 +/////////////////////////////////////////////////////////////////////////////
  60 +
  61 +/**
  62 + * Class that represents a UNIX domain address.
  63 + * This inherits from the UNIX form of a socket address, @em sockaddr_un.
  64 + */
  65 +class unix_address : public sock_address
  66 +{
  67 + /** The underlying C struct for unix-domain addresses */
  68 + sockaddr_un addr_;
  69 +
  70 + /** The size of the underlying address struct, in bytes */
  71 + static constexpr size_t SZ = sizeof(sockaddr_un);
  72 +
  73 +public:
  74 + /** The address family for this type of address */
  75 + static constexpr sa_family_t ADDRESS_FAMILY = AF_UNIX;
  76 +
  77 + // TODO: This only applies to Linux
  78 + static constexpr size_t MAX_PATH_NAME = 108;
  79 +
  80 + /**
  81 + * Constructs an empty address.
  82 + * The address is initialized to all zeroes.
  83 + */
  84 + unix_address() : addr_() {}
  85 + /**
  86 + * Constructs an address for the specified path.
  87 + * @param path The
  88 + */
  89 + unix_address(const std::string& path);
  90 + /**
  91 + * Constructs the address by copying the specified structure.
  92 + * @param addr The generic address
  93 + * @throws std::invalid_argument if the address is not a UNIX-domain
  94 + * address (i.e. family is not AF_UNIX)
  95 + */
  96 + explicit unix_address(const sockaddr& addr);
  97 + /**
  98 + * Constructs the address by copying the specified structure.
  99 + * @param addr The other address
  100 + */
  101 + unix_address(const sock_address& addr) {
  102 + std::memcpy(&addr_, addr.sockaddr_ptr(), SZ);
  103 + }
  104 + /**
  105 + * Constructs the address by copying the specified structure.
  106 + * @param addr The other address
  107 + * @throws std::invalid_argument if the address is not properly
  108 + * initialized as a UNIX-domain address (i.e. family is not
  109 + * AF_UNIX)
  110 + */
  111 + unix_address(const sockaddr_un& addr) : addr_(addr) {}
  112 + /**
  113 + * Constructs the address by copying the specified address.
  114 + * @param addr The other address
  115 + */
  116 + unix_address(const unix_address& addr) : addr_(addr.addr_) {}
  117 + /**
  118 + * Checks if the address is set to some value.
  119 + * This doesn't attempt to determine if the address is valid, simply
  120 + * that it's not all zero.
  121 + * @return @em true if the address has been set, @em false otherwise.
  122 + */
  123 + bool is_set() const { return addr_.sun_path[0] != '\0'; }
  124 + /**
  125 + * Gets the path to which this address refers.
  126 + * @return The path to which this address refers.
  127 + */
  128 + std::string path() const { return std::string(addr_.sun_path); }
  129 + /**
  130 + * Gets the size of the address structure.
  131 + * Note: In this implementation, this should return sizeof(this) but
  132 + * more convenient in some places, and the implementation might change
  133 + * in the future, so it might be more compatible with future revisions
  134 + * to use this call.
  135 + * @return The size of the address structure.
  136 + */
  137 + socklen_t size() const override { return socklen_t(SZ); }
  138 +
  139 + // TODO: Do we need a:
  140 + // create(path)
  141 + // to mimic the inet_address behavior?
  142 +
  143 + /**
  144 + * Gets a pointer to this object cast to a const @em sockaddr.
  145 + * @return A pointer to this object cast to a const @em sockaddr.
  146 + */
  147 + const sockaddr* sockaddr_ptr() const override {
  148 + return reinterpret_cast<const sockaddr*>(&addr_);
  149 + }
  150 + /**
  151 + * Gets a pointer to this object cast to a @em sockaddr.
  152 + * @return A pointer to this object cast to a @em sockaddr.
  153 + */
  154 + sockaddr* sockaddr_ptr() override {
  155 + return reinterpret_cast<sockaddr*>(&addr_);
  156 + }
  157 + /**
  158 + * Gets a const pointer to this object cast to a @em sockaddr_un.
  159 + * @return const sockaddr_un pointer to this object.
  160 + */
  161 + const sockaddr_un* sockaddr_un_ptr() const { return &addr_; }
  162 + /**
  163 + * Gets a pointer to this object cast to a @em sockaddr_un.
  164 + * @return sockaddr_un pointer to this object.
  165 + */
  166 + sockaddr_un* sockaddr_un_ptr() { return &addr_; }
  167 + /**
  168 + * Gets a printable string for the address.
  169 + * @return A string representation of the address in the form
  170 + * "unix:<path>"
  171 + */
  172 + std::string to_string() const {
  173 + return std::string("unix:") + std::string(addr_.sun_path);
  174 + }
  175 +};
  176 +
  177 +// --------------------------------------------------------------------------
  178 +
  179 +/**
  180 + * Stream inserter for the address.
  181 + * @param os The output stream
  182 + * @param addr The address
  183 + * @return A reference to the output stream.
  184 + */
  185 +std::ostream& operator<<(std::ostream& os, const unix_address& addr);
  186 +
  187 +/////////////////////////////////////////////////////////////////////////////
  188 +// end namespace sockpp
  189 +}
  190 +
  191 +#endif // __sockpp_unix_addr_h
  192 +
include/socket-cpp/unix_connector.h 0 โ†’ 100644
  1 +++ a/include/socket-cpp/unix_connector.h
  1 +/**
  2 + * @file unix_connector.h
  3 + *
  4 + * Class for creating client-side UNIX-domain socket connections.
  5 + *
  6 + * @author Frank Pagliughi
  7 + * @author SoRo Systems, Inc.
  8 + * @author www.sorosys.com
  9 + *
  10 + * @date December 2018
  11 + */
  12 +
  13 +// --------------------------------------------------------------------------
  14 +// This file is part of the "sockpp" C++ socket library.
  15 +//
  16 +// Copyright (c) 2014-2017 Frank Pagliughi
  17 +// All rights reserved.
  18 +//
  19 +// Redistribution and use in source and binary forms, with or without
  20 +// modification, are permitted provided that the following conditions are
  21 +// met:
  22 +//
  23 +// 1. Redistributions of source code must retain the above copyright notice,
  24 +// this list of conditions and the following disclaimer.
  25 +//
  26 +// 2. Redistributions in binary form must reproduce the above copyright
  27 +// notice, this list of conditions and the following disclaimer in the
  28 +// documentation and/or other materials provided with the distribution.
  29 +//
  30 +// 3. Neither the name of the copyright holder nor the names of its
  31 +// contributors may be used to endorse or promote products derived from this
  32 +// software without specific prior written permission.
  33 +//
  34 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  35 +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  36 +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  37 +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  38 +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  39 +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  40 +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  41 +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  42 +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  43 +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  44 +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  45 +// --------------------------------------------------------------------------
  46 +
  47 +#ifndef __sockpp_unix_connector_h
  48 +#define __sockpp_unix_connector_h
  49 +
  50 +#include "sockpp/connector.h"
  51 +#include "sockpp/unix_stream_socket.h"
  52 +
  53 +namespace sockpp {
  54 +
  55 +/////////////////////////////////////////////////////////////////////////////
  56 +
  57 +/** Unix-domain active connector socket. */
  58 +using unix_connector = connector_tmpl<unix_socket, unix_address>;
  59 +
  60 +/////////////////////////////////////////////////////////////////////////////
  61 +// end namespace sockpp
  62 +};
  63 +
  64 +#endif // __sockpp_unix_connector_h
  65 +
include/socket-cpp/unix_dgram_socket.h 0 โ†’ 100644
  1 +++ a/include/socket-cpp/unix_dgram_socket.h
  1 +/**
  2 + * @file unix_dgram_socket.h
  3 + *
  4 + * Class (typedef) for Unix-domain UDP socket.
  5 + *
  6 + * @author Frank Pagliughi
  7 + * @author SoRo Systems, Inc.
  8 + * @author www.sorosys.com
  9 + *
  10 + * @date August 2019
  11 + */
  12 +
  13 +// --------------------------------------------------------------------------
  14 +// This file is part of the "sockpp" C++ socket library.
  15 +//
  16 +// Copyright (c) 2019 Frank Pagliughi
  17 +// All rights reserved.
  18 +//
  19 +// Redistribution and use in source and binary forms, with or without
  20 +// modification, are permitted provided that the following conditions are
  21 +// met:
  22 +//
  23 +// 1. Redistributions of source code must retain the above copyright notice,
  24 +// this list of conditions and the following disclaimer.
  25 +//
  26 +// 2. Redistributions in binary form must reproduce the above copyright
  27 +// notice, this list of conditions and the following disclaimer in the
  28 +// documentation and/or other materials provided with the distribution.
  29 +//
  30 +// 3. Neither the name of the copyright holder nor the names of its
  31 +// contributors may be used to endorse or promote products derived from this
  32 +// software without specific prior written permission.
  33 +//
  34 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  35 +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  36 +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  37 +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  38 +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  39 +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  40 +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  41 +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  42 +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  43 +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  44 +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  45 +// --------------------------------------------------------------------------
  46 +
  47 +#ifndef __sockpp_unix_dgram_socket_h
  48 +#define __sockpp_unix_dgram_socket_h
  49 +
  50 +#include "sockpp/datagram_socket.h"
  51 +#include "sockpp/unix_address.h"
  52 +
  53 +namespace sockpp {
  54 +
  55 +/////////////////////////////////////////////////////////////////////////////
  56 +
  57 +/** Unix-domain datagram socket */
  58 +using unix_datagram_socket = datagram_socket_tmpl<unix_address>;
  59 +
  60 +/** Unix-domain datagram socket (same as `unix_datagram_socket`) */
  61 +using unix_dgram_socket = unix_datagram_socket;
  62 +
  63 +/////////////////////////////////////////////////////////////////////////////
  64 +// end namespace sockpp
  65 +}
  66 +
  67 +#endif // __sockpp_unix_dgram_socket_h
  68 +
include/socket-cpp/unix_stream_socket.h 0 โ†’ 100644
  1 +++ a/include/socket-cpp/unix_stream_socket.h
  1 +/**
  2 + * @file unix_stream_socket.h
  3 + *
  4 + * Class (typedef) for Unix-domain streaming socket.
  5 + *
  6 + * @author Frank Pagliughi
  7 + * @author SoRo Systems, Inc.
  8 + * @author www.sorosys.com
  9 + *
  10 + * @date August 2019
  11 + */
  12 +
  13 +// --------------------------------------------------------------------------
  14 +// This file is part of the "sockpp" C++ socket library.
  15 +//
  16 +// Copyright (c) 2019 Frank Pagliughi
  17 +// All rights reserved.
  18 +//
  19 +// Redistribution and use in source and binary forms, with or without
  20 +// modification, are permitted provided that the following conditions are
  21 +// met:
  22 +//
  23 +// 1. Redistributions of source code must retain the above copyright notice,
  24 +// this list of conditions and the following disclaimer.
  25 +//
  26 +// 2. Redistributions in binary form must reproduce the above copyright
  27 +// notice, this list of conditions and the following disclaimer in the
  28 +// documentation and/or other materials provided with the distribution.
  29 +//
  30 +// 3. Neither the name of the copyright holder nor the names of its
  31 +// contributors may be used to endorse or promote products derived from this
  32 +// software without specific prior written permission.
  33 +//
  34 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  35 +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  36 +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  37 +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  38 +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  39 +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  40 +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  41 +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  42 +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  43 +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  44 +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  45 +// --------------------------------------------------------------------------
  46 +
  47 +#ifndef __sockpp_unix_stream_socket_h
  48 +#define __sockpp_unix_stream_socket_h
  49 +
  50 +#include "sockpp/stream_socket.h"
  51 +#include "sockpp/unix_address.h"
  52 +
  53 +namespace sockpp {
  54 +
  55 +/////////////////////////////////////////////////////////////////////////////
  56 +
  57 +/** Streaming Unix-domain socket */
  58 +using unix_stream_socket = stream_socket_tmpl<unix_address>;
  59 +
  60 +/** Streaming Unix-domain socket (same as a `unix_stream_socket` */
  61 +using unix_socket = unix_stream_socket;
  62 +
  63 +/////////////////////////////////////////////////////////////////////////////
  64 +// end namespace sockpp
  65 +}
  66 +
  67 +#endif // __sockpp_unix_stream_socket_h
  68 +
scripts/setup_submodules 0 โ†’ 100755
  1 +++ a/scripts/setup_submodules
  1 +#!/bin/bash
  2 +
  3 +# ===============================================
  4 +# == Setting some environment variables
  5 +# ===============================================
  6 +GIT_URL_SUBS="http://gitlab.osdev.nl/open_source"
  7 +FUNC_RESULT="-1"
  8 +
  9 +# Name : print_usage_exit()
  10 +# Description : Print the way this script is intended to be used and exit.
  11 +# Parameters : None.
  12 +# Returns : err_code 1 to the Operating System
  13 +# --------------------------------------------------------------------------------------
  14 +function print_usage_exit()
  15 +{
  16 + echo "Usage $0 -i|--install|-u|--update"
  17 + echo " -i or --install Install the submodules mentioned in the submodules.list"
  18 + echo " -u or --update Update the submodules mentioned in the submodules.list"
  19 + echo " "
  20 + exit 1
  21 +}
  22 +
  23 +# Name : check_top_or_sub
  24 +# Description : Determine if we're running in a "single" lib-build or part of a
  25 +# "meta"-repository ( submodule ).
  26 +# Parameters : None
  27 +# Returns : Updates the value FUNC_RESULT.
  28 +# -1 - We're neither a git-repo or submodule.
  29 +# 0 - We're a submodule
  30 +# 1 - We're a top-repo ( Single library )
  31 +# --------------------------------------------------------------------------------------
  32 +function check_top_or_sub()
  33 +{
  34 + # This function checks if we're the top-repository.
  35 + # In that case we need the submodules.. If we're already a submodule,
  36 + # we simply exit this script with a message
  37 + if [ -e ./.git ]; then
  38 + FUNC_RESULT="1"
  39 + return
  40 + elif [ -e ../.git ]; then
  41 + if [ -e ../.submodules ]; then
  42 + echo "Seems like we're already a submodule. Nothing to do here."
  43 + FUNC_RESULT="0"
  44 + return
  45 + fi
  46 + fi
  47 + FUNC_RESULT="-1"
  48 + return
  49 +}
  50 +
  51 +# Name : check_working_dir
  52 +# Description : If we're in the top of our repo, we can run this script further.
  53 +# Parameters : None.
  54 +# Returns : Updates the value FUNC_RESULT.
  55 +# -1 - Not used.
  56 +# 0 - We're not on the top-level
  57 +# 1 - We're at the top-level. Good to go.
  58 +# --------------------------------------------------------------------------------------
  59 +function check_working_dir()
  60 +{
  61 + FUNC_RESULT="-1"
  62 + # Check if we're in the top-level directory of our repository.
  63 + if [ -f ./scripts/submodules.list ]; then
  64 + # We're good to go
  65 + FUNC_RESULT="1"
  66 + return
  67 + fi
  68 + FUNC_RESULT="0"
  69 + return
  70 +}
  71 +
  72 +# Name : read_submodules
  73 +# Description : Read the list of submodules needed for this project
  74 +# Parameters : None
  75 +# Returns : Updates the value FUNC_RESULT
  76 +# 0 - Module list was not found
  77 +# 1 - Module list was found and read.
  78 +# --------------------------------------------------------------------------------------
  79 +function read_submodules()
  80 +{
  81 + FUNC_RESULT="-1"
  82 + if [ -e ./scripts/submodules.list ]; then
  83 + source ./scripts/submodules.list
  84 + FUNC_RESULT="1"
  85 + return
  86 + fi
  87 +
  88 + echo "Submodules list not found...."
  89 + FUNC_RESULT="0"
  90 + return
  91 +}
  92 +
  93 +# Name : add_submodules
  94 +# Description : Configure the repo to add the submodules.
  95 +# Parameters : None.
  96 +# Returns : None.
  97 +# --------------------------------------------------------------------------------------
  98 +function add_submodules()
  99 +{
  100 + echo -e "Adding SubModule(s)."
  101 + for SUB_MODULE in ${SUB_MODULES}
  102 + do
  103 + echo -e "< ${SUB_MODULE} >"
  104 + git submodule add -f ${GIT_URL_SUBS}/${SUB_MODULE}.git ${SUB_MODULE}
  105 + git config submodule.${SUB_MODULE}.url ${GIT_URL_SUBS}/${SUB_MODULE}.git
  106 + done
  107 +}
  108 +
  109 +# Name : get_submodules
  110 +# Description : Actually get the submodules from gitlab and add them.
  111 +# Parameters : None
  112 +# Returns : None
  113 +# --------------------------------------------------------------------------------------
  114 +function get_submodules()
  115 +{
  116 + git submodule update --init --recursive
  117 +}
  118 +
  119 +# Name : update_submodules
  120 +# Description : Update the submodules already added.
  121 +# Parameters : None
  122 +# Returns : None
  123 +# --------------------------------------------------------------------------------------
  124 +function update_submodules()
  125 +{
  126 + git submodule update --recursive
  127 +}
  128 +
  129 +# =============================================================================
  130 +# == T H E M A I N E N T R Y O F T H I S S C R I P T ==
  131 +# =============================================================================
  132 +check_top_or_sub
  133 +if [ "${FUNC_RESULT}" == "0" ]; then
  134 + echo "Seems like we're a submodule already or not part of a repository."
  135 + exit 0
  136 +fi
  137 +
  138 +check_working_dir
  139 +if [ "${FUNC_RESULT}" == "0" ]; then
  140 + echo "Go to the top of this repository and type : scripts/setup_submodules [-i|--install]"
  141 + exit 0
  142 +fi
  143 +
  144 +read_submodules
  145 +
  146 +case "$1" in
  147 + -i*|--install*)
  148 + echo "Installing submodules for this repository ( ${PWD} )"
  149 + add_submodules
  150 + get_submodules
  151 + ;;
  152 + -u*|--update*)
  153 + echo "Update submodules : ${SUB_MODULES}"
  154 + update_submodules
  155 + ;;
  156 + *)
  157 + echo "No parameters found..."
  158 + print_usage_exit
  159 + ;;
  160 +esac
  161 +
scripts/submodules.list 0 โ†’ 100644
  1 +++ a/scripts/submodules.list
  1 +SUB_MODULES="versioning
  2 +cmake"
src/acceptor.cpp 0 โ†’ 100644
  1 +++ a/src/acceptor.cpp
  1 +#include <cstring>
  2 +#include "sockpp/acceptor.h"
  3 +
  4 +using namespace std;
  5 +
  6 +namespace sockpp {
  7 +
  8 +/////////////////////////////////////////////////////////////////////////////
  9 +
  10 +acceptor acceptor::create(int domain)
  11 +{
  12 + acceptor acc(create_handle(domain));
  13 + if (!acc)
  14 + acc.clear(get_last_error());
  15 + return acc;
  16 +}
  17 +
  18 +// --------------------------------------------------------------------------
  19 +
  20 +// This attempts to open the acceptor, bind to the requested address, and
  21 +// start listening. On any error it will be sure to leave the underlying
  22 +// socket in an unopened/invalid state.
  23 +// If the acceptor appears to already be opened, this will quietly succeed
  24 +// without doing anything.
  25 +
  26 +bool acceptor::open(const sock_address& addr,
  27 + int queSize /*=DFLT_QUE_SIZE*/,
  28 + bool reuseSock /*=true*/)
  29 +{
  30 + // TODO: What to do if we are open but bound to a different address?
  31 + if (is_open())
  32 + return true;
  33 +
  34 + sa_family_t domain = addr.family();
  35 + socket_t h = create_handle(domain);
  36 +
  37 + if (!check_socket_bool(h))
  38 + return false;
  39 +
  40 + reset(h);
  41 +
  42 + #if defined(_WIN32)
  43 + const int REUSE = SO_REUSEADDR;
  44 + #else
  45 + const int REUSE = SO_REUSEPORT;
  46 + #endif
  47 +
  48 + if (reuseSock && (domain == AF_INET || domain == AF_INET6)) {
  49 + int reuse = 1;
  50 + if (!set_option(SOL_SOCKET, REUSE, reuse))
  51 + return close_on_err();
  52 + }
  53 +
  54 + if (!bind(addr) || !listen(queSize))
  55 + return close_on_err();
  56 +
  57 + return true;
  58 +}
  59 +
  60 +// --------------------------------------------------------------------------
  61 +
  62 +stream_socket acceptor::accept(sock_address* clientAddr /*=nullptr*/)
  63 +{
  64 + sockaddr* p = clientAddr ? clientAddr->sockaddr_ptr() : nullptr;
  65 + socklen_t len = clientAddr ? clientAddr->size() : 0;
  66 +
  67 + socket_t s = check_socket(::accept(handle(), p, clientAddr ? &len : nullptr));
  68 + return stream_socket(s);
  69 +}
  70 +
  71 +/////////////////////////////////////////////////////////////////////////////
  72 +// end namespace sockpp
  73 +}
  74 +
src/connector.cpp 0 โ†’ 100644
  1 +++ a/src/connector.cpp
  1 +#include "sockpp/connector.h"
  2 +
  3 +namespace sockpp {
  4 +
  5 +bool connector::connect(const sock_address& addr)
  6 +{
  7 + sa_family_t domain = addr.family();
  8 + socket_t h = create_handle(domain);
  9 +
  10 + if (!check_ret_bool(h))
  11 + return false;
  12 +
  13 + // This will close the old connection, if any.
  14 + reset(h);
  15 +
  16 + if (!check_ret_bool(::connect(h, addr.sockaddr_ptr(), addr.size())))
  17 + return close_on_err();
  18 +
  19 + return true;
  20 +}
  21 +
  22 +}
  23 +
src/datagram_socket.cpp 0 โ†’ 100644
  1 +++ a/src/datagram_socket.cpp
  1 +#include "sockpp/datagram_socket.h"
  2 +#include "sockpp/exception.h"
  3 +#include <algorithm>
  4 +
  5 +using namespace std::chrono;
  6 +
  7 +namespace sockpp {
  8 +
  9 +datagram_socket::datagram_socket(const sock_address& addr)
  10 +{
  11 + auto domain = addr.family();
  12 + socket_t h = create_handle(domain);
  13 +
  14 + if (check_socket_bool(h)) {
  15 + reset(h);
  16 + // TODO: If the bind fails, should we close the socket and fail completely?
  17 + bind(addr);
  18 + }
  19 +}
  20 +
  21 +ssize_t datagram_socket::recv_from(void* buf, size_t n, int flags,
  22 + sock_address* srcAddr /*=nullptr*/)
  23 +{
  24 + sockaddr* p = srcAddr ? srcAddr->sockaddr_ptr() : nullptr;
  25 + socklen_t len = srcAddr ? srcAddr->size() : 0;
  26 +
  27 + // TODO: Check returned length
  28 + #if defined(_WIN32)
  29 + return check_ret(::recvfrom(handle(), reinterpret_cast<char*>(buf),
  30 + int(n), flags, p, &len));
  31 + #else
  32 + return check_ret(::recvfrom(handle(), buf, n, flags, p, &len));
  33 + #endif
  34 +}
  35 +
  36 +
  37 +}
  38 +
src/exception.cpp 0 โ†’ 100644
  1 +++ a/src/exception.cpp
  1 +#include "sockpp/exception.h"
  2 +#include "sockpp/platform.h"
  3 +#include <cstring>
  4 +
  5 +// Used to explicitly ignore the returned value of a function call.
  6 +#define ignore_result(x) if (x) {}
  7 +
  8 +using namespace std;
  9 +
  10 +namespace sockpp {
  11 +
  12 +sys_error::sys_error(int err) : runtime_error(error_str(err)), errno_(err)
  13 +{
  14 +}
  15 +
  16 +std::string sys_error::error_str(int err)
  17 +{
  18 + char buf[1024];
  19 + buf[0] = '\x0';
  20 +
  21 + #if defined(_WIN32)
  22 + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
  23 + NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  24 + buf, sizeof(buf), NULL);
  25 + #else
  26 + #ifdef _GNU_SOURCE
  27 + #if !defined(__GLIBC__)
  28 + // use the XSI standard behavior.
  29 + int e = strerror_r(err, buf, sizeof(buf));
  30 + auto s = strerror(e);
  31 + return s ? std::string(s) : std::string();
  32 + #else
  33 + // assume GNU exception
  34 + auto s = strerror_r(err, buf, sizeof(buf));
  35 + return s ? std::string(s) : std::string();
  36 + #endif
  37 + #else
  38 + ignore_result(strerror_r(err, buf, sizeof(buf)));
  39 + #endif
  40 + #endif
  41 + return std::string(buf);
  42 +}
  43 +
  44 +getaddrinfo_error::getaddrinfo_error(int err, const string& hostname)
  45 + : runtime_error(gai_strerror(err)), error_(err), hostname_(hostname)
  46 +{
  47 +}
  48 +
  49 +}
  50 +
src/inet6_address.cpp 0 โ†’ 100644
  1 +++ a/src/inet6_address.cpp
  1 +#include "sockpp/inet6_address.h"
  2 +#include "sockpp/exception.h"
  3 +
  4 +using namespace std;
  5 +
  6 +namespace sockpp {
  7 +
  8 +bool inet6_address::is_set() const
  9 +{
  10 + static const auto EMPTY_ADDR = sockaddr_in6{};
  11 + return std::memcmp(&addr_, &EMPTY_ADDR, SZ) != 0;
  12 +}
  13 +
  14 +in6_addr inet6_address::resolve_name(const string& saddr)
  15 +{
  16 + #if !defined(_WIN32)
  17 + in6_addr ia;
  18 + if (::inet_pton(ADDRESS_FAMILY, saddr.c_str(), &ia) == 1)
  19 + return ia;
  20 + #endif
  21 +
  22 + addrinfo *res, hints = addrinfo{};
  23 + hints.ai_family = ADDRESS_FAMILY;
  24 + hints.ai_socktype = SOCK_STREAM;
  25 +
  26 + int gai_err = ::getaddrinfo(saddr.c_str(), NULL, &hints, &res);
  27 +
  28 + #if !defined(_WIN32)
  29 + if (gai_err == EAI_SYSTEM)
  30 + throw sys_error();
  31 + #endif
  32 +
  33 + if (gai_err != 0)
  34 + throw getaddrinfo_error(gai_err, saddr);
  35 +
  36 +
  37 + auto ipv6 = reinterpret_cast<sockaddr_in6*>(res->ai_addr);
  38 + auto addr = ipv6->sin6_addr;
  39 + freeaddrinfo(res);
  40 + return addr;
  41 +}
  42 +
  43 +void inet6_address::create(const in6_addr& addr, in_port_t port)
  44 +{
  45 + addr_ = sockaddr_in6{};
  46 + addr_.sin6_family = AF_INET6;
  47 + addr_.sin6_flowinfo = 0;
  48 + addr_.sin6_addr = addr;
  49 + addr_.sin6_port = htons(port);
  50 +}
  51 +
  52 +void inet6_address::create(const string& saddr, in_port_t port)
  53 +{
  54 + addr_ = sockaddr_in6{};
  55 + addr_.sin6_family = AF_INET6;
  56 + addr_.sin6_flowinfo = 0;
  57 + addr_.sin6_addr = resolve_name(saddr.c_str());
  58 + addr_.sin6_port = htons(port);
  59 +}
  60 +
  61 +string inet6_address::to_string() const
  62 +{
  63 + char buf[INET6_ADDRSTRLEN];
  64 + auto str = inet_ntop(AF_INET6, (void*) &(addr_.sin6_addr),
  65 + buf, INET6_ADDRSTRLEN);
  66 + return std::string("[") + std::string(str ? str : "<unknown>")
  67 + + "]:" + std::to_string(unsigned(port()));
  68 +}
  69 +
  70 +ostream& operator<<(ostream& os, const inet6_address& addr)
  71 +{
  72 + char buf[INET6_ADDRSTRLEN];
  73 + auto str = inet_ntop(AF_INET6, (void*) &(addr.sockaddr_in6_ptr()->sin6_addr),
  74 + buf, INET6_ADDRSTRLEN);
  75 + os << "[" << (str ? str : "<unknown>") << "]:" << unsigned(addr.port());
  76 + return os;
  77 +}
  78 +
  79 +}
  80 +
src/inet_address.cpp 0 โ†’ 100644
  1 +++ a/src/inet_address.cpp
  1 +#include "sockpp/inet_address.h"
  2 +#include "sockpp/exception.h"
  3 +
  4 +using namespace std;
  5 +
  6 +namespace sockpp {
  7 +
  8 +bool inet_address::is_set() const
  9 +{
  10 + static const auto EMPTY_ADDR = sockaddr_in{};
  11 + return std::memcmp(&addr_, &EMPTY_ADDR, SZ) != 0;
  12 +}
  13 +
  14 +in_addr_t inet_address::resolve_name(const std::string& saddr)
  15 +{
  16 + #if !defined(_WIN32)
  17 + in_addr ia;
  18 + if (::inet_pton(ADDRESS_FAMILY, saddr.c_str(), &ia) == 1)
  19 + return ia.s_addr;
  20 + #endif
  21 +
  22 + addrinfo *res, hints = addrinfo{};
  23 + hints.ai_family = ADDRESS_FAMILY;
  24 + hints.ai_socktype = SOCK_STREAM;
  25 +
  26 + int gai_err = ::getaddrinfo(saddr.c_str(), NULL, &hints, &res);
  27 +
  28 + #if !defined(_WIN32)
  29 + if (gai_err == EAI_SYSTEM)
  30 + throw sys_error();
  31 + #endif
  32 +
  33 + if (gai_err != 0)
  34 + throw getaddrinfo_error(gai_err, saddr);
  35 +
  36 + auto ipv4 = reinterpret_cast<sockaddr_in*>(res->ai_addr);
  37 + auto addr = ipv4->sin_addr.s_addr;
  38 + freeaddrinfo(res);
  39 + return addr;
  40 +}
  41 +
  42 +void inet_address::create(uint32_t addr, in_port_t port)
  43 +{
  44 + addr_ = sockaddr_in{};
  45 + addr_.sin_family = AF_INET;
  46 + addr_.sin_addr.s_addr = htonl(addr);
  47 + addr_.sin_port = htons(port);
  48 +}
  49 +
  50 +void inet_address::create(const std::string& saddr, in_port_t port)
  51 +{
  52 + addr_ = sockaddr_in{};
  53 + addr_.sin_family = AF_INET;
  54 + addr_.sin_addr.s_addr = resolve_name(saddr.c_str());
  55 + addr_.sin_port = htons(port);
  56 +}
  57 +
  58 +string inet_address::to_string() const
  59 +{
  60 + char buf[INET_ADDRSTRLEN];
  61 + auto str = inet_ntop(AF_INET, (void*) &(addr_.sin_addr), buf, INET_ADDRSTRLEN);
  62 + return std::string(str ? str : "<unknown>")
  63 + + ":" + std::to_string(unsigned(port()));
  64 +}
  65 +
  66 +ostream& operator<<(ostream& os, const inet_address& addr)
  67 +{
  68 + char buf[INET_ADDRSTRLEN];
  69 + auto str = inet_ntop(AF_INET, (void*) &(addr.sockaddr_in_ptr()->sin_addr),
  70 + buf, INET_ADDRSTRLEN);
  71 + os << (str ? str : "<unknown>") << ":" << unsigned(addr.port());
  72 + return os;
  73 +}
  74 +
  75 +}
src/linux/can_address.cpp 0 โ†’ 100644
  1 +++ a/src/linux/can_address.cpp
  1 +// can_address.cpp
  2 +//
  3 +// --------------------------------------------------------------------------
  4 +// This file is part of the "sockpp" C++ socket library.
  5 +//
  6 +// Copyright (c) 2014-2021 Frank Pagliughi
  7 +// All rights reserved.
  8 +//
  9 +// Redistribution and use in source and binary forms, with or without
  10 +// modification, are permitted provided that the following conditions are
  11 +// met:
  12 +//
  13 +// 1. Redistributions of source code must retain the above copyright notice,
  14 +// this list of conditions and the following disclaimer.
  15 +//
  16 +// 2. Redistributions in binary form must reproduce the above copyright
  17 +// notice, this list of conditions and the following disclaimer in the
  18 +// documentation and/or other materials provided with the distribution.
  19 +//
  20 +// 3. Neither the name of the copyright holder nor the names of its
  21 +// contributors may be used to endorse or promote products derived from this
  22 +// software without specific prior written permission.
  23 +//
  24 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  25 +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  26 +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  27 +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  28 +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  29 +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  30 +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  31 +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  32 +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  33 +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  34 +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  35 +// --------------------------------------------------------------------------
  36 +
  37 +#include "sockpp/can_address.h"
  38 +#include "sockpp/socket.h"
  39 +#include <cstring>
  40 +#include <stdexcept>
  41 +#include <sys/ioctl.h>
  42 +#include <net/if.h>
  43 +
  44 +using namespace std;
  45 +
  46 +namespace sockpp {
  47 +
  48 +/////////////////////////////////////////////////////////////////////////////
  49 +
  50 +constexpr sa_family_t can_address::ADDRESS_FAMILY;
  51 +
  52 +// --------------------------------------------------------------------------
  53 +
  54 +can_address::can_address(unsigned ifindex) : addr_{}
  55 +{
  56 + addr_.can_family = AF_CAN;
  57 + addr_.can_ifindex = ifindex;
  58 +}
  59 +
  60 +can_address::can_address(const string& iface) : addr_{}
  61 +{
  62 + unsigned idx = if_nametoindex(iface.c_str());
  63 +
  64 + if (idx != 0) {
  65 + addr_.can_family = AF_CAN;
  66 + addr_.can_ifindex = idx;
  67 + }
  68 +}
  69 +
  70 +can_address::can_address(const sockaddr& addr)
  71 +{
  72 + auto domain = addr.sa_family;
  73 + if (domain != AF_CAN)
  74 + throw std::invalid_argument("Not a SocketCAN address");
  75 +
  76 + std::memcpy(&addr_, &addr, sizeof(sockaddr));
  77 +}
  78 +
  79 +string can_address::iface() const
  80 +{
  81 + if (addr_.can_family == AF_UNSPEC)
  82 + return string("none");
  83 +
  84 + if (addr_.can_ifindex == 0)
  85 + return string("any");
  86 +
  87 + char buf[IF_NAMESIZE];
  88 + const char* iface = if_indextoname(addr_.can_ifindex, buf);
  89 +
  90 + return string(iface ? iface : "unknown");
  91 +}
  92 +
  93 +
  94 +// --------------------------------------------------------------------------
  95 +
  96 +ostream& operator<<(ostream& os, const can_address& addr)
  97 +{
  98 + os << "can:" << addr.iface();
  99 + return os;
  100 +}
  101 +
  102 +/////////////////////////////////////////////////////////////////////////////
  103 +// End namespace sockpp
  104 +}
src/linux/can_socket.cpp 0 โ†’ 100644
  1 +++ a/src/linux/can_socket.cpp
  1 +// can_socket.cpp
  2 +//
  3 +// --------------------------------------------------------------------------
  4 +// This file is part of the "sockpp" C++ socket library.
  5 +//
  6 +// Copyright (c) 2021 Frank Pagliughi
  7 +// All rights reserved.
  8 +//
  9 +// Redistribution and use in source and binary forms, with or without
  10 +// modification, are permitted provided that the following conditions are
  11 +// met:
  12 +//
  13 +// 1. Redistributions of source code must retain the above copyright notice,
  14 +// this list of conditions and the following disclaimer.
  15 +//
  16 +// 2. Redistributions in binary form must reproduce the above copyright
  17 +// notice, this list of conditions and the following disclaimer in the
  18 +// documentation and/or other materials provided with the distribution.
  19 +//
  20 +// 3. Neither the name of the copyright holder nor the names of its
  21 +// contributors may be used to endorse or promote products derived from this
  22 +// software without specific prior written permission.
  23 +//
  24 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  25 +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  26 +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  27 +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  28 +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  29 +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  30 +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  31 +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  32 +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  33 +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  34 +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  35 +// --------------------------------------------------------------------------
  36 +
  37 +#include "sockpp/can_socket.h"
  38 +#include "sockpp/socket.h"
  39 +#include <sys/ioctl.h>
  40 +
  41 +using namespace std;
  42 +using namespace std::chrono;
  43 +
  44 +namespace sockpp {
  45 +
  46 +/////////////////////////////////////////////////////////////////////////////
  47 +
  48 +can_socket::can_socket(const can_address& addr)
  49 +{
  50 + socket_t h = create_handle(SOCK_RAW, CAN_RAW);
  51 +
  52 + if (check_socket_bool(h)) {
  53 + reset(h);
  54 + bind(addr);
  55 + }
  56 +}
  57 +
  58 +system_clock::time_point can_socket::last_frame_time()
  59 +{
  60 + timeval tv {};
  61 +
  62 + // TODO: Handle error
  63 + ::ioctl(handle(), SIOCGSTAMP, &tv);
  64 + return to_timepoint(tv);
  65 +}
  66 +
  67 +double can_socket::last_frame_timestamp()
  68 +{
  69 + timeval tv {};
  70 +
  71 + // TODO: Handle error
  72 + ::ioctl(handle(), SIOCGSTAMP, &tv);
  73 + return double(tv.tv_sec) + 1.0e-6 * tv.tv_usec;
  74 +}
  75 +
  76 +
  77 +// --------------------------------------------------------------------------
  78 +
  79 +ssize_t can_socket::recv_from(can_frame *frame, int flags,
  80 + can_address* srcAddr /*=nullptr*/)
  81 +{
  82 + sockaddr* p = srcAddr ? srcAddr->sockaddr_ptr() : nullptr;
  83 + socklen_t len = srcAddr ? srcAddr->size() : 0;
  84 +
  85 + // TODO: Check returned length
  86 + return check_ret(::recvfrom(handle(), frame, sizeof(can_frame),
  87 + flags, p, &len));
  88 +}
  89 +
  90 +/////////////////////////////////////////////////////////////////////////////
  91 +// End namespace sockpp
  92 +}
src/socket.cpp 0 โ†’ 100644
  1 +++ a/src/socket.cpp
  1 +#include "sockpp/socket.h"
  2 +#include "sockpp/exception.h"
  3 +#include <algorithm>
  4 +#include <cstring>
  5 +#include <fcntl.h>
  6 +
  7 +// Used to explicitly ignore the returned value of a function call.
  8 +#define ignore_result(x) if (x) {}
  9 +
  10 +using namespace std::chrono;
  11 +
  12 +namespace sockpp {
  13 +
  14 +timeval to_timeval(const microseconds& dur)
  15 +{
  16 + const seconds sec = duration_cast<seconds>(dur);
  17 +
  18 + timeval tv;
  19 + #if defined(_WIN32)
  20 + tv.tv_sec = long(sec.count());
  21 + #else
  22 + tv.tv_sec = time_t(sec.count());
  23 + #endif
  24 + tv.tv_usec = suseconds_t(duration_cast<microseconds>(dur - sec).count());
  25 + return tv;
  26 +}
  27 +
  28 +int socket::get_last_error()
  29 +{
  30 + #if defined(_WIN32)
  31 + return ::WSAGetLastError();
  32 + #else
  33 + int err = errno;
  34 + return err;
  35 + #endif
  36 +}
  37 +
  38 +bool socket::close(socket_t h)
  39 +{
  40 + #if defined(_WIN32)
  41 + return ::closesocket(h) >= 0;
  42 + #else
  43 + return ::close(h) >= 0;
  44 + #endif
  45 +}
  46 +
  47 +void socket::initialize()
  48 +{
  49 + #if defined(_WIN32)
  50 + WSADATA wsadata;
  51 + ::WSAStartup(MAKEWORD(2, 0), &wsadata);
  52 + #else
  53 + // Don't signal on socket write errors.
  54 + ::signal(SIGPIPE, SIG_IGN);
  55 + #endif
  56 +}
  57 +
  58 +void socket::destroy()
  59 +{
  60 + #if defined(_WIN32)
  61 + ::WSACleanup();
  62 + #endif
  63 +}
  64 +
  65 +socket socket::create(int domain, int type, int protocol /*=0*/)
  66 +{
  67 + socket sock(::socket(domain, type, protocol));
  68 + if (!sock)
  69 + sock.clear(get_last_error());
  70 + return sock;
  71 +}
  72 +
  73 +socket socket::clone() const
  74 +{
  75 + socket_t h = INVALID_SOCKET;
  76 + #if defined(_WIN32)
  77 + WSAPROTOCOL_INFO protInfo;
  78 + if (::WSADuplicateSocket(handle_, ::GetCurrentProcessId(), &protInfo) == 0)
  79 + h = ::WSASocket(AF_INET, SOCK_STREAM, 0, &protInfo, 0, WSA_FLAG_OVERLAPPED);
  80 + // TODO: Set lastErr_ on failure
  81 + #else
  82 + h = ::dup(handle_);
  83 + #endif
  84 +
  85 + return socket(h);
  86 +}
  87 +
  88 +std::tuple<socket, socket> socket::pair(int domain, int type, int protocol /*=0*/)
  89 +{
  90 + socket sock0, sock1;
  91 +
  92 + #if !defined(_WIN32)
  93 + int sv[2];
  94 + int ret = ::socketpair(domain, type, protocol, sv);
  95 +
  96 + if (ret == 0) {
  97 + sock0.reset(sv[0]);
  98 + sock1.reset(sv[1]);
  99 + }
  100 + else {
  101 + int err = get_last_error();
  102 + sock0.clear(err);
  103 + sock1.clear(err);
  104 + }
  105 + #else
  106 + sock0.clear(ENOTSUP);
  107 + sock1.clear(ENOTSUP);
  108 + #endif
  109 +
  110 + // TODO: Should we set an "unsupported" error on Windows?
  111 +
  112 + return std::make_tuple<socket, socket>(std::move(sock0), std::move(sock1));
  113 +}
  114 +
  115 +void socket::reset(socket_t h /*=INVALID_SOCKET*/)
  116 +{
  117 + socket_t oh = handle_;
  118 + handle_ = h;
  119 + if (oh != INVALID_SOCKET)
  120 + close(oh);
  121 + clear();
  122 +}
  123 +
  124 +bool socket::bind(const sock_address& addr)
  125 +{
  126 + return check_ret_bool(::bind(handle_, addr.sockaddr_ptr(), addr.size()));
  127 +}
  128 +
  129 +sock_address_any socket::address() const
  130 +{
  131 + auto addrStore = sockaddr_storage{};
  132 + socklen_t len = sizeof(sockaddr_storage);
  133 +
  134 + if (!check_ret_bool(::getsockname(handle_,
  135 + reinterpret_cast<sockaddr*>(&addrStore), &len)))
  136 + return sock_address_any{};
  137 +
  138 + return sock_address_any(addrStore, len);
  139 +}
  140 +
  141 +sock_address_any socket::peer_address() const
  142 +{
  143 + auto addrStore = sockaddr_storage{};
  144 + socklen_t len = sizeof(sockaddr_storage);
  145 +
  146 + if (!check_ret_bool(::getpeername(handle_,
  147 + reinterpret_cast<sockaddr*>(&addrStore), &len)))
  148 + return sock_address_any{};
  149 +
  150 + return sock_address_any(addrStore, len);
  151 +}
  152 +
  153 +bool socket::get_option(int level, int optname, void* optval, socklen_t* optlen) const
  154 +{
  155 + #if defined(_WIN32)
  156 + if (optval && optlen) {
  157 + int len = static_cast<int>(*optlen);
  158 + if (check_ret_bool(::getsockopt(handle_, level, optname,
  159 + static_cast<char*>(optval), &len))) {
  160 + *optlen = static_cast<socklen_t>(len);
  161 + return true;
  162 + }
  163 + }
  164 + return false;
  165 + #else
  166 + return check_ret_bool(::getsockopt(handle_, level, optname, optval, optlen));
  167 + #endif
  168 +}
  169 +
  170 +bool socket::set_option(int level, int optname, const void* optval, socklen_t optlen)
  171 +{
  172 + #if defined(_WIN32)
  173 + return check_ret_bool(::setsockopt(handle_, level, optname,
  174 + static_cast<const char*>(optval),
  175 + static_cast<int>(optlen)));
  176 + #else
  177 + return check_ret_bool(::setsockopt(handle_, level, optname, optval, optlen));
  178 + #endif
  179 +}
  180 +
  181 +bool socket::set_non_blocking(bool on /*=true*/)
  182 +{
  183 + #if defined(_WIN32)
  184 + unsigned long mode = on ? 1 : 0;
  185 + return check_ret_bool(::ioctlsocket(handle_, FIONBIO, &mode));
  186 + #else
  187 + /**
  188 + * TODO: Consider a generic function:
  189 + * bool set_flag(int flag, bool on=true);
  190 + * Used like:
  191 + * set_flag(O_NONBLOCK, on);
  192 + */
  193 + int flags = ::fcntl(handle_, F_GETFL, 0);
  194 +
  195 + if (flags == -1) {
  196 + set_last_error();
  197 + return false;
  198 + }
  199 + flags = on ? (flags | O_NONBLOCK) : (flags & ~O_NONBLOCK);
  200 +
  201 + if (::fcntl(handle_, F_SETFL, flags) == -1) {
  202 + set_last_error();
  203 + return false;
  204 + }
  205 + return true;
  206 + #endif
  207 +}
  208 +
  209 +std::string socket::error_str(int err)
  210 +{
  211 + return sys_error::error_str(err);
  212 +}
  213 +
  214 +bool socket::shutdown(int how /*=SHUT_RDWR*/)
  215 +{
  216 + return check_ret_bool(::shutdown(handle_, how));
  217 +}
  218 +
  219 +bool socket::close()
  220 +{
  221 + if (handle_ != INVALID_SOCKET) {
  222 + if (!close(release())){
  223 + set_last_error();
  224 + return false;
  225 + }
  226 + }
  227 + return true;
  228 +}
  229 +
  230 +}
  231 +
src/stream_socket.cpp 0 โ†’ 100644
  1 +++ a/src/stream_socket.cpp
  1 +#include "socket-cpp/stream_socket.h"
  2 +#include "socket-cpp/exception.h"
  3 +#include <algorithm>
  4 +#include <memory>
  5 +
  6 +using namespace std::chrono;
  7 +
  8 +namespace socket-cpp {
  9 +
  10 +stream_socket stream_socket::create(int domain, int protocol /*=0*/)
  11 +{
  12 + stream_socket sock(::socket(domain, COMM_TYPE, protocol));
  13 + if (!sock)
  14 + sock.clear(get_last_error());
  15 + return sock;
  16 +}
  17 +
  18 +ssize_t stream_socket::read(void *buf, size_t n)
  19 +{
  20 + #if defined(_WIN32)
  21 + return check_ret(::recv(handle(), reinterpret_cast<char*>(buf),
  22 + int(n), 0));
  23 + #else
  24 + return check_ret(::recv(handle(), buf, n, 0));
  25 + #endif
  26 +}
  27 +
  28 +ssize_t stream_socket::read_n(void *buf, size_t n)
  29 +{
  30 + size_t nr = 0;
  31 + ssize_t nx = 0;
  32 +
  33 + uint8_t *b = reinterpret_cast<uint8_t*>(buf);
  34 +
  35 + while (nr < n) {
  36 + if ((nx = read(b+nr, n-nr)) < 0 && last_error() == EINTR)
  37 + continue;
  38 +
  39 + if (nx <= 0)
  40 + break;
  41 +
  42 + nr += nx;
  43 + }
  44 +
  45 + return (nr == 0 && nx < 0) ? nx : ssize_t(nr);
  46 +}
  47 +
  48 +
  49 +ssize_t stream_socket::read(const std::vector<iovec>& ranges)
  50 +{
  51 + if (ranges.empty())
  52 + return 0;
  53 +
  54 + #if !defined(_WIN32)
  55 + return check_ret(::readv(handle(), ranges.data(), int(ranges.size())));
  56 + #else
  57 + std::vector<WSABUF> bufs;
  58 + for (const auto& iovec : ranges) {
  59 + bufs.push_back({
  60 + static_cast<ULONG>(iovec.iov_len),
  61 + static_cast<CHAR*>(iovec.iov_base)
  62 + });
  63 + }
  64 +
  65 + DWORD flags = 0,
  66 + nread = 0,
  67 + nbuf = DWORD(bufs.size());
  68 +
  69 + auto ret = check_ret(::WSARecv(handle(), bufs.data(), nbuf, &nread, &flags, nullptr, nullptr));
  70 + return ssize_t(ret == SOCKET_ERROR ? ret : nread);
  71 + #endif
  72 +}
  73 +
  74 +bool stream_socket::read_timeout(const microseconds& to)
  75 +{
  76 + auto tv =
  77 + #if defined(_WIN32)
  78 + DWORD(duration_cast<milliseconds>(to).count());
  79 + #else
  80 + to_timeval(to);
  81 + #endif
  82 + return set_option(SOL_SOCKET, SO_RCVTIMEO, tv);
  83 +}
  84 +
  85 +ssize_t stream_socket::write(const void *buf, size_t n)
  86 +{
  87 + #if defined(_WIN32)
  88 + return check_ret(::send(handle(), reinterpret_cast<const char*>(buf),
  89 + int(n) , 0));
  90 + #else
  91 + return check_ret(::send(handle(), buf, n , 0));
  92 + #endif
  93 +}
  94 +
  95 +ssize_t stream_socket::write_n(const void *buf, size_t n)
  96 +{
  97 + size_t nw = 0;
  98 + ssize_t nx = 0;
  99 +
  100 + const uint8_t *b = reinterpret_cast<const uint8_t*>(buf);
  101 +
  102 + while (nw < n) {
  103 + if ((nx = write(b+nw, n-nw)) < 0 && last_error() == EINTR)
  104 + continue;
  105 +
  106 + if (nx <= 0)
  107 + break;
  108 +
  109 + nw += nx;
  110 + }
  111 +
  112 + return (nw == 0 && nx < 0) ? nx : ssize_t(nw);
  113 +}
  114 +
  115 +ssize_t stream_socket::write(const std::vector<iovec>& ranges)
  116 +{
  117 + if (ranges.empty())
  118 + return 0;
  119 +
  120 + #if !defined(_WIN32)
  121 + return check_ret(::writev(handle(), ranges.data(), int(ranges.size())));
  122 + #else
  123 + std::vector<WSABUF> bufs;
  124 + for (const auto& iovec : ranges) {
  125 + bufs.push_back({
  126 + static_cast<ULONG>(iovec.iov_len),
  127 + static_cast<CHAR*>(iovec.iov_base)
  128 + });
  129 + }
  130 +
  131 + DWORD nwritten = 0,
  132 + nmsg = DWORD(bufs.size());
  133 +
  134 + auto ret = check_ret(::WSASend(handle(), bufs.data(), nmsg, &nwritten, 0, nullptr, nullptr));
  135 + return ssize_t(ret == SOCKET_ERROR ? ret : nwritten);
  136 + #endif
  137 +}
  138 +
  139 +bool stream_socket::write_timeout(const microseconds& to)
  140 +{
  141 + auto tv =
  142 + #if defined(_WIN32)
  143 + DWORD(duration_cast<milliseconds>(to).count());
  144 + #else
  145 + to_timeval(to);
  146 + #endif
  147 +
  148 + return set_option(SOL_SOCKET, SO_SNDTIMEO, tv);
  149 +}
  150 +
  151 +}
  152 +
src/unix/unix_address.cpp 0 โ†’ 100644
  1 +++ a/src/unix/unix_address.cpp
  1 +// unix_address.cpp
  2 +//
  3 +// --------------------------------------------------------------------------
  4 +// This file is part of the "sockpp" C++ socket library.
  5 +//
  6 +// Copyright (c) 2014-2017 Frank Pagliughi
  7 +// All rights reserved.
  8 +//
  9 +// Redistribution and use in source and binary forms, with or without
  10 +// modification, are permitted provided that the following conditions are
  11 +// met:
  12 +//
  13 +// 1. Redistributions of source code must retain the above copyright notice,
  14 +// this list of conditions and the following disclaimer.
  15 +//
  16 +// 2. Redistributions in binary form must reproduce the above copyright
  17 +// notice, this list of conditions and the following disclaimer in the
  18 +// documentation and/or other materials provided with the distribution.
  19 +//
  20 +// 3. Neither the name of the copyright holder nor the names of its
  21 +// contributors may be used to endorse or promote products derived from this
  22 +// software without specific prior written permission.
  23 +//
  24 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  25 +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  26 +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  27 +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  28 +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  29 +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  30 +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  31 +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  32 +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  33 +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  34 +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  35 +// --------------------------------------------------------------------------
  36 +
  37 +#include "sockpp/unix_address.h"
  38 +#include <cstring>
  39 +#include <stdexcept>
  40 +
  41 +using namespace std;
  42 +
  43 +namespace sockpp {
  44 +
  45 +/////////////////////////////////////////////////////////////////////////////
  46 +
  47 +constexpr sa_family_t unix_address::ADDRESS_FAMILY;
  48 +constexpr size_t unix_address::MAX_PATH_NAME;
  49 +
  50 +// --------------------------------------------------------------------------
  51 +
  52 +unix_address::unix_address(const string& path)
  53 +{
  54 + addr_.sun_family = ADDRESS_FAMILY;
  55 + ::strncpy(addr_.sun_path, path.c_str(), MAX_PATH_NAME);
  56 +}
  57 +
  58 +unix_address::unix_address(const sockaddr& addr)
  59 +{
  60 + auto domain = addr.sa_family;
  61 + if (domain != AF_UNIX)
  62 + throw std::invalid_argument("Not a UNIX-domain address");
  63 +
  64 + // TODO: We should check the path, or at least see that it has
  65 + // proper NUL termination.
  66 + std::memcpy(&addr_, &addr, sizeof(sockaddr));
  67 +}
  68 +
  69 +// --------------------------------------------------------------------------
  70 +
  71 +ostream& operator<<(ostream& os, const unix_address& addr)
  72 +{
  73 + os << "unix:" << addr.path();
  74 + return os;
  75 +}
  76 +
  77 +/////////////////////////////////////////////////////////////////////////////
  78 +// End namespace sockpp
  79 +}
tests/udptst.cpp 0 โ†’ 100644
  1 +++ a/tests/udptst.cpp
  1 +// udptst.cpp
  2 +
  3 +#include <iostream>
  4 +#include "sockpp/socket.h"
  5 +
  6 +using namespace std;
  7 +
  8 +// --------------------------------------------------------------------------
  9 +
  10 +int do_recv(sockpp::udp_socket& sock)
  11 +{
  12 + char buf[6];
  13 + int n = sock.recv(buf, sizeof(buf));
  14 +
  15 + if (n < 0) {
  16 + cerr << "Error sending packet: ["
  17 + << sock.last_error() << "]" << endl;
  18 + return -1;
  19 + }
  20 +
  21 + cout << "Received " << n << " bytes" << flush;
  22 + buf[n] = '\0';
  23 + cout << " '" << buf << "'" << endl;
  24 + return 0;
  25 +}
  26 +
  27 +// --------------------------------------------------------------------------
  28 +
  29 +int main()
  30 +{
  31 + in_port_t port = 12345;
  32 +
  33 + cout << "Testing UDP sockets" << endl;
  34 + sockpp::udp_socket srvrSock;
  35 +
  36 + if (!srvrSock) {
  37 + cerr << "Error creating server socket ["
  38 + << srvrSock.last_error() << "]" << endl;
  39 + return 1;
  40 + }
  41 +
  42 + if (!srvrSock.bind(port)) {
  43 + cerr << "Error binding to port: " << port << " ["
  44 + << srvrSock.last_error() << "]" << endl;
  45 + return 1;
  46 + }
  47 +
  48 + sockpp::udp_socket cliSock;
  49 +
  50 + if (!cliSock) {
  51 + cerr << "Error creating server socket ["
  52 + << cliSock.last_error() << "]" << endl;
  53 + return 1;
  54 + }
  55 +
  56 + sockpp::inet_address localAddr("localhost", port);
  57 +
  58 + if (!cliSock.connect(localAddr)) {
  59 + cerr << "Error connecting to port: " << port << " ["
  60 + << cliSock.last_error() << "]" << endl;
  61 + return 1;
  62 + }
  63 +
  64 + cliSock.send("Hello");
  65 + do_recv(srvrSock);
  66 +
  67 + cliSock.close();
  68 +
  69 + sockpp::udp_socket sock;
  70 + sock.sendto("bubba", localAddr);
  71 + do_recv(srvrSock);
  72 +
  73 + return 0;
  74 +}
  75 +
tests/unit/test_acceptor.cpp 0 โ†’ 100644
  1 +++ a/tests/unit/test_acceptor.cpp
  1 +// test_acceptor.cpp
  2 +//
  3 +// Unit tests for the `acceptor` class(es).
  4 +//
  5 +
  6 +// --------------------------------------------------------------------------
  7 +// This file is part of the "sockpp" C++ socket library.
  8 +//
  9 +// Copyright (c) 2019 Frank Pagliughi
  10 +// All rights reserved.
  11 +//
  12 +// Redistribution and use in source and binary forms, with or without
  13 +// modification, are permitted provided that the following conditions are
  14 +// met:
  15 +//
  16 +// 1. Redistributions of source code must retain the above copyright notice,
  17 +// this list of conditions and the following disclaimer.
  18 +//
  19 +// 2. Redistributions in binary form must reproduce the above copyright
  20 +// notice, this list of conditions and the following disclaimer in the
  21 +// documentation and/or other materials provided with the distribution.
  22 +//
  23 +// 3. Neither the name of the copyright holder nor the names of its
  24 +// contributors may be used to endorse or promote products derived from this
  25 +// software without specific prior written permission.
  26 +//
  27 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  28 +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  29 +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  30 +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  31 +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  32 +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  33 +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  34 +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  35 +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  36 +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  37 +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  38 +// --------------------------------------------------------------------------
  39 +//
  40 +
  41 +#include "sockpp/acceptor.h"
  42 +#include "sockpp/inet_address.h"
  43 +#include "catch2/catch.hpp"
  44 +#include <string>
  45 +
  46 +using namespace sockpp;
  47 +
  48 +TEST_CASE("acceptor default constructor", "[acceptor]") {
  49 + acceptor sock;
  50 + REQUIRE(!sock);
  51 + REQUIRE(!sock.is_open());
  52 +}
  53 +
  54 +TEST_CASE("acceptor handle constructor", "[acceptor]") {
  55 + constexpr auto HANDLE = socket_t(3);
  56 +
  57 + SECTION("valid handle") {
  58 + acceptor sock(HANDLE);
  59 + REQUIRE(sock);
  60 + REQUIRE(sock.is_open());
  61 + }
  62 +
  63 + SECTION("invalid handle") {
  64 + acceptor sock(INVALID_SOCKET);
  65 + REQUIRE(!sock);
  66 + REQUIRE(!sock.is_open());
  67 + // TODO: Should this set an error?
  68 + REQUIRE(sock.last_error() == 0);
  69 + }
  70 +}
  71 +
  72 +TEST_CASE("acceptor address constructor", "[acceptor]") {
  73 + SECTION("valid address") {
  74 + const auto ADDR = inet_address("localhost", 12345);
  75 +
  76 + acceptor sock(ADDR);
  77 + REQUIRE(sock);
  78 + REQUIRE(sock.is_open());
  79 + REQUIRE(sock.last_error() == 0);
  80 + REQUIRE(sock.address() == ADDR);
  81 + }
  82 +
  83 + SECTION("invalid address") {
  84 + const auto ADDR = sock_address_any{};
  85 +
  86 + acceptor sock(ADDR);
  87 + REQUIRE(!sock);
  88 + REQUIRE(!sock.is_open());
  89 +
  90 + // Windows returns a different error code than *nix
  91 + #if defined(_WIN32)
  92 + REQUIRE(sock.last_error() == WSAEINVAL);
  93 + #else
  94 + REQUIRE(sock.last_error() == EAFNOSUPPORT);
  95 + #endif
  96 + }
  97 +}
  98 +
  99 +TEST_CASE("acceptor create", "[acceptor]") {
  100 + SECTION("valid domain") {
  101 + auto sock = acceptor::create(AF_INET);
  102 +
  103 + REQUIRE(sock);
  104 + REQUIRE(sock.is_open());
  105 + REQUIRE(sock.last_error() == 0);
  106 +
  107 + // Windows returns unknown family for unbound socket
  108 + // Windows returns a different error code than *nix
  109 + #if defined(_WIN32)
  110 + REQUIRE(sock.family() == AF_UNSPEC);
  111 + #else
  112 + REQUIRE(sock.family() == AF_INET);
  113 + #endif
  114 + }
  115 +
  116 + SECTION("invalid domain") {
  117 + auto sock = acceptor::create(AF_UNSPEC);
  118 +
  119 + REQUIRE(!sock);
  120 + REQUIRE(!sock.is_open());
  121 +
  122 + // Windows returns a different error code than *nix
  123 + #if defined(_WIN32)
  124 + REQUIRE(sock.last_error() == WSAEINVAL);
  125 + #else
  126 + REQUIRE(sock.last_error() == EAFNOSUPPORT);
  127 + #endif
  128 + }
  129 +}
  130 +
tests/unit/test_connector.cpp 0 โ†’ 100644
  1 +++ a/tests/unit/test_connector.cpp
  1 +// test_connector.cpp
  2 +//
  3 +// Unit tests for the `connector` class(es).
  4 +//
  5 +
  6 +// --------------------------------------------------------------------------
  7 +// This file is part of the "sockpp" C++ socket library.
  8 +//
  9 +// Copyright (c) 2019 Frank Pagliughi
  10 +// All rights reserved.
  11 +//
  12 +// Redistribution and use in source and binary forms, with or without
  13 +// modification, are permitted provided that the following conditions are
  14 +// met:
  15 +//
  16 +// 1. Redistributions of source code must retain the above copyright notice,
  17 +// this list of conditions and the following disclaimer.
  18 +//
  19 +// 2. Redistributions in binary form must reproduce the above copyright
  20 +// notice, this list of conditions and the following disclaimer in the
  21 +// documentation and/or other materials provided with the distribution.
  22 +//
  23 +// 3. Neither the name of the copyright holder nor the names of its
  24 +// contributors may be used to endorse or promote products derived from this
  25 +// software without specific prior written permission.
  26 +//
  27 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  28 +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  29 +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  30 +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  31 +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  32 +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  33 +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  34 +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  35 +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  36 +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  37 +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  38 +// --------------------------------------------------------------------------
  39 +//
  40 +
  41 +#include "sockpp/connector.h"
  42 +#include "sockpp/sock_address.h"
  43 +#include "catch2/catch.hpp"
  44 +#include <string>
  45 +
  46 +using namespace sockpp;
  47 +
  48 +// Test that connector errors properly when given an empty address.
  49 +TEST_CASE("connector unspecified address", "[connector]") {
  50 + connector conn;
  51 + REQUIRE(!conn);
  52 +
  53 + sock_address_any addr;
  54 +
  55 + bool ok = conn.connect(addr);
  56 + REQUIRE(!ok);
  57 +
  58 + // Windows returns a different error code than *nix
  59 + #if defined(_WIN32)
  60 + REQUIRE(conn.last_error() == WSAENOTSOCK);
  61 + #else
  62 + REQUIRE(conn.last_error() == EAFNOSUPPORT);
  63 + #endif
  64 +}
  65 +
  66 +
tests/unit/test_datagram_socket.cpp 0 โ†’ 100644
  1 +++ a/tests/unit/test_datagram_socket.cpp
  1 +// test_datagram_socket.cpp
  2 +//
  3 +// Unit tests for the `datagram_socket` class(es).
  4 +//
  5 +
  6 +// --------------------------------------------------------------------------
  7 +// This file is part of the "sockpp" C++ socket library.
  8 +//
  9 +// Copyright (c) 2019 Frank Pagliughi
  10 +// All rights reserved.
  11 +//
  12 +// Redistribution and use in source and binary forms, with or without
  13 +// modification, are permitted provided that the following conditions are
  14 +// met:
  15 +//
  16 +// 1. Redistributions of source code must retain the above copyright notice,
  17 +// this list of conditions and the following disclaimer.
  18 +//
  19 +// 2. Redistributions in binary form must reproduce the above copyright
  20 +// notice, this list of conditions and the following disclaimer in the
  21 +// documentation and/or other materials provided with the distribution.
  22 +//
  23 +// 3. Neither the name of the copyright holder nor the names of its
  24 +// contributors may be used to endorse or promote products derived from this
  25 +// software without specific prior written permission.
  26 +//
  27 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  28 +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  29 +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  30 +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  31 +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  32 +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  33 +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  34 +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  35 +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  36 +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  37 +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  38 +// --------------------------------------------------------------------------
  39 +//
  40 +
  41 +#include "sockpp/datagram_socket.h"
  42 +#include "sockpp/inet_address.h"
  43 +#include "catch2/catch.hpp"
  44 +#include <string>
  45 +
  46 +using namespace sockpp;
  47 +
  48 +TEST_CASE("datagram_socket default constructor", "[datagram_socket]") {
  49 + datagram_socket sock;
  50 + REQUIRE(!sock);
  51 + REQUIRE(!sock.is_open());
  52 +}
  53 +
  54 +TEST_CASE("datagram_socket handle constructor", "[datagram_socket]") {
  55 + constexpr auto HANDLE = socket_t(3);
  56 +
  57 + SECTION("valid handle") {
  58 + datagram_socket sock(HANDLE);
  59 + REQUIRE(sock);
  60 + REQUIRE(sock.is_open());
  61 + }
  62 +
  63 + SECTION("invalid handle") {
  64 + datagram_socket sock(INVALID_SOCKET);
  65 + REQUIRE(!sock);
  66 + REQUIRE(!sock.is_open());
  67 + // TODO: Should this set an error?
  68 + REQUIRE(sock.last_error() == 0);
  69 + }
  70 +}
  71 +
  72 +TEST_CASE("datagram_socket address constructor", "[datagram_socket]") {
  73 + SECTION("valid address") {
  74 + const auto ADDR = inet_address("localhost", 12345);
  75 +
  76 + datagram_socket sock(ADDR);
  77 + REQUIRE(sock);
  78 + REQUIRE(sock.is_open());
  79 + REQUIRE(sock.last_error() == 0);
  80 + REQUIRE(sock.address() == ADDR);
  81 + }
  82 +
  83 + SECTION("invalid address") {
  84 + const auto ADDR = sock_address_any();
  85 +
  86 + datagram_socket sock(ADDR);
  87 + REQUIRE(!sock);
  88 + REQUIRE(!sock.is_open());
  89 +
  90 + // Windows returns a different error code than *nix
  91 + #if defined(_WIN32)
  92 + REQUIRE(sock.last_error() == WSAEINVAL);
  93 + #else
  94 + REQUIRE(sock.last_error() == EAFNOSUPPORT);
  95 + #endif
  96 + }
  97 +}
  98 +
tests/unit/test_inet_address.cpp 0 โ†’ 100644
  1 +++ a/tests/unit/test_inet_address.cpp
  1 +// test_inet_address.cpp
  2 +//
  3 +// Unit tests for the `inet_address` class.
  4 +//
  5 +
  6 +// --------------------------------------------------------------------------
  7 +// This file is part of the "sockpp" C++ socket library.
  8 +//
  9 +// Copyright (c) 2018 Frank Pagliughi
  10 +// All rights reserved.
  11 +//
  12 +// Redistribution and use in source and binary forms, with or without
  13 +// modification, are permitted provided that the following conditions are
  14 +// met:
  15 +//
  16 +// 1. Redistributions of source code must retain the above copyright notice,
  17 +// this list of conditions and the following disclaimer.
  18 +//
  19 +// 2. Redistributions in binary form must reproduce the above copyright
  20 +// notice, this list of conditions and the following disclaimer in the
  21 +// documentation and/or other materials provided with the distribution.
  22 +//
  23 +// 3. Neither the name of the copyright holder nor the names of its
  24 +// contributors may be used to endorse or promote products derived from this
  25 +// software without specific prior written permission.
  26 +//
  27 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  28 +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  29 +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  30 +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  31 +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  32 +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  33 +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  34 +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  35 +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  36 +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  37 +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  38 +// --------------------------------------------------------------------------
  39 +//
  40 +
  41 +#include "sockpp/inet_address.h"
  42 +#include "catch2/catch.hpp"
  43 +#include <string>
  44 +
  45 +using namespace sockpp;
  46 +
  47 +const uint32_t ANY_ADDR { INADDR_ANY }; // Any iface 0x00000000
  48 +const uint32_t LOCALHOST_ADDR { INADDR_LOOPBACK }; // Localhost 0x7F000001
  49 +const std::string LOCALHOST_STR { "localhost" };
  50 +const in_port_t PORT { 12345 };
  51 +
  52 +TEST_CASE("inet_address default constructor", "[address]") {
  53 + inet_address addr;
  54 +
  55 + REQUIRE(!addr.is_set());
  56 + REQUIRE(0 == addr.address());
  57 + REQUIRE(0 == addr.port());
  58 + REQUIRE(sizeof(sockaddr_in) == addr.size());
  59 +
  60 + SECTION("creating address from int32") {
  61 + addr.create(LOCALHOST_ADDR, PORT);
  62 +
  63 + REQUIRE(addr.is_set());
  64 + REQUIRE(LOCALHOST_ADDR == addr.address());
  65 + REQUIRE(PORT == addr.port());
  66 +
  67 + REQUIRE(uint8_t((LOCALHOST_ADDR >> 0) &0xFF) == addr[0]);
  68 + REQUIRE(uint8_t((LOCALHOST_ADDR >> 8) &0xFF) == addr[1]);
  69 + REQUIRE(uint8_t((LOCALHOST_ADDR >> 16) &0xFF) == addr[2]);
  70 + REQUIRE(uint8_t((LOCALHOST_ADDR >> 24) &0xFF) == addr[3]);
  71 +
  72 + // Check the low-level struct
  73 + REQUIRE(AF_INET == addr.sockaddr_in_ptr()->sin_family);
  74 + REQUIRE(LOCALHOST_ADDR == ntohl(addr.sockaddr_in_ptr()->sin_addr.s_addr));
  75 + REQUIRE(PORT == ntohs(addr.sockaddr_in_ptr()->sin_port));
  76 + }
  77 +
  78 + SECTION("creating address from name") {
  79 + addr.create(LOCALHOST_STR, PORT);
  80 +
  81 + REQUIRE(addr.is_set());
  82 + REQUIRE(LOCALHOST_ADDR == addr.address());
  83 + REQUIRE(PORT == addr.port());
  84 +
  85 + // Check the low-level struct
  86 + REQUIRE(AF_INET == addr.sockaddr_in_ptr()->sin_family);
  87 + REQUIRE(LOCALHOST_ADDR == ntohl(addr.sockaddr_in_ptr()->sin_addr.s_addr));
  88 + REQUIRE(PORT == ntohs(addr.sockaddr_in_ptr()->sin_port));
  89 + }
  90 +}
  91 +
  92 +// When created using only a port number this should use the
  93 +// "any" address to bind to all interfaces (typ for server)
  94 +TEST_CASE("inet_address port-only constructor", "[address]") {
  95 + inet_address addr(PORT);
  96 +
  97 + REQUIRE(addr.is_set());
  98 + REQUIRE(ANY_ADDR == addr.address());
  99 + REQUIRE(PORT == addr.port());
  100 +
  101 + // Check the low-level struct
  102 + REQUIRE(AF_INET == addr.sockaddr_in_ptr()->sin_family);
  103 +}
  104 +
  105 +TEST_CASE("inet_address int32_t constructor", "[address]") {
  106 + inet_address addr(LOCALHOST_ADDR, PORT);
  107 +
  108 + REQUIRE(addr.is_set());
  109 + REQUIRE(LOCALHOST_ADDR == addr.address());
  110 + REQUIRE(PORT == addr.port());
  111 +
  112 + REQUIRE(uint8_t((LOCALHOST_ADDR >> 0) &0xFF) == addr[0]);
  113 + REQUIRE(uint8_t((LOCALHOST_ADDR >> 8) &0xFF) == addr[1]);
  114 + REQUIRE(uint8_t((LOCALHOST_ADDR >> 16) &0xFF) == addr[2]);
  115 + REQUIRE(uint8_t((LOCALHOST_ADDR >> 24) &0xFF) == addr[3]);
  116 +
  117 + // Check the low-level struct
  118 + REQUIRE(AF_INET == addr.sockaddr_in_ptr()->sin_family);
  119 + REQUIRE(LOCALHOST_ADDR == ntohl(addr.sockaddr_in_ptr()->sin_addr.s_addr));
  120 + REQUIRE(PORT == ntohs(addr.sockaddr_in_ptr()->sin_port));
  121 +}
  122 +
  123 +TEST_CASE("inet_address name constructor", "[address]") {
  124 + inet_address addr(LOCALHOST_STR, PORT);
  125 +
  126 + REQUIRE(addr.is_set());
  127 + REQUIRE(LOCALHOST_ADDR == addr.address());
  128 + REQUIRE(PORT == addr.port());
  129 +
  130 + REQUIRE(uint8_t((LOCALHOST_ADDR >> 0) &0xFF) == addr[0]);
  131 + REQUIRE(uint8_t((LOCALHOST_ADDR >> 8) &0xFF) == addr[1]);
  132 + REQUIRE(uint8_t((LOCALHOST_ADDR >> 16) &0xFF) == addr[2]);
  133 + REQUIRE(uint8_t((LOCALHOST_ADDR >> 24) &0xFF) == addr[3]);
  134 +
  135 + // Check the low-level struct
  136 + REQUIRE(AF_INET == addr.sockaddr_in_ptr()->sin_family);
  137 + REQUIRE(LOCALHOST_ADDR == ntohl(addr.sockaddr_in_ptr()->sin_addr.s_addr));
  138 + REQUIRE(PORT == ntohs(addr.sockaddr_in_ptr()->sin_port));
  139 +}
  140 +
  141 +TEST_CASE("IPv4 resolve_address", "[address]") {
  142 + REQUIRE(inet_address::resolve_name("127.0.0.1") == htonl(LOCALHOST_ADDR));
  143 + REQUIRE(inet_address::resolve_name(LOCALHOST_STR) == htonl(LOCALHOST_ADDR));
  144 +}
tests/unit/test_socket.cpp 0 โ†’ 100644
  1 +++ a/tests/unit/test_socket.cpp
  1 +// test_socket.cpp
  2 +//
  3 +// Unit tests for the base `socket` class.
  4 +//
  5 +
  6 +// --------------------------------------------------------------------------
  7 +// This file is part of the "sockpp" C++ socket library.
  8 +//
  9 +// Copyright (c) 2019 Frank Pagliughi
  10 +// All rights reserved.
  11 +//
  12 +// Redistribution and use in source and binary forms, with or without
  13 +// modification, are permitted provided that the following conditions are
  14 +// met:
  15 +//
  16 +// 1. Redistributions of source code must retain the above copyright notice,
  17 +// this list of conditions and the following disclaimer.
  18 +//
  19 +// 2. Redistributions in binary form must reproduce the above copyright
  20 +// notice, this list of conditions and the following disclaimer in the
  21 +// documentation and/or other materials provided with the distribution.
  22 +//
  23 +// 3. Neither the name of the copyright holder nor the names of its
  24 +// contributors may be used to endorse or promote products derived from this
  25 +// software without specific prior written permission.
  26 +//
  27 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  28 +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  29 +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  30 +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  31 +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  32 +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  33 +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  34 +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  35 +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  36 +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  37 +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  38 +// --------------------------------------------------------------------------
  39 +//
  40 +
  41 +#include "sockpp/socket.h"
  42 +#include "sockpp/inet_address.h"
  43 +#include "catch2/catch.hpp"
  44 +#include <string>
  45 +
  46 +using namespace sockpp;
  47 +using namespace std::chrono;
  48 +
  49 +/////////////////////////////////////////////////////////////////////////////
  50 +// Aux functions
  51 +
  52 +TEST_CASE("test to_timeval", "aux") {
  53 + SECTION("concrete function") {
  54 + timeval tv = to_timeval(microseconds(500));
  55 + REQUIRE(tv.tv_sec == 0);
  56 + REQUIRE(tv.tv_usec == 500);
  57 +
  58 + tv = to_timeval(microseconds(2500000));
  59 + REQUIRE(tv.tv_sec == 2);
  60 + REQUIRE(tv.tv_usec == 500000);
  61 + }
  62 +
  63 + SECTION("template") {
  64 + timeval tv = to_timeval(milliseconds(1));
  65 + REQUIRE(tv.tv_sec == 0);
  66 + REQUIRE(tv.tv_usec == 1000);
  67 +
  68 + tv = to_timeval(milliseconds(2500));
  69 + REQUIRE(tv.tv_sec == 2);
  70 + REQUIRE(tv.tv_usec == 500000);
  71 +
  72 + tv = to_timeval(seconds(5));
  73 + REQUIRE(tv.tv_sec == 5);
  74 + REQUIRE(tv.tv_usec == 0);
  75 + }
  76 +}
  77 +
  78 +/////////////////////////////////////////////////////////////////////////////
  79 +// socket class
  80 +
  81 +constexpr in_port_t INET_TEST_PORT = 12346;
  82 +
  83 +TEST_CASE("socket constructors", "[socket]") {
  84 + SECTION("default constructor") {
  85 + sockpp::socket sock;
  86 +
  87 + REQUIRE(!sock);
  88 + REQUIRE(!sock.is_open());
  89 + REQUIRE(sock.handle() == INVALID_SOCKET);
  90 + REQUIRE(sock.last_error() == 0);
  91 + }
  92 +
  93 + SECTION("handle constructor") {
  94 + constexpr auto HANDLE = socket_t(3);
  95 + sockpp::socket sock(HANDLE);
  96 +
  97 + REQUIRE(sock);
  98 + REQUIRE(sock.is_open());
  99 + REQUIRE(sock.handle() == HANDLE);
  100 + REQUIRE(sock.last_error() == 0);
  101 + }
  102 +
  103 +
  104 + SECTION("move constructor") {
  105 + constexpr auto HANDLE = socket_t(3);
  106 + sockpp::socket org_sock(HANDLE);
  107 +
  108 + sockpp::socket sock(std::move(org_sock));
  109 +
  110 + // Make sure the new socket got the handle
  111 + REQUIRE(sock);
  112 + REQUIRE(sock.handle() == HANDLE);
  113 + REQUIRE(sock.last_error() == 0);
  114 +
  115 + // Make sure the handle was moved out of the org_sock
  116 + REQUIRE(!org_sock);
  117 + REQUIRE(org_sock.handle() == INVALID_SOCKET);
  118 + }
  119 +}
  120 +
  121 +// Test the socket error behavior
  122 +TEST_CASE("socket errors", "[socket]") {
  123 + SECTION("basic errors") {
  124 + sockpp::socket sock;
  125 +
  126 + // Operations on an unopened socket should give an error
  127 + int reuse = 1;
  128 + socklen_t len = sizeof(int);
  129 + bool ok = sock.get_option(SOL_SOCKET, SO_REUSEADDR, &reuse, &len);
  130 +
  131 + // Socket should be in error state
  132 + REQUIRE(!ok);
  133 + REQUIRE(!sock);
  134 +
  135 + int err = sock.last_error();
  136 + REQUIRE(err != 0);
  137 +
  138 + // last_error() is sticky, unlike `errno`
  139 + REQUIRE(sock.last_error() == err);
  140 +
  141 + // We can clear the error
  142 + sock.clear();
  143 + REQUIRE(sock.last_error() == 0);
  144 +
  145 + // Test arbitrary clear value
  146 + sock.clear(42);
  147 + REQUIRE(sock.last_error() == 42);
  148 + REQUIRE(!sock);
  149 + }
  150 +
  151 + SECTION("clear error") {
  152 + auto sock = sockpp::socket::create(AF_INET, SOCK_STREAM);
  153 + REQUIRE(sock);
  154 +
  155 + sock.clear(42);
  156 + REQUIRE(!sock);
  157 +
  158 + sock.clear();
  159 + REQUIRE(sock);
  160 + }
  161 +}
  162 +
  163 +TEST_CASE("socket handles", "[socket]") {
  164 +
  165 + constexpr auto HANDLE = socket_t(3);
  166 +
  167 + SECTION("test release") {
  168 + sockpp::socket sock(HANDLE);
  169 +
  170 + REQUIRE(sock.handle() == HANDLE);
  171 + REQUIRE(sock.release() == HANDLE);
  172 +
  173 + // Make sure the handle was moved out of the sock
  174 + REQUIRE(!sock);
  175 + REQUIRE(sock.handle() == INVALID_SOCKET);
  176 + }
  177 +
  178 + SECTION("test reset") {
  179 + sockpp::socket sock(HANDLE);
  180 + REQUIRE(sock.handle() == HANDLE);
  181 +
  182 + sock.reset(); // Default reset acts like release w/o return
  183 +
  184 + // Make sure the handle was moved out of the sock
  185 + REQUIRE(!sock);
  186 + REQUIRE(sock.handle() == INVALID_SOCKET);
  187 +
  188 + // Now reset with a "valid" handle
  189 + sock.reset(HANDLE);
  190 + REQUIRE(sock);
  191 + REQUIRE(sock.handle() == HANDLE);
  192 + }
  193 +}
  194 +
  195 +TEST_CASE("socket family", "[socket]") {
  196 + SECTION("uninitialized socket") {
  197 + // Uninitialized socket should have unspecified family
  198 + sockpp::socket sock;
  199 + REQUIRE(sock.family() == AF_UNSPEC);
  200 + }
  201 +
  202 + SECTION("unbound socket") {
  203 + // Unbound socket should have creation family
  204 + auto sock = socket::create(AF_INET, SOCK_STREAM);
  205 +
  206 + // Windows and *nix behave differently
  207 + #if defined(_WIN32)
  208 + REQUIRE(sock.family() == AF_UNSPEC);
  209 + #else
  210 + REQUIRE(sock.family() == AF_INET);
  211 + #endif
  212 + }
  213 +
  214 + SECTION("bound socket") {
  215 + // Bound socket should have same family as
  216 + // address to which it's bound
  217 + auto sock = socket::create(AF_INET, SOCK_STREAM);
  218 + inet_address addr(INET_TEST_PORT);
  219 +
  220 + int reuse = 1;
  221 + REQUIRE(sock.set_option(SOL_SOCKET, SO_REUSEADDR, reuse));
  222 + REQUIRE(sock.bind(addr));
  223 + REQUIRE(sock.family() == addr.family());
  224 + }
  225 +}
  226 +
  227 +TEST_CASE("socket address", "[socket]") {
  228 + SECTION("uninitialized socket") {
  229 + // Uninitialized socket should have empty address
  230 + sockpp::socket sock;
  231 + REQUIRE(sock.address() == sock_address_any{});
  232 + }
  233 +
  234 + // The address has the specified family but all zeros
  235 + SECTION("unbound socket") {
  236 + auto sock = socket::create(AF_INET, SOCK_STREAM);
  237 + auto addr = inet_address(sock.address());
  238 +
  239 + // Windows and *nix behave differently for family
  240 + #if defined(_WIN32)
  241 + REQUIRE(sock.family() == AF_UNSPEC);
  242 + #else
  243 + REQUIRE(sock.family() == AF_INET);
  244 + #endif
  245 +
  246 + REQUIRE(addr.address() == 0);
  247 + REQUIRE(addr.port() == 0);
  248 + }
  249 +
  250 + SECTION("bound socket") {
  251 + // Bound socket should have same family as
  252 + // address to which it's bound
  253 + auto sock = socket::create(AF_INET, SOCK_STREAM);
  254 + const inet_address ADDR(INET_TEST_PORT);
  255 +
  256 + int reuse = 1;
  257 + REQUIRE(sock.set_option(SOL_SOCKET, SO_REUSEADDR, reuse));
  258 +
  259 + REQUIRE(sock.bind(ADDR));
  260 + REQUIRE(sock.address() == ADDR);
  261 + }
  262 +}
  263 +
  264 +// Socket pair shouldn't work for TCP sockets on any known platform.
  265 +// So this should fail, but fail gracefully and retain the error
  266 +// in both sockets.
  267 +TEST_CASE("failed socket pair", "[socket]") {
  268 + sockpp::socket sock1, sock2;
  269 + std::tie(sock1, sock2) = std::move(socket::pair(AF_INET, SOCK_STREAM));
  270 +
  271 + REQUIRE(!sock1);
  272 + REQUIRE(!sock2);
  273 +
  274 + REQUIRE(sock1.last_error() != 0);
  275 + REQUIRE(sock1.last_error() == sock2.last_error());
  276 +}
  277 +
  278 +// --------------------------------------------------------------------------
  279 +
  280 +// Test that the "last error" call to a socket gives the proper result
  281 +// for the current thread.
  282 +// Here we share a socket across two threads, force an error in one
  283 +// thread, and then check to make sure that the error did not propagate
  284 +// to the other thread.
  285 +//
  286 +#if 0
  287 +TEST_CASE("thread-safe last error", "[socket]") {
  288 + sockpp::socket sock;
  289 +
  290 + int state = 0;
  291 + std::mutex m;
  292 + std::condition_variable cv;
  293 +
  294 + std::thread thr([&] {
  295 + // Test #1
  296 + REQUIRE(sock.last_error() == 0);
  297 + {
  298 + // Wait for Test #2
  299 + std::unique_lock<std::mutex> lk(m);
  300 + state = 1;
  301 + cv.notify_one();
  302 + cv.wait(lk, [&state]{return state >= 2;});
  303 + }
  304 +
  305 + // Test #3
  306 + REQUIRE(sock.last_error() == 0);
  307 + });
  308 +
  309 + {
  310 + // Wait for Test #1
  311 + std::unique_lock<std::mutex> lk(m);
  312 + cv.wait(lk, [&state]{return state >= 1;});
  313 + }
  314 +
  315 + // Test #2
  316 + // Setting options on an un-opened socket should generate an error
  317 + int reuse = 1;
  318 + socklen_t len = sizeof(int);
  319 + bool ok = sock.get_option(SOL_SOCKET, SO_REUSEADDR, &reuse, &len);
  320 +
  321 + REQUIRE(!ok);
  322 + REQUIRE(sock.last_error() != 0);
  323 +
  324 + {
  325 + std::unique_lock<std::mutex> lk(m);
  326 + state = 2;
  327 + cv.notify_one();
  328 + }
  329 + thr.join();
  330 +}
  331 +#endif
  332 +
tests/unit/test_stream_socket.cpp 0 โ†’ 100644
  1 +++ a/tests/unit/test_stream_socket.cpp
  1 +// test_stream_socket.cpp
  2 +//
  3 +// Unit tests for the `stream_socket` class(es).
  4 +//
  5 +
  6 +// --------------------------------------------------------------------------
  7 +// This file is part of the "sockpp" C++ socket library.
  8 +//
  9 +// Copyright (c) 2019 Frank Pagliughi
  10 +// All rights reserved.
  11 +//
  12 +// Redistribution and use in source and binary forms, with or without
  13 +// modification, are permitted provided that the following conditions are
  14 +// met:
  15 +//
  16 +// 1. Redistributions of source code must retain the above copyright notice,
  17 +// this list of conditions and the following disclaimer.
  18 +//
  19 +// 2. Redistributions in binary form must reproduce the above copyright
  20 +// notice, this list of conditions and the following disclaimer in the
  21 +// documentation and/or other materials provided with the distribution.
  22 +//
  23 +// 3. Neither the name of the copyright holder nor the names of its
  24 +// contributors may be used to endorse or promote products derived from this
  25 +// software without specific prior written permission.
  26 +//
  27 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  28 +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  29 +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  30 +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  31 +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  32 +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  33 +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  34 +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  35 +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  36 +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  37 +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  38 +// --------------------------------------------------------------------------
  39 +//
  40 +
  41 +#include "sockpp/stream_socket.h"
  42 +#include "sockpp/inet_address.h"
  43 +#include "catch2/catch.hpp"
  44 +#include <string>
  45 +
  46 +using namespace sockpp;
  47 +
  48 +TEST_CASE("stream_socket default constructor", "[stream_socket]") {
  49 + stream_socket sock;
  50 + REQUIRE(!sock);
  51 + REQUIRE(!sock.is_open());
  52 +}
  53 +
  54 +TEST_CASE("stream_socket handle constructor", "[stream_socket]") {
  55 + constexpr auto HANDLE = socket_t(3);
  56 +
  57 + SECTION("valid handle") {
  58 + stream_socket sock(HANDLE);
  59 + REQUIRE(sock);
  60 + REQUIRE(sock.is_open());
  61 + }
  62 +
  63 + SECTION("invalid handle") {
  64 + stream_socket sock(INVALID_SOCKET);
  65 + REQUIRE(!sock);
  66 + REQUIRE(!sock.is_open());
  67 + // TODO: Should this set an error?
  68 + REQUIRE(sock.last_error() == 0);
  69 + }
  70 +}
  71 +
  72 +#if 0
  73 +TEST_CASE("stream_socket address constructor", "[stream_socket]") {
  74 + SECTION("valid address") {
  75 + const auto ADDR = inet_address("localhost", 12345);
  76 +
  77 + stream_socket sock(ADDR);
  78 + REQUIRE(sock);
  79 + REQUIRE(sock.is_open());
  80 + REQUIRE(sock.last_error() == 0);
  81 + REQUIRE(sock.address() == ADDR);
  82 + }
  83 +
  84 + SECTION("invalid address") {
  85 + const auto ADDR = sock_address_any();
  86 +
  87 + stream_socket sock(ADDR);
  88 + REQUIRE(!sock);
  89 + REQUIRE(!sock.is_open());
  90 + REQUIRE(sock.last_error() == EAFNOSUPPORT);
  91 + }
  92 +}
  93 +#endif
  94 +
  95 +// --------------------------------------------------------------------------
  96 +// Connected tests
  97 +
  98 +TEST_CASE("stream_socket readn, writen", "[stream_socket]") {
  99 + //auto lsock = stream_socket::create(AF
  100 +}
tests/unit/test_tcp_socket.cpp 0 โ†’ 100644
  1 +++ a/tests/unit/test_tcp_socket.cpp
  1 +// test_tcp_socket.cpp
  2 +//
  3 +// Unit tests for the `tcp_socket` class(es).
  4 +//
  5 +
  6 +// --------------------------------------------------------------------------
  7 +// This file is part of the "sockpp" C++ socket library.
  8 +//
  9 +// Copyright (c) 2019 Frank Pagliughi
  10 +// All rights reserved.
  11 +//
  12 +// Redistribution and use in source and binary forms, with or without
  13 +// modification, are permitted provided that the following conditions are
  14 +// met:
  15 +//
  16 +// 1. Redistributions of source code must retain the above copyright notice,
  17 +// this list of conditions and the following disclaimer.
  18 +//
  19 +// 2. Redistributions in binary form must reproduce the above copyright
  20 +// notice, this list of conditions and the following disclaimer in the
  21 +// documentation and/or other materials provided with the distribution.
  22 +//
  23 +// 3. Neither the name of the copyright holder nor the names of its
  24 +// contributors may be used to endorse or promote products derived from this
  25 +// software without specific prior written permission.
  26 +//
  27 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  28 +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  29 +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  30 +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  31 +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  32 +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  33 +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  34 +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  35 +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  36 +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  37 +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  38 +// --------------------------------------------------------------------------
  39 +//
  40 +
  41 +#include "sockpp/tcp_socket.h"
  42 +#include "sockpp/tcp_connector.h"
  43 +#include "sockpp/tcp_acceptor.h"
  44 +#include "catch2/catch.hpp"
  45 +#include <string>
  46 +
  47 +using namespace sockpp;
  48 +
  49 +static const in_port_t TEST_PORT = 12345;
  50 +
  51 +TEST_CASE("tcp_socket default constructor", "[tcp_socket]") {
  52 + tcp_socket sock;
  53 + REQUIRE(!sock);
  54 + REQUIRE(!sock.is_open());
  55 +
  56 + //REQUIRE(sock.family() == AF_INET);
  57 +}
  58 +
  59 +TEST_CASE("tcp_socket handle constructor", "[tcp_socket]") {
  60 + constexpr auto HANDLE = socket_t(3);
  61 +
  62 + SECTION("valid handle") {
  63 + tcp_socket sock(HANDLE);
  64 + REQUIRE(sock);
  65 + REQUIRE(sock.is_open());
  66 +
  67 + //REQUIRE(sock.family() == AF_INET);
  68 + }
  69 +
  70 + SECTION("invalid handle") {
  71 + tcp_socket sock(INVALID_SOCKET);
  72 + REQUIRE(!sock);
  73 + REQUIRE(!sock.is_open());
  74 + // TODO: Should this set an error?
  75 + REQUIRE(sock.last_error() == 0);
  76 +
  77 + //REQUIRE(sock.family() == AF_INET);
  78 + }
  79 +}
  80 +
  81 +// --------------------------------------------------------------------------
  82 +// Connected tests
  83 +
  84 +TEST_CASE("tcp_socket read/write", "[stream_socket]") {
  85 + const std::string STR { "This is a test. This is only a test." };
  86 + const size_t N = STR.length();
  87 +
  88 + inet_address addr { "localhost", TEST_PORT };
  89 + tcp_acceptor asock{ addr };
  90 +
  91 + tcp_connector csock;
  92 + csock.set_non_blocking();
  93 +
  94 + REQUIRE(csock.connect(addr));
  95 +
  96 + auto ssock = asock.accept();
  97 + REQUIRE(ssock);
  98 +
  99 + SECTION("read_n/write_n") {
  100 + char buf[512]; // N
  101 +
  102 + REQUIRE(csock.write_n(STR.data(), N) == N);
  103 + REQUIRE(ssock.read_n(buf, N) == N);
  104 +
  105 + std::string str { buf, buf+N };
  106 + REQUIRE(str == STR);
  107 +
  108 + char buf2[512]; // N
  109 +
  110 + // string write is a write_n()
  111 + REQUIRE(csock.write(STR) == N);
  112 + REQUIRE(ssock.read_n(buf2, N) == N);
  113 +
  114 + std::string str2 { buf2, buf2+N };
  115 + REQUIRE(str2 == STR);
  116 + }
  117 +
  118 + SECTION("scatter/gather") {
  119 + const std::string HEADER { "<start>" },
  120 + FOOTER { "<end>" };
  121 +
  122 + const size_t N_HEADER = HEADER.length(),
  123 + N_FOOTER = FOOTER.length(),
  124 + N_TOT = N_HEADER + N + N_FOOTER;
  125 +
  126 + std::vector<iovec> outv {
  127 + iovec { (void*) HEADER.data(), N_HEADER },
  128 + iovec { (void*) STR.data(), N },
  129 + iovec { (void*) FOOTER.data(), N_FOOTER }
  130 + };
  131 +
  132 + char hbuf[512], // N_HEADER
  133 + buf[512], // N
  134 + fbuf[512]; // N_FOOTER
  135 +
  136 + std::vector<iovec> inv {
  137 + iovec { (void*) hbuf, N_HEADER },
  138 + iovec { (void*) buf, N },
  139 + iovec { (void*) fbuf, N_FOOTER }
  140 + };
  141 +
  142 + REQUIRE(csock.write(outv) == N_TOT);
  143 + REQUIRE(csock.write(outv) == N_TOT);
  144 + REQUIRE(csock.write(outv) == N_TOT);
  145 +
  146 + REQUIRE(ssock.read(inv) == N_TOT);
  147 +
  148 + REQUIRE(std::string(hbuf, N_HEADER) == HEADER);
  149 + REQUIRE(std::string(buf, N) == STR);
  150 + REQUIRE(std::string(fbuf, N_FOOTER) == FOOTER);
  151 + }
  152 +}
  153 +
  154 +
tests/unit/test_unix_address.cpp 0 โ†’ 100644
  1 +++ a/tests/unit/test_unix_address.cpp
  1 +// test_unix_address.cpp
  2 +//
  3 +// Unit tests for the `unix_address` class.
  4 +//
  5 +
  6 +// --------------------------------------------------------------------------
  7 +// This file is part of the "sockpp" C++ socket library.
  8 +//
  9 +// Copyright (c) 2018 Frank Pagliughi
  10 +// All rights reserved.
  11 +//
  12 +// Redistribution and use in source and binary forms, with or without
  13 +// modification, are permitted provided that the following conditions are
  14 +// met:
  15 +//
  16 +// 1. Redistributions of source code must retain the above copyright notice,
  17 +// this list of conditions and the following disclaimer.
  18 +//
  19 +// 2. Redistributions in binary form must reproduce the above copyright
  20 +// notice, this list of conditions and the following disclaimer in the
  21 +// documentation and/or other materials provided with the distribution.
  22 +//
  23 +// 3. Neither the name of the copyright holder nor the names of its
  24 +// contributors may be used to endorse or promote products derived from this
  25 +// software without specific prior written permission.
  26 +//
  27 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  28 +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  29 +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  30 +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  31 +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  32 +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  33 +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  34 +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  35 +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  36 +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  37 +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  38 +// --------------------------------------------------------------------------
  39 +//
  40 +
  41 +#include "sockpp/unix_address.h"
  42 +#include "catch2/catch.hpp"
  43 +#include <string>
  44 +
  45 +using namespace sockpp;
  46 +
  47 +std::string PATH { "/tmp/sock" };
  48 +
  49 +TEST_CASE("unix_address default constructor", "[address]") {
  50 + unix_address addr;
  51 +
  52 + REQUIRE(!addr.is_set());
  53 + REQUIRE(addr.path().empty());
  54 + REQUIRE(sizeof(sockaddr_un) == addr.size());
  55 +
  56 + // TODO: Do we have a unix_address::create() method yet?
  57 +}
  58 +
  59 +TEST_CASE("unix_address path constructor", "[address]") {
  60 + unix_address addr(PATH);
  61 +
  62 + REQUIRE(addr.is_set());
  63 + REQUIRE(PATH == addr.path());
  64 + REQUIRE(sizeof(sockaddr_un) == addr.size());
  65 +
  66 + // Check the low-level struct
  67 + REQUIRE(AF_UNIX == addr.sockaddr_un_ptr()->sun_family);
  68 + REQUIRE(0 == strcmp(PATH.c_str(),
  69 + (const char*) &addr.sockaddr_un_ptr()->sun_path));
  70 +
  71 + SECTION("copy constructor") {
  72 + unix_address addr2(addr);
  73 +
  74 + REQUIRE(addr2.is_set());
  75 + REQUIRE(PATH == addr2.path());
  76 + REQUIRE(sizeof(sockaddr_un) == addr2.size());
  77 +
  78 + // Check the low-level struct
  79 + REQUIRE(AF_UNIX == addr2.sockaddr_un_ptr()->sun_family);
  80 + REQUIRE(0 == strcmp(PATH.c_str(),
  81 + (const char*) &addr2.sockaddr_un_ptr()->sun_path));
  82 + }
  83 +
  84 + SECTION("sockaddr conversions") {
  85 + auto sa = addr.sockaddr_ptr();
  86 + unix_address addr2(*sa);
  87 +
  88 + REQUIRE(addr2.is_set());
  89 + REQUIRE(PATH == addr2.path());
  90 + REQUIRE(sizeof(sockaddr_un) == addr2.size());
  91 +
  92 + // Check the low-level struct
  93 + REQUIRE(AF_UNIX == addr2.sockaddr_un_ptr()->sun_family);
  94 + REQUIRE(0 == strcmp(PATH.c_str(),
  95 + (const char*) &(addr2.sockaddr_un_ptr()->sun_path)));
  96 + }
  97 +}
  98 +
  99 +TEST_CASE("unix_address sockaddr_un constructor", "[address]") {
  100 + sockaddr_un unaddr;
  101 + unaddr.sun_family = AF_UNIX;
  102 + strcpy(unaddr.sun_path, PATH.c_str());
  103 +
  104 + unix_address addr(unaddr);
  105 +
  106 + REQUIRE(addr.is_set());
  107 + REQUIRE(PATH == addr.path());
  108 + REQUIRE(sizeof(sockaddr_un) == addr.size());
  109 +
  110 + // Check the low-level struct
  111 + REQUIRE(AF_UNIX == addr.sockaddr_un_ptr()->sun_family);
  112 + REQUIRE(0 == strcmp(PATH.c_str(),
  113 + (const char*) &addr.sockaddr_un_ptr()->sun_path));
  114 +
  115 + // TODO: Restore this when all address checks in place
  116 + /*
  117 + SECTION("reject bad sockaddr_un") {
  118 + unaddr.sun_family = AF_INET;
  119 + REQUIRE_THROWS_AS([&] {
  120 + unix_address addr2(unaddr);
  121 + }(), std::invalid_argument);
  122 + }
  123 + */
  124 +}
tests/unit/test_unix_dgram_socket.cpp 0 โ†’ 100644
  1 +++ a/tests/unit/test_unix_dgram_socket.cpp
  1 +// test_unix_dgram_socket.cpp
  2 +//
  3 +// Unit tests for the `unix_dgram_socket` class.
  4 +//
  5 +
  6 +// --------------------------------------------------------------------------
  7 +// This file is part of the "sockpp" C++ socket library.
  8 +//
  9 +// Copyright (c) 2019 Frank Pagliughi
  10 +// All rights reserved.
  11 +//
  12 +// Redistribution and use in source and binary forms, with or without
  13 +// modification, are permitted provided that the following conditions are
  14 +// met:
  15 +//
  16 +// 1. Redistributions of source code must retain the above copyright notice,
  17 +// this list of conditions and the following disclaimer.
  18 +//
  19 +// 2. Redistributions in binary form must reproduce the above copyright
  20 +// notice, this list of conditions and the following disclaimer in the
  21 +// documentation and/or other materials provided with the distribution.
  22 +//
  23 +// 3. Neither the name of the copyright holder nor the names of its
  24 +// contributors may be used to endorse or promote products derived from this
  25 +// software without specific prior written permission.
  26 +//
  27 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  28 +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  29 +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  30 +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  31 +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  32 +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  33 +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  34 +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  35 +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  36 +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  37 +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  38 +// --------------------------------------------------------------------------
  39 +//
  40 +
  41 +#include "sockpp/unix_dgram_socket.h"
  42 +#include "catch2/catch.hpp"
  43 +#include <string>
  44 +
  45 +using namespace sockpp;
  46 +
  47 +// Test that we can create a Unix-domain datagram socket pair and send data
  48 +// from one of the sockets to the other.
  49 +TEST_CASE("unix dgram socket pair", "[unix_dgram_socket]") {
  50 + unix_dgram_socket sock1, sock2;
  51 + std::tie(sock1, sock2) = std::move(unix_dgram_socket::pair());
  52 +
  53 + REQUIRE(sock1);
  54 + REQUIRE(sock2);
  55 +
  56 + REQUIRE(sock1.is_open());
  57 + REQUIRE(sock2.is_open());
  58 +
  59 + const std::string MSG { "Hello there!" };
  60 + const size_t N = MSG.length();
  61 +
  62 + char buf[512];
  63 +
  64 + REQUIRE(sock1.send(MSG) == N);
  65 + REQUIRE(sock2.recv(buf, N) == N);
  66 +
  67 + std::string msg { buf, buf+N };
  68 + REQUIRE(msg == MSG);
  69 +}
  70 +
  71 +
tests/unit/test_unix_stream_socket.cpp 0 โ†’ 100644
  1 +++ a/tests/unit/test_unix_stream_socket.cpp
  1 +// test_unix_stream_socket.cpp
  2 +//
  3 +// Unit tests for the `unix_stream_socket` class.
  4 +//
  5 +
  6 +// --------------------------------------------------------------------------
  7 +// This file is part of the "sockpp" C++ socket library.
  8 +//
  9 +// Copyright (c) 2019 Frank Pagliughi
  10 +// All rights reserved.
  11 +//
  12 +// Redistribution and use in source and binary forms, with or without
  13 +// modification, are permitted provided that the following conditions are
  14 +// met:
  15 +//
  16 +// 1. Redistributions of source code must retain the above copyright notice,
  17 +// this list of conditions and the following disclaimer.
  18 +//
  19 +// 2. Redistributions in binary form must reproduce the above copyright
  20 +// notice, this list of conditions and the following disclaimer in the
  21 +// documentation and/or other materials provided with the distribution.
  22 +//
  23 +// 3. Neither the name of the copyright holder nor the names of its
  24 +// contributors may be used to endorse or promote products derived from this
  25 +// software without specific prior written permission.
  26 +//
  27 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  28 +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  29 +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  30 +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  31 +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  32 +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  33 +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  34 +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  35 +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  36 +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  37 +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  38 +// --------------------------------------------------------------------------
  39 +//
  40 +
  41 +#include "sockpp/unix_stream_socket.h"
  42 +#include "catch2/catch.hpp"
  43 +#include <string>
  44 +
  45 +using namespace sockpp;
  46 +
  47 +// Test that we can create a Unix-domain stream socket pair and send
  48 +// data from one of the sockets to the other.
  49 +TEST_CASE("unix stream socket pair", "[unix_stream_socket]") {
  50 + unix_stream_socket sock1, sock2;
  51 + std::tie(sock1, sock2) = std::move(unix_stream_socket::pair());
  52 +
  53 + REQUIRE(sock1);
  54 + REQUIRE(sock2);
  55 +
  56 + REQUIRE(sock1.is_open());
  57 + REQUIRE(sock2.is_open());
  58 +
  59 + const std::string MSG { "Hello there!" };
  60 + const size_t N = MSG.length();
  61 +
  62 + char buf[512];
  63 +
  64 + REQUIRE(sock1.write(MSG) == N);
  65 + REQUIRE(sock2.read_n(buf, N) == N);
  66 +
  67 + std::string msg { buf, buf+N };
  68 + REQUIRE(msg == MSG);
  69 +}
  70 +
  71 +
tests/unit/unit_tests.cpp 0 โ†’ 100644
  1 +++ a/tests/unit/unit_tests.cpp
  1 +// unit_tests.cpp
  2 +//
  3 +// Main for unit tests.
  4 +//
  5 +
  6 +// --------------------------------------------------------------------------
  7 +// This file is part of the "sockpp" C++ socket library.
  8 +//
  9 +// Copyright (c) 2018 Frank Pagliughi
  10 +// All rights reserved.
  11 +//
  12 +// Redistribution and use in source and binary forms, with or without
  13 +// modification, are permitted provided that the following conditions are
  14 +// met:
  15 +//
  16 +// 1. Redistributions of source code must retain the above copyright notice,
  17 +// this list of conditions and the following disclaimer.
  18 +//
  19 +// 2. Redistributions in binary form must reproduce the above copyright
  20 +// notice, this list of conditions and the following disclaimer in the
  21 +// documentation and/or other materials provided with the distribution.
  22 +//
  23 +// 3. Neither the name of the copyright holder nor the names of its
  24 +// contributors may be used to endorse or promote products derived from this
  25 +// software without specific prior written permission.
  26 +//
  27 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  28 +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  29 +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  30 +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  31 +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  32 +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  33 +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  34 +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  35 +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  36 +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  37 +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  38 +// --------------------------------------------------------------------------
  39 +//
  40 +
  41 +// Normally, we would just tell Catch2 to define main() like this...
  42 +// This tells Catch to provide a main() - only do this in one cpp file
  43 +//#define CATCH_CONFIG_MAIN
  44 +
  45 +// ...but we need to run the sockpp global initialization before running
  46 +// any of the tests. Defining a main() is described here:
  47 +// https://github.com/catchorg/Catch2/blob/master/docs/own-main.md
  48 +//
  49 +
  50 +#include "sockpp/socket.h"
  51 +
  52 +// This seems to be required, at least for MSVS 2015 on Win7,
  53 +// using Catch2 v2.9.2
  54 +#if defined(_WIN32)
  55 + #define CATCH_CONFIG_DISABLE_EXCEPTIONS
  56 +#endif
  57 +
  58 +#define CATCH_CONFIG_RUNNER
  59 +#include "catch2/catch.hpp"
  60 +
  61 +int main(int argc, char* argv[])
  62 +{
  63 + // global setup...
  64 + sockpp::socket_initializer sockInit;
  65 +
  66 + int result = Catch::Session().run(argc, argv);
  67 +
  68 + // global clean-up...
  69 +
  70 + return result;
  71 +}