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 --- common.mk | 2 +- debian/changelog | 1 + debian/control | 2 +- process.cpp | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ process.h | 9 +++++ 5 files changed, 124 insertions(+), 2 deletions(-) diff --git a/common.mk b/common.mk index 405982d..563602e 100644 --- a/common.mk +++ b/common.mk @@ -101,4 +101,4 @@ LIBS+= \ -lstdc++fs endif -LIBS+=-lboost_context -lboost_system -lpthread +LIBS+=-lboost_context -lboost_system -lpthread -lfmt diff --git a/debian/changelog b/debian/changelog index 9c72966..0bba3c2 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,6 +1,7 @@ libreichwein (1.2) UNRELEASED; urgency=medium * Added process.h+cpp: Reichwein::Process::is_running() + * process.h+cpp: Added functions for checking running pids -- Roland Reichwein Sat, 07 Jan 2023 19:15:07 +0100 diff --git a/debian/control b/debian/control index 83988c8..3b883b5 100644 --- a/debian/control +++ b/debian/control @@ -2,7 +2,7 @@ Source: libreichwein Section: devel Priority: optional Maintainer: Roland Reichwein -Build-Depends: debhelper (>= 12), libboost-all-dev | libboost1.71-all-dev, clang | g++-9, llvm | g++-9, lld | g++-9, googletest, gcovr +Build-Depends: debhelper (>= 12), libboost-all-dev | libboost1.71-all-dev, clang | g++-9, llvm | g++-9, lld | g++-9, googletest, gcovr, libfmt-dev Standards-Version: 4.5.0 Homepage: http://www.reichwein.it/libreichwein/ 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)); + } +} + diff --git a/process.h b/process.h index b13a54c..fb24017 100644 --- a/process.h +++ b/process.h @@ -1,5 +1,7 @@ #pragma once +#include + #include #define EXPORT __attribute__((visibility("default"))) @@ -8,4 +10,11 @@ namespace Reichwein::Process { EXPORT bool is_running(pid_t pid); +EXPORT bool unix_is_pid_listening_on(pid_t pid, const std::string& path); +EXPORT void wait_for_pid_listening_on(pid_t pid, const std::string& path); + +EXPORT bool tcp_is_pid_listening_on(const std::string& tcp, pid_t pid, int port); +EXPORT bool is_pid_listening_on(pid_t pid, int port); +EXPORT void wait_for_pid_listening_on(pid_t pid, int port); + } // namespace -- cgit v1.2.3