23 #include "openprs_server_proxy.h" 25 #include <core/exception.h> 26 #include <core/exceptions/system.h> 27 #include <core/threading/mutex_locker.h> 28 #include <logging/logger.h> 29 #include <boost/bind.hpp> 30 #include <boost/lexical_cast.hpp> 37 typedef enum {MESSAGE_MT = 1, BROADCAST_MT, MULTICAST_MT, DISCONNECT_MT } Message_Type;
38 typedef enum {REGISTER_OK, REGISTER_NAME_CONFLICT, REGISTER_DENIED} Register_Type;
39 typedef enum {MESSAGES_PT, STRINGS_PT} Protocol_Type;
62 OpenPRSServerProxy::OpenPRSServerProxy(
unsigned short tcp_port,
63 const std::string &server_host,
unsigned short server_port,
65 : io_service_work_(io_service_), acceptor_(io_service_, ip::tcp::endpoint(ip::tcp::v6(), tcp_port)),
66 server_host_(server_host), server_port_(server_port), logger_(logger)
68 acceptor_.set_option(socket_base::reuse_address(
true));
69 io_service_thread_ = std::thread([
this]() { this->io_service_.run(); });
78 io_service_thread_.join();
89 auto map_it = find_if(mappings_.begin(), mappings_.end(),
90 [&kernel_name] (
const Mapping::Ptr &mapping)
91 {
return mapping->client_name == kernel_name; });
92 return (map_it != mappings_.end());
96 OpenPRSServerProxy::Mapping::Ptr
97 OpenPRSServerProxy::find_mapping(
const std::string &recipient)
99 auto map_it = find_if(mappings_.begin(), mappings_.end(),
100 [&recipient] (
const Mapping::Ptr &mapping)
101 {
return mapping->client_name == recipient; });
102 if (map_it != mappings_.end()) {
105 throw Exception(
"Client %s is not connected to OpenPRS server proxy", recipient.c_str());
118 Mapping::Ptr mapping = find_mapping(recipient);
119 mapping->transmit_command(command);
135 Mapping::Ptr mapping = find_mapping(recipient);
138 va_start(arg, format);
141 if (vasprintf(&msg, format, arg) == -1) {
145 std::string command = msg;
148 mapping->transmit_command(command);
164 Mapping::Ptr mapping = find_mapping(recipient);
167 if (vasprintf(&msg, format, arg) == -1) {
170 std::string command = msg;
173 mapping->transmit_command(command);
179 OpenPRSServerProxy::start_accept()
181 Mapping::Ptr mapping(
new Mapping(io_service_, server_host_, server_port_, logger_));
182 acceptor_.async_accept(mapping->client_socket,
183 boost::bind(&OpenPRSServerProxy::handle_accept,
this,
184 mapping, boost::asio::placeholders::error));
188 OpenPRSServerProxy::handle_accept(Mapping::Ptr mapping,
189 const boost::system::error_code& error)
193 mappings_.push_back(mapping);
201 OpenPRSServerProxy::Mapping::Mapping(boost::asio::io_service &io_service,
202 const std::string &server_host,
unsigned short server_port,
204 : io_service_(io_service), resolver_(io_service_),
205 server_host_(server_host), server_port_(server_port), logger_(logger),
206 client_socket(io_service_), server_socket(io_service_)
215 OpenPRSServerProxy::Mapping::~Mapping()
217 boost::system::error_code err;
218 client_socket.shutdown(ip::tcp::socket::shutdown_both, err);
219 client_socket.close();
220 server_socket.shutdown(ip::tcp::socket::shutdown_both, err);
221 server_socket.close();
227 OpenPRSServerProxy::Mapping::start()
229 logger_->
log_info(
"OPRS-server-proxy",
"Client connected, connecting to server");
230 ip::tcp::resolver::query query(server_host_, boost::lexical_cast<std::string>(server_port_));
231 resolver_.async_resolve(query,
232 boost::bind(&OpenPRSServerProxy::Mapping::handle_resolve,
this,
233 boost::asio::placeholders::error,
234 boost::asio::placeholders::iterator));
240 OpenPRSServerProxy::Mapping::alive()
const 242 return client_socket.is_open();
247 OpenPRSServerProxy::Mapping::disconnect()
249 logger_->
log_info(
"OPRS-server-proxy",
"Disconnecting %s", client_name.c_str());
250 boost::system::error_code ec;
251 client_socket.shutdown(ip::tcp::socket::shutdown_both, ec);
252 client_socket.close();
257 OpenPRSServerProxy::Mapping::handle_resolve(
const boost::system::error_code& err,
258 ip::tcp::resolver::iterator endpoint_iterator)
263 #if BOOST_ASIO_VERSION > 100409 264 boost::asio::async_connect(server_socket, endpoint_iterator,
266 server_socket.async_connect(*endpoint_iterator,
268 boost::bind(&OpenPRSServerProxy::Mapping::handle_connect,
this,
269 boost::asio::placeholders::error));
276 OpenPRSServerProxy::Mapping::handle_connect(
const boost::system::error_code &err)
283 logger_->
log_info(
"OPRS-server-proxy",
"Forwarding greeting '%s'", greeting.c_str());
287 int client_use_x = 0;
289 logger_->
log_info(
"OPRS-server-proxy",
"Reading client details");
295 logger_->
log_info(
"OPRS-server-proxy",
"Got client info: %s %i %s",
296 client_name.c_str(), client_pid, client_use_x ?
"XOPRS" :
"OPRS");
315 OpenPRSServerProxy::Mapping::start_recv_client()
317 boost::asio::async_read(client_socket,
318 boost::asio::buffer(&client_in_num_completions_,
sizeof(client_in_num_completions_)),
319 boost::bind(&OpenPRSServerProxy::Mapping::handle_recv_client,
320 this, boost::asio::placeholders::error));
324 OpenPRSServerProxy::Mapping::start_recv_server()
326 boost::asio::async_read_until(server_socket, server_buffer_,
'\n',
327 boost::bind(&OpenPRSServerProxy::Mapping::handle_recv_server,
328 this, boost::asio::placeholders::error));
333 OpenPRSServerProxy::Mapping::handle_recv_server(
const boost::system::error_code &err)
337 std::istream in_stream(&server_buffer_);
338 std::getline(in_stream, line);
340 logger_->
log_info(
"OPRS-server-proxy",
"Forwarding S->C line '%s'", line.c_str());
351 OpenPRSServerProxy::Mapping::handle_recv_client(
const boost::system::error_code &err)
354 client_in_num_completions_ = ntohl(client_in_num_completions_);
355 for (
int i = 0; i < client_in_num_completions_; ++i) {
368 OpenPRSServerProxy::Mapping::transmit_command(
const std::string &command)
381 boost::system::error_code ec;
382 boost::asio::read(socket, boost::asio::buffer(&value,
sizeof(value)), ec);
384 throw Exception(
"Failed to read int from socket: %s", ec.message().c_str());
398 boost::system::error_code ec;
399 boost::asio::read(socket, boost::asio::buffer(&s_size,
sizeof(s_size)), ec);
401 throw Exception(
"Failed to read string size from socket: %s", ec.message().c_str());
403 s_size = ntohl(s_size);
406 boost::asio::read(socket, boost::asio::buffer(s, s_size), ec);
408 throw Exception(
"Failed to read string content from socket: %s", ec.message().c_str());
423 boost::system::error_code ec;
424 int32_t value = htonl(i);
425 boost::asio::write(socket, boost::asio::buffer(&value,
sizeof(value)), ec);
427 throw Exception(
"Failed to write int to socket: %s", ec.message().c_str());
437 const std::string &str)
439 boost::system::error_code ec;
440 uint32_t s_size = htonl(str.size());
441 std::array<boost::asio::const_buffer, 2> buffers;
442 buffers[0] = boost::asio::buffer(&s_size,
sizeof(s_size));
443 buffers[1] = boost::asio::buffer(str.c_str(), str.size());
445 boost::asio::write(socket, buffers, ec);
447 throw Exception(
"Failed to write string to socket: %s", ec.message().c_str());
458 const std::string &str)
460 boost::system::error_code ec;
461 std::string s = str +
"\n";
462 boost::asio::write(socket, boost::asio::buffer(s.c_str(), s.size()), ec);
464 throw Exception(
"Failed to write string to socket: %s", ec.message().c_str());
virtual void log_info(const char *component, const char *format,...)=0
Log informational message.
Fawkes library namespace.
RefPtr< Mutex > mutex() const
Get access to the internal mutex.
Base class for exceptions in Fawkes.
System ran out of memory and desired operation could not be fulfilled.