Commit d81e4e93 authored by Dominik Charousset's avatar Dominik Charousset

Rename ssl::{ => tcp_}acceptor

parent d6461dac
...@@ -31,7 +31,6 @@ caf_add_component( ...@@ -31,7 +31,6 @@ caf_add_component(
SOURCES SOURCES
src/detail/convert_ip_endpoint.cpp src/detail/convert_ip_endpoint.cpp
src/detail/rfc6455.cpp src/detail/rfc6455.cpp
src/detail/shared_ssl_acceptor.cpp
src/net/abstract_actor_shell.cpp src/net/abstract_actor_shell.cpp
src/net/actor_shell.cpp src/net/actor_shell.cpp
src/net/binary/default_trait.cpp src/net/binary/default_trait.cpp
...@@ -63,7 +62,6 @@ caf_add_component( ...@@ -63,7 +62,6 @@ caf_add_component(
src/net/socket.cpp src/net/socket.cpp
src/net/socket_event_layer.cpp src/net/socket_event_layer.cpp
src/net/socket_manager.cpp src/net/socket_manager.cpp
src/net/ssl/acceptor.cpp
src/net/ssl/connection.cpp src/net/ssl/connection.cpp
src/net/ssl/context.cpp src/net/ssl/context.cpp
src/net/ssl/dtls.cpp src/net/ssl/dtls.cpp
...@@ -71,6 +69,7 @@ caf_add_component( ...@@ -71,6 +69,7 @@ caf_add_component(
src/net/ssl/format.cpp src/net/ssl/format.cpp
src/net/ssl/password.cpp src/net/ssl/password.cpp
src/net/ssl/startup.cpp src/net/ssl/startup.cpp
src/net/ssl/tcp_acceptor.cpp
src/net/ssl/tls.cpp src/net/ssl/tls.cpp
src/net/ssl/transport.cpp src/net/ssl/transport.cpp
src/net/ssl/verify.cpp src/net/ssl/verify.cpp
......
// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#pragma once
#include "caf/detail/net_export.hpp"
#include "caf/expected.hpp"
#include "caf/net/ssl/context.hpp"
#include "caf/net/ssl/fwd.hpp"
#include "caf/net/tcp_accept_socket.hpp"
#include <variant>
namespace caf::detail {
/// Like @ref net::ssl::acceptor but with a `shared_ptr` to the context.
class CAF_NET_EXPORT shared_ssl_acceptor {
public:
// -- member types -----------------------------------------------------------
using transport_type = net::ssl::transport;
// -- constructors, destructors, and assignment operators --------------------
shared_ssl_acceptor() = delete;
shared_ssl_acceptor(const shared_ssl_acceptor&) = default;
shared_ssl_acceptor& operator=(const shared_ssl_acceptor&) = default;
shared_ssl_acceptor(shared_ssl_acceptor&& other);
shared_ssl_acceptor& operator=(shared_ssl_acceptor&& other);
shared_ssl_acceptor(net::tcp_accept_socket fd,
std::shared_ptr<net::ssl::context> ctx)
: fd_(fd), ctx_(std::move(ctx)) {
// nop
}
// -- properties -------------------------------------------------------------
net::tcp_accept_socket fd() const noexcept {
return fd_;
}
net::ssl::context& ctx() noexcept {
return *ctx_;
}
const net::ssl::context& ctx() const noexcept {
return *ctx_;
}
private:
net::tcp_accept_socket fd_;
std::shared_ptr<net::ssl::context> ctx_;
};
// -- free functions -----------------------------------------------------------
/// Checks whether `acc` has a valid socket descriptor.
bool CAF_NET_EXPORT valid(const shared_ssl_acceptor& acc);
/// Closes the socket of `obj`.
void CAF_NET_EXPORT close(shared_ssl_acceptor& acc);
/// Tries to accept a new connection on `acc`. On success, wraps the new socket
/// into an SSL @ref connection and returns it.
expected<net::ssl::connection> CAF_NET_EXPORT accept(shared_ssl_acceptor& acc);
} // namespace caf::detail
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
#include "caf/net/dsl/base.hpp" #include "caf/net/dsl/base.hpp"
#include "caf/net/dsl/client_config.hpp" #include "caf/net/dsl/client_config.hpp"
#include "caf/net/fwd.hpp" #include "caf/net/fwd.hpp"
#include "caf/net/ssl/acceptor.hpp" #include "caf/net/ssl/tcp_acceptor.hpp"
#include "caf/net/tcp_accept_socket.hpp" #include "caf/net/tcp_accept_socket.hpp"
#include <cstdint> #include <cstdint>
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
#include "caf/net/dsl/base.hpp" #include "caf/net/dsl/base.hpp"
#include "caf/net/dsl/server_config.hpp" #include "caf/net/dsl/server_config.hpp"
#include "caf/net/fwd.hpp" #include "caf/net/fwd.hpp"
#include "caf/net/ssl/acceptor.hpp" #include "caf/net/ssl/tcp_acceptor.hpp"
#include "caf/net/tcp_accept_socket.hpp" #include "caf/net/tcp_accept_socket.hpp"
#include <cstdint> #include <cstdint>
...@@ -42,9 +42,9 @@ public: ...@@ -42,9 +42,9 @@ public:
/// Creates an `accept_factory` object for the given acceptor. /// Creates an `accept_factory` object for the given acceptor.
/// ///
/// @param acc The SSL acceptor for incoming connections. /// @param acc The SSL acceptor for incoming TCP connections.
/// @returns an `accept_factory` object that will start a server on `acc`. /// @returns an `accept_factory` object that will start a server on `acc`.
auto accept(ssl::acceptor acc) { auto accept(ssl::tcp_acceptor acc) {
auto& dref = static_cast<Subtype&>(*this); auto& dref = static_cast<Subtype&>(*this);
auto& cfg = dref.config(); auto& cfg = dref.config();
auto ptr = cfg.as_has_ctx(); auto ptr = cfg.as_has_ctx();
...@@ -53,7 +53,7 @@ public: ...@@ -53,7 +53,7 @@ public:
return dref.make(server_config::fail_v, cfg, cfg.cannot_add_ctx()); return dref.make(server_config::fail_v, cfg, cfg.cannot_add_ctx());
} else if (ptr->ctx) { } else if (ptr->ctx) {
auto err = make_error(sec::logic_error, auto err = make_error(sec::logic_error,
"passed an ssl::acceptor to a factory " "passed an ssl::tcp_acceptor to a factory "
"with a valid SSL context"); "with a valid SSL context");
return dref.make(server_config::fail_v, std::move(err)); return dref.make(server_config::fail_v, std::move(err));
} else { } else {
......
...@@ -5,9 +5,9 @@ ...@@ -5,9 +5,9 @@
#pragma once #pragma once
#include "caf/expected.hpp" #include "caf/expected.hpp"
#include "caf/net/ssl/acceptor.hpp"
#include "caf/net/ssl/connection.hpp" #include "caf/net/ssl/connection.hpp"
#include "caf/net/ssl/context.hpp" #include "caf/net/ssl/context.hpp"
#include "caf/net/ssl/tcp_acceptor.hpp"
#include "caf/net/stream_socket.hpp" #include "caf/net/stream_socket.hpp"
#include <memory> #include <memory>
...@@ -46,7 +46,7 @@ public: ...@@ -46,7 +46,7 @@ public:
auto acceptor_with_ctx(F&& f) { auto acceptor_with_ctx(F&& f) {
return [this, g = std::forward<F>(f)](auto fd) mutable { return [this, g = std::forward<F>(f)](auto fd) mutable {
if (ctx) { if (ctx) {
auto acc = ssl::acceptor{fd, std::move(*ctx)}; auto acc = ssl::tcp_acceptor{fd, std::move(*ctx)};
return g(acc); return g(acc);
} else } else
return g(fd); return g(fd);
......
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
#include "caf/net/dsl/base.hpp" #include "caf/net/dsl/base.hpp"
#include "caf/net/dsl/server_config.hpp" #include "caf/net/dsl/server_config.hpp"
#include "caf/net/fwd.hpp" #include "caf/net/fwd.hpp"
#include "caf/net/ssl/acceptor.hpp"
#include "caf/net/tcp_accept_socket.hpp" #include "caf/net/tcp_accept_socket.hpp"
#include <cstdint> #include <cstdint>
......
...@@ -10,7 +10,6 @@ ...@@ -10,7 +10,6 @@
#include "caf/detail/binary_flow_bridge.hpp" #include "caf/detail/binary_flow_bridge.hpp"
#include "caf/detail/connection_factory.hpp" #include "caf/detail/connection_factory.hpp"
#include "caf/detail/net_export.hpp" #include "caf/detail/net_export.hpp"
#include "caf/detail/shared_ssl_acceptor.hpp"
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
#include "caf/net/checked_socket.hpp" #include "caf/net/checked_socket.hpp"
#include "caf/net/dsl/server_factory_base.hpp" #include "caf/net/dsl/server_factory_base.hpp"
......
...@@ -13,7 +13,6 @@ ...@@ -13,7 +13,6 @@
#include "caf/net/http/request.hpp" #include "caf/net/http/request.hpp"
#include "caf/net/http/server_factory.hpp" #include "caf/net/http/server_factory.hpp"
#include "caf/net/multiplexer.hpp" #include "caf/net/multiplexer.hpp"
#include "caf/net/ssl/acceptor.hpp"
#include "caf/net/ssl/context.hpp" #include "caf/net/ssl/context.hpp"
#include "caf/net/tcp_accept_socket.hpp" #include "caf/net/tcp_accept_socket.hpp"
......
...@@ -132,7 +132,7 @@ public: ...@@ -132,7 +132,7 @@ public:
/// Listens for incoming connection on @p fd. /// Listens for incoming connection on @p fd.
/// @param sys The host system. /// @param sys The host system.
/// @param acc A connection acceptor such as @ref tcp_accept_socket or /// @param acc A connection acceptor such as @ref tcp_accept_socket or
/// @ref ssl::acceptor. /// @ref ssl::tcp_acceptor.
/// @param cfg Configures the acceptor. Currently, the only supported /// @param cfg Configures the acceptor. Currently, the only supported
/// configuration parameter is `max-connections`. /// configuration parameter is `max-connections`.
template <class Acceptor> template <class Acceptor>
......
...@@ -9,7 +9,6 @@ ...@@ -9,7 +9,6 @@
#include "caf/detail/accept_handler.hpp" #include "caf/detail/accept_handler.hpp"
#include "caf/detail/binary_flow_bridge.hpp" #include "caf/detail/binary_flow_bridge.hpp"
#include "caf/detail/connection_factory.hpp" #include "caf/detail/connection_factory.hpp"
#include "caf/detail/shared_ssl_acceptor.hpp"
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
#include "caf/net/checked_socket.hpp" #include "caf/net/checked_socket.hpp"
#include "caf/net/dsl/server_factory_base.hpp" #include "caf/net/dsl/server_factory_base.hpp"
......
...@@ -13,7 +13,6 @@ ...@@ -13,7 +13,6 @@
#include "caf/net/lp/client_factory.hpp" #include "caf/net/lp/client_factory.hpp"
#include "caf/net/lp/server_factory.hpp" #include "caf/net/lp/server_factory.hpp"
#include "caf/net/multiplexer.hpp" #include "caf/net/multiplexer.hpp"
#include "caf/net/ssl/acceptor.hpp"
#include "caf/net/ssl/context.hpp" #include "caf/net/ssl/context.hpp"
#include "caf/net/tcp_accept_socket.hpp" #include "caf/net/tcp_accept_socket.hpp"
......
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
#include "caf/defaults.hpp" #include "caf/defaults.hpp"
#include "caf/detail/accept_handler.hpp" #include "caf/detail/accept_handler.hpp"
#include "caf/detail/connection_factory.hpp" #include "caf/detail/connection_factory.hpp"
#include "caf/detail/shared_ssl_acceptor.hpp"
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
#include "caf/net/checked_socket.hpp" #include "caf/net/checked_socket.hpp"
#include "caf/net/dsl/server_config.hpp" #include "caf/net/dsl/server_config.hpp"
......
...@@ -9,7 +9,6 @@ ...@@ -9,7 +9,6 @@
#include "caf/net/dsl/has_accept.hpp" #include "caf/net/dsl/has_accept.hpp"
#include "caf/net/dsl/has_context.hpp" #include "caf/net/dsl/has_context.hpp"
#include "caf/net/prometheus/server_factory.hpp" #include "caf/net/prometheus/server_factory.hpp"
#include "caf/net/ssl/acceptor.hpp"
#include "caf/net/ssl/context.hpp" #include "caf/net/ssl/context.hpp"
#include "caf/net/tcp_accept_socket.hpp" #include "caf/net/tcp_accept_socket.hpp"
......
...@@ -14,8 +14,8 @@ ...@@ -14,8 +14,8 @@
namespace caf::net::ssl { namespace caf::net::ssl {
/// Wraps an accept socket and an SSL context. /// Wraps a TCP accept socket and an SSL context.
class CAF_NET_EXPORT acceptor { class CAF_NET_EXPORT tcp_acceptor {
public: public:
// -- member types ----------------------------------------------------------- // -- member types -----------------------------------------------------------
...@@ -25,33 +25,34 @@ public: ...@@ -25,33 +25,34 @@ public:
// -- constructors, destructors, and assignment operators -------------------- // -- constructors, destructors, and assignment operators --------------------
acceptor() = delete; tcp_acceptor() = delete;
acceptor(const acceptor&) = delete; tcp_acceptor(const tcp_acceptor&) = delete;
acceptor& operator=(const acceptor&) = delete; tcp_acceptor& operator=(const tcp_acceptor&) = delete;
acceptor(acceptor&& other); tcp_acceptor(tcp_acceptor&& other);
acceptor& operator=(acceptor&& other); tcp_acceptor& operator=(tcp_acceptor&& other);
acceptor(tcp_accept_socket fd, context ctx) : fd_(fd), ctx_(std::move(ctx)) { tcp_acceptor(tcp_accept_socket fd, context ctx)
: fd_(fd), ctx_(std::move(ctx)) {
// nop // nop
} }
// -- factories -------------------------------------------------------------- // -- factories --------------------------------------------------------------
static expected<acceptor> static expected<tcp_acceptor>
make_with_cert_file(tcp_accept_socket fd, const char* cert_file_path, make_with_cert_file(tcp_accept_socket fd, const char* cert_file_path,
const char* key_file_path, const char* key_file_path,
format file_format = format::pem); format file_format = format::pem);
static expected<acceptor> static expected<tcp_acceptor>
make_with_cert_file(uint16_t port, const char* cert_file_path, make_with_cert_file(uint16_t port, const char* cert_file_path,
const char* key_file_path, const char* key_file_path,
format file_format = format::pem); format file_format = format::pem);
static expected<acceptor> static expected<tcp_acceptor>
make_with_cert_file(tcp_accept_socket fd, const std::string& cert_file_path, make_with_cert_file(tcp_accept_socket fd, const std::string& cert_file_path,
const std::string& key_file_path, const std::string& key_file_path,
format file_format = format::pem) { format file_format = format::pem) {
...@@ -59,7 +60,7 @@ public: ...@@ -59,7 +60,7 @@ public:
key_file_path.c_str(), file_format); key_file_path.c_str(), file_format);
} }
static expected<acceptor> static expected<tcp_acceptor>
make_with_cert_file(uint16_t port, const std::string& cert_file_path, make_with_cert_file(uint16_t port, const std::string& cert_file_path,
const std::string& key_file_path, const std::string& key_file_path,
format file_format = format::pem) { format file_format = format::pem) {
...@@ -89,13 +90,13 @@ private: ...@@ -89,13 +90,13 @@ private:
// -- free functions ----------------------------------------------------------- // -- free functions -----------------------------------------------------------
/// Checks whether `acc` has a valid socket descriptor. /// Checks whether `acc` has a valid socket descriptor.
bool CAF_NET_EXPORT valid(const acceptor& acc); bool CAF_NET_EXPORT valid(const tcp_acceptor& acc);
/// Closes the socket of `obj`. /// Closes the socket of `obj`.
void CAF_NET_EXPORT close(acceptor& acc); void CAF_NET_EXPORT close(tcp_acceptor& acc);
/// Tries to accept a new connection on `acc`. On success, wraps the new socket /// Tries to accept a new connection on `acc`. On success, wraps the new socket
/// into an SSL @ref connection and returns it. /// into an SSL @ref connection and returns it.
expected<connection> CAF_NET_EXPORT accept(acceptor& acc); expected<connection> CAF_NET_EXPORT accept(tcp_acceptor& acc);
} // namespace caf::net::ssl } // namespace caf::net::ssl
...@@ -10,7 +10,6 @@ ...@@ -10,7 +10,6 @@
#include "caf/detail/accept_handler.hpp" #include "caf/detail/accept_handler.hpp"
#include "caf/detail/binary_flow_bridge.hpp" #include "caf/detail/binary_flow_bridge.hpp"
#include "caf/detail/connection_factory.hpp" #include "caf/detail/connection_factory.hpp"
#include "caf/detail/shared_ssl_acceptor.hpp"
#include "caf/detail/ws_flow_bridge.hpp" #include "caf/detail/ws_flow_bridge.hpp"
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
#include "caf/net/dsl/server_factory_base.hpp" #include "caf/net/dsl/server_factory_base.hpp"
......
...@@ -10,7 +10,6 @@ ...@@ -10,7 +10,6 @@
#include "caf/net/dsl/has_context.hpp" #include "caf/net/dsl/has_context.hpp"
#include "caf/net/dsl/has_uri_connect.hpp" #include "caf/net/dsl/has_uri_connect.hpp"
#include "caf/net/multiplexer.hpp" #include "caf/net/multiplexer.hpp"
#include "caf/net/ssl/acceptor.hpp"
#include "caf/net/ssl/context.hpp" #include "caf/net/ssl/context.hpp"
#include "caf/net/tcp_accept_socket.hpp" #include "caf/net/tcp_accept_socket.hpp"
#include "caf/net/web_socket/client_factory.hpp" #include "caf/net/web_socket/client_factory.hpp"
......
// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#include "caf/detail/shared_ssl_acceptor.hpp"
#include "caf/expected.hpp"
#include "caf/net/ssl/connection.hpp"
#include "caf/net/tcp_stream_socket.hpp"
namespace caf::detail {
// -- constructors, destructors, and assignment operators ----------------------
shared_ssl_acceptor::shared_ssl_acceptor(shared_ssl_acceptor&& other)
: fd_(other.fd_), ctx_(std::move(other.ctx_)) {
other.fd_.id = net::invalid_socket_id;
}
shared_ssl_acceptor&
shared_ssl_acceptor::operator=(shared_ssl_acceptor&& other) {
fd_ = other.fd_;
ctx_ = std::move(other.ctx_);
other.fd_.id = net::invalid_socket_id;
return *this;
}
// -- free functions -----------------------------------------------------------
bool valid(const shared_ssl_acceptor& acc) {
return valid(acc.fd());
}
void close(shared_ssl_acceptor& acc) {
close(acc.fd());
}
expected<net::ssl::connection> accept(shared_ssl_acceptor& acc) {
auto fd = accept(acc.fd());
if (fd)
return acc.ctx().new_connection(*fd);
return expected<net::ssl::connection>{std::move(fd.error())};
}
} // namespace caf::detail
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// the main distribution directory for license terms and copyright or visit // the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE. // https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#include "caf/net/ssl/acceptor.hpp" #include "caf/net/ssl/tcp_acceptor.hpp"
#include "caf/expected.hpp" #include "caf/expected.hpp"
#include "caf/net/ssl/connection.hpp" #include "caf/net/ssl/connection.hpp"
...@@ -12,12 +12,12 @@ namespace caf::net::ssl { ...@@ -12,12 +12,12 @@ namespace caf::net::ssl {
// -- constructors, destructors, and assignment operators ---------------------- // -- constructors, destructors, and assignment operators ----------------------
acceptor::acceptor(acceptor&& other) tcp_acceptor::tcp_acceptor(tcp_acceptor&& other)
: fd_(other.fd_), ctx_(std::move(other.ctx_)) { : fd_(other.fd_), ctx_(std::move(other.ctx_)) {
other.fd_.id = invalid_socket_id; other.fd_.id = invalid_socket_id;
} }
acceptor& acceptor::operator=(acceptor&& other) { tcp_acceptor& tcp_acceptor::operator=(tcp_acceptor&& other) {
fd_ = other.fd_; fd_ = other.fd_;
ctx_ = std::move(other.ctx_); ctx_ = std::move(other.ctx_);
other.fd_.id = invalid_socket_id; other.fd_.id = invalid_socket_id;
...@@ -26,9 +26,11 @@ acceptor& acceptor::operator=(acceptor&& other) { ...@@ -26,9 +26,11 @@ acceptor& acceptor::operator=(acceptor&& other) {
// -- factories ---------------------------------------------------------------- // -- factories ----------------------------------------------------------------
expected<acceptor> expected<tcp_acceptor>
acceptor::make_with_cert_file(tcp_accept_socket fd, const char* cert_file_path, tcp_acceptor::make_with_cert_file(tcp_accept_socket fd,
const char* key_file_path, format file_format) { const char* cert_file_path,
const char* key_file_path,
format file_format) {
auto ctx = context::make_server(tls::any); auto ctx = context::make_server(tls::any);
if (!ctx) { if (!ctx) {
return {make_error(sec::runtime_error, "unable to create SSL context")}; return {make_error(sec::runtime_error, "unable to create SSL context")};
...@@ -41,14 +43,15 @@ acceptor::make_with_cert_file(tcp_accept_socket fd, const char* cert_file_path, ...@@ -41,14 +43,15 @@ acceptor::make_with_cert_file(tcp_accept_socket fd, const char* cert_file_path,
return {make_error(sec::runtime_error, "unable to load private key file", return {make_error(sec::runtime_error, "unable to load private key file",
ctx->last_error_string())}; ctx->last_error_string())};
} }
return {acceptor{fd, std::move(*ctx)}}; return {tcp_acceptor{fd, std::move(*ctx)}};
} }
expected<acceptor> expected<tcp_acceptor>
acceptor::make_with_cert_file(uint16_t port, const char* cert_file_path, tcp_acceptor::make_with_cert_file(uint16_t port, const char* cert_file_path,
const char* key_file_path, format file_format) { const char* key_file_path,
format file_format) {
if (auto fd = make_tcp_accept_socket(port)) { if (auto fd = make_tcp_accept_socket(port)) {
return acceptor::make_with_cert_file(*fd, cert_file_path, key_file_path, return tcp_acceptor::make_with_cert_file(*fd, cert_file_path, key_file_path,
file_format); file_format);
} else { } else {
return {make_error(sec::cannot_open_port)}; return {make_error(sec::cannot_open_port)};
...@@ -57,15 +60,15 @@ acceptor::make_with_cert_file(uint16_t port, const char* cert_file_path, ...@@ -57,15 +60,15 @@ acceptor::make_with_cert_file(uint16_t port, const char* cert_file_path,
// -- free functions ----------------------------------------------------------- // -- free functions -----------------------------------------------------------
bool valid(const acceptor& acc) { bool valid(const tcp_acceptor& acc) {
return valid(acc.fd()); return valid(acc.fd());
} }
void close(acceptor& acc) { void close(tcp_acceptor& acc) {
close(acc.fd()); close(acc.fd());
} }
expected<connection> accept(acceptor& acc) { expected<connection> accept(tcp_acceptor& acc) {
auto fd = accept(acc.fd()); auto fd = accept(acc.fd());
if (fd) if (fd)
return acc.ctx().new_connection(*fd); return acc.ctx().new_connection(*fd);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment