2
Copyright (C) 2009 Red Hat, Inc.
4
This library is free software; you can redistribute it and/or
5
modify it under the terms of the GNU Lesser General Public
6
License as published by the Free Software Foundation; either
7
version 2.1 of the License, or (at your option) any later version.
9
This library is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
Lesser General Public License for more details.
14
You should have received a copy of the GNU Lesser General Public
15
License along with this library; if not, see <http://www.gnu.org/licenses/>.
26
#include "tunnel_channel.h"
27
#include <spice/protocol.h>
29
#define SOCKET_WINDOW_SIZE 60
30
#define SOCKET_TOKENS_TO_SEND 20
32
/* classes for tunneling msgs without reallocations and memcpy */
34
class InSocketMessage;
35
class OutSocketMessage;
37
class InSocketMessage: public ClientNetSocket::SendBuffer {
39
InSocketMessage(RedChannel::CompoundInMessage& full_msg);
41
const uint8_t* data();
43
ClientNetSocket::SendBuffer* ref();
47
virtual ~InSocketMessage() {}
51
RedChannel::CompoundInMessage& _full_msg;
52
SpiceMsgTunnelSocketData* _sckt_msg;
56
InSocketMessage::InSocketMessage(RedChannel::CompoundInMessage& full_msg)
58
, _full_msg (full_msg)
60
ASSERT(full_msg.type() == SPICE_MSG_TUNNEL_SOCKET_DATA);
62
_sckt_msg = (SpiceMsgTunnelSocketData*)(_full_msg.data());
63
_buf_size = _full_msg.size() - sizeof(SpiceMsgTunnelSocketData);
66
const uint8_t* InSocketMessage::data()
68
return _sckt_msg->data;
71
uint32_t InSocketMessage::size()
76
ClientNetSocket::SendBuffer* InSocketMessage::ref()
83
void InSocketMessage::unref()
91
class OutSocketMessage: public RedPeer::OutMessage,
92
public RedChannel::OutMessage,
93
public ClientNetSocket::ReceiveBuffer {
96
virtual RedPeer::OutMessage& peer_message() { return *this;}
97
virtual void release();
99
virtual uint8_t* buf() { return _the_buf; };
100
virtual uint32_t buf_max_size() {return _max_data_size;}
101
virtual void set_buf_size(uint32_t size);
102
virtual void release_buf();
104
static void init(uint32_t max_data_size);
105
static OutSocketMessage& alloc_message(uint16_t id, SpiceMessageMarshallers *marshallers);
107
static void clear_free_messages();
111
virtual ~OutSocketMessage() {}
114
static std::list<OutSocketMessage*> _free_messages;
115
static uint32_t _max_data_size;
119
std::list<OutSocketMessage*> OutSocketMessage::_free_messages;
120
uint32_t OutSocketMessage::_max_data_size;
122
OutSocketMessage::OutSocketMessage()
123
: RedPeer::OutMessage(SPICE_MSGC_TUNNEL_SOCKET_DATA)
124
, RedChannel::OutMessage()
125
, ClientNetSocket::ReceiveBuffer()
129
void OutSocketMessage::set_buf_size(uint32_t size)
131
spice_marshaller_unreserve_space(_marshaller, _max_data_size - size);
134
void OutSocketMessage::release()
136
OutSocketMessage::_free_messages.push_front(this);
139
void OutSocketMessage::release_buf()
144
void OutSocketMessage::init(uint32_t max_data_size)
146
_max_data_size = max_data_size;
149
OutSocketMessage& OutSocketMessage::alloc_message(uint16_t id, SpiceMessageMarshallers *marshallers)
151
OutSocketMessage* ret;
152
if (!_free_messages.empty()) {
153
ret = _free_messages.front();
154
_free_messages.pop_front();
155
spice_marshaller_reset(ret->marshaller());
157
ret = new OutSocketMessage();
160
SpiceMsgcTunnelSocketData data;
161
data.connection_id = id;
162
marshallers->msgc_tunnel_socket_data(ret->marshaller(), &data);
163
ret->_the_buf = spice_marshaller_reserve_space(ret->marshaller(), _max_data_size);
168
void OutSocketMessage::clear_free_messages()
170
while (!_free_messages.empty()) {
171
OutSocketMessage* message = _free_messages.front();
172
_free_messages.pop_front();
177
struct TunnelService {
184
std::string description;
186
struct in_addr virtual_ip;
188
TunnelConfigConnectionIfc* service_src;
192
class TunnelChannel::TunnelSocket: public ClientNetSocket {
194
TunnelSocket(uint16_t id, TunnelService& dst_service, ProcessLoop& process_loop,
195
EventHandler & event_handler, SpiceMessageMarshallers *marshallers);
196
virtual ~TunnelSocket() {}
198
void set_num_tokens(uint32_t tokens) {_num_tokens = tokens;}
199
void set_server_num_tokens(uint32_t tokens) {_server_num_tokens = tokens;}
200
void set_guest_closed() {_guest_closed = true;}
202
uint32_t get_num_tokens() {return _num_tokens;}
203
uint32_t get_server_num_tokens() {return _server_num_tokens;}
204
bool get_guest_closed() {return _guest_closed;}
207
virtual ReceiveBuffer& alloc_receive_buffer() {return OutSocketMessage::alloc_message(id(), _marshallers);}
210
uint32_t _num_tokens;
211
uint32_t _server_num_tokens;
212
uint32_t _service_id;
214
SpiceMessageMarshallers *_marshallers;
217
TunnelChannel::TunnelSocket::TunnelSocket(uint16_t id, TunnelService& dst_service,
218
ProcessLoop& process_loop,
219
ClientNetSocket::EventHandler& event_handler,
220
SpiceMessageMarshallers *marshallers)
221
: ClientNetSocket(id, dst_service.ip, htons((uint16_t)dst_service.port),
222
process_loop, event_handler)
224
, _server_num_tokens (0)
225
, _service_id (dst_service.id)
226
, _guest_closed (false)
227
, _marshallers(marshallers)
231
class TunnelHandler: public MessageHandlerImp<TunnelChannel, SPICE_CHANNEL_TUNNEL> {
233
TunnelHandler(TunnelChannel& channel)
234
: MessageHandlerImp<TunnelChannel, SPICE_CHANNEL_TUNNEL>(channel) {}
237
TunnelChannel::TunnelChannel(RedClient& client, uint32_t id)
238
: RedChannel(client, SPICE_CHANNEL_TUNNEL, id, new TunnelHandler(*this))
239
, _max_socket_data_size(0)
243
, _config_listener (NULL)
246
TunnelHandler* handler = static_cast<TunnelHandler*>(get_message_handler());
248
handler->set_handler(SPICE_MSG_MIGRATE, &TunnelChannel::handle_migrate);
249
handler->set_handler(SPICE_MSG_SET_ACK, &TunnelChannel::handle_set_ack);
250
handler->set_handler(SPICE_MSG_PING, &TunnelChannel::handle_ping);
251
handler->set_handler(SPICE_MSG_WAIT_FOR_CHANNELS, &TunnelChannel::handle_wait_for_channels);
253
handler->set_handler(SPICE_MSG_TUNNEL_INIT,
254
&TunnelChannel::handle_init);
255
handler->set_handler(SPICE_MSG_TUNNEL_SERVICE_IP_MAP,
256
&TunnelChannel::handle_service_ip_map);
257
handler->set_handler(SPICE_MSG_TUNNEL_SOCKET_OPEN,
258
&TunnelChannel::handle_socket_open);
259
handler->set_handler(SPICE_MSG_TUNNEL_SOCKET_CLOSE,
260
&TunnelChannel::handle_socket_close);
261
handler->set_handler(SPICE_MSG_TUNNEL_SOCKET_FIN,
262
&TunnelChannel::handle_socket_fin);
263
handler->set_handler(SPICE_MSG_TUNNEL_SOCKET_TOKEN,
264
&TunnelChannel::handle_socket_token);
265
handler->set_handler(SPICE_MSG_TUNNEL_SOCKET_CLOSED_ACK,
266
&TunnelChannel::handle_socket_closed_ack);
267
handler->set_handler(SPICE_MSG_TUNNEL_SOCKET_DATA,
268
&TunnelChannel::handle_socket_data);
271
TunnelChannel::~TunnelChannel()
274
OutSocketMessage::clear_free_messages();
277
void TunnelChannel::handle_init(RedPeer::InMessage* message)
279
SpiceMsgTunnelInit* init_msg = (SpiceMsgTunnelInit*)message->data();
280
_max_socket_data_size = init_msg->max_socket_data_size;
281
OutSocketMessage::init(_max_socket_data_size);
282
_sockets.resize(init_msg->max_num_of_sockets);
285
void TunnelChannel::send_service(TunnelService& service)
287
if (service.type != SPICE_TUNNEL_SERVICE_TYPE_IPP &&
288
service.type == SPICE_TUNNEL_SERVICE_TYPE_GENERIC) {
289
THROW("%s: invalid service type", __FUNCTION__);
292
Message* service_msg = new Message(SPICE_MSGC_TUNNEL_SERVICE_ADD);
293
SpiceMsgcTunnelAddGenericService add;
294
SpiceMarshaller *name_out, *description_out;
296
add.group = service.group;
297
add.type = service.type;
298
add.port = service.port;
300
if (service.type == SPICE_TUNNEL_SERVICE_TYPE_IPP) {
301
add.u.ip.type = SPICE_TUNNEL_IP_TYPE_IPv4;
304
_marshallers->msgc_tunnel_service_add(service_msg->marshaller(), &add,
305
&name_out, &description_out);
307
spice_marshaller_add(name_out, (uint8_t *)service.name.c_str(), service.name.length() + 1);
308
spice_marshaller_add(description_out, (uint8_t *)service.description.c_str(), service.description.length() + 1);
310
post_message(service_msg);
313
void TunnelChannel::handle_service_ip_map(RedPeer::InMessage* message)
315
SpiceMsgTunnelServiceIpMap* service_ip_msg = (SpiceMsgTunnelServiceIpMap*)message->data();
316
TunnelService* service = find_service(service_ip_msg->service_id);
318
THROW("%s: attempt to map non-existing service id=%d", __FUNCTION__,
319
service_ip_msg->service_id);
322
if (service_ip_msg->virtual_ip.type == SPICE_TUNNEL_IP_TYPE_IPv4) {
323
memcpy(&service->virtual_ip.s_addr, service_ip_msg->virtual_ip.data,
324
sizeof(SpiceTunnelIPv4));
326
THROW("unexpected ip type %d", service_ip_msg->virtual_ip.type);
328
DBG(0, "service_id=%d (%s), virtual_ip=%s", service->id, service->name.c_str(),
329
inet_ntoa(service->virtual_ip));
331
service->service_src->send_virtual_ip(service->virtual_ip);
335
void TunnelChannel::handle_socket_open(RedPeer::InMessage* message)
337
SpiceMsgTunnelSocketOpen* open_msg = (SpiceMsgTunnelSocketOpen*)message->data();
341
if (_sockets[open_msg->connection_id]) {
342
THROW("%s: attempt to open an already opened connection id=%d", __FUNCTION__,
343
open_msg->connection_id);
346
TunnelService* service = find_service(open_msg->service_id);
348
THROW("%s: attempt to access non-existing service id=%d", __FUNCTION__,
349
open_msg->service_id);
352
sckt = new TunnelSocket(open_msg->connection_id, *service, get_process_loop(), *this, _marshallers);
354
if (sckt->connect(open_msg->tokens)) {
355
_sockets[open_msg->connection_id] = sckt;
356
out_msg = new Message(SPICE_MSGC_TUNNEL_SOCKET_OPEN_ACK);
357
sckt->set_num_tokens(0);
358
sckt->set_server_num_tokens(SOCKET_WINDOW_SIZE);
359
SpiceMsgcTunnelSocketOpenAck ack;
360
ack.connection_id = open_msg->connection_id;
361
ack.tokens = SOCKET_WINDOW_SIZE;
362
_marshallers->msgc_tunnel_socket_open_ack(out_msg->marshaller(), &ack);
364
out_msg = new Message(SPICE_MSGC_TUNNEL_SOCKET_OPEN_NACK);
365
SpiceMsgcTunnelSocketOpenNack nack;
366
nack.connection_id = open_msg->connection_id;
367
_marshallers->msgc_tunnel_socket_open_nack(out_msg->marshaller(), &nack);
371
post_message(out_msg);
374
void TunnelChannel::handle_socket_fin(RedPeer::InMessage* message)
376
SpiceMsgTunnelSocketFin* fin_msg = (SpiceMsgTunnelSocketFin*)message->data();
377
TunnelSocket* sckt = _sockets[fin_msg->connection_id];
380
THROW("%s: fin connection that doesn't exist id=%d", __FUNCTION__, fin_msg->connection_id);
383
DBG(0, "guest fin connection_id=%d", fin_msg->connection_id);
384
if (sckt->is_connected()) {
389
void TunnelChannel::handle_socket_close(RedPeer::InMessage* message)
391
SpiceMsgTunnelSocketClose* close_msg = (SpiceMsgTunnelSocketClose*)message->data();
392
TunnelSocket* sckt = _sockets[close_msg->connection_id];
395
THROW("%s: closing connection that doesn't exist id=%d", __FUNCTION__,
396
close_msg->connection_id);
398
DBG(0, "guest closed connection_id=%d", close_msg->connection_id);
400
sckt->set_guest_closed();
402
if (sckt->is_connected()) {
403
sckt->push_disconnect();
405
// close happened in the server side before it received the client
406
// close msg. we should ack the server and free the socket
407
on_socket_disconnect(*sckt);
411
void TunnelChannel::handle_socket_closed_ack(RedPeer::InMessage* message)
413
SpiceMsgTunnelSocketClosedAck* close_ack_msg = (SpiceMsgTunnelSocketClosedAck*)message->data();
414
TunnelSocket* sckt = _sockets[close_ack_msg->connection_id];
416
THROW("%s: close ack to connection that doesn't exist id=%d", __FUNCTION__,
417
close_ack_msg->connection_id);
420
if (sckt->is_connected()) {
421
THROW("%s: close ack to connection that is not closed id=%d",
422
__FUNCTION__, close_ack_msg->connection_id);
424
_sockets[sckt->id()] = NULL;
425
DBG(0, "guest Acked closed connection_id=%d", close_ack_msg->connection_id);
429
void TunnelChannel::handle_socket_data(RedPeer::InMessage* message)
431
SpiceMsgTunnelSocketData* send_msg = (SpiceMsgTunnelSocketData*)message->data();
432
TunnelSocket* sckt = _sockets[send_msg->connection_id];
435
THROW("%s: sending data to connection that doesn't exist id=%d", __FUNCTION__,
436
send_msg->connection_id);
439
if (!sckt->get_server_num_tokens()) {
440
THROW("%s: token violation connectio_id=%d", __FUNCTION__, sckt->id());
443
sckt->set_server_num_tokens(sckt->get_server_num_tokens() - 1);
445
if (!sckt->is_connected()) {
446
// server hasn't handled the close msg yet
450
InSocketMessage* sckt_msg = new InSocketMessage(*(
451
static_cast<RedChannel::CompoundInMessage*>(message)));
452
if (sckt_msg->size() > _max_socket_data_size) {
453
THROW("%s: socket data exceeds size limit %d > %d connection_id=%d", __FUNCTION__,
454
sckt_msg->size(), _max_socket_data_size, sckt->id());
456
sckt->push_send(*sckt_msg);
460
void TunnelChannel::handle_socket_token(RedPeer::InMessage* message)
462
SpiceMsgTunnelSocketTokens* token_msg = (SpiceMsgTunnelSocketTokens*)message->data();
463
TunnelSocket* sckt = _sockets[token_msg->connection_id];
466
THROW("%s: ack connection that doesn't exist id=%d", __FUNCTION__,
467
token_msg->connection_id);
469
if (!sckt->is_connected()) {
472
sckt->add_recv_tokens(token_msg->num_tokens);
475
void TunnelChannel::on_socket_message_recv_done(ClientNetSocket& sckt,
476
ClientNetSocket::ReceiveBuffer& buf)
478
OutSocketMessage* out_msg = static_cast<OutSocketMessage*>(&buf);
480
post_message(out_msg);
483
void TunnelChannel::on_socket_fin_recv(ClientNetSocket& sckt)
485
TunnelChannel::TunnelSocket* tunnel_sckt = static_cast<TunnelChannel::TunnelSocket*>(&sckt);
486
Message* out_msg = new Message(SPICE_MSGC_TUNNEL_SOCKET_FIN);
487
DBG(0, "FIN from client coonection id=%d", tunnel_sckt->id());
488
SpiceMsgcTunnelSocketFin fin;
489
fin.connection_id = tunnel_sckt->id();
490
_marshallers->msgc_tunnel_socket_fin(out_msg->marshaller(), &fin);
491
post_message(out_msg);
494
void TunnelChannel::on_socket_disconnect(ClientNetSocket& sckt)
496
TunnelChannel::TunnelSocket* tunnel_sckt = static_cast<TunnelChannel::TunnelSocket*>(&sckt);
498
// close initiated by server -> needs ack
499
if (tunnel_sckt->get_guest_closed()) {
500
DBG(0, "send close ack connection_id=%d", tunnel_sckt->id());
501
out_msg = new Message(SPICE_MSGC_TUNNEL_SOCKET_CLOSED_ACK);
502
SpiceMsgcTunnelSocketClosedAck ack;
503
ack.connection_id = tunnel_sckt->id();
504
_marshallers->msgc_tunnel_socket_closed_ack(out_msg->marshaller(), &ack);
505
_sockets[tunnel_sckt->id()] = NULL;
507
} else { // close initiated by client
508
DBG(0, "send close coonection_id=%d", tunnel_sckt->id());
509
out_msg = new Message(SPICE_MSGC_TUNNEL_SOCKET_CLOSED);
510
SpiceMsgcTunnelSocketClosed closed;
511
closed.connection_id = tunnel_sckt->id();
512
_marshallers->msgc_tunnel_socket_closed(out_msg->marshaller(), &closed);
515
post_message(out_msg);
518
void TunnelChannel::on_socket_message_send_done(ClientNetSocket& sckt)
520
TunnelChannel::TunnelSocket* tunnel_sckt = static_cast<TunnelChannel::TunnelSocket*>(&sckt);
521
uint32_t num_tokens = tunnel_sckt->get_num_tokens();
524
if (num_tokens == SOCKET_TOKENS_TO_SEND) {
525
Message* out_msg = new Message(SPICE_MSGC_TUNNEL_SOCKET_TOKEN);
526
SpiceMsgcTunnelSocketTokens tokens_msg;
527
tokens_msg.connection_id = tunnel_sckt->id();
528
tokens_msg.num_tokens = num_tokens;
529
_marshallers->msgc_tunnel_socket_token(out_msg->marshaller(), &tokens_msg);
530
post_message(out_msg);
532
tunnel_sckt->set_num_tokens(0);
533
tunnel_sckt->set_server_num_tokens(tunnel_sckt->get_server_num_tokens() + num_tokens);
535
ASSERT(tunnel_sckt->get_server_num_tokens() <= SOCKET_WINDOW_SIZE);
537
tunnel_sckt->set_num_tokens(num_tokens);
541
TunnelService* TunnelChannel::find_service(uint32_t id)
543
for (std::list<TunnelService*>::iterator iter = _services.begin();
544
iter != _services.end(); iter++) {
545
if ((*iter)->id == id) {
552
/* returns the first service with the same ip */
553
TunnelService* TunnelChannel::find_service(struct in_addr& ip)
555
for (std::list<TunnelService*>::iterator iter = _services.begin();
556
iter != _services.end(); iter++) {
557
if ((*iter)->ip.s_addr == ip.s_addr) {
564
TunnelService* TunnelChannel::find_service(struct in_addr& ip, uint32_t port)
566
for (std::list<TunnelService*>::iterator iter = _services.begin();
567
iter != _services.end(); iter++) {
568
if (((*iter)->ip.s_addr == ip.s_addr) && ((*iter)->port == port)) {
575
void TunnelChannel::destroy_sockets()
577
for (unsigned int i = 0; i < _sockets.size(); i++) {
586
void TunnelChannel::on_connect()
588
_config_listener = new TunnelConfigListenerIfc(*this);
592
void TunnelChannel::on_disconnect()
595
OutSocketMessage::clear_free_messages();
597
if (_config_listener) {
598
delete _config_listener;
599
_config_listener = NULL;
605
void TunnelChannel::add_service(TunnelConfigConnectionIfc& source,
606
uint32_t type, struct in_addr& ip, uint32_t port,
607
std::string& name, std::string& description)
609
if (find_service(ip, port)) {
610
LOG_WARN("service ip=%s port=%d was already added",
611
inet_ntoa(ip), port);
614
TunnelService* new_service = new TunnelService;
615
TunnelService* service_group = find_service(ip);
616
new_service->type = type;
617
new_service->id = _service_id++;
619
if (name != service_group->name) {
620
LOG_WARN("service ip=%s port=%d was not added because of inconsistent name for ip",
621
inet_ntoa(ip), port);
625
new_service->group = service_group->group;
627
new_service->group = _service_group++;
629
new_service->ip.s_addr = ip.s_addr;
630
new_service->port = port;
631
new_service->name = name;
632
new_service->description = description;
633
new_service->service_src = &source;
634
_services.push_back(new_service);
635
send_service(*new_service);
640
class TunnelFactory: public ChannelFactory {
642
TunnelFactory() : ChannelFactory(SPICE_CHANNEL_TUNNEL) {}
643
virtual RedChannel* construct(RedClient& client, uint32_t id)
645
return new TunnelChannel(client, id);
649
static TunnelFactory factory;
651
ChannelFactory& TunnelChannel::Factory()
657
class CreatePipeListenerEvent: public SyncEvent {
659
CreatePipeListenerEvent(NamedPipe::ListenerInterface& listener_ifc)
660
: _listener_ifc (listener_ifc)
664
virtual void do_response(AbstractProcessLoop& events_loop)
666
_listener_ref = NamedPipe::create(TUNNEL_CONFIG_PIPE_NAME, _listener_ifc);
669
NamedPipe::ListenerRef get_listener() { return _listener_ref;}
671
NamedPipe::ListenerInterface& _listener_ifc;
672
NamedPipe::ListenerRef _listener_ref;
675
class DestroyPipeListenerEvent: public SyncEvent {
677
DestroyPipeListenerEvent(NamedPipe::ListenerRef listener_ref)
678
: _listener_ref (listener_ref)
682
virtual void do_response(AbstractProcessLoop& events_loop)
684
NamedPipe::destroy(_listener_ref);
688
NamedPipe::ListenerRef _listener_ref;
691
class DestroyPipeConnectionEvent: public SyncEvent {
693
DestroyPipeConnectionEvent(NamedPipe::ConnectionRef ref) : _conn_ref(ref) {}
694
virtual void do_response(AbstractProcessLoop& events_loop)
696
NamedPipe::destroy_connection(_conn_ref);
699
NamedPipe::ConnectionRef _conn_ref;
702
TunnelConfigListenerIfc::TunnelConfigListenerIfc(TunnelChannel& tunnel)
705
AutoRef<CreatePipeListenerEvent> event(new CreatePipeListenerEvent(*this));
706
_tunnel.get_client().push_event(*event);
708
_listener_ref = (*event)->get_listener();
711
TunnelConfigListenerIfc::~TunnelConfigListenerIfc()
713
AutoRef<DestroyPipeListenerEvent> listen_event(new DestroyPipeListenerEvent(_listener_ref));
714
_tunnel.get_client().push_event(*listen_event);
715
(*listen_event)->wait();
716
for (std::list<TunnelConfigConnectionIfc*>::iterator it = _connections.begin();
717
it != _connections.end(); ++it) {
718
if ((*it)->get_ref() != NamedPipe::INVALID_CONNECTION) {
719
AutoRef<DestroyPipeConnectionEvent> conn_event(new DestroyPipeConnectionEvent(
721
_tunnel.get_client().push_event(*conn_event);
722
(*conn_event)->wait();
728
NamedPipe::ConnectionInterface& TunnelConfigListenerIfc::create()
730
DBG(0, "new_connection");
731
TunnelConfigConnectionIfc* new_conn = new TunnelConfigConnectionIfc(_tunnel, *this);
732
_connections.push_back(new_conn);
736
void TunnelConfigListenerIfc::destroy_connection(TunnelConfigConnectionIfc* conn)
738
if (conn->get_ref() != NamedPipe::INVALID_CONNECTION) {
739
NamedPipe::destroy_connection(conn->get_ref());
741
_connections.remove(conn);
745
TunnelConfigConnectionIfc::TunnelConfigConnectionIfc(TunnelChannel& tunnel,
746
TunnelConfigListenerIfc& listener)
748
, _listener (listener)
755
void TunnelConfigConnectionIfc::bind(NamedPipe::ConnectionRef conn_ref)
761
void TunnelConfigConnectionIfc::on_data()
763
if (!_out_msg.empty()) {
764
int ret = NamedPipe::write(_opaque, (uint8_t*)_out_msg.c_str() + _out_msg_pos,
765
_out_msg.length() - _out_msg_pos);
767
_listener.destroy_connection(this);
771
if (_out_msg_pos == _out_msg.length()) {
776
int ret = NamedPipe::read(_opaque, (uint8_t*)_in_msg + _in_msg_len,
777
TUNNEL_CONFIG_MAX_MSG_LEN - _in_msg_len);
780
_listener.destroy_connection(this);
785
if (_in_msg[_in_msg_len - 1] != '\n') {
793
void TunnelConfigConnectionIfc::send_virtual_ip(struct in_addr& ip)
795
_out_msg = inet_ntoa(ip);
801
void TunnelConfigConnectionIfc::handle_msg()
803
std::string space = " \t";
804
_in_msg[_in_msg_len - 1] = '\0';
805
std::string msg(_in_msg);
807
uint32_t service_type;
813
DBG(0, "msg=%s", _in_msg);
814
size_t start_token = 0;
817
start_token = msg.find_first_not_of(space);
818
end_token = msg.find_first_of(space, start_token);
820
if ((end_token - start_token) != 1) {
821
THROW("unexpected service type length");
823
if (msg[start_token] == '0') {
824
service_type = SPICE_TUNNEL_SERVICE_TYPE_GENERIC;
825
} else if (msg[start_token] == '1') {
826
service_type = SPICE_TUNNEL_SERVICE_TYPE_IPP;
828
THROW("unexpected service type");
831
start_token = msg.find_first_not_of(space, end_token);
832
end_token = msg.find_first_of(space, start_token);
834
inet_aton(msg.substr(start_token, end_token - start_token).c_str(), &ip);
836
start_token = msg.find_first_not_of(space, end_token);
837
end_token = msg.find_first_of(space, start_token);
839
port = atoi(msg.substr(start_token, end_token - start_token).c_str());
841
start_token = msg.find_first_not_of(space, end_token);
842
end_token = msg.find_first_of(space, start_token);
844
name = msg.substr(start_token, end_token - start_token);
846
start_token = msg.find_first_not_of(space, end_token);
847
desc = msg.substr(start_token);
849
_tunnel.add_service(*this, service_type, ip, port, name, desc);