From 02fbb7a8ea54d1188b2a8410ecd64ae93ac0210e Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Fri, 13 Jan 2023 15:52:17 +0100 Subject: Added process functions --- process.cpp | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) (limited to 'process.cpp') diff --git a/process.cpp b/process.cpp index b30ef3d..67cf1ce 100644 --- a/process.cpp +++ b/process.cpp @@ -1,9 +1,16 @@ #include "process.h" #include +#include #include +#include + +#include + +#include #include "file.h" +#include "stringhelper.h" namespace fs = std::filesystem; @@ -25,3 +32,108 @@ bool Reichwein::Process::is_running(pid_t pid) return state == "R" || state == "S"; } + +// tcp: tcp or tcp6 +bool Reichwein::Process::tcp_is_pid_listening_on(const std::string& tcp, pid_t pid, int port) +{ + std::string filename{fmt::format("/proc/{}/net/{}", pid, tcp)}; + std::ifstream f{filename, std::ios::in}; + // e.g.: + // sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode + // 0: 00000000:C799 00000000:0000 0A 00000000:00000000 00:00000000 00000000 107 0 21869 1 00000000335416a4 100 0 0 10 0 + std::string s; + std::getline(f, s); // skip head line + while (std::getline(f, s)) { + boost::algorithm::trim_left(s); + + size_t pos_space1{s.find(' ')}; + if (pos_space1 == std::string::npos) + throw std::runtime_error("Expected first space in " + filename); + + size_t pos_colon1{s.find(':', pos_space1 + 1)}; + if (pos_colon1 == std::string::npos) + throw std::runtime_error("Expected first colon in " + filename); + + size_t pos_space2{s.find(' ', pos_colon1 + 1)}; + if (pos_space2 == std::string::npos) + throw std::runtime_error("Expected second space in " + filename); + + std::string port_s{s.substr(pos_colon1 + 1, pos_space2 - (pos_colon1 + 1))}; + auto current_port{std::stoul(port_s, nullptr, 16)}; + if (current_port != port) + continue; + + // now, we are in a line related to matching local port + + size_t pos_space3{s.find(' ', pos_space2 + 1)}; + if (pos_space3 == std::string::npos) + throw std::runtime_error("Expected third space in " + filename); + + size_t pos_space4{s.find(' ', pos_space3 + 1)}; + if (pos_space4 == std::string::npos) + throw std::runtime_error("Expected fourth space in " + filename); + + std::string state_s{s.substr(pos_space3 + 1, pos_space4 - (pos_space3 + 1))}; + if (state_s == "0A") // listening state TCP_LISTEN, from /include/net/tcp_states.h + return true; + } + + return false; // not found +} + +bool Reichwein::Process::is_pid_listening_on(pid_t pid, int port) +{ + return tcp_is_pid_listening_on("tcp", pid, port) || tcp_is_pid_listening_on("tcp6", pid, port); +} + +bool Reichwein::Process::unix_is_pid_listening_on(pid_t pid, const std::string& path) +{ + std::string filename{fmt::format("/proc/{}/net/unix", pid)}; + std::ifstream f{filename, std::ios::in}; + // e.g.: + // Num RefCount Protocol Flags Type St Inode Path + // 000000009ce259a6: 00000003 00000000 00000000 0001 03 29015 + // 000000003a686108: 00000003 00000000 00000000 0001 03 27263 /run/user/1000/pulse/native + // 000000006d62b584: 00000002 00000000 00010000 0001 01 6126359 @/tmp/dbus-b8l6vAYN + std::string s; + std::getline(f, s); // skip head line + while (std::getline(f, s)) { + boost::algorithm::trim_left(s); + std::vector columns{Reichwein::Stringhelper::split(s, " ")}; + if (columns.size() < 8) + continue; + + std::string current_path = columns[7]; + + if (current_path[0] == '@') + current_path = current_path.substr(1); + + if (current_path != path) + continue; + + std::string state = columns[5]; + + // I would expect "0A" here, since net/unix/af_unix.c also uses + // TCP_LISTEN etc. as in TCP sockets /proc/{}/net/tcp. + // But practically, I always get "01" + if (state == "0A" || state == "01") // listening state TCP_LISTEN, from /include/net/tcp_states.h + return true; + } + + return false; // not found +} + +void Reichwein::Process::wait_for_pid_listening_on(pid_t pid, int port) +{ + while (!is_pid_listening_on(pid, port)) { + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } +} + +void Reichwein::Process::wait_for_pid_listening_on(pid_t pid, const std::string& path) +{ + while (!unix_is_pid_listening_on(pid, path)) { + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } +} + -- cgit v1.2.3