Skip to content

Commit fc3a023

Browse files
committed
Merge branch 'unix_socket' into master_merge_unix_socket
* unix_socket: add unix_socket test fix unittesterror add example for unix socket set reuse addr false add handle_upgrade for unix socket add unix domain socket
2 parents 00065e9 + ce262a2 commit fc3a023

11 files changed

Lines changed: 324 additions & 45 deletions

File tree

examples/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,10 @@ add_executable(example_file_upload example_file_upload.cpp)
9393
add_warnings_optimizations(example_file_upload)
9494
target_link_libraries(example_file_upload PUBLIC Crow::Crow)
9595

96+
add_executable(example_unix_socket example_unix_socket.cpp)
97+
add_warnings_optimizations(example_unix_socket)
98+
target_link_libraries(example_unix_socket PUBLIC Crow::Crow)
99+
96100
if(MSVC)
97101
add_executable(example_vs example_vs.cpp)
98102
add_warnings_optimizations(example_vs)

examples/example_unix_socket.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#include "crow.h"
2+
3+
#include <sys/stat.h>
4+
5+
int main()
6+
{
7+
crow::SimpleApp app;
8+
9+
CROW_ROUTE(app, "/")
10+
([]() {
11+
return "Hello, world!";
12+
});
13+
14+
std::string local_socket_path = "example.sock";
15+
unlink(local_socket_path.c_str());
16+
app.local_socket_path(local_socket_path).run();
17+
18+
}

include/crow.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "crow/TinySHA1.hpp"
66
#include "crow/settings.h"
77
#include "crow/socket_adaptors.h"
8+
#include "crow/socket_acceptors.h"
89
#include "crow/json.h"
910
#include "crow/mustache.h"
1011
#include "crow/logging.h"

include/crow/app.h

Lines changed: 60 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -202,11 +202,12 @@ namespace crow
202202
using self_t = Crow;
203203

204204
/// \brief The HTTP server
205-
using server_t = Server<Crow, SocketAdaptor, Middlewares...>;
206-
205+
using server_t = Server<Crow, TCPAcceptor, SocketAdaptor, Middlewares...>;
206+
/// \brief An HTTP server that runs on unix domain socket
207+
using unix_server_t = Server<Crow, UnixSocketAcceptor, UnixSocketAdaptor, Middlewares...>;
207208
#ifdef CROW_ENABLE_SSL
208209
/// \brief An HTTP server that runs on SSL with an SSLAdaptor
209-
using ssl_server_t = Server<Crow, SSLAdaptor, Middlewares...>;
210+
using ssl_server_t = Server<Crow, TCPAcceptor, SSLAdaptor, Middlewares...>;
210211
#endif
211212
Crow()
212213
{}
@@ -349,6 +350,20 @@ namespace crow
349350
return bindaddr_;
350351
}
351352

353+
/// \brief Disable tcp/ip and use unix domain socket instead
354+
self_t& local_socket_path(std::string path)
355+
{
356+
bindaddr_ = path;
357+
use_unix_ = true;
358+
return *this;
359+
}
360+
361+
/// \brief Get the unix domain socket path
362+
std::string local_socket_path()
363+
{
364+
return bindaddr_;
365+
}
366+
352367
/// \brief Run the server on multiple threads using all available threads
353368
self_t& multithreaded()
354369
{
@@ -506,16 +521,17 @@ namespace crow
506521
#endif
507522
validate();
508523

509-
error_code ec;
510-
asio::ip::address addr = asio::ip::make_address(bindaddr_,ec);
511-
if (ec){
512-
CROW_LOG_ERROR << ec.message() << " - Can not create valid ip address from string: \"" << bindaddr_ << "\"";
513-
return;
514-
}
515-
tcp::endpoint endpoint(addr, port_);
516524
#ifdef CROW_ENABLE_SSL
517525
if (ssl_used_)
518526
{
527+
528+
error_code ec;
529+
asio::ip::address addr = asio::ip::make_address(bindaddr_,ec);
530+
if (ec){
531+
CROW_LOG_ERROR << ec.message() << " - Can not create valid ip address from string: \"" << bindaddr_ << "\"";
532+
return;
533+
}
534+
tcp::endpoint endpoint(addr, port_);
519535
router_.using_ssl = true;
520536
ssl_server_ = std::move(std::unique_ptr<ssl_server_t>(new ssl_server_t(this, endpoint, server_name_, &middlewares_, concurrency_, timeout_, &ssl_context_)));
521537
ssl_server_->set_tick_function(tick_interval_, tick_function_);
@@ -530,14 +546,36 @@ namespace crow
530546
else
531547
#endif
532548
{
533-
server_ = std::move(std::unique_ptr<server_t>(new server_t(this, endpoint, server_name_, &middlewares_, concurrency_, timeout_, nullptr)));
534-
server_->set_tick_function(tick_interval_, tick_function_);
535-
for (auto snum : signals_)
549+
if (use_unix_)
536550
{
537-
server_->signal_add(snum);
551+
UnixSocketAcceptor::endpoint endpoint(bindaddr_);
552+
unix_server_ = std::move(std::unique_ptr<unix_server_t>(new unix_server_t(this, endpoint, server_name_, &middlewares_, concurrency_, timeout_, nullptr)));
553+
unix_server_->set_tick_function(tick_interval_, tick_function_);
554+
for (auto snum : signals_)
555+
{
556+
unix_server_->signal_add(snum);
557+
}
558+
notify_server_start();
559+
unix_server_->run();
560+
}
561+
else
562+
{
563+
error_code ec;
564+
asio::ip::address addr = asio::ip::make_address(bindaddr_,ec);
565+
if (ec){
566+
CROW_LOG_ERROR << ec.message() << " - Can not create valid ip address from string: \"" << bindaddr_ << "\"";
567+
return;
568+
}
569+
TCPAcceptor::endpoint endpoint(addr, port_);
570+
server_ = std::move(std::unique_ptr<server_t>(new server_t(this, endpoint, server_name_, &middlewares_, concurrency_, timeout_, nullptr)));
571+
server_->set_tick_function(tick_interval_, tick_function_);
572+
for (auto snum : signals_)
573+
{
574+
server_->signal_add(snum);
575+
}
576+
notify_server_start();
577+
server_->run();
538578
}
539-
notify_server_start();
540-
server_->run();
541579
}
542580
}
543581

@@ -565,6 +603,7 @@ namespace crow
565603
{
566604
close_websockets();
567605
if (server_) { server_->stop(); }
606+
if (unix_server_) { unix_server_->stop(); }
568607
}
569608
}
570609

@@ -717,12 +756,12 @@ namespace crow
717756
status = cv_started_.wait_until(lock, wait_until);
718757
}
719758
}
720-
721759
if (status == std::cv_status::no_timeout)
722760
{
723-
if (server_)
724-
{
761+
if (server_) {
725762
status = server_->wait_for_start(wait_until);
763+
} else if (unix_server_) {
764+
status = unix_server_->wait_for_start(wait_until);
726765
}
727766
#ifdef CROW_ENABLE_SSL
728767
else if (ssl_server_)
@@ -767,6 +806,7 @@ namespace crow
767806
uint64_t max_payload_{UINT64_MAX};
768807
std::string server_name_ = std::string("Crow/") + VERSION;
769808
std::string bindaddr_ = "0.0.0.0";
809+
bool use_unix_ = false;
770810
size_t res_stream_threshold_ = 1048576;
771811
Router router_;
772812
bool static_routes_added_{false};
@@ -788,6 +828,7 @@ namespace crow
788828
#endif
789829

790830
std::unique_ptr<server_t> server_;
831+
std::unique_ptr<unix_server_t> unix_server_;
791832

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

include/crow/http_connection.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -146,9 +146,7 @@ namespace crow
146146
req_.middleware_context = static_cast<void*>(&ctx_);
147147
req_.middleware_container = static_cast<void*>(middlewares_);
148148
req_.io_context = &adaptor_.get_io_context();
149-
150-
req_.remote_ip_address = adaptor_.remote_endpoint().address().to_string();
151-
149+
req_.remote_ip_address = adaptor_.address();
152150
add_keep_alive_ = req_.keep_alive;
153151
close_connection_ = req_.close_connection;
154152

include/crow/http_server.h

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "crow/http_connection.h"
2727
#include "crow/logging.h"
2828
#include "crow/task_timer.h"
29+
#include "crow/socket_acceptors.h"
2930

3031

3132
namespace crow // NOTE: Already documented in "crow/app.h"
@@ -37,13 +38,14 @@ namespace crow // NOTE: Already documented in "crow/app.h"
3738
using error_code = asio::error_code;
3839
#endif
3940
using tcp = asio::ip::tcp;
41+
using stream_protocol = asio::local::stream_protocol;
4042

41-
template<typename Handler, typename Adaptor = SocketAdaptor, typename... Middlewares>
43+
template<typename Handler, typename Acceptor = TCPAcceptor, typename Adaptor = SocketAdaptor, typename... Middlewares>
4244
class Server
4345
{
4446
public:
4547
Server(Handler* handler,
46-
const tcp::endpoint& endpoint,
48+
typename Acceptor::endpoint endpoint,
4749
std::string server_name = std::string("Crow/") + VERSION,
4850
std::tuple<Middlewares...>* middlewares = nullptr,
4951
uint16_t concurrency = 1,
@@ -67,29 +69,29 @@ namespace crow // NOTE: Already documented in "crow/app.h"
6769

6870
error_code ec;
6971

70-
acceptor_.open(endpoint.protocol(), ec);
72+
acceptor_.raw_acceptor().open(endpoint.protocol(), ec);
7173
if (ec) {
7274
CROW_LOG_ERROR << "Failed to open acceptor: " << ec.message();
7375
startup_failed_ = true;
7476
return;
7577
}
7678

77-
acceptor_.set_option(tcp::acceptor::reuse_address(true), ec);
79+
acceptor_.raw_acceptor().set_option(Acceptor::reuse_address_option(), ec);
7880
if (ec) {
7981
CROW_LOG_ERROR << "Failed to set socket option: " << ec.message();
8082
startup_failed_ = true;
8183
return;
8284
}
8385

84-
acceptor_.bind(endpoint, ec);
86+
acceptor_.raw_acceptor().bind(endpoint, ec);
8587
if (ec) {
86-
CROW_LOG_ERROR << "Failed to bind to " << endpoint.address().to_string()
87-
<< ":" << endpoint.port() << " - " << ec.message();
88+
CROW_LOG_ERROR << "Failed to bind to " << acceptor_.address()
89+
<< ":" << acceptor_.port() << " - " << ec.message();
8890
startup_failed_ = true;
8991
return;
9092
}
9193

92-
acceptor_.listen(tcp::acceptor::max_listen_connections, ec);
94+
acceptor_.raw_acceptor().listen(tcp::acceptor::max_listen_connections, ec);
9395
if (ec) {
9496
CROW_LOG_ERROR << "Failed to listen on port: " << ec.message();
9597
startup_failed_ = true;
@@ -197,13 +199,10 @@ namespace crow // NOTE: Already documented in "crow/app.h"
197199
on_tick();
198200
});
199201
}
200-
201-
handler_->port(acceptor_.local_endpoint().port());
202-
203-
204-
CROW_LOG_INFO << server_name_
205-
<< " server is running at " << (handler_->ssl_used() ? "https://" : "http://")
206-
<< acceptor_.local_endpoint().address() << ":" << acceptor_.local_endpoint().port() << " using " << concurrency_ << " threads";
202+
handler_->port(acceptor_.port());
203+
CROW_LOG_INFO << server_name_
204+
<< " server is running at " << acceptor_.url_display(handler_->ssl_used())
205+
<< " using " << concurrency_ << " threads";
207206
CROW_LOG_INFO << "Call `app.loglevel(crow::LogLevel::Warning)` to hide Info level logs.";
208207

209208
signals_.async_wait(
@@ -232,10 +231,15 @@ namespace crow // NOTE: Already documented in "crow/app.h"
232231
// Explicitly close the acceptor
233232
// else asio will throw an exception (linux only), when trying to start server again:
234233
// what(): bind: Address already in use
235-
if (acceptor_.is_open())
234+
if (acceptor_.raw_acceptor().is_open())
236235
{
237236
CROW_LOG_INFO << "Closing acceptor. " << &acceptor_;
238-
acceptor_.close();
237+
error_code ec;
238+
acceptor_.raw_acceptor().close(ec);
239+
if (ec)
240+
{
241+
CROW_LOG_WARNING << "Failed to close acceptor: " << ec.message();
242+
}
239243
}
240244

241245
for (auto& io_context : io_context_pool_)
@@ -307,7 +311,7 @@ namespace crow // NOTE: Already documented in "crow/app.h"
307311

308312
CROW_LOG_DEBUG << &ic << " {" << context_idx << "} queue length: " << task_queue_length_pool_[context_idx];
309313

310-
acceptor_.async_accept(
314+
acceptor_.raw_acceptor().async_accept(
311315
p->socket(),
312316
[this, p, &ic, context_idx](error_code ec) {
313317
if (!ec)
@@ -337,7 +341,7 @@ namespace crow // NOTE: Already documented in "crow/app.h"
337341
asio::io_context io_context_;
338342
std::vector<detail::task_timer*> task_timer_pool_;
339343
std::vector<std::function<std::string()>> get_cached_date_str_pool_;
340-
tcp::acceptor acceptor_;
344+
Acceptor acceptor_;
341345
bool shutting_down_ = false;
342346
bool server_started_{false};
343347
bool startup_failed_ = false;
@@ -350,6 +354,7 @@ namespace crow // NOTE: Already documented in "crow/app.h"
350354
Handler* handler_;
351355
std::uint8_t timeout_;
352356
std::string server_name_;
357+
bool use_unix_;
353358

354359
std::chrono::milliseconds tick_interval_;
355360
std::function<void()> tick_function_;

include/crow/routing.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,11 @@ namespace crow // NOTE: Already documented in "crow/app.h"
121121
res = response(404);
122122
res.end();
123123
}
124+
virtual void handle_upgrade(const request&, response& res, UnixSocketAdaptor&&)
125+
{
126+
res = response(404);
127+
res.end();
128+
}
124129
#ifdef CROW_ENABLE_SSL
125130
virtual void handle_upgrade(const request&, response& res, SSLAdaptor&&)
126131
{
@@ -442,6 +447,11 @@ namespace crow // NOTE: Already documented in "crow/app.h"
442447
max_payload_ = max_payload_override_ ? max_payload_ : app_->websocket_max_payload();
443448
new crow::websocket::Connection<SocketAdaptor, App>(req, std::move(adaptor), app_, max_payload_, subprotocols_, open_handler_, message_handler_, close_handler_, error_handler_, accept_handler_, mirror_protocols_);
444449
}
450+
void handle_upgrade(const request& req, response&, UnixSocketAdaptor&& adaptor) override
451+
{
452+
max_payload_ = max_payload_override_ ? max_payload_ : app_->websocket_max_payload();
453+
new crow::websocket::Connection<UnixSocketAdaptor, App>(req, std::move(adaptor), app_, max_payload_, subprotocols_, open_handler_, message_handler_, close_handler_, error_handler_, accept_handler_, mirror_protocols_);
454+
}
445455
#ifdef CROW_ENABLE_SSL
446456
void handle_upgrade(const request& req, response&, SSLAdaptor&& adaptor) override
447457
{

0 commit comments

Comments
 (0)