/* * VizionStreamer - Unix Socket Server Implementation * Copyright (c) 2025 Maik Jurischka * * Licensed under CC BY-NC-SA 4.0 * https://creativecommons.org/licenses/by-nc-sa/4.0/ */ #include "SocketServer.h" #include #include #include #include #include SocketServer::SocketServer(const std::string& socketPath) : socketPath_(socketPath), serverFd_(-1), running_(false) {} SocketServer::~SocketServer() { stop(); } bool SocketServer::start(CommandCallback callback) { if (running_) { return false; } commandCallback_ = std::move(callback); // Remove existing socket file if it exists unlink(socketPath_.c_str()); // Create Unix domain socket serverFd_ = socket(AF_UNIX, SOCK_STREAM, 0); if (serverFd_ < 0) { std::cerr << "Failed to create socket" << std::endl; return false; } // Bind socket struct sockaddr_un addr = {}; addr.sun_family = AF_UNIX; strncpy(addr.sun_path, socketPath_.c_str(), sizeof(addr.sun_path) - 1); if (bind(serverFd_, reinterpret_cast(&addr), sizeof(addr)) < 0) { std::cerr << "Failed to bind socket: " << strerror(errno) << std::endl; close(serverFd_); return false; } // Listen for connections if (listen(serverFd_, 5) < 0) { std::cerr << "Failed to listen on socket" << std::endl; close(serverFd_); unlink(socketPath_.c_str()); return false; } running_ = true; serverThread_ = std::make_unique(&SocketServer::serverLoop, this); std::cout << "Socket server started on " << socketPath_ << std::endl; return true; } void SocketServer::stop() { if (!running_) { return; } running_ = false; // Close server socket to unblock accept() if (serverFd_ >= 0) { shutdown(serverFd_, SHUT_RDWR); close(serverFd_); serverFd_ = -1; } // Wait for server thread to finish if (serverThread_ && serverThread_->joinable()) { serverThread_->join(); } unlink(socketPath_.c_str()); std::cout << "Socket server stopped" << std::endl; } void SocketServer::serverLoop() { while (running_) { int clientFd = accept(serverFd_, nullptr, nullptr); if (clientFd < 0) { if (running_) { std::cerr << "Accept failed: " << strerror(errno) << std::endl; } continue; } handleClient(clientFd); close(clientFd); } } void SocketServer::handleClient(const int clientFd) { char buffer[4096]; const ssize_t bytesRead = recv(clientFd, buffer, sizeof(buffer) - 1, 0); if (bytesRead > 0) { buffer[bytesRead] = '\0'; const std::string command(buffer); // Call the command callback const std::string response = commandCallback_(command); // Send response back to client send(clientFd, response.c_str(), response.length(), 0); } }