Skip to content

Commit 627753d

Browse files
author
Artiom N.
committed
Zero-copy example add
1 parent e7313a4 commit 627753d

File tree

3 files changed

+103
-0
lines changed

3 files changed

+103
-0
lines changed

src/book01/ch23/cpp/CMakeLists.txt

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

44
if (UNIX)
55
add_subdirectory("tun_example")
6+
add_subdirectory("zc_example")
67
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}zc-example" C CXX)
4+
5+
add_executable("${PROJECT_NAME}" "main.cpp")
6+
target_link_libraries("${PROJECT_NAME}" socket-wrapper)
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
extern "C"
2+
{
3+
#include <netinet/ip.h>
4+
// sock_extended_err.
5+
#include <linux/errqueue.h>
6+
#include <linux/tcp.h>
7+
#include <poll.h>
8+
}
9+
10+
#include <socket_wrapper/socket_functions.h>
11+
#include <socket_wrapper/socket_headers.h>
12+
#include <socket_wrapper/socket_wrapper.h>
13+
14+
#include <array>
15+
#include <cinttypes>
16+
#include <cstdint>
17+
#include <exception>
18+
#include <iostream>
19+
#include <string>
20+
21+
22+
std::pair<uint32_t, uint32_t> read_notification(const msghdr *msg)
23+
{
24+
const cmsghdr *cm = CMSG_FIRSTHDR(msg);
25+
26+
if (cm->cmsg_level != SOL_IP && cm->cmsg_type != IP_RECVERR)
27+
throw std::system_error(errno, std::system_category(), "cmsg");
28+
29+
const sock_extended_err *serr = reinterpret_cast<const sock_extended_err *>(CMSG_DATA(cm));
30+
31+
if (serr->ee_errno != 0 || serr->ee_origin != SO_EE_ORIGIN_ZEROCOPY)
32+
throw std::system_error(errno, std::system_category(), "recvmsg");
33+
34+
return std::make_pair(serr->ee_data, serr->ee_info);
35+
}
36+
37+
38+
int main()
39+
{
40+
const socket_wrapper::SocketWrapper sock_wrap;
41+
const int sock_fd{socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)};
42+
43+
if (!sock_fd) return EXIT_FAILURE;
44+
45+
try
46+
{
47+
const int one = 1;
48+
49+
if (setsockopt(sock_fd, SOL_SOCKET, SO_ZEROCOPY, &one, sizeof(one)))
50+
throw std::system_error(errno, std::system_category(), "setsockopt");
51+
52+
std::string buf{"test data"};
53+
54+
auto c_i = socket_wrapper::get_client_info("localhost", "12345");
55+
56+
if (-1 == connect(sock_fd, c_i->ai_addr, c_i->ai_addrlen))
57+
{
58+
throw std::system_error(errno, std::system_category(), "connect");
59+
}
60+
61+
if (send(sock_fd, buf.data(), buf.size(), MSG_ZEROCOPY) != buf.size())
62+
throw std::system_error(errno, std::system_category(), "send");
63+
64+
pollfd pfd = {.fd = sock_fd, .events = 0};
65+
66+
if (poll(&pfd, 1, -1) != 1 || !(pfd.revents & POLLERR))
67+
throw std::system_error(errno, std::system_category(), "poll");
68+
69+
std::array<char, CMSG_SPACE(sizeof(uint32_t))> ancil_data_buff;
70+
iovec iov[1] = {{buf.data(), buf.size()}};
71+
72+
msghdr msg = {
73+
.msg_name = nullptr,
74+
.msg_namelen = 0,
75+
.msg_iov = iov,
76+
.msg_iovlen = 1,
77+
.msg_control = &ancil_data_buff[0],
78+
.msg_controllen = ancil_data_buff.size(),
79+
.msg_flags = 0};
80+
81+
if (-1 == recvmsg(sock_fd, &msg, MSG_ERRQUEUE))
82+
throw std::system_error(errno, std::system_category(), "recvmsg");
83+
84+
auto [data, info] = read_notification(&msg);
85+
std::cout << "Data: " << data << ", Info: " << info << std::endl;
86+
close(sock_fd);
87+
}
88+
catch (const std::exception &e)
89+
{
90+
std::cerr << "Error: " << e.what() << std::endl;
91+
close(sock_fd);
92+
return EXIT_FAILURE;
93+
}
94+
95+
return EXIT_SUCCESS;
96+
}

0 commit comments

Comments
 (0)