Skip to content
API Documentation
BastionGuard™
UIServer::Impl Class Reference

Public Member Functions

 Impl (UIServer *owner)
 ~Impl ()
bool start (const std::string &socketPath)
void stop ()
void accept_loop ()
bool read_exact (int fd, std::uint8_t *buf, std::size_t n)
void client_session (int fd)
bool send_frame (const std::string &payload)
void flush_pending_notifs ()
void send_reply (ReplyAction action)
void queue_notification (int type, const std::string &data)
void dispatch_connected ()
void dispatch_disconnected ()
void dispatch_new_connection (const ConnectionInfo &info)
void dispatch_alert (const AlertInfo &a)

Public Attributes

UIServer * owner_
int listen_fd_ {-1}
std::string socket_file_
std::atomic_int client_fd_ {-1}
std::thread accept_thread_
std::atomic_bool running_ {false}
std::thread reader_thread_
std::mutex write_mutex_
std::atomic_uint64_t next_id_ {1}
std::mutex notif_mutex_
std::deque< json > pending_notifs_
std::mutex reply_mutex_
std::condition_variable reply_cv_
bool reply_ready_ {false}
ReplyAction reply_action_ {ReplyAction::DENY_ONCE}
std::uint64_t current_ask_id_ {0}

Detailed Description

Definition at line 63 of file UIServer.cpp.

Constructor & Destructor Documentation

◆ Impl()

UIServer::Impl::Impl ( UIServer * owner)
inline

Definition at line 65 of file UIServer.cpp.

65: owner_(owner) {}
UIServer * owner_
Definition UIServer.cpp:68

References owner_, and UIServer::UIServer().

◆ ~Impl()

UIServer::Impl::~Impl ( )
inline

Definition at line 66 of file UIServer.cpp.

66{ stop(); }

References stop().

Member Function Documentation

◆ accept_loop()

void UIServer::Impl::accept_loop ( )
inline

Definition at line 168 of file UIServer.cpp.

168 {
169 while (running_) {
170 int fd = ::accept4(listen_fd_, nullptr, nullptr, SOCK_CLOEXEC);
171 if (fd < 0) {
172 if (errno == EINTR) continue;
173 if (!running_) break;
174 std::cerr << "[UIServer] accept fallita: " << std::strerror(errno) << "\n";
175 std::this_thread::sleep_for(std::chrono::milliseconds(200));
176 continue;
177 }
178
179 // Chiudi client precedente se c'e' (un solo daemon alla volta)
180 int old = client_fd_.exchange(fd);
181 if (old >= 0) { ::shutdown(old, SHUT_RDWR); ::close(old); }
182 if (reader_thread_.joinable()) reader_thread_.join();
183
184 reader_thread_ = std::thread([this, fd]() { client_session(fd); });
185 }
186 }
std::atomic_bool running_
Definition UIServer.cpp:79
void client_session(int fd)
Definition UIServer.cpp:201
std::thread reader_thread_
Definition UIServer.cpp:82
std::atomic_int client_fd_
Definition UIServer.cpp:75

References client_fd_, client_session(), listen_fd_, reader_thread_, and running_.

Referenced by start().

◆ client_session()

void UIServer::Impl::client_session ( int fd)
inline

Definition at line 201 of file UIServer.cpp.

