diff options
| -rw-r--r-- | common.mk | 2 | ||||
| -rw-r--r-- | debian/changelog | 1 | ||||
| -rw-r--r-- | debian/control | 2 | ||||
| -rw-r--r-- | process.cpp | 112 | ||||
| -rw-r--r-- | process.h | 9 | 
5 files changed, 124 insertions, 2 deletions
| @@ -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 <mail@reichwein.it>  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 <mail@reichwein.it> -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 <filesystem> +#include <fstream>  #include <string> +#include <thread> + +#include <boost/algorithm/string.hpp> + +#include <fmt/core.h>  #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 <linux_source>/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<std::string> 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 <linux_source>/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)); + } +} + @@ -1,5 +1,7 @@  #pragma once +#include <string> +  #include <sys/types.h>  #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 | 
