Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add unix domain socket support #803

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
4 changes: 4 additions & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@ add_executable(example_file_upload example_file_upload.cpp)
add_warnings_optimizations(example_file_upload)
target_link_libraries(example_file_upload PUBLIC Crow::Crow)

add_executable(example_unix_socket example_unix_socket.cpp)
add_warnings_optimizations(example_unix_socket)
target_link_libraries(example_unix_socket PUBLIC Crow::Crow)

if(MSVC)
add_executable(example_vs example_vs.cpp)
add_warnings_optimizations(example_vs)
Expand Down
18 changes: 18 additions & 0 deletions examples/example_unix_socket.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#include "crow.h"

#include <sys/stat.h>

int main()
{
crow::SimpleApp app;

CROW_ROUTE(app, "/")
([]() {
return "Hello, world!";
});

std::string local_socket_path = "example.sock";
unlink(local_socket_path.c_str());
app.local_socket_path(local_socket_path).run();

}
1 change: 1 addition & 0 deletions include/crow.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "crow/TinySHA1.hpp"
#include "crow/settings.h"
#include "crow/socket_adaptors.h"
#include "crow/socket_acceptors.h"
#include "crow/json.h"
#include "crow/mustache.h"
#include "crow/logging.h"
Expand Down
57 changes: 47 additions & 10 deletions include/crow/app.h
Original file line number Diff line number Diff line change
Expand Up @@ -202,11 +202,12 @@ namespace crow
using self_t = Crow;

/// \brief The HTTP server
using server_t = Server<Crow, SocketAdaptor, Middlewares...>;

using server_t = Server<Crow, TCPAcceptor, SocketAdaptor, Middlewares...>;
/// \brief An HTTP server that runs on unix domain socket
using unix_server_t = Server<Crow, UnixSocketAcceptor, UnixSocketAdaptor, Middlewares...>;
#ifdef CROW_ENABLE_SSL
/// \brief An HTTP server that runs on SSL with an SSLAdaptor
using ssl_server_t = Server<Crow, SSLAdaptor, Middlewares...>;
using ssl_server_t = Server<Crow, TCPAcceptor, SSLAdaptor, Middlewares...>;
#endif
Crow()
{}
Expand Down Expand Up @@ -344,6 +345,20 @@ namespace crow
return bindaddr_;
}

/// \brief Disable tcp/ip and use unix domain socket instead
self_t& local_socket_path(std::string path)
{
bindaddr_ = path;
use_unix_ = true;
return *this;
}

/// \brief Get the unix domain socket path
std::string local_socket_path()
{
return bindaddr_;
}

/// \brief Run the server on multiple threads using all available threads
self_t& multithreaded()
{
Expand Down Expand Up @@ -502,7 +517,8 @@ namespace crow
#ifdef CROW_ENABLE_SSL
if (ssl_used_)
{
ssl_server_ = std::move(std::unique_ptr<ssl_server_t>(new ssl_server_t(this, bindaddr_, port_, server_name_, &middlewares_, concurrency_, timeout_, &ssl_context_)));
TCPAcceptor::endpoint endpoint(asio::ip::address::from_string(bindaddr_), port_);
ssl_server_ = std::move(std::unique_ptr<ssl_server_t>(new ssl_server_t(this, endpoint, server_name_, &middlewares_, concurrency_, timeout_, &ssl_context_)));
ssl_server_->set_tick_function(tick_interval_, tick_function_);
ssl_server_->signal_clear();
for (auto snum : signals_)
Expand All @@ -515,14 +531,30 @@ namespace crow
else
#endif
{
server_ = std::move(std::unique_ptr<server_t>(new server_t(this, bindaddr_, port_, server_name_, &middlewares_, concurrency_, timeout_, nullptr)));
server_->set_tick_function(tick_interval_, tick_function_);
for (auto snum : signals_)
if (use_unix_)
{
server_->signal_add(snum);
UnixSocketAcceptor::endpoint endpoint(bindaddr_);
unix_server_ = std::move(std::unique_ptr<unix_server_t>(new unix_server_t(this, endpoint, server_name_, &middlewares_, concurrency_, timeout_, nullptr)));
unix_server_->set_tick_function(tick_interval_, tick_function_);
for (auto snum : signals_)
{
unix_server_->signal_add(snum);
}
notify_server_start();
unix_server_->run();
}
else
{
TCPAcceptor::endpoint endpoint(asio::ip::address::from_string(bindaddr_), port_);
server_ = std::move(std::unique_ptr<server_t>(new server_t(this, endpoint, server_name_, &middlewares_, concurrency_, timeout_, nullptr)));
server_->set_tick_function(tick_interval_, tick_function_);
for (auto snum : signals_)
{
server_->signal_add(snum);
}
notify_server_start();
server_->run();
}
notify_server_start();
server_->run();
}
}

Expand Down Expand Up @@ -556,6 +588,7 @@ namespace crow
websocket->close("Server Application Terminated");
}
if (server_) { server_->stop(); }
if (unix_server_) { unix_server_->stop(); }
}
}