201 {
202 // Emetti "connected" al primo frame ricevuto (hello) — non subito,
203 // cosi' non segnaliamo client che si connettono e rompono il socket
204 // senza inviare niente. La pratica: appena ci arriva un hello
205 // dispatchiamo connected.
206 bool announced = false;
207
208 while (running_ && fd == client_fd_.load()) {
209 std::uint8_t lenbuf[4];
210 if (!read_exact(fd, lenbuf, 4)) break;
211 const std::int64_t len = bsc::proto::frame_peek_length(lenbuf, 4);
212 if (len < 0 || static_cast<std::size_t>(len) > bsc::proto::kMaxFrameSize) break;
213 std::vector<std::uint8_t> payload(static_cast<std::size_t>(len));
214 if (!read_exact(fd, payload.data(), payload.size())) break;
215
216 try {
217 json j = json::parse(payload.begin(), payload.end());
218 const std::string type = j.value("type", std::string{});
219
220 if (type == bsc::proto::msg::kHello) {
221 if (!announced) {
222 announced = true;
224 // Spedisci eventuali notifiche accodate prima della
225 // connessione.
227 }
228 continue;
229 }
230
231 if (!announced) {
232 // Pazienza: il daemon non ci ha mandato hello, ma
233 // accettiamo messaggi comunque.
234 announced = true;
236 }
237
238 if (type == bsc::proto::msg::kPing) {
239 // Rispondi con pong; il payload stats lo ignoriamo per ora
240 json pong = { {"type", bsc::proto::msg::kPong}, {"id", j.value("id", std::uint64_t{0})} };
241 send_frame(pong.dump());
242 continue;
243 }
244
245 if (type == bsc::proto::msg::kAskRule) {
246 const auto id = j.value("id", std::uint64_t{0});
247 ConnectionInfo info;
248 if (j.contains("connection")) info = connection_info_from_json(j["connection"]);
249
250 // Registra l'id come "corrente"; sendReply verra' chiamato
251 // dalla UI (thread GTK) e spedira' il reply.
252 {
253 std::lock_guard<std::mutex> lk(reply_mutex_);
254 reply_ready_ = false;
255 current_ask_id_ = id;
256 }
257
259
260 // Aspetta sendReply (timeout 20s)
261 std::unique_lock<std::mutex> lk(reply_mutex_);
262 const bool got = reply_cv_.wait_for(lk, std::chrono::seconds(20),
263 [this]() { return reply_ready_; });
264 const ReplyAction action = got ? reply_action_ : ReplyAction::DENY_ONCE;
265 reply_ready_ = false;
266 lk.unlock();
267
268 json reply = {
270 {"id", id},
271 };
272 switch (action) {
273 case ReplyAction::ALLOW_ONCE: reply["action"] = "allow"; reply["duration"] = "once"; break;
274 case ReplyAction::ALLOW_ALWAYS: reply["action"] = "allow"; reply["duration"] = "always"; break;
275 case ReplyAction::DENY_ONCE: reply["action"] = "deny"; reply["duration"] = "once"; break;
276 case ReplyAction::DENY_ALWAYS: reply["action"] = "deny"; reply["duration"] = "always"; break;
277 }
278 send_frame(reply.dump());
279 continue;
280 }
281
282 if (type == bsc::proto::msg::kAlert) {
283 AlertInfo ai;
284 ai.id = j.value("id", std::uint64_t{0});
285 const std::string level = j.value("level", std::string{"info"});
286 ai.type = level == "error" ? 0
287 : level == "warning" ? 1
288 : 2;
289 const std::string what = j.value("what", std::string{"generic"});
290 ai.what = what == "firewall" ? 2
291 : what == "connection" ? 3
292 : 0;
293 ai.action = 1; // show_alert
294 ai.priority = 1;
295 ai.text = j.value("text", std::string{});
296 if (j.contains("connection")) {
297 ai.connection = connection_info_from_json(j["connection"]);
298 ai.has_connection = true;
299 }
300 if (j.contains("rule")) {
301 ai.rule_name = j["rule"].value("name", std::string{});
302 }
303 if (ai.text.empty() && ai.has_connection) {
304 const auto host = !ai.connection.dest_host.empty()
306 : ai.connection.dest_ip;
308 + " -> " + host + ":" + std::to_string(ai.connection.dest_port);
309 }
310 dispatch_alert(ai);
311 continue;
312 }
313
314 // tipo sconosciuto: ignora
315 } catch (const std::exception& e) {
316 std::cerr << "[UIServer] JSON parse error: " << e.what() << "\n";
317 }
318 }
319
320 // Disconnessione
321 if (announced) dispatch_disconnected();
322 int expected = fd;
323 client_fd_.compare_exchange_strong(expected, -1);
324 ::close(fd);
325
326 // Sblocca eventuale sendReply pendente
327 {
328 std::lock_guard<std::mutex> lk(reply_mutex_);
329 reply_ready_ = true;
331 }
332 reply_cv_.notify_all();
333 }
nlohmann::json json
Definition Backend.cpp:2908
static std::string display_app_name(const ConnectionInfo &info)
Definition UIServer.cpp:55
static ConnectionInfo connection_info_from_json(const json &j)
Definition UIServer.cpp:35
ReplyAction
Definition UIServer.hpp:42
void dispatch_disconnected()
Definition UIServer.cpp:404
void dispatch_new_connection(const ConnectionInfo &info)
Definition UIServer.cpp:405
ReplyAction reply_action_
Definition UIServer.cpp:98
void dispatch_connected()
Definition UIServer.cpp:403
void flush_pending_notifs()
Definition UIServer.cpp:352
std::condition_variable reply_cv_
Definition UIServer.cpp:96
void dispatch_alert(const AlertInfo &a)
Definition UIServer.cpp:408
std::mutex reply_mutex_
Definition UIServer.cpp:95
bool read_exact(int fd, std::uint8_t *buf, std::size_t n)
Definition UIServer.cpp:190
std::uint64_t current_ask_id_
Definition UIServer.cpp:99
bool send_frame(const std::string &payload)
Definition UIServer.cpp:337
constexpr std::string_view kHello
Definition Wire.hpp:48
constexpr std::string_view kAskRuleReply
Definition Wire.hpp:52
constexpr std::string_view kPing
Definition Wire.hpp:49
constexpr std::string_view kAskRule
Definition Wire.hpp:51
constexpr std::string_view kPong
Definition Wire.hpp:50
constexpr std::string_view kAlert
Definition Wire.hpp:53
constexpr std::size_t kMaxFrameSize
Definition Wire.hpp:89
std::int64_t frame_peek_length(const std::uint8_t *buf, std::size_t len)
Definition Wire.hpp:78
uint64_t id
Definition UIServer.hpp:59
ConnectionInfo connection
Definition UIServer.hpp:68
bool has_connection
Definition UIServer.hpp:69
int priority
Definition UIServer.hpp:62
std::string rule_name
Definition UIServer.hpp:65
std::string text
Definition UIServer.hpp:64
std::string protocol
Definition UIServer.hpp:34
std::string dest_host
Definition UIServer.hpp:37
uint32_t dest_port
Definition UIServer.hpp:39
std::string dest_ip
Definition UIServer.hpp:38

