forked from sony/nmos-cpp
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathserver_utils.cpp
105 lines (94 loc) · 4.67 KB
/
server_utils.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#include "nmos/server_utils.h"
#include <algorithm>
#if !defined(_WIN32) || !defined(__cplusplus_winrt) || defined(CPPREST_FORCE_HTTP_CLIENT_ASIO)
#include "boost/asio/ssl/set_cipher_list.hpp"
#include "boost/asio/ssl/use_tmp_ecdh.hpp"
#endif
#include "cpprest/basic_utils.h"
#include "cpprest/http_listener.h"
#include "cpprest/ws_listener.h"
#include "nmos/ssl_context_options.h"
// Utility types, constants and functions for implementing NMOS REST API servers
namespace nmos
{
namespace details
{
#if !defined(_WIN32) || !defined(__cplusplus_winrt) || defined(CPPREST_FORCE_HTTP_CLIENT_ASIO)
template <typename ExceptionType>
inline std::function<void(boost::asio::ssl::context&)> make_listener_ssl_context_callback(const nmos::settings& settings)
{
const auto& private_key_files = nmos::experimental::fields::private_key_files(settings);
const auto& certificate_chain_files = nmos::experimental::fields::certificate_chain_files(settings);
const auto& dh_param_file = utility::us2s(nmos::experimental::fields::dh_param_file(settings));
return [private_key_files, certificate_chain_files, dh_param_file](boost::asio::ssl::context& ctx)
{
try
{
ctx.set_options(nmos::details::ssl_context_options);
if (private_key_files.size() == 0)
{
throw ExceptionType({},"Missing private key file");
}
for (const auto& private_key_file : private_key_files.as_array())
{
ctx.use_private_key_file(utility::us2s(private_key_file.as_string()), boost::asio::ssl::context::pem);
}
if (certificate_chain_files.size() == 0)
{
throw ExceptionType({},"Missing certificate chain file");
}
for (const auto& certificate_chain_file : certificate_chain_files.as_array())
{
ctx.use_certificate_chain_file(utility::us2s(certificate_chain_file.as_string()));
// any one of the certificates may have ECDH parameters, so ignore errors...
boost::system::error_code ec;
use_tmp_ecdh_file(ctx, utility::us2s(certificate_chain_file.as_string()), ec);
}
set_cipher_list(ctx, nmos::details::ssl_cipher_list);
if (!dh_param_file.empty()) ctx.use_tmp_dh_file(dh_param_file);
}
catch (const boost::system::system_error& e)
{
throw ExceptionType(e.code(), e.what());
}
};
}
#endif
}
// construct listener config based on settings
web::http::experimental::listener::http_listener_config make_http_listener_config(const nmos::settings& settings)
{
web::http::experimental::listener::http_listener_config config;
config.set_backlog(nmos::fields::listen_backlog(settings));
#if !defined(_WIN32) || defined(CPPREST_FORCE_HTTP_LISTENER_ASIO)
// hmm, hostport_listener::on_accept(...) in http_server_asio.cpp
// only expects boost::system::system_error to be thrown, so for now
// don't use web::http::http_exception
config.set_ssl_context_callback(details::make_listener_ssl_context_callback<boost::system::system_error>(settings));
#endif
return config;
}
// construct listener config based on settings
web::websockets::experimental::listener::websocket_listener_config make_websocket_listener_config(const nmos::settings& settings)
{
web::websockets::experimental::listener::websocket_listener_config config;
config.set_backlog(nmos::fields::listen_backlog(settings));
#if !defined(_WIN32) || !defined(__cplusplus_winrt)
config.set_ssl_context_callback(details::make_listener_ssl_context_callback<web::websockets::websocket_exception>(settings));
#endif
return config;
}
namespace experimental
{
// map the configured client port to the server port on which to listen
int server_port(int client_port, const nmos::settings& settings)
{
const auto& port_map = nmos::experimental::fields::proxy_map(settings).as_array();
const auto found = std::find_if(port_map.begin(), port_map.end(), [&](const web::json::value& m)
{
return client_port == m.at(U("client_port")).as_integer();
});
return port_map.end() != found ? found->at(U("server_port")).as_integer() : client_port;
}
}
}