Expand Down Expand Up @@ -696,6 +729,8 @@ namespace crow
}
if (server_)
server_->wait_for_start();
else if (unix_server_)
unix_server_->wait_for_start();
#ifdef CROW_ENABLE_SSL
else if (ssl_server_)
ssl_server_->wait_for_start();
Expand Down Expand Up @@ -735,6 +770,7 @@ namespace crow
uint64_t max_payload_{UINT64_MAX};
std::string server_name_ = std::string("Crow/") + VERSION;
std::string bindaddr_ = "0.0.0.0";
bool use_unix_ = false;
size_t res_stream_threshold_ = 1048576;
Router router_;
bool static_routes_added_{false};
Expand All @@ -756,6 +792,7 @@ namespace crow
#endif

std::unique_ptr<server_t> server_;
std::unique_ptr<unix_server_t> unix_server_;

std::vector<int> signals_{SIGINT, SIGTERM};

Expand Down
2 changes: 1 addition & 1 deletion include/crow/http_connection.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ namespace crow
req_.middleware_container = static_cast<void*>(middlewares_);
req_.io_service = &adaptor_.get_io_service();

req_.remote_ip_address = adaptor_.remote_endpoint().address().to_string();
req_.remote_ip_address = adaptor_.address();

add_keep_alive_ = req_.keep_alive;
close_connection_ = req_.close_connection;
Expand Down
19 changes: 9 additions & 10 deletions include/crow/http_server.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,21 +37,20 @@ namespace crow // NOTE: Already documented in "crow/app.h"
using error_code = asio::error_code;
#endif
using tcp = asio::ip::tcp;
using stream_protocol = asio::local::stream_protocol;

template<typename Handler, typename Adaptor = SocketAdaptor, typename... Middlewares>
template<typename Handler, typename Acceptor = TCPAcceptor, typename Adaptor = SocketAdaptor, typename... Middlewares>
class Server
{
public:
Server(Handler* handler, std::string bindaddr, uint16_t port, std::string server_name = std::string("Crow/") + VERSION, std::tuple<Middlewares...>* middlewares = nullptr, uint16_t concurrency = 1, uint8_t timeout = 5, typename Adaptor::context* adaptor_ctx = nullptr):
acceptor_(io_service_, tcp::endpoint(asio::ip::address::from_string(bindaddr), port)),
Server(Handler* handler, typename Acceptor::endpoint endpoint, std::string server_name = std::string("Crow/") + VERSION, std::tuple<Middlewares...>* middlewares = nullptr, uint16_t concurrency = 1, uint8_t timeout = 5, typename Adaptor::context* adaptor_ctx = nullptr):
acceptor_(io_service_, endpoint),
signals_(io_service_),
tick_timer_(io_service_),
handler_(handler),
concurrency_(concurrency),
timeout_(timeout),
server_name_(server_name),
port_(port),
bindaddr_(bindaddr),
task_queue_length_pool_(concurrency_ - 1),
middlewares_(middlewares),
adaptor_ctx_(adaptor_ctx)
Expand Down Expand Up @@ -150,11 +149,10 @@ namespace crow // NOTE: Already documented in "crow/app.h"
});
}

port_ = acceptor_.local_endpoint().port();
port_ = acceptor_.port();
handler_->port(port_);


CROW_LOG_INFO << server_name_ << " server is running at " << (handler_->ssl_used() ? "https://" : "http://") << bindaddr_ << ":" << acceptor_.local_endpoint().port() << " using " << concurrency_ << " threads";
CROW_LOG_INFO << server_name_ << " server is running at " << acceptor_.url_display(handler_->ssl_used()) << " using " << concurrency_ << " threads";
CROW_LOG_INFO << "Call `app.loglevel(crow::LogLevel::Warning)` to hide Info level logs.";