References AlertInfo::action, ALLOW_ALWAYS, ALLOW_ONCE, client_fd_, AlertInfo::connection, connection_info_from_json(), current_ask_id_, DENY_ALWAYS, DENY_ONCE, ConnectionInfo::dest_host, ConnectionInfo::dest_ip, ConnectionInfo::dest_port, dispatch_alert(), dispatch_connected(), dispatch_disconnected(), dispatch_new_connection(), display_app_name(), flush_pending_notifs(), bsc::proto::frame_peek_length(), AlertInfo::has_connection, AlertInfo::id, bsc::proto::msg::kAlert, bsc::proto::msg::kAskRule, bsc::proto::msg::kAskRuleReply, bsc::proto::msg::kHello, bsc::proto::kMaxFrameSize, bsc::proto::msg::kPing, bsc::proto::msg::kPong, AlertInfo::priority, ConnectionInfo::protocol, read_exact(), reply_action_, reply_cv_, reply_mutex_, reply_ready_, AlertInfo::rule_name, running_, send_frame(), AlertInfo::text, AlertInfo::type, and AlertInfo::what.

Referenced by accept_loop().

◆ dispatch_alert()

void UIServer::Impl::dispatch_alert ( const AlertInfo & a)
inline

Definition at line 408 of file UIServer.cpp.

408 {
409 Glib::signal_idle().connect_once([this, a]() { owner_->signal_alert.emit(a); });
410 }
sigc::signal< void(const AlertInfo &)> signal_alert
Definition UIServer.hpp:92

References owner_, and UIServer::signal_alert.

Referenced by client_session().

◆ dispatch_connected()

void UIServer::Impl::dispatch_connected ( )
inline

Definition at line 403 of file UIServer.cpp.

403{ Glib::signal_idle().connect_once([this]() { owner_->signal_daemon_connected.emit(); }); }
sigc::signal< void()> signal_daemon_connected
Definition UIServer.hpp:89

References owner_, and UIServer::signal_daemon_connected.

Referenced by client_session().

◆ dispatch_disconnected()

void UIServer::Impl::dispatch_disconnected ( )
inline

Definition at line 404 of file UIServer.cpp.

404{ Glib::signal_idle().connect_once([this]() { owner_->signal_daemon_disconnected.emit(); }); }
sigc::signal< void()> signal_daemon_disconnected
Definition UIServer.hpp:90

References owner_, and UIServer::signal_daemon_disconnected.

Referenced by client_session().

◆ dispatch_new_connection()

void UIServer::Impl::dispatch_new_connection ( const ConnectionInfo & info)
inline

Definition at line 405 of file UIServer.cpp.

405 {
406 Glib::signal_idle().connect_once([this, info]() { owner_->signal_new_connection.emit(info); });
407 }
sigc::signal< void(const ConnectionInfo &)> signal_new_connection
Definition UIServer.hpp:91

References owner_, and UIServer::signal_new_connection.

Referenced by client_session().

◆ flush_pending_notifs()

void UIServer::Impl::flush_pending_notifs ( )
inline

Definition at line 352 of file UIServer.cpp.

352 {
353 std::deque<json> q;
354 {
355 std::lock_guard<std::mutex> lk(notif_mutex_);
356 q.swap(pending_notifs_);
357 }
358 for (const auto& j : q) {
359 if (!send_frame(j.dump())) {
360 std::lock_guard<std::mutex> lk(notif_mutex_);
361 pending_notifs_.push_front(j);
362 break;
363 }
364 }
365 }
std::mutex notif_mutex_
Definition UIServer.cpp:91
std::deque< json > pending_notifs_
Definition UIServer.cpp:92

References notif_mutex_, pending_notifs_, and send_frame().

Referenced by client_session().

◆ queue_notification()

void UIServer::Impl::queue_notification ( int type,
const std::string & data )
inline

Definition at line 380 of file UIServer.cpp.

380 {
381 static const char* kinds[] = {
382 "none", "enable_interception", "disable_interception",
383 "enable_firewall", "disable_firewall", "reload_fw_rules",
384 "change_config", "enable_rule", "disable_rule", "delete_rule",
385 "change_rule", "log_level", "stop", "task_start", "task_stop",
386 "desktop_active", "desktop_idle"
387 };
388 const std::string kind = (type >= 0 && type < 17) ? kinds[type] : "none";
389 json j = {
391 {"id", next_id_++},
392 {"kind", kind},
393 {"data", data}
394 };
395 if (client_fd_.load() >= 0 && send_frame(j.dump())) return;
396 std::lock_guard<std::mutex> lk(notif_mutex_);
397 if (pending_notifs_.size() > 128) pending_notifs_.pop_front();
398 pending_notifs_.push_back(std::move(j));
399 }
std::atomic_uint64_t next_id_
Definition UIServer.cpp:88
constexpr std::string_view kNotification
Definition Wire.hpp:54

References client_fd_, bsc::proto::msg::kNotification, next_id_, notif_mutex_, pending_notifs_, and send_frame().

◆ read_exact()

bool UIServer::Impl::read_exact ( int fd,
std::uint8_t * buf,
std::size_t n )
inline

Definition at line 190 of file UIServer.cpp.

190 {
191 std::size_t got = 0;
192 while (got < n) {
193 ssize_t r = ::recv(fd, buf + got, n - got, 0);
194 if (r == 0) return false;
195 if (r < 0) { if (errno == EINTR) continue; return false; }
196 got += static_cast<std::size_t>(r);
197 }
198 return true;
199 }

Referenced by client_session().

◆ send_frame()

bool UIServer::Impl::send_frame ( const std::string & payload)
inline

Definition at line 337 of file UIServer.cpp.

337 {
338 int fd = client_fd_.load();
339 if (fd < 0) return false;
340 std::vector<std::uint8_t> frame;
341 bsc::proto::frame_encode(payload, frame);
342 std::lock_guard<std::mutex> lk(write_mutex_);
343 std::size_t total = 0;
344 while (total < frame.size()) {
345 ssize_t n = ::send(fd, frame.data() + total, frame.size() - total, MSG_NOSIGNAL);
346 if (n < 0) { if (errno == EINTR) continue; return false; }
347 total += static_cast<std::size_t>(n);
348 }
349 return true;
350 }
std::mutex write_mutex_
Definition UIServer.cpp:85
void frame_encode(std::string_view payload, std::vector< std::uint8_t > &out)
Definition Wire.hpp:66

References client_fd_, bsc::proto::frame_encode(), and write_mutex_.

Referenced by client_session(), flush_pending_notifs(), and queue_notification().

◆ send_reply()

void UIServer::Impl::send_reply ( ReplyAction action)
inline

Definition at line 369 of file UIServer.cpp.

369 {
370 {
371 std::lock_guard<std::mutex> lk(reply_mutex_);
372 reply_action_ = action;
373 reply_ready_ = true;
374 }
375 reply_cv_.notify_one();
376 }

References reply_action_, reply_cv_, reply_mutex_, and reply_ready_.

◆ start()

bool UIServer::Impl::start ( const std::string & socketPath)
inline

Definition at line 103 of file UIServer.cpp.

103 {
104 if (running_.exchange(true)) return false;
105
107 try {
108 fs::path p(socket_file_);
109 if (p.has_parent_path()) fs::create_directories(p.parent_path());
110 if (fs::exists(p)) fs::remove(p);
111 } catch (const std::exception& e) {
112 std::cerr << "[UIServer] prep socket: " << e.what() << "\n";
113 }
114
115 listen_fd_ = ::socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
116 if (listen_fd_ < 0) { running_ = false; return false; }
117
118 sockaddr_un addr{};
119 addr.sun_family = AF_UNIX;
120 if (socket_file_.size() >= sizeof(addr.sun_path)) {
121 ::close(listen_fd_); listen_fd_ = -1; running_ = false; return false;
122 }
123 std::memcpy(addr.sun_path, socket_file_.c_str(), socket_file_.size());
124
125 if (::bind(listen_fd_, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) < 0) {
126 std::cerr << "[UIServer] bind fallita: " << std::strerror(errno) << "\n";
127 ::close(listen_fd_); listen_fd_ = -1; running_ = false; return false;
128 }
129
130 // Permessi: il daemon gira come root, la UI come utente. Il socket
131 // deve essere accessibile da entrambi → 0666.
132 ::chmod(socket_file_.c_str(), 0666);
133
134 if (::listen(listen_fd_, 4) < 0) {
135 ::close(listen_fd_); listen_fd_ = -1; running_ = false; return false;
136 }
137
138 std::cout << "[UIServer] in ascolto su " << socket_file_ << "\n";
139
140 accept_thread_ = std::thread([this]() { accept_loop(); });
141 return true;
142 }
std::thread accept_thread_
Definition UIServer.cpp:78
std::string socket_file_
Definition UIServer.cpp:72
void accept_loop()
Definition UIServer.cpp:168
std::string resolve_socket_path(std::string uri)
Definition Wire.hpp:58

References accept_loop(), accept_thread_, listen_fd_, bsc::proto::resolve_socket_path(), running_, and socket_file_.

◆ stop()

void UIServer::Impl::stop ( )
inline

Definition at line 144 of file UIServer.cpp.

144 {
145 if (!running_.exchange(false)) return;
146
147 // Chiudi listen e client
148 int lfd = listen_fd_; listen_fd_ = -1;
149 if (lfd >= 0) { ::shutdown(lfd, SHUT_RDWR); ::close(lfd); }
150 int cfd = client_fd_.exchange(-1);
151 if (cfd >= 0) { ::shutdown(cfd, SHUT_RDWR); ::close(cfd); }
152
153 // Sblocca eventuali sendReply in attesa
154 {
155 std::lock_guard<std::mutex> lk(reply_mutex_);
156 reply_ready_ = true;
157 }
158 reply_cv_.notify_all();
159
160 if (accept_thread_.joinable()) accept_thread_.join();
161 if (reader_thread_.joinable()) reader_thread_.join();
162
163 try { if (!socket_file_.empty()) fs::remove(socket_file_); } catch (...) {}
164 }

References accept_thread_, client_fd_, listen_fd_, reader_thread_, reply_cv_, reply_mutex_, reply_ready_, running_, and socket_file_.

Referenced by ~Impl().

Member Data Documentation

◆ accept_thread_

std::thread UIServer::Impl::accept_thread_

Definition at line 78 of file UIServer.cpp.

Referenced by start(), and stop().

◆ client_fd_

std::atomic_int UIServer::Impl::client_fd_ {-1}

Definition at line 75 of file UIServer.cpp.

Referenced by accept_loop(), client_session(), queue_notification(), send_frame(), and stop().

◆ current_ask_id_

std::uint64_t UIServer::Impl::current_ask_id_ {0}

Definition at line 99 of file UIServer.cpp.

Referenced by client_session().

◆ listen_fd_

int UIServer::Impl::listen_fd_ {-1}

Definition at line 71 of file UIServer.cpp.

Referenced by accept_loop(), start(), and stop().

◆ next_id_

std::atomic_uint64_t UIServer::Impl::next_id_ {1}

Definition at line 88 of file UIServer.cpp.

Referenced by queue_notification().

◆ notif_mutex_

std::mutex UIServer::Impl::notif_mutex_

Definition at line 91 of file UIServer.cpp.

Referenced by flush_pending_notifs(), and queue_notification().

◆ owner_

UIServer* UIServer::Impl::owner_

◆ pending_notifs_

std::deque<json> UIServer::Impl::pending_notifs_

Definition at line 92 of file UIServer.cpp.

Referenced by flush_pending_notifs(), and queue_notification().

◆ reader_thread_

std::thread UIServer::Impl::reader_thread_

Definition at line 82 of file UIServer.cpp.

Referenced by accept_loop(), and stop().

◆ reply_action_

ReplyAction UIServer::Impl::reply_action_ {ReplyAction::DENY_ONCE}

Definition at line 98 of file UIServer.cpp.

Referenced by client_session(), and send_reply().

◆ reply_cv_

std::condition_variable UIServer::Impl::reply_cv_

Definition at line 96 of file UIServer.cpp.

Referenced by client_session(), send_reply(), and stop().

◆ reply_mutex_

std::mutex UIServer::Impl::reply_mutex_

Definition at line 95 of file UIServer.cpp.

Referenced by client_session(), send_reply(), and stop().

◆ reply_ready_

bool UIServer::Impl::reply_ready_ {false}

Definition at line 97 of file UIServer.cpp.

Referenced by client_session(), send_reply(), and stop().

◆ running_

std::atomic_bool UIServer::Impl::running_ {false}

Definition at line 79 of file UIServer.cpp.

Referenced by accept_loop(), client_session(), start(), and stop().

◆ socket_file_

std::string UIServer::Impl::socket_file_

Definition at line 72 of file UIServer.cpp.

Referenced by start(), and stop().

◆ write_mutex_

std::mutex UIServer::Impl::write_mutex_

Definition at line 85 of file UIServer.cpp.

Referenced by send_frame().


The documentation for this class was generated from the following file:
  • BastionGuard/thirdparty/bastionguard-secure-connection/ui/src/ipc/UIServer.cpp