summaryrefslogtreecommitdiffhomepage
path: root/process.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'process.cpp')
-rw-r--r--process.cpp112
1 files changed, 112 insertions, 0 deletions
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));
+ }
+}
+