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 | +} | ... | ... |