~ubuntu-branches/debian/jessie/spice/jessie

« back to all changes in this revision

Viewing changes to client/tunnel_channel.cpp

  • Committer: Package Import Robot
  • Author(s): Michael Tokarev
  • Date: 2014-05-23 19:26:44 UTC
  • mfrom: (0.4.7) (2.1.12 sid)
  • Revision ID: package-import@ubuntu.com-20140523192644-j9sbho5ghud5keje
Tags: 0.12.5-1
* new upstream release.  Can now build without celt!
* Dropped patches:
  - make-celt-to-be-optional.patch
  - link-server-test-with-libm-libpthread.patch
  - enable_subdir-objects.patch
  - fix-buffer-overflow-when-decrypting-client-spice-ticket.patch
* build-depend on libopus-dev, which enables opus support
  (no --enable-opus configure flag for now)
* do not remove .version in clean anymore (it is part of the tarball)
* do not use dh_autoreconf, since we aren't changing autoconf anymore
* update libspice-server1.symbols with new symbols
* introduce libspice-server1-dbg package (Closes: #743850)
* fix the vcs-browse url (Closes: #722241)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
    Copyright (C) 2009 Red Hat, Inc.
3
 
 
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.
8
 
 
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.
13
 
 
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/>.
16
 
 
17
 
 
18
 
    Author:
19
 
        yhalperi@redhat.com
20
 
*/
21
 
#ifdef HAVE_CONFIG_H
22
 
#include <config.h>
23
 
#endif
24
 
 
25
 
#include "common.h"
26
 
#include "tunnel_channel.h"
27
 
#include <spice/protocol.h>
28
 
 
29
 
#define SOCKET_WINDOW_SIZE 60
30
 
#define SOCKET_TOKENS_TO_SEND 20
31
 
 
32
 
/* classes for tunneling msgs without reallocations and memcpy */
33
 
 
34
 
class InSocketMessage;
35
 
class OutSocketMessage;
36
 
 
37
 
class InSocketMessage: public ClientNetSocket::SendBuffer {
38
 
public:
39
 
    InSocketMessage(RedChannel::CompoundInMessage& full_msg);
40
 
 
41
 
    const uint8_t* data();
42
 
    uint32_t size();
43
 
    ClientNetSocket::SendBuffer* ref();
44
 
    void unref();
45
 
 
46
 
protected:
47
 
    virtual ~InSocketMessage() {}
48
 
 
49
 
private:
50
 
    int _refs;
51
 
    RedChannel::CompoundInMessage& _full_msg;
52
 
    SpiceMsgTunnelSocketData* _sckt_msg;
53
 
    uint32_t _buf_size;
54
 
};
55
 
 
56
 
InSocketMessage::InSocketMessage(RedChannel::CompoundInMessage& full_msg)
57
 
    : _refs (1)
58
 
    , _full_msg (full_msg)
59
 
{
60
 
    ASSERT(full_msg.type() == SPICE_MSG_TUNNEL_SOCKET_DATA);
61
 
    _full_msg.ref();
62
 
    _sckt_msg = (SpiceMsgTunnelSocketData*)(_full_msg.data());
63
 
    _buf_size = _full_msg.size() - sizeof(SpiceMsgTunnelSocketData);
64
 
}
65
 
 
66
 
const uint8_t* InSocketMessage::data()
67
 
{
68
 
    return _sckt_msg->data;
69
 
}
70
 
 
71
 
uint32_t InSocketMessage::size()
72
 
{
73
 
    return _buf_size;
74
 
}
75
 
 
76
 
ClientNetSocket::SendBuffer* InSocketMessage::ref()
77
 
{
78
 
    _full_msg.ref();
79
 
    _refs++;
80
 
    return this;
81
 
}
82
 
 
83
 
void InSocketMessage::unref()
84
 
{
85
 
    _full_msg.unref();
86
 
    if (!--_refs) {
87
 
        delete this;
88
 
    }
89
 
}
90
 
 
91
 
class OutSocketMessage: public RedPeer::OutMessage,
92
 
                        public RedChannel::OutMessage,
93
 
                        public ClientNetSocket::ReceiveBuffer {
94
 
public:
95
 
 
96
 
    virtual RedPeer::OutMessage& peer_message() { return *this;}
97
 
    virtual void release();
98
 
 
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();
103
 
 
104
 
    static void init(uint32_t max_data_size);
105
 
    static OutSocketMessage& alloc_message(uint16_t id, SpiceMessageMarshallers *marshallers);
106
 
 
107
 
    static void clear_free_messages();
108
 
 
109
 
protected:
110
 
    OutSocketMessage();
111
 
    virtual ~OutSocketMessage() {}
112
 
 
113
 
private:
114
 
    static std::list<OutSocketMessage*> _free_messages;
115
 
    static uint32_t _max_data_size;
116
 
    uint8_t *_the_buf;
117
 
};
118
 
 
119
 
std::list<OutSocketMessage*> OutSocketMessage::_free_messages;
120
 
uint32_t OutSocketMessage::_max_data_size;
121
 
 
122
 
OutSocketMessage::OutSocketMessage()
123
 
    : RedPeer::OutMessage(SPICE_MSGC_TUNNEL_SOCKET_DATA)
124
 
    , RedChannel::OutMessage()
125
 
    , ClientNetSocket::ReceiveBuffer()
126
 
{
127
 
}
128
 
 
129
 
void OutSocketMessage::set_buf_size(uint32_t size)
130
 
{
131
 
    spice_marshaller_unreserve_space(_marshaller, _max_data_size - size);
132
 
}
133
 
 
134
 
void OutSocketMessage::release()
135
 
{
136
 
    OutSocketMessage::_free_messages.push_front(this);
137
 
}
138
 
 
139
 
void OutSocketMessage::release_buf()
140
 
{
141
 
    release();
142
 
}
143
 
 
144
 
void OutSocketMessage::init(uint32_t max_data_size)
145
 
{
146
 
    _max_data_size = max_data_size;
147
 
}
148
 
 
149
 
OutSocketMessage& OutSocketMessage::alloc_message(uint16_t id, SpiceMessageMarshallers *marshallers)
150
 
{
151
 
    OutSocketMessage* ret;
152
 
    if (!_free_messages.empty()) {
153
 
        ret = _free_messages.front();
154
 
        _free_messages.pop_front();
155
 
        spice_marshaller_reset(ret->marshaller());
156
 
    } else {
157
 
        ret = new OutSocketMessage();
158
 
    }
159
 
 
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);
164
 
 
165
 
    return *ret;
166
 
}
167
 
 
168
 
void OutSocketMessage::clear_free_messages()
169
 
{
170
 
    while (!_free_messages.empty()) {
171
 
        OutSocketMessage* message = _free_messages.front();
172
 
        _free_messages.pop_front();
173
 
        delete message;
174
 
    }
175
 
}
176
 
 
177
 
struct TunnelService {
178
 
    uint32_t type;
179
 
    uint32_t id;
180
 
    uint32_t group;
181
 
    struct in_addr ip;
182
 
    uint32_t port;
183
 
    std::string name;
184
 
    std::string description;
185
 
 
186
 
    struct in_addr virtual_ip;
187
 
#ifdef TUNNEL_CONFIG
188
 
    TunnelConfigConnectionIfc* service_src;
189
 
#endif
190
 
};
191
 
 
192
 
class TunnelChannel::TunnelSocket: public ClientNetSocket {
193
 
public:
194
 
    TunnelSocket(uint16_t id, TunnelService& dst_service, ProcessLoop& process_loop,
195
 
                 EventHandler & event_handler, SpiceMessageMarshallers *marshallers);
196
 
    virtual ~TunnelSocket() {}
197
 
 
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;}
201
 
 
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;}
205
 
 
206
 
protected:
207
 
    virtual ReceiveBuffer& alloc_receive_buffer() {return OutSocketMessage::alloc_message(id(), _marshallers);}
208
 
 
209
 
private:
210
 
    uint32_t _num_tokens;
211
 
    uint32_t _server_num_tokens;
212
 
    uint32_t _service_id;
213
 
    bool _guest_closed;
214
 
    SpiceMessageMarshallers *_marshallers;
215
 
};
216
 
 
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)
223
 
    , _num_tokens (0)
224
 
    , _server_num_tokens (0)
225
 
    , _service_id (dst_service.id)
226
 
    , _guest_closed (false)
227
 
    , _marshallers(marshallers)
228
 
{
229
 
}
230
 
 
231
 
class TunnelHandler: public MessageHandlerImp<TunnelChannel, SPICE_CHANNEL_TUNNEL> {
232
 
public:
233
 
    TunnelHandler(TunnelChannel& channel)
234
 
        : MessageHandlerImp<TunnelChannel, SPICE_CHANNEL_TUNNEL>(channel) {}
235
 
};
236
 
 
237
 
TunnelChannel::TunnelChannel(RedClient& client, uint32_t id)
238
 
    : RedChannel(client, SPICE_CHANNEL_TUNNEL, id, new TunnelHandler(*this))
239
 
    , _max_socket_data_size(0)
240
 
    , _service_id(0)
241
 
    , _service_group(0)
242
 
#ifdef TUNNEL_CONFIG
243
 
    , _config_listener (NULL)
244
 
#endif
245
 
{
246
 
    TunnelHandler* handler = static_cast<TunnelHandler*>(get_message_handler());
247
 
 
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);
252
 
 
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);
269
 
}
270
 
 
271
 
TunnelChannel::~TunnelChannel()
272
 
{
273
 
    destroy_sockets();
274
 
    OutSocketMessage::clear_free_messages();
275
 
}
276
 
 
277
 
void TunnelChannel::handle_init(RedPeer::InMessage* message)
278
 
{
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);
283
 
}
284
 
 
285
 
void TunnelChannel::send_service(TunnelService& service)
286
 
{
287
 
    if (service.type != SPICE_TUNNEL_SERVICE_TYPE_IPP &&
288
 
        service.type == SPICE_TUNNEL_SERVICE_TYPE_GENERIC) {
289
 
        THROW("%s: invalid service type", __FUNCTION__);
290
 
    }
291
 
 
292
 
    Message* service_msg = new Message(SPICE_MSGC_TUNNEL_SERVICE_ADD);
293
 
    SpiceMsgcTunnelAddGenericService add;
294
 
    SpiceMarshaller *name_out, *description_out;
295
 
    add.id = service.id;
296
 
    add.group = service.group;
297
 
    add.type = service.type;
298
 
    add.port = service.port;
299
 
 
300
 
    if (service.type == SPICE_TUNNEL_SERVICE_TYPE_IPP) {
301
 
        add.u.ip.type = SPICE_TUNNEL_IP_TYPE_IPv4;
302
 
    }
303
 
 
304
 
    _marshallers->msgc_tunnel_service_add(service_msg->marshaller(), &add,
305
 
                                           &name_out, &description_out);
306
 
 
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);
309
 
 
310
 
    post_message(service_msg);
311
 
}
312
 
 
313
 
void TunnelChannel::handle_service_ip_map(RedPeer::InMessage* message)
314
 
{
315
 
    SpiceMsgTunnelServiceIpMap* service_ip_msg = (SpiceMsgTunnelServiceIpMap*)message->data();
316
 
    TunnelService* service = find_service(service_ip_msg->service_id);
317
 
    if (!service) {
318
 
        THROW("%s: attempt to map non-existing service id=%d", __FUNCTION__,
319
 
              service_ip_msg->service_id);
320
 
    }
321
 
 
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));
325
 
    } else {
326
 
        THROW("unexpected ip type %d", service_ip_msg->virtual_ip.type);
327
 
    }
328
 
    DBG(0, "service_id=%d (%s), virtual_ip=%s", service->id, service->name.c_str(),
329
 
        inet_ntoa(service->virtual_ip));
330
 
#ifdef TUNNEL_CONFIG
331
 
    service->service_src->send_virtual_ip(service->virtual_ip);
332
 
#endif
333
 
}
334
 
 
335
 
void TunnelChannel::handle_socket_open(RedPeer::InMessage* message)
336
 
{
337
 
    SpiceMsgTunnelSocketOpen* open_msg = (SpiceMsgTunnelSocketOpen*)message->data();
338
 
    TunnelSocket* sckt;
339
 
    Message* out_msg;
340
 
 
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);
344
 
    }
345
 
 
346
 
    TunnelService* service = find_service(open_msg->service_id);
347
 
    if (!service) {
348
 
        THROW("%s: attempt to access non-existing service id=%d", __FUNCTION__,
349
 
              open_msg->service_id);
350
 
    }
351
 
 
352
 
    sckt = new TunnelSocket(open_msg->connection_id, *service, get_process_loop(), *this, _marshallers);
353
 
 
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);
363
 
    } else {
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);
368
 
        delete sckt;
369
 
    }
370
 
 
371
 
    post_message(out_msg);
372
 
}
373
 
 
374
 
void TunnelChannel::handle_socket_fin(RedPeer::InMessage* message)
375
 
{
376
 
    SpiceMsgTunnelSocketFin* fin_msg = (SpiceMsgTunnelSocketFin*)message->data();
377
 
    TunnelSocket* sckt = _sockets[fin_msg->connection_id];
378
 
 
379
 
    if (!sckt) {
380
 
        THROW("%s: fin connection that doesn't exist id=%d", __FUNCTION__, fin_msg->connection_id);
381
 
    }
382
 
 
383
 
    DBG(0, "guest fin connection_id=%d", fin_msg->connection_id);
384
 
    if (sckt->is_connected()) {
385
 
        sckt->push_fin();
386
 
    }
387
 
}
388
 
 
389
 
void TunnelChannel::handle_socket_close(RedPeer::InMessage* message)
390
 
{
391
 
    SpiceMsgTunnelSocketClose* close_msg = (SpiceMsgTunnelSocketClose*)message->data();
392
 
    TunnelSocket* sckt = _sockets[close_msg->connection_id];
393
 
 
394
 
    if (!sckt) {
395
 
        THROW("%s: closing connection that doesn't exist id=%d", __FUNCTION__,
396
 
              close_msg->connection_id);
397
 
    }
398
 
    DBG(0, "guest closed connection_id=%d", close_msg->connection_id);
399
 
 
400
 
    sckt->set_guest_closed();
401
 
 
402
 
    if (sckt->is_connected()) {
403
 
        sckt->push_disconnect();
404
 
    } else {
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);
408
 
    }
409
 
}
410
 
 
411
 
void TunnelChannel::handle_socket_closed_ack(RedPeer::InMessage* message)
412
 
{
413
 
    SpiceMsgTunnelSocketClosedAck* close_ack_msg = (SpiceMsgTunnelSocketClosedAck*)message->data();
414
 
    TunnelSocket* sckt = _sockets[close_ack_msg->connection_id];
415
 
    if (!sckt) {
416
 
        THROW("%s: close ack to connection that doesn't exist id=%d", __FUNCTION__,
417
 
              close_ack_msg->connection_id);
418
 
    }
419
 
 
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);
423
 
    }
424
 
    _sockets[sckt->id()] = NULL;
425
 
    DBG(0, "guest Acked closed connection_id=%d", close_ack_msg->connection_id);
426
 
    delete sckt;
427
 
}
428
 
 
429
 
void TunnelChannel::handle_socket_data(RedPeer::InMessage* message)
430
 
{
431
 
    SpiceMsgTunnelSocketData* send_msg = (SpiceMsgTunnelSocketData*)message->data();
432
 
    TunnelSocket* sckt = _sockets[send_msg->connection_id];
433
 
 
434
 
    if (!sckt) {
435
 
        THROW("%s: sending data to connection that doesn't exist id=%d", __FUNCTION__,
436
 
              send_msg->connection_id);
437
 
    }
438
 
 
439
 
    if (!sckt->get_server_num_tokens()) {
440
 
        THROW("%s: token violation connectio_id=%d", __FUNCTION__, sckt->id());
441
 
    }
442
 
 
443
 
    sckt->set_server_num_tokens(sckt->get_server_num_tokens() - 1);
444
 
 
445
 
    if (!sckt->is_connected()) {
446
 
        // server hasn't handled the close msg yet
447
 
        return;
448
 
    }
449
 
 
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());
455
 
    }
456
 
    sckt->push_send(*sckt_msg);
457
 
    sckt_msg->unref();
458
 
}
459
 
 
460
 
void TunnelChannel::handle_socket_token(RedPeer::InMessage* message)
461
 
{
462
 
    SpiceMsgTunnelSocketTokens* token_msg = (SpiceMsgTunnelSocketTokens*)message->data();
463
 
    TunnelSocket* sckt = _sockets[token_msg->connection_id];
464
 
 
465
 
    if (!sckt) {
466
 
        THROW("%s: ack connection that doesn't exist id=%d", __FUNCTION__,
467
 
              token_msg->connection_id);
468
 
    }
469
 
    if (!sckt->is_connected()) {
470
 
        return;
471
 
    }
472
 
    sckt->add_recv_tokens(token_msg->num_tokens);
473
 
}
474
 
 
475
 
void TunnelChannel::on_socket_message_recv_done(ClientNetSocket& sckt,
476
 
                                                ClientNetSocket::ReceiveBuffer& buf)
477
 
{
478
 
    OutSocketMessage* out_msg = static_cast<OutSocketMessage*>(&buf);
479
 
 
480
 
    post_message(out_msg);
481
 
}
482
 
 
483
 
void TunnelChannel::on_socket_fin_recv(ClientNetSocket& sckt)
484
 
{
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);
492
 
}
493
 
 
494
 
void TunnelChannel::on_socket_disconnect(ClientNetSocket& sckt)
495
 
{
496
 
    TunnelChannel::TunnelSocket* tunnel_sckt = static_cast<TunnelChannel::TunnelSocket*>(&sckt);
497
 
    Message* out_msg;
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;
506
 
        delete &sckt;
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);
513
 
    }
514
 
 
515
 
    post_message(out_msg);
516
 
}
517
 
 
518
 
void TunnelChannel::on_socket_message_send_done(ClientNetSocket& sckt)
519
 
{
520
 
    TunnelChannel::TunnelSocket* tunnel_sckt = static_cast<TunnelChannel::TunnelSocket*>(&sckt);
521
 
    uint32_t num_tokens = tunnel_sckt->get_num_tokens();
522
 
    num_tokens++;
523
 
 
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);
531
 
 
532
 
        tunnel_sckt->set_num_tokens(0);
533
 
        tunnel_sckt->set_server_num_tokens(tunnel_sckt->get_server_num_tokens() + num_tokens);
534
 
 
535
 
        ASSERT(tunnel_sckt->get_server_num_tokens() <= SOCKET_WINDOW_SIZE);
536
 
    } else {
537
 
        tunnel_sckt->set_num_tokens(num_tokens);
538
 
    }
539
 
}
540
 
 
541
 
TunnelService* TunnelChannel::find_service(uint32_t id)
542
 
{
543
 
    for (std::list<TunnelService*>::iterator iter = _services.begin();
544
 
            iter != _services.end(); iter++) {
545
 
        if ((*iter)->id == id) {
546
 
            return *iter;
547
 
        }
548
 
    }
549
 
    return NULL;
550
 
}
551
 
 
552
 
/* returns the first service with the same ip */
553
 
TunnelService* TunnelChannel::find_service(struct in_addr& ip)
554
 
{
555
 
    for (std::list<TunnelService*>::iterator iter = _services.begin();
556
 
            iter != _services.end(); iter++) {
557
 
        if ((*iter)->ip.s_addr == ip.s_addr) {
558
 
            return *iter;
559
 
        }
560
 
    }
561
 
    return NULL;
562
 
}
563
 
 
564
 
TunnelService* TunnelChannel::find_service(struct in_addr& ip, uint32_t port)
565
 
{
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)) {
569
 
            return *iter;
570
 
        }
571
 
    }
572
 
    return NULL;
573
 
}
574
 
 
575
 
void TunnelChannel::destroy_sockets()
576
 
{
577
 
    for (unsigned int i = 0; i < _sockets.size(); i++) {
578
 
        if (_sockets[i]) {
579
 
            delete _sockets[i];
580
 
            _sockets[i] = NULL;
581
 
        }
582
 
    }
583
 
}
584
 
 
585
 
#ifdef TUNNEL_CONFIG
586
 
void TunnelChannel::on_connect()
587
 
{
588
 
    _config_listener = new TunnelConfigListenerIfc(*this);
589
 
}
590
 
#endif
591
 
 
592
 
void TunnelChannel::on_disconnect()
593
 
{
594
 
    destroy_sockets();
595
 
    OutSocketMessage::clear_free_messages();
596
 
#ifdef TUNNEL_CONFIG
597
 
    if (_config_listener) {
598
 
        delete _config_listener;
599
 
        _config_listener = NULL;
600
 
    }
601
 
#endif
602
 
}
603
 
 
604
 
#ifdef TUNNEL_CONFIG
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)
608
 
{
609
 
    if (find_service(ip, port)) {
610
 
        LOG_WARN("service ip=%s port=%d was already added",
611
 
                 inet_ntoa(ip), port);
612
 
        return;
613
 
    }
614
 
    TunnelService* new_service = new TunnelService;
615
 
    TunnelService* service_group = find_service(ip);
616
 
    new_service->type = type;
617
 
    new_service->id = _service_id++;
618
 
    if (service_group) {
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);
622
 
            delete new_service;
623
 
            return;
624
 
        }
625
 
        new_service->group = service_group->group;
626
 
    } else {
627
 
        new_service->group = _service_group++;
628
 
    }
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);
636
 
}
637
 
 
638
 
#endif
639
 
 
640
 
class TunnelFactory: public ChannelFactory {
641
 
public:
642
 
    TunnelFactory() : ChannelFactory(SPICE_CHANNEL_TUNNEL) {}
643
 
    virtual RedChannel* construct(RedClient& client, uint32_t id)
644
 
    {
645
 
        return new TunnelChannel(client, id);
646
 
    }
647
 
};
648
 
 
649
 
static TunnelFactory factory;
650
 
 
651
 
ChannelFactory& TunnelChannel::Factory()
652
 
{
653
 
    return factory;
654
 
}
655
 
 
656
 
#ifdef TUNNEL_CONFIG
657
 
class CreatePipeListenerEvent: public SyncEvent {
658
 
public:
659
 
    CreatePipeListenerEvent(NamedPipe::ListenerInterface& listener_ifc)
660
 
        : _listener_ifc (listener_ifc)
661
 
    {
662
 
    }
663
 
 
664
 
    virtual void do_response(AbstractProcessLoop& events_loop)
665
 
    {
666
 
        _listener_ref =  NamedPipe::create(TUNNEL_CONFIG_PIPE_NAME, _listener_ifc);
667
 
    }
668
 
 
669
 
    NamedPipe::ListenerRef get_listener() { return _listener_ref;}
670
 
private:
671
 
    NamedPipe::ListenerInterface& _listener_ifc;
672
 
    NamedPipe::ListenerRef _listener_ref;
673
 
};
674
 
 
675
 
class DestroyPipeListenerEvent: public SyncEvent {
676
 
public:
677
 
    DestroyPipeListenerEvent(NamedPipe::ListenerRef listener_ref)
678
 
        : _listener_ref (listener_ref)
679
 
    {
680
 
    }
681
 
 
682
 
    virtual void do_response(AbstractProcessLoop& events_loop)
683
 
    {
684
 
        NamedPipe::destroy(_listener_ref);
685
 
    }
686
 
 
687
 
private:
688
 
    NamedPipe::ListenerRef _listener_ref;
689
 
};
690
 
 
691
 
class DestroyPipeConnectionEvent: public SyncEvent {
692
 
public:
693
 
    DestroyPipeConnectionEvent(NamedPipe::ConnectionRef ref) : _conn_ref(ref) {}
694
 
    virtual void do_response(AbstractProcessLoop& events_loop)
695
 
    {
696
 
        NamedPipe::destroy_connection(_conn_ref);
697
 
    }
698
 
private:
699
 
    NamedPipe::ConnectionRef _conn_ref;
700
 
};
701
 
 
702
 
TunnelConfigListenerIfc::TunnelConfigListenerIfc(TunnelChannel& tunnel)
703
 
    : _tunnel (tunnel)
704
 
{
705
 
    AutoRef<CreatePipeListenerEvent> event(new CreatePipeListenerEvent(*this));
706
 
    _tunnel.get_client().push_event(*event);
707
 
    (*event)->wait();
708
 
    _listener_ref = (*event)->get_listener();
709
 
}
710
 
 
711
 
TunnelConfigListenerIfc::~TunnelConfigListenerIfc()
712
 
{
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(
720
 
                                                                    (*it)->get_ref()));
721
 
            _tunnel.get_client().push_event(*conn_event);
722
 
            (*conn_event)->wait();
723
 
        }
724
 
        delete (*it);
725
 
    }
726
 
}
727
 
 
728
 
NamedPipe::ConnectionInterface& TunnelConfigListenerIfc::create()
729
 
{
730
 
    DBG(0, "new_connection");
731
 
    TunnelConfigConnectionIfc* new_conn = new TunnelConfigConnectionIfc(_tunnel, *this);
732
 
    _connections.push_back(new_conn);
733
 
    return *new_conn;
734
 
}
735
 
 
736
 
void TunnelConfigListenerIfc::destroy_connection(TunnelConfigConnectionIfc* conn)
737
 
{
738
 
    if (conn->get_ref() != NamedPipe::INVALID_CONNECTION) {
739
 
        NamedPipe::destroy_connection(conn->get_ref());
740
 
    }
741
 
    _connections.remove(conn);
742
 
    delete conn;
743
 
}
744
 
 
745
 
TunnelConfigConnectionIfc::TunnelConfigConnectionIfc(TunnelChannel& tunnel,
746
 
                                                     TunnelConfigListenerIfc& listener)
747
 
    : _tunnel (tunnel)
748
 
    , _listener (listener)
749
 
    , _in_msg_len (0)
750
 
    , _out_msg ("")
751
 
    , _out_msg_pos (0)
752
 
{
753
 
}
754
 
 
755
 
void TunnelConfigConnectionIfc::bind(NamedPipe::ConnectionRef conn_ref)
756
 
{
757
 
    _opaque = conn_ref;
758
 
    on_data();
759
 
}
760
 
 
761
 
void TunnelConfigConnectionIfc::on_data()
762
 
{
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);
766
 
        if (ret == -1) {
767
 
            _listener.destroy_connection(this);
768
 
            return;
769
 
        }
770
 
        _out_msg_pos += ret;
771
 
        if (_out_msg_pos == _out_msg.length()) {
772
 
            _out_msg = "";
773
 
            _out_msg_pos = 0;
774
 
        }
775
 
    } else {
776
 
        int ret = NamedPipe::read(_opaque, (uint8_t*)_in_msg + _in_msg_len,
777
 
                                  TUNNEL_CONFIG_MAX_MSG_LEN - _in_msg_len);
778
 
 
779
 
        if (ret == -1) {
780
 
            _listener.destroy_connection(this);
781
 
            return;
782
 
        }
783
 
        _in_msg_len += ret;
784
 
 
785
 
        if (_in_msg[_in_msg_len - 1] != '\n') {
786
 
            return;
787
 
        }
788
 
        handle_msg();
789
 
        _in_msg_len = 0;
790
 
    }
791
 
}
792
 
 
793
 
void TunnelConfigConnectionIfc::send_virtual_ip(struct in_addr& ip)
794
 
{
795
 
    _out_msg = inet_ntoa(ip);
796
 
    _out_msg += "\n";
797
 
    _out_msg_pos = 0;
798
 
    on_data();
799
 
}
800
 
 
801
 
void TunnelConfigConnectionIfc::handle_msg()
802
 
{
803
 
    std::string space = " \t";
804
 
    _in_msg[_in_msg_len - 1] = '\0';
805
 
    std::string msg(_in_msg);
806
 
 
807
 
    uint32_t service_type;
808
 
    struct in_addr ip;
809
 
    uint32_t port;
810
 
    std::string name;
811
 
    std::string desc;
812
 
 
813
 
    DBG(0, "msg=%s", _in_msg);
814
 
    size_t start_token = 0;
815
 
    size_t end_token;
816
 
 
817
 
    start_token = msg.find_first_not_of(space);
818
 
    end_token = msg.find_first_of(space, start_token);
819
 
 
820
 
    if ((end_token - start_token) != 1) {
821
 
        THROW("unexpected service type length");
822
 
    }
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;
827
 
    } else {
828
 
        THROW("unexpected service type");
829
 
    }
830
 
 
831
 
    start_token = msg.find_first_not_of(space, end_token);
832
 
    end_token = msg.find_first_of(space, start_token);
833
 
 
834
 
    inet_aton(msg.substr(start_token, end_token - start_token).c_str(), &ip);
835
 
 
836
 
    start_token = msg.find_first_not_of(space, end_token);
837
 
    end_token = msg.find_first_of(space, start_token);
838
 
 
839
 
    port = atoi(msg.substr(start_token, end_token - start_token).c_str());
840
 
 
841
 
    start_token = msg.find_first_not_of(space, end_token);
842
 
    end_token = msg.find_first_of(space, start_token);
843
 
 
844
 
    name = msg.substr(start_token, end_token - start_token);
845
 
 
846
 
    start_token = msg.find_first_not_of(space, end_token);
847
 
    desc = msg.substr(start_token);
848
 
 
849
 
    _tunnel.add_service(*this, service_type, ip, port, name, desc);
850
 
}
851
 
 
852
 
#endif