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>
30 #include <boost/bind/bind.hpp>
31 #include <boost/lexical_cast.hpp>
33 using namespace boost::asio;
38 typedef enum { MESSAGE_MT = 1, BROADCAST_MT, MULTICAST_MT, DISCONNECT_MT } Message_Type;
39 typedef enum { REGISTER_OK, REGISTER_NAME_CONFLICT, REGISTER_DENIED } Register_Type;
40 typedef enum { MESSAGES_PT, STRINGS_PT } Protocol_Type;
59 OpenPRSServerProxy::OpenPRSServerProxy(
unsigned short tcp_port,
60 const std::string &server_host,
61 unsigned short server_port,
63 : io_service_work_(io_service_),
64 acceptor_(io_service_, ip::tcp::endpoint(ip::tcp::v6(), tcp_port)),
65 server_host_(server_host),
66 server_port_(server_port),
69 acceptor_.set_option(socket_base::reuse_address(
true));
70 io_service_thread_ = std::thread([
this]() { this->io_service_.run(); });
78 io_service_thread_.join();
89 find_if(mappings_.begin(), mappings_.end(), [&kernel_name](
const Mapping::Ptr &mapping) {
90 return mapping->client_name == kernel_name;
92 return (map_it != mappings_.end());
95 OpenPRSServerProxy::Mapping::Ptr
96 OpenPRSServerProxy::find_mapping(
const std::string &recipient)
99 find_if(mappings_.begin(), mappings_.end(), [&recipient](
const Mapping::Ptr &mapping) {
100 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);
134 Mapping::Ptr mapping = find_mapping(recipient);
137 va_start(arg, format);
140 if (vasprintf(&msg, format, arg) == -1) {
145 std::string command = msg;
148 mapping->transmit_command(command);
166 Mapping::Ptr mapping = find_mapping(recipient);
169 if (vasprintf(&msg, format, arg) == -1) {
172 std::string command = msg;
175 mapping->transmit_command(command);
180 OpenPRSServerProxy::start_accept()
182 Mapping::Ptr mapping(
new Mapping(io_service_, server_host_, server_port_, logger_));
183 acceptor_.async_accept(mapping->client_socket,
184 boost::bind(&OpenPRSServerProxy::handle_accept,
187 boost::asio::placeholders::error));
191 OpenPRSServerProxy::handle_accept(Mapping::Ptr mapping,
const boost::system::error_code &error)
194 MutexLocker lock(mappings_.
mutex());
195 mappings_.push_back(mapping);
202 OpenPRSServerProxy::Mapping::Mapping(boost::asio::io_service &io_service,
203 const std::string & server_host,
204 unsigned short server_port,
206 : io_service_(io_service),
207 resolver_(io_service_),
208 server_host_(server_host),
209 server_port_(server_port),
211 client_socket(io_service_),
212 server_socket(io_service_)
220 OpenPRSServerProxy::Mapping::~Mapping()
222 boost::system::error_code err;
223 client_socket.shutdown(ip::tcp::socket::shutdown_both, err);
224 client_socket.close();
225 server_socket.shutdown(ip::tcp::socket::shutdown_both, err);
226 server_socket.close();
231 OpenPRSServerProxy::Mapping::start()
233 logger_->log_info(
"OPRS-server-proxy",
"Client connected, connecting to server");
234 ip::tcp::resolver::query query(server_host_, boost::lexical_cast<std::string>(server_port_));
235 resolver_.async_resolve(query,
236 boost::bind(&OpenPRSServerProxy::Mapping::handle_resolve,
238 boost::asio::placeholders::error,
239 boost::asio::placeholders::iterator));
243 OpenPRSServerProxy::Mapping::alive()
const
245 return client_socket.is_open();
249 OpenPRSServerProxy::Mapping::disconnect()
251 logger_->log_info(
"OPRS-server-proxy",
"Disconnecting %s", client_name.c_str());
252 boost::system::error_code ec;
253 client_socket.shutdown(ip::tcp::socket::shutdown_both, ec);
254 client_socket.close();
258 OpenPRSServerProxy::Mapping::handle_resolve(
const boost::system::error_code &err,
259 ip::tcp::resolver::iterator endpoint_iterator)
264 #if BOOST_ASIO_VERSION > 100409
265 boost::asio::async_connect(server_socket,
268 server_socket.async_connect(*endpoint_iterator,
270 boost::bind(&OpenPRSServerProxy::Mapping::handle_connect,
272 boost::asio::placeholders::error));
279 OpenPRSServerProxy::Mapping::handle_connect(
const boost::system::error_code &err)
284 std::string greeting = read_string_from_socket(server_socket);
285 logger_->log_info(
"OPRS-server-proxy",
"Forwarding greeting '%s'", greeting.c_str());
286 write_string_to_socket(client_socket, greeting);
289 int client_use_x = 0;
291 logger_->log_info(
"OPRS-server-proxy",
"Reading client details");
293 client_name = read_string_from_socket(client_socket);
294 client_pid = read_int_from_socket(client_socket);
295 client_use_x = read_int_from_socket(client_socket);
297 logger_->log_info(
"OPRS-server-proxy",
298 "Got client info: %s %i %s",
301 client_use_x ?
"XOPRS" :
"OPRS");
304 write_string_to_socket(server_socket, client_name);
305 write_int_to_socket(server_socket, client_pid);
306 write_int_to_socket(server_socket, client_use_x);
310 }
catch (Exception &e) {
319 OpenPRSServerProxy::Mapping::start_recv_client()
321 boost::asio::async_read(client_socket,
322 boost::asio::buffer(&client_in_num_completions_,
323 sizeof(client_in_num_completions_)),
324 boost::bind(&OpenPRSServerProxy::Mapping::handle_recv_client,
326 boost::asio::placeholders::error));
330 OpenPRSServerProxy::Mapping::start_recv_server()
332 boost::asio::async_read_until(server_socket,
335 boost::bind(&OpenPRSServerProxy::Mapping::handle_recv_server,
337 boost::asio::placeholders::error));
341 OpenPRSServerProxy::Mapping::handle_recv_server(
const boost::system::error_code &err)
345 std::istream in_stream(&server_buffer_);
346 std::getline(in_stream, line);
348 logger_->log_info(
"OPRS-server-proxy",
"Forwarding S->C line '%s'", line.c_str());
349 write_string_newline_to_socket(client_socket, line);
358 OpenPRSServerProxy::Mapping::handle_recv_client(
const boost::system::error_code &err)
361 client_in_num_completions_ = ntohl(client_in_num_completions_);
362 for (
int i = 0; i < client_in_num_completions_; ++i) {
363 std::string c = read_string_from_socket(client_socket);
364 write_string_to_socket(server_socket, c);
374 OpenPRSServerProxy::Mapping::transmit_command(
const std::string &command)
376 write_string_newline_to_socket(client_socket, command);
387 boost::system::error_code ec;
388 boost::asio::read(socket, boost::asio::buffer(&value,
sizeof(value)), ec);
390 throw Exception(
"Failed to read int from socket: %s", ec.message().c_str());
404 boost::system::error_code ec;
405 boost::asio::read(socket, boost::asio::buffer(&s_size,
sizeof(s_size)), ec);
407 throw Exception(
"Failed to read string size from socket: %s", ec.message().c_str());
409 s_size = ntohl(s_size);
412 boost::asio::read(socket, boost::asio::buffer(s, s_size), ec);
414 throw Exception(
"Failed to read string content from socket: %s", ec.message().c_str());
428 boost::system::error_code ec;
429 int32_t value = htonl(i);
430 boost::asio::write(socket, boost::asio::buffer(&value,
sizeof(value)), ec);
432 throw Exception(
"Failed to write int to socket: %s", ec.message().c_str());
442 const std::string & str)
444 boost::system::error_code ec;
445 uint32_t s_size = htonl(str.size());
446 std::array<boost::asio::const_buffer, 2> buffers;
447 buffers[0] = boost::asio::buffer(&s_size,
sizeof(s_size));
448 buffers[1] = boost::asio::buffer(str.c_str(), str.size());
450 boost::asio::write(socket, buffers, ec);
452 throw Exception(
"Failed to write string to socket: %s", ec.message().c_str());
462 const std::string & str)
464 boost::system::error_code ec;
465 std::string s = str +
"\n";
466 boost::asio::write(socket, boost::asio::buffer(s.c_str(), s.size()), ec);
468 throw Exception(
"Failed to write string to socket: %s", ec.message().c_str());
Base class for exceptions in Fawkes.
RefPtr< Mutex > mutex() const
Get access to the internal mutex.
System ran out of memory and desired operation could not be fulfilled.
Fawkes library namespace.