Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion scripts/build-and-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,13 @@ ENABLE_STATIC="ON"
else
ENABLE_STATIC="OFF"
fi
cmake .. -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DENABLE_TESTS=ON -DENABLE_CI=ON -DENABLE_STATIC_LINKING=$ENABLE_STATIC

if [[ "$BUILD_TYPE" == "debug" ]]; then
ENABLE_DEBUG="ON"
else
ENABLE_DEBUG="OFF"
fi
cmake .. -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DENABLE_TESTS=ON -DENABLE_CI=ON -DENABLE_DEBUG=$ENABLE_DEBUG -DENABLE_STATIC_LINKING=$ENABLE_STATIC

make -j4
ctest --output-on-failure --verbose
Expand Down
8 changes: 7 additions & 1 deletion scripts/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,13 @@ ENABLE_STATIC="ON"
else
ENABLE_STATIC="OFF"
fi
cmake .. -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DENABLE_TESTS=OFF -DENABLE_CI=ON -DENABLE_STATIC_LINKING=$ENABLE_STATIC

if [[ "$BUILD_TYPE" == "debug" ]]; then
ENABLE_DEBUG="ON"
else
ENABLE_DEBUG="OFF"
fi
cmake .. -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DENABLE_TESTS=OFF -DENABLE_CI=ON -DENABLE_DEBUG=$ENABLE_DEBUG -DENABLE_STATIC_LINKING=$ENABLE_STATIC

make -j16
make install
Expand Down
24 changes: 24 additions & 0 deletions src/include/framework/errors/tcp/connection_cancelled.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright (C) 2025 Ian Torres <iantorres@outlook.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

#ifndef FRAMEWORK_ERRORS_TCP_CONNECTION_CANCELLED_HPP
#define FRAMEWORK_ERRORS_TCP_CONNECTION_CANCELLED_HPP

#include <exception>

namespace framework::errors::tcp {
class connection_cancelled final : public std::exception {};
} // namespace framework::errors::tcp

#endif // FRAMEWORK_ERRORS_TCP_CONNECTION_CANCELLED_HPP
24 changes: 24 additions & 0 deletions src/include/framework/errors/tcp/host_not_resolved.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright (C) 2025 Ian Torres <iantorres@outlook.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

#ifndef FRAMEWORK_ERRORS_TCP_HOST_NOT_RESOLVED_HPP
#define FRAMEWORK_ERRORS_TCP_HOST_NOT_RESOLVED_HPP

#include <exception>

namespace framework::errors::tcp {
class host_not_resolved final : public std::exception {};
} // namespace framework::errors::tcp

#endif // FRAMEWORK_ERRORS_TCP_HOST_NOT_RESOLVED_HPP
24 changes: 24 additions & 0 deletions src/include/framework/errors/tcp/service_not_found.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright (C) 2025 Ian Torres <iantorres@outlook.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

#ifndef FRAMEWORK_ERRORS_TCP_SERVICE_NOT_FOUND_HPP
#define FRAMEWORK_ERRORS_TCP_SERVICE_NOT_FOUND_HPP

#include <exception>

namespace framework::errors::tcp {
class service_not_found final : public std::exception {};
} // namespace framework::errors::tcp

#endif // FRAMEWORK_ERRORS_TCP_SERVICE_NOT_FOUND_HPP
12 changes: 5 additions & 7 deletions src/include/framework/server.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,20 @@
#ifndef FRAMEWORK_SERVER_HPP
#define FRAMEWORK_SERVER_HPP

#include <framework/state.hpp>
#include <framework/support.hpp>

namespace framework {
class server : public std::enable_shared_from_this<server> {
shared_state state_ = std::make_shared<state>();
shared_state state_;
shared_of<task_group> task_group_;

public:
server();
void start(unsigned short int port = 0);
shared_of<tcp_service> serve(shared_of<tcp_handlers> callbacks,
unsigned short int port = 0) const;
shared_of<tcp_service> connect(shared_of<tcp_handlers> callbacks,
std::string host,
unsigned short int port = 0) const;
shared_of<tcp_service> bind(tcp_kind kind, std::string host,
unsigned short int port,
shared_of<tcp_handlers> callbacks,
unsigned short int connections = 1) const;
shared_state get_state() const;
shared_of<task_group> get_task_group();
};
Expand Down
16 changes: 16 additions & 0 deletions src/include/framework/support.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,24 @@
#include <ranges>
#include <regex>
#include <string>
#include <syncstream>
#include <thread>
#include <vector>

namespace framework {
#ifdef DEBUG_ENABLED
inline std::mutex LOG_MUTEX;
#define LOG(msg) \
do { \
std::osyncstream(std::cout) << "[" << __FILE__ << ":" << __LINE__ << " - " \
<< __func__ << "] " << msg << std::endl; \
} while (0)
#else
#define LOG(x) \
do { \
} while (0)
#endif

class task_group;

class metrics;
Expand Down Expand Up @@ -79,6 +93,8 @@ class tcp_connection;
class tcp_handlers;
class tcp_service;

enum class tcp_kind : int;

class validator;

using shared_validator = std::shared_ptr<validator>;
Expand Down
19 changes: 19 additions & 0 deletions src/include/framework/tcp_connection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,35 +33,54 @@ class tcp_connection : public std::enable_shared_from_this<tcp_connection> {
shared_of<tcp_executor> get_strand() const noexcept;
shared_of<tcp_stream> get_stream() const noexcept;
async_of<void> notify_write();

template <typename Buffer>
void invoke(Buffer &&buf) {
LOG("tcp_connection::invoke() start id=" << id_);

auto _self = this->shared_from_this();
LOG("tcp_connection::invoke() shared_from_this acquired");

co_spawn(
*strand_,
[_self, _buf = std::forward<Buffer>(buf)]() mutable -> async_of<void> {
LOG("tcp_connection::invoke() coroutine start id=" << _self->id_);

auto _payload_buffer = boost::asio::buffer(_buf);
const std::size_t _payload_size =
boost::asio::buffer_size(_payload_buffer);

LOG("invoke(): payload size = " << _payload_size);

if (_payload_size > MAX_FRAME_SIZE) {
LOG("invoke(): ERROR payload too big: " << _payload_size);
std::cerr << "Payload size is too big" << std::endl;
co_return;
}

const auto _length = static_cast<std::uint32_t>(_payload_size);
LOG("invoke(): writing header with length=" << _length);

std::array<unsigned char, 4> _header;
_header[0] = static_cast<unsigned char>(_length >> 24 & 0xFF);
_header[1] = static_cast<unsigned char>(_length >> 16 & 0xFF);
_header[2] = static_cast<unsigned char>(_length >> 8 & 0xFF);
_header[3] = static_cast<unsigned char>(_length >> 0 & 0xFF);

LOG("invoke(): header created");

std::array<boost::asio::const_buffer, 2> _buffers{
boost::asio::buffer(_header), _payload_buffer};

LOG("invoke(): calling async_write() id=" << _self->id_);
co_await boost::asio::async_write(*_self->stream_, _buffers,
boost::asio::as_tuple);
LOG("invoke(): async_write() completed id=" << _self->id_);

LOG("invoke(): calling notify_write()");
co_await _self->notify_write();

LOG("invoke(): coroutine exit id=" << _self->id_);
co_return;
},
boost::asio::detached);
Expand Down
22 changes: 8 additions & 14 deletions src/include/framework/tcp_handlers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,20 +36,14 @@ class tcp_handlers : public std::enable_shared_from_this<tcp_handlers> {
read_handler_type on_read = nullptr,
handler_type on_write = nullptr,
handler_type on_disconnected = nullptr,
error_handler_type on_error = nullptr)
: on_connect_(on_connect),
on_accepted_(on_accepted),
on_read_(on_read),
on_write_(on_write),
on_disconnected_(on_disconnected),
on_error_(on_error) {}

handler_type on_connect() const { return on_connect_; }
handler_type on_accepted() const { return on_accepted_; }
read_handler_type on_read() const { return on_read_; }
handler_type on_write() const { return on_write_; }
handler_type on_disconnected() const { return on_disconnected_; }
error_handler_type on_error() const { return on_error_; }
error_handler_type on_error = nullptr);

handler_type on_connect() const;
handler_type on_accepted() const;
read_handler_type on_read() const;
handler_type on_write() const;
handler_type on_disconnected() const;
error_handler_type on_error() const;

private:
handler_type on_connect_;
Expand Down
27 changes: 27 additions & 0 deletions src/include/framework/tcp_kind.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright (C) 2025 Ian Torres <iantorres@outlook.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

#pragma once

#ifndef FRAMEWORK_TCP_KIND_HPP
#define FRAMEWORK_TCP_KIND_HPP

namespace framework {
enum class tcp_kind {
SERVER = 0,
CLIENT = 1,
};
} // namespace framework

#endif // FRAMEWORK_TCP_KIND_HPP
10 changes: 9 additions & 1 deletion src/include/framework/tcp_service.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,26 +22,34 @@
namespace framework {
class tcp_service : public std::enable_shared_from_this<tcp_service> {
atomic_of<bool> running_{false};
atomic_of<int> scale_{0};
uuid id_;
std::string host_;
unsigned short int port_;
std::mutex mutex_;
vector_of<shared_of<tcp_connection>> writers_;
shared_of<tcp_handlers> callback_;
shared_of<task_group> task_group_;

public:
explicit tcp_service(uuid id, std::string host, unsigned short int port = 0,
shared_of<tcp_handlers> handlers = nullptr);
shared_of<tcp_handlers> handlers() const;
void set_task_group(shared_of<task_group> tg);
shared_of<task_group> get_task_group() const;
void stop();
uuid get_id() const;
int get_scale() const;
std::string get_host() const;
unsigned short int get_port() const;
void set_port(unsigned short int port);
bool get_running() const;
void set_running(bool running);
void stop_clients();
void add(shared_of<tcp_connection> writer);
void remove(uuid session_id);
bool remove(uuid session_id);
void scale_to(int quantity);
bool contains(uuid session_id);
vector_of<shared_of<tcp_connection>> snapshot();
};
} // namespace framework
Expand Down
Loading
Loading