Skip to content

Commit 4fe9926

Browse files
author
Artiom N.
committed
OOB example with select() add
1 parent a81565a commit 4fe9926

File tree

3 files changed

+174
-0
lines changed

3 files changed

+174
-0
lines changed

src/book01/ch06/cpp/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@ cmake_minimum_required(VERSION 3.10)
33

44
if (UNIX)
55
add_subdirectory("oob_example")
6+
add_subdirectory("oob_select")
67
add_subdirectory(namespaces)
78
endif()
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
cmake_minimum_required(VERSION 3.10)
2+
3+
project("${CHAPTER_NAME}oob-server-select" C CXX)
4+
5+
add_executable("${PROJECT_NAME}" main.cpp)
6+
target_link_libraries("${PROJECT_NAME}" socket-wrapper)
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
extern "C"
2+
{
3+
#include <fcntl.h>
4+
#include <sys/ioctl.h>
5+
}
6+
7+
#include <socket_wrapper/socket_class.h>
8+
#include <socket_wrapper/socket_functions.h>
9+
#include <socket_wrapper/socket_headers.h>
10+
#include <socket_wrapper/socket_wrapper.h>
11+
12+
#include <array>
13+
#include <cassert>
14+
#include <csignal>
15+
#include <fstream>
16+
#include <functional>
17+
#include <iostream>
18+
#include <memory>
19+
#include <stdexcept>
20+
#include <string>
21+
#include <vector>
22+
23+
24+
constexpr size_t buffer_size = 255;
25+
26+
void set_nonblock(SocketDescriptorType fd)
27+
{
28+
const IoctlType flag = 1;
29+
30+
if (ioctl(fd, FIONBIO, const_cast<IoctlType *>(&flag)) < 0)
31+
{
32+
throw std::system_error(errno, std::system_category(), "Setting non-blocking mode");
33+
}
34+
}
35+
36+
37+
void recv_data(
38+
const socket_wrapper::SocketWrapper &sock_wrap, const socket_wrapper::Socket &client_sock,
39+
std::array<char, buffer_size> &data_buff)
40+
{
41+
if (ssize_t n = recv(client_sock, data_buff.data(), data_buff.size(), 0); n < 0)
42+
{
43+
if (auto e_code = sock_wrap.get_last_error_code(); EINTR == e_code || EAGAIN == e_code)
44+
{
45+
std::cout << "recv was interrupted!" << std::endl;
46+
}
47+
else
48+
throw std::system_error(sock_wrap.get_last_error_code(), std::system_category(), "recv data");
49+
}
50+
else if (!n)
51+
{
52+
std::cout << "No data, exiting..." << std::endl;
53+
exit(EXIT_SUCCESS);
54+
}
55+
else
56+
{
57+
std::cout << "Ordinary data received...\n"
58+
<< n << " bytes was read: " << std::string(data_buff.begin(), data_buff.begin() + n) << std::endl;
59+
}
60+
}
61+
62+
63+
int main(int argc, const char *const argv[])
64+
{
65+
if (argc != 2)
66+
{
67+
std::cout << "Usage: " << argv[0] << " <port>" << std::endl;
68+
return EXIT_FAILURE;
69+
}
70+
71+
const socket_wrapper::SocketWrapper sock_wrap;
72+
73+
try
74+
{
75+
assert(argv[1]);
76+
auto server_sock = socket_wrapper::create_tcp_server(argv[1]);
77+
auto client_sock = socket_wrapper::accept_client(server_sock);
78+
79+
set_nonblock(client_sock);
80+
81+
fd_set read_descriptors_set;
82+
// fd_set write_descriptors_set;
83+
fd_set err_descriptors_set;
84+
85+
std::array<char, buffer_size> data_buff;
86+
87+
while (true)
88+
{
89+
timeval timeout = {.tv_sec = 1, .tv_usec = 0};
90+
FD_ZERO(&err_descriptors_set);
91+
FD_ZERO(&read_descriptors_set);
92+
FD_SET(client_sock, &err_descriptors_set);
93+
FD_SET(client_sock, &read_descriptors_set);
94+
95+
auto active_descriptors = select(
96+
client_sock + 1, &read_descriptors_set, nullptr /* &write_descriptors_set */, &err_descriptors_set,
97+
&timeout);
98+
99+
if (active_descriptors < 0)
100+
{
101+
throw std::system_error(errno, std::system_category(), "select");
102+
}
103+
104+
if (0 == active_descriptors)
105+
{
106+
// Nothing to do.
107+
std::cout << "No active descriptors..." << std::endl;
108+
continue;
109+
}
110+
111+
if (FD_ISSET(client_sock, &err_descriptors_set))
112+
{
113+
std::cout << "OOB or error" << std::endl;
114+
switch (sockatmark(client_sock))
115+
{
116+
case -1:
117+
throw std::system_error(errno, std::system_category(), "sockatmark");
118+
break;
119+
case 1:
120+
std::cout << "OOB data received..?" << std::endl;
121+
if (char oob_data = 0; -1 == recv(client_sock, &oob_data, 1, MSG_OOB))
122+
{
123+
if (EINVAL == sock_wrap.get_last_error_code())
124+
{
125+
std::cout << "EINVAL - this is not OOB" << std::endl;
126+
recv_data(sock_wrap, client_sock, data_buff);
127+
continue;
128+
}
129+
throw std::system_error(
130+
sock_wrap.get_last_error_code(), std::system_category(), "recv oob");
131+
}
132+
else
133+
std::cout << "OOB data = " << oob_data << std::endl;
134+
break;
135+
case 0:
136+
std::cout << "sockatmark() is 0" << std::endl;
137+
break;
138+
default:
139+
throw std::runtime_error("unexpected sockatmark");
140+
}
141+
}
142+
143+
if (FD_ISSET(client_sock, &read_descriptors_set))
144+
{
145+
recv_data(sock_wrap, client_sock, data_buff);
146+
continue;
147+
}
148+
}
149+
}
150+
catch (const std::system_error &e)
151+
{
152+
std::cerr << e.what() << ": " << sock_wrap.get_last_error_string() << "!" << std::endl;
153+
return EXIT_FAILURE;
154+
}
155+
catch (const std::exception &e)
156+
{
157+
std::cerr << e.what() << std::endl;
158+
return EXIT_FAILURE;
159+
}
160+
catch (...)
161+
{
162+
std::cerr << "Unknown exception!" << std::endl;
163+
return EXIT_FAILURE;
164+
}
165+
166+
return EXIT_SUCCESS;
167+
}

0 commit comments

Comments
 (0)