Commit 48b4c725c9739b3959576d5f9043d2fa1338445a
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
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 | +} |