/proc/self/cwd/test/integration/tcp_dump.cc
Line | Count | Source (jump to first uncovered line) |
1 | | #include "test/integration/tcp_dump.h" |
2 | | |
3 | | #include <sys/types.h> |
4 | | |
5 | | #include <csignal> |
6 | | #include <fstream> |
7 | | |
8 | | #include "envoy/common/platform.h" |
9 | | |
10 | | #include "source/common/common/assert.h" |
11 | | #include "source/common/common/fmt.h" |
12 | | |
13 | | namespace Envoy { |
14 | | |
15 | | TcpDump::TcpDump(const std::string& path, const std::string& iface, |
16 | 0 | const std::vector<uint32_t>& ports) { |
17 | | #ifdef WIN32 |
18 | | ENVOY_LOG_MISC(debug, "tcpdump not supported on windows"); |
19 | | #else |
20 | | // Remove any extant pcap file. |
21 | 0 | ::unlink(path.c_str()); |
22 | | // Derive the port filter expression. |
23 | 0 | std::string port_expr; |
24 | 0 | for (uint32_t port : ports) { |
25 | 0 | if (!port_expr.empty()) { |
26 | 0 | port_expr += " or "; |
27 | 0 | } |
28 | 0 | port_expr += "tcp port " + std::to_string(port); |
29 | 0 | } |
30 | 0 | ENVOY_LOG_MISC(debug, "tcpdumping iface {} to {} with filter \"{}\"", iface, path, port_expr); |
31 | | // Fork a child process. We use explicit fork/wait over popen/pclose to gain |
32 | | // the ability to send signals to the pid. |
33 | 0 | tcpdump_pid_ = ::fork(); |
34 | 0 | RELEASE_ASSERT(tcpdump_pid_ >= 0, ""); |
35 | | // execlp in the child process. |
36 | 0 | if (tcpdump_pid_ == 0) { |
37 | 0 | const int rc = ::execlp("tcpdump", "tcpdump", "-i", iface.c_str(), "-w", path.c_str(), |
38 | 0 | "--immediate-mode", port_expr.c_str(), nullptr); |
39 | 0 | if (rc == -1) { |
40 | 0 | ::perror("tcpdump"); |
41 | 0 | exit(1); |
42 | 0 | } |
43 | 0 | } |
44 | | // Wait in parent process until tcpdump is running and has created the pcap |
45 | | // file. |
46 | 0 | while (true) { |
47 | 0 | std::ifstream test_file{path}; |
48 | 0 | if (test_file.good()) { |
49 | 0 | break; |
50 | 0 | } |
51 | | // If the child died unexpectedly, handle this. |
52 | 0 | int status; |
53 | 0 | int rc = ::waitpid(tcpdump_pid_, &status, WNOHANG); |
54 | 0 | RELEASE_ASSERT(rc != -1, ""); |
55 | 0 | if (rc > 0) { |
56 | 0 | RELEASE_ASSERT(rc == tcpdump_pid_, ""); |
57 | 0 | RELEASE_ASSERT(WIFEXITED(status), ""); |
58 | 0 | RELEASE_ASSERT(WEXITSTATUS(status) == 1, ""); |
59 | 0 | ENVOY_LOG_MISC(debug, "tcpdump exited abnormally"); |
60 | 0 | tcpdump_pid_ = 0; |
61 | 0 | break; |
62 | 0 | } |
63 | | // Give 50ms sleep. |
64 | 0 | ::usleep(50000); // NO_CHECK_FORMAT(real_time) |
65 | 0 | } |
66 | 0 | #endif |
67 | 0 | } |
68 | | |
69 | 0 | TcpDump::~TcpDump() { |
70 | 0 | #ifndef WIN32 |
71 | 0 | if (tcpdump_pid_ > 0) { |
72 | 0 | RELEASE_ASSERT(::kill(tcpdump_pid_, SIGINT) == 0, ""); |
73 | 0 | int status; |
74 | 0 | RELEASE_ASSERT(::waitpid(tcpdump_pid_, &status, 0) != -1, ""); |
75 | 0 | RELEASE_ASSERT(WIFEXITED(status), ""); |
76 | 0 | RELEASE_ASSERT(WEXITSTATUS(status) == 0, ""); |
77 | 0 | ENVOY_LOG_MISC(debug, "tcpdump terminated"); |
78 | 0 | } |
79 | 0 | #endif |
80 | 0 | } |
81 | | |
82 | | } // namespace Envoy |