signals_.async_wait(
Expand Down Expand Up @@ -240,7 +238,7 @@ namespace crow // NOTE: Already documented in "crow/app.h"
is, handler_, server_name_, middlewares_,
get_cached_date_str_pool_[service_idx], *task_timer_pool_[service_idx], adaptor_ctx_, task_queue_length_pool_[service_idx]);

acceptor_.async_accept(
acceptor_.raw_acceptor().async_accept(
p->socket(),
[this, p, &is, service_idx](error_code ec) {
if (!ec)
Expand Down Expand Up @@ -273,7 +271,7 @@ namespace crow // NOTE: Already documented in "crow/app.h"
asio::io_service io_service_;
std::vector<detail::task_timer*> task_timer_pool_;
std::vector<std::function<std::string()>> get_cached_date_str_pool_;
tcp::acceptor acceptor_;
Acceptor acceptor_;
bool shutting_down_ = false;
bool server_started_{false};
std::condition_variable cv_started_;
Expand All @@ -288,6 +286,7 @@ namespace crow // NOTE: Already documented in "crow/app.h"
std::string server_name_;
uint16_t port_;
std::string bindaddr_;
bool use_unix_;
std::vector<std::atomic<unsigned int>> task_queue_length_pool_;

std::chrono::milliseconds tick_interval_;
Expand Down
10 changes: 10 additions & 0 deletions include/crow/routing.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,11 @@ namespace crow // NOTE: Already documented in "crow/app.h"
res = response(404);
res.end();
}
virtual void handle_upgrade(const request&, response& res, UnixSocketAdaptor&&)
{
res = response(404);
res.end();
}
#ifdef CROW_ENABLE_SSL
virtual void handle_upgrade(const request&, response& res, SSLAdaptor&&)
{
Expand Down Expand Up @@ -463,6 +468,11 @@ namespace crow // NOTE: Already documented in "crow/app.h"
max_payload_ = max_payload_override_ ? max_payload_ : app_->websocket_max_payload();
new crow::websocket::Connection<SocketAdaptor, App>(req, std::move(adaptor), app_, max_payload_, open_handler_, message_handler_, close_handler_, error_handler_, accept_handler_);
}
void handle_upgrade(const request& req, response&, UnixSocketAdaptor&& adaptor) override
{
max_payload_ = max_payload_override_ ? max_payload_ : app_->websocket_max_payload();
new crow::websocket::Connection<UnixSocketAdaptor, App>(req, std::move(adaptor), app_, max_payload_, open_handler_, message_handler_, close_handler_, error_handler_, accept_handler_);
}
#ifdef CROW_ENABLE_SSL
void handle_upgrade(const request& req, response&, SSLAdaptor&& adaptor) override
{
Expand Down
54 changes: 54 additions & 0 deletions include/crow/socket_acceptors.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#pragma once
#ifndef ASIO_STANDALONE
#define ASIO_STANDALONE
#endif
#include <asio.hpp>

namespace crow
{
using tcp = asio::ip::tcp;
using stream_protocol = asio::local::stream_protocol;

struct TCPAcceptor
{
using endpoint = tcp::endpoint;
tcp::acceptor acceptor_;
TCPAcceptor(asio::io_service& io_service, const endpoint& endpoint):
acceptor_(io_service, endpoint) {}

int16_t port() const
{
return acceptor_.local_endpoint().port();
}
std::string url_display(bool ssl_used) const
{
return (ssl_used ? "https://" : "http://") + acceptor_.local_endpoint().address().to_string() + ":" + std::to_string(acceptor_.local_endpoint().port());
}
tcp::acceptor& raw_acceptor()
{
return acceptor_;
}
};

struct UnixSocketAcceptor
{
using endpoint = stream_protocol::endpoint;
stream_protocol::acceptor acceptor_;
UnixSocketAcceptor(asio::io_service& io_service, const endpoint& endpoint):
acceptor_(io_service, endpoint, false) {}
// reuse addr must be false (https://github.com/chriskohlhoff/asio/issues/622)

int16_t port() const
{
return 0;
}
std::string url_display(bool) const
{
return acceptor_.local_endpoint().path();
}
stream_protocol::acceptor& raw_acceptor()
{
return acceptor_;
}
};
} // namespace crow
Loading