Skip to content

Commit

Permalink
Extract server
Browse files Browse the repository at this point in the history
  • Loading branch information
uweseimet committed Jan 27, 2025
1 parent d365dbf commit 9d68224
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 47 deletions.
68 changes: 68 additions & 0 deletions cpp/s2p/s2p_server.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
//---------------------------------------------------------------------------
//
// SCSI2Pi, SCSI device emulator and SCSI tools for the Raspberry Pi
//
// Copyright (C) 2023-2025 Uwe Seimet
//
//---------------------------------------------------------------------------

#include "s2p_server.h"
#include <cassert>
#include <csignal>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <spdlog/spdlog.h>

using namespace spdlog;

string S2pServer::Init(int port)
{
assert(server_socket == -1);

if (port <= 0 || port > 65535) {
return fmt::format("Invalid port number: {}", port);
}

server_socket = socket(PF_INET, SOCK_STREAM, 0);
if (server_socket == -1) {
return fmt::format("Can't create server socket: {}", strerror(errno));
}

if (const int enable = 1; setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable)) == -1) {
Stop();
return fmt::format("Can't reuse socket: {}", strerror(errno));
}

sockaddr_in server = { };
server.sin_family = PF_INET;
server.sin_port = htons((uint16_t)port);
server.sin_addr.s_addr = INADDR_ANY;
if (bind(server_socket, reinterpret_cast<const sockaddr*>(&server), // NOSONAR bit_cast is not supported by the bullseye compiler
static_cast<socklen_t>(sizeof(sockaddr_in))) < 0) {
Stop();
return fmt::format("Port {} is in use, s2p may already be running", port);
}

if (listen(server_socket, 2) == -1) {
Stop();
return "Can't listen to service socket: " + string(strerror(errno));
}

return "";
}

void S2pServer::Stop()
{
if (server_socket != -1) {
shutdown(server_socket, SHUT_RD);
close(server_socket);

server_socket = -1;
}
}

int S2pServer::Accept() const
{
return accept(server_socket, nullptr, nullptr);
}
34 changes: 34 additions & 0 deletions cpp/s2p/s2p_server.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//---------------------------------------------------------------------------
//
// SCSI2Pi, SCSI device emulator and SCSI tools for the Raspberry Pi
//
// Copyright (C) 2023-2025 Uwe Seimet
//
//---------------------------------------------------------------------------

#pragma once

#include <string>

using namespace std;

class S2pServer
{

public:

string Init(int);

void Stop();

int Accept() const;

bool IsRunning() const
{
return server_socket != -1;
}

private:

int server_socket = -1;
};
55 changes: 9 additions & 46 deletions cpp/s2p/s2p_thread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,64 +2,32 @@
//
// SCSI2Pi, SCSI device emulator and SCSI tools for the Raspberry Pi
//
// Copyright (C) 2022-2024 Uwe Seimet
// Copyright (C) 2022-2025 Uwe Seimet
//
//---------------------------------------------------------------------------

#include "s2p_thread.h"
#include <cassert>
#include <csignal>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include "command/command_context.h"
#include "shared/s2p_exceptions.h"

using namespace s2p_util;

string S2pThread::Init(const callback &cb, int port, shared_ptr<logger> logger)
{
assert(service_socket == -1);

if (port <= 0 || port > 65535) {
return fmt::format("Invalid port number: {}", port);
}

service_socket = socket(PF_INET, SOCK_STREAM, 0);
if (service_socket == -1) {
return fmt::format("Can't create s2p service socket: {}", strerror(errno));
}

if (const int enable = 1; setsockopt(service_socket, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable)) == -1) {
Stop();
return fmt::format("Can't reuse socket: {}", strerror(errno));
}

sockaddr_in server = { };
server.sin_family = PF_INET;
server.sin_port = htons((uint16_t)port);
server.sin_addr.s_addr = INADDR_ANY;
if (bind(service_socket, reinterpret_cast<const sockaddr*>(&server), // NOSONAR bit_cast is not supported by the bullseye compiler
static_cast<socklen_t>(sizeof(sockaddr_in))) < 0) {
Stop();
return fmt::format("Port {} is in use, s2p may already be running", port);
if (const string &error = server.Init(port); !error.empty()) {
return error;
}

if (listen(service_socket, 2) == -1) {
Stop();
return "Can't listen to service socket: " + string(strerror(errno));
}
exec = cb;

s2p_logger = logger;

exec = cb;

return "";
}

void S2pThread::Start()
{
assert(service_socket != -1);
assert(server.IsRunning());

#ifndef __APPLE__
service_thread = jthread([this]() {Execute();});
Expand All @@ -71,23 +39,18 @@ void S2pThread::Start()
void S2pThread::Stop()
{
// This method might be called twice when pressing Ctrl-C, because of the installed handlers
if (service_socket != -1) {
shutdown(service_socket, SHUT_RD);
close(service_socket);

service_socket = -1;
}
server.Stop();
}

bool S2pThread::IsRunning() const
{
return service_socket != -1 && service_thread.joinable();
return server.IsRunning() && service_thread.joinable();
}

void S2pThread::Execute() const
{
while (service_socket != -1) {
const int fd = accept(service_socket, nullptr, nullptr);
while (server.IsRunning()) {
const int fd = server.Accept();
if (fd != -1) {
ExecuteCommand(fd);
close(fd);
Expand Down
3 changes: 2 additions & 1 deletion cpp/s2p/s2p_thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <string>
#include <thread>
#include <spdlog/spdlog.h>
#include "s2p_server.h"

class CommandContext;

Expand Down Expand Up @@ -43,7 +44,7 @@ class S2pThread
thread service_thread;
#endif

int service_socket = -1;
S2pServer server;

shared_ptr<logger> s2p_logger;
};

0 comments on commit 9d68224

Please sign in to comment.