[Spice-devel] [PATCH] Remove tunneling support
Marc-André Lureau
mlureau at redhat.com
Fri Oct 18 19:16:59 CEST 2013
ack
----- Original Message -----
> It's depending on an unmaintained package (slirp), and I don't
> think anyone uses that code. It's not tested upstream nor in fedora,
> so let's remove it.
> ---
> client/Makefile.am | 7 -
> client/application.cpp | 14 -
> client/tunnel_channel.cpp | 852 -----------
> client/tunnel_channel.h | 140 --
> configure.ac | 21 +-
> server/Makefile.am | 7 -
> server/red_tunnel_worker.c | 3481
> --------------------------------------------
> server/red_tunnel_worker.h | 27 -
> server/reds.c | 26 -
> 9 files changed, 1 insertion(+), 4574 deletions(-)
> delete mode 100644 client/tunnel_channel.cpp
> delete mode 100644 client/tunnel_channel.h
> delete mode 100644 server/red_tunnel_worker.c
> delete mode 100644 server/red_tunnel_worker.h
>
> diff --git a/client/Makefile.am b/client/Makefile.am
> index ebc6ce0..97b56f6 100644
> --- a/client/Makefile.am
> +++ b/client/Makefile.am
> @@ -155,13 +155,6 @@ else
> PLATFORM_INCLUDES=-I$(top_srcdir)/client/x11
> endif
>
> -if SUPPORT_TUNNEL
> -spicec_SOURCES += \
> - tunnel_channel.cpp \
> - tunnel_channel.h \
> - $(NULL)
> -endif
> -
> if SUPPORT_GUI
> spicec_SOURCES += \
> gui/gui.cpp \
> diff --git a/client/application.cpp b/client/application.cpp
> index 8902642..cdce86d 100644
> --- a/client/application.cpp
> +++ b/client/application.cpp
> @@ -43,9 +43,6 @@
> #include "red_gl_canvas.h"
> #endif
> #include "cmd_line_parser.h"
> -#ifdef USE_TUNNEL
> -#include "tunnel_channel.h"
> -#endif
> #ifdef USE_GUI
> #include "gui/gui.h"
> #endif
> @@ -1960,9 +1957,6 @@ bool Application::set_channels_security(CmdLineParser&
> parser, bool on, char *va
> channels_names["cursor"] = SPICE_CHANNEL_CURSOR;
> channels_names["playback"] = SPICE_CHANNEL_PLAYBACK;
> channels_names["record"] = SPICE_CHANNEL_RECORD;
> -#ifdef USE_TUNNEL
> - channels_names["tunnel"] = SPICE_CHANNEL_TUNNEL;
> -#endif
> #ifdef USE_SMARTCARD
> channels_names["smartcard"] = SPICE_CHANNEL_SMARTCARD;
> #endif
> @@ -2133,9 +2127,6 @@ bool Application::set_enable_channels(CmdLineParser&
> parser, bool enable, char *
> channels_names["cursor"] = SPICE_CHANNEL_CURSOR;
> channels_names["playback"] = SPICE_CHANNEL_PLAYBACK;
> channels_names["record"] = SPICE_CHANNEL_RECORD;
> -#ifdef USE_TUNNEL
> - channels_names["tunnel"] = SPICE_CHANNEL_TUNNEL;
> -#endif
> #ifdef USE_SMARTCARD
> channels_names["smartcard"] = SPICE_CHANNEL_SMARTCARD;
> #endif
> @@ -2224,11 +2215,6 @@ void Application::register_channels()
> _client.register_channel_factory(RecordChannel::Factory());
> }
>
> -#ifdef USE_TUNNEL
> - if (_enabled_channels[SPICE_CHANNEL_TUNNEL]) {
> - _client.register_channel_factory(TunnelChannel::Factory());
> - }
> -#endif
> #ifdef USE_SMARTCARD
> if (_enabled_channels[SPICE_CHANNEL_SMARTCARD] &&
> _smartcard_options->enable) {
> smartcard_init(_smartcard_options); // throws Exception
> diff --git a/client/tunnel_channel.cpp b/client/tunnel_channel.cpp
> deleted file mode 100644
> index 3ed4572..0000000
> --- a/client/tunnel_channel.cpp
> +++ /dev/null
> @@ -1,852 +0,0 @@
> -/*
> - Copyright (C) 2009 Red Hat, Inc.
> -
> - This library is free software; you can redistribute it and/or
> - modify it under the terms of the GNU Lesser General Public
> - License as published by the Free Software Foundation; either
> - version 2.1 of the License, or (at your option) any later version.
> -
> - This library is distributed in the hope that it will be useful,
> - but WITHOUT ANY WARRANTY; without even the implied warranty of
> - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> - Lesser General Public License for more details.
> -
> - You should have received a copy of the GNU Lesser General Public
> - License along with this library; if not, see
> <http://www.gnu.org/licenses/>.
> -
> -
> - Author:
> - yhalperi at redhat.com
> -*/
> -#ifdef HAVE_CONFIG_H
> -#include <config.h>
> -#endif
> -
> -#include "common.h"
> -#include "tunnel_channel.h"
> -#include <spice/protocol.h>
> -
> -#define SOCKET_WINDOW_SIZE 60
> -#define SOCKET_TOKENS_TO_SEND 20
> -
> -/* classes for tunneling msgs without reallocations and memcpy */
> -
> -class InSocketMessage;
> -class OutSocketMessage;
> -
> -class InSocketMessage: public ClientNetSocket::SendBuffer {
> -public:
> - InSocketMessage(RedChannel::CompoundInMessage& full_msg);
> -
> - const uint8_t* data();
> - uint32_t size();
> - ClientNetSocket::SendBuffer* ref();
> - void unref();
> -
> -protected:
> - virtual ~InSocketMessage() {}
> -
> -private:
> - int _refs;
> - RedChannel::CompoundInMessage& _full_msg;
> - SpiceMsgTunnelSocketData* _sckt_msg;
> - uint32_t _buf_size;
> -};
> -
> -InSocketMessage::InSocketMessage(RedChannel::CompoundInMessage& full_msg)
> - : _refs (1)
> - , _full_msg (full_msg)
> -{
> - ASSERT(full_msg.type() == SPICE_MSG_TUNNEL_SOCKET_DATA);
> - _full_msg.ref();
> - _sckt_msg = (SpiceMsgTunnelSocketData*)(_full_msg.data());
> - _buf_size = _full_msg.size() - sizeof(SpiceMsgTunnelSocketData);
> -}
> -
> -const uint8_t* InSocketMessage::data()
> -{
> - return _sckt_msg->data;
> -}
> -
> -uint32_t InSocketMessage::size()
> -{
> - return _buf_size;
> -}
> -
> -ClientNetSocket::SendBuffer* InSocketMessage::ref()
> -{
> - _full_msg.ref();
> - _refs++;
> - return this;
> -}
> -
> -void InSocketMessage::unref()
> -{
> - _full_msg.unref();
> - if (!--_refs) {
> - delete this;
> - }
> -}
> -
> -class OutSocketMessage: public RedPeer::OutMessage,
> - public RedChannel::OutMessage,
> - public ClientNetSocket::ReceiveBuffer {
> -public:
> -
> - virtual RedPeer::OutMessage& peer_message() { return *this;}
> - virtual void release();
> -
> - virtual uint8_t* buf() { return _the_buf; };
> - virtual uint32_t buf_max_size() {return _max_data_size;}
> - virtual void set_buf_size(uint32_t size);
> - virtual void release_buf();
> -
> - static void init(uint32_t max_data_size);
> - static OutSocketMessage& alloc_message(uint16_t id,
> SpiceMessageMarshallers *marshallers);
> -
> - static void clear_free_messages();
> -
> -protected:
> - OutSocketMessage();
> - virtual ~OutSocketMessage() {}
> -
> -private:
> - static std::list<OutSocketMessage*> _free_messages;
> - static uint32_t _max_data_size;
> - uint8_t *_the_buf;
> -};
> -
> -std::list<OutSocketMessage*> OutSocketMessage::_free_messages;
> -uint32_t OutSocketMessage::_max_data_size;
> -
> -OutSocketMessage::OutSocketMessage()
> - : RedPeer::OutMessage(SPICE_MSGC_TUNNEL_SOCKET_DATA)
> - , RedChannel::OutMessage()
> - , ClientNetSocket::ReceiveBuffer()
> -{
> -}
> -
> -void OutSocketMessage::set_buf_size(uint32_t size)
> -{
> - spice_marshaller_unreserve_space(_marshaller, _max_data_size - size);
> -}
> -
> -void OutSocketMessage::release()
> -{
> - OutSocketMessage::_free_messages.push_front(this);
> -}
> -
> -void OutSocketMessage::release_buf()
> -{
> - release();
> -}
> -
> -void OutSocketMessage::init(uint32_t max_data_size)
> -{
> - _max_data_size = max_data_size;
> -}
> -
> -OutSocketMessage& OutSocketMessage::alloc_message(uint16_t id,
> SpiceMessageMarshallers *marshallers)
> -{
> - OutSocketMessage* ret;
> - if (!_free_messages.empty()) {
> - ret = _free_messages.front();
> - _free_messages.pop_front();
> - spice_marshaller_reset(ret->marshaller());
> - } else {
> - ret = new OutSocketMessage();
> - }
> -
> - SpiceMsgcTunnelSocketData data;
> - data.connection_id = id;
> - marshallers->msgc_tunnel_socket_data(ret->marshaller(), &data);
> - ret->_the_buf = spice_marshaller_reserve_space(ret->marshaller(),
> _max_data_size);
> -
> - return *ret;
> -}
> -
> -void OutSocketMessage::clear_free_messages()
> -{
> - while (!_free_messages.empty()) {
> - OutSocketMessage* message = _free_messages.front();
> - _free_messages.pop_front();
> - delete message;
> - }
> -}
> -
> -struct TunnelService {
> - uint32_t type;
> - uint32_t id;
> - uint32_t group;
> - struct in_addr ip;
> - uint32_t port;
> - std::string name;
> - std::string description;
> -
> - struct in_addr virtual_ip;
> -#ifdef TUNNEL_CONFIG
> - TunnelConfigConnectionIfc* service_src;
> -#endif
> -};
> -
> -class TunnelChannel::TunnelSocket: public ClientNetSocket {
> -public:
> - TunnelSocket(uint16_t id, TunnelService& dst_service, ProcessLoop&
> process_loop,
> - EventHandler & event_handler, SpiceMessageMarshallers
> *marshallers);
> - virtual ~TunnelSocket() {}
> -
> - void set_num_tokens(uint32_t tokens) {_num_tokens = tokens;}
> - void set_server_num_tokens(uint32_t tokens) {_server_num_tokens =
> tokens;}
> - void set_guest_closed() {_guest_closed = true;}
> -
> - uint32_t get_num_tokens() {return _num_tokens;}
> - uint32_t get_server_num_tokens() {return _server_num_tokens;}
> - bool get_guest_closed() {return _guest_closed;}
> -
> -protected:
> - virtual ReceiveBuffer& alloc_receive_buffer() {return
> OutSocketMessage::alloc_message(id(), _marshallers);}
> -
> -private:
> - uint32_t _num_tokens;
> - uint32_t _server_num_tokens;
> - uint32_t _service_id;
> - bool _guest_closed;
> - SpiceMessageMarshallers *_marshallers;
> -};
> -
> -TunnelChannel::TunnelSocket::TunnelSocket(uint16_t id, TunnelService&
> dst_service,
> - ProcessLoop& process_loop,
> - ClientNetSocket::EventHandler&
> event_handler,
> - SpiceMessageMarshallers *marshallers)
> - : ClientNetSocket(id, dst_service.ip, htons((uint16_t)dst_service.port),
> - process_loop, event_handler)
> - , _num_tokens (0)
> - , _server_num_tokens (0)
> - , _service_id (dst_service.id)
> - , _guest_closed (false)
> - , _marshallers(marshallers)
> -{
> -}
> -
> -class TunnelHandler: public MessageHandlerImp<TunnelChannel,
> SPICE_CHANNEL_TUNNEL> {
> -public:
> - TunnelHandler(TunnelChannel& channel)
> - : MessageHandlerImp<TunnelChannel, SPICE_CHANNEL_TUNNEL>(channel) {}
> -};
> -
> -TunnelChannel::TunnelChannel(RedClient& client, uint32_t id)
> - : RedChannel(client, SPICE_CHANNEL_TUNNEL, id, new TunnelHandler(*this))
> - , _max_socket_data_size(0)
> - , _service_id(0)
> - , _service_group(0)
> -#ifdef TUNNEL_CONFIG
> - , _config_listener (NULL)
> -#endif
> -{
> - TunnelHandler* handler =
> static_cast<TunnelHandler*>(get_message_handler());
> -
> - handler->set_handler(SPICE_MSG_MIGRATE, &TunnelChannel::handle_migrate);
> - handler->set_handler(SPICE_MSG_SET_ACK, &TunnelChannel::handle_set_ack);
> - handler->set_handler(SPICE_MSG_PING, &TunnelChannel::handle_ping);
> - handler->set_handler(SPICE_MSG_WAIT_FOR_CHANNELS,
> &TunnelChannel::handle_wait_for_channels);
> -
> - handler->set_handler(SPICE_MSG_TUNNEL_INIT,
> - &TunnelChannel::handle_init);
> - handler->set_handler(SPICE_MSG_TUNNEL_SERVICE_IP_MAP,
> - &TunnelChannel::handle_service_ip_map);
> - handler->set_handler(SPICE_MSG_TUNNEL_SOCKET_OPEN,
> - &TunnelChannel::handle_socket_open);
> - handler->set_handler(SPICE_MSG_TUNNEL_SOCKET_CLOSE,
> - &TunnelChannel::handle_socket_close);
> - handler->set_handler(SPICE_MSG_TUNNEL_SOCKET_FIN,
> - &TunnelChannel::handle_socket_fin);
> - handler->set_handler(SPICE_MSG_TUNNEL_SOCKET_TOKEN,
> - &TunnelChannel::handle_socket_token);
> - handler->set_handler(SPICE_MSG_TUNNEL_SOCKET_CLOSED_ACK,
> - &TunnelChannel::handle_socket_closed_ack);
> - handler->set_handler(SPICE_MSG_TUNNEL_SOCKET_DATA,
> - &TunnelChannel::handle_socket_data);
> -}
> -
> -TunnelChannel::~TunnelChannel()
> -{
> - destroy_sockets();
> - OutSocketMessage::clear_free_messages();
> -}
> -
> -void TunnelChannel::handle_init(RedPeer::InMessage* message)
> -{
> - SpiceMsgTunnelInit* init_msg = (SpiceMsgTunnelInit*)message->data();
> - _max_socket_data_size = init_msg->max_socket_data_size;
> - OutSocketMessage::init(_max_socket_data_size);
> - _sockets.resize(init_msg->max_num_of_sockets);
> -}
> -
> -void TunnelChannel::send_service(TunnelService& service)
> -{
> - if (service.type != SPICE_TUNNEL_SERVICE_TYPE_IPP &&
> - service.type == SPICE_TUNNEL_SERVICE_TYPE_GENERIC) {
> - THROW("%s: invalid service type", __FUNCTION__);
> - }
> -
> - Message* service_msg = new Message(SPICE_MSGC_TUNNEL_SERVICE_ADD);
> - SpiceMsgcTunnelAddGenericService add;
> - SpiceMarshaller *name_out, *description_out;
> - add.id = service.id;
> - add.group = service.group;
> - add.type = service.type;
> - add.port = service.port;
> -
> - if (service.type == SPICE_TUNNEL_SERVICE_TYPE_IPP) {
> - add.u.ip.type = SPICE_TUNNEL_IP_TYPE_IPv4;
> - }
> -
> - _marshallers->msgc_tunnel_service_add(service_msg->marshaller(), &add,
> - &name_out, &description_out);
> -
> - spice_marshaller_add(name_out, (uint8_t *)service.name.c_str(),
> service.name.length() + 1);
> - spice_marshaller_add(description_out, (uint8_t
> *)service.description.c_str(), service.description.length() + 1);
> -
> - post_message(service_msg);
> -}
> -
> -void TunnelChannel::handle_service_ip_map(RedPeer::InMessage* message)
> -{
> - SpiceMsgTunnelServiceIpMap* service_ip_msg =
> (SpiceMsgTunnelServiceIpMap*)message->data();
> - TunnelService* service = find_service(service_ip_msg->service_id);
> - if (!service) {
> - THROW("%s: attempt to map non-existing service id=%d", __FUNCTION__,
> - service_ip_msg->service_id);
> - }
> -
> - if (service_ip_msg->virtual_ip.type == SPICE_TUNNEL_IP_TYPE_IPv4) {
> - memcpy(&service->virtual_ip.s_addr, service_ip_msg->virtual_ip.data,
> - sizeof(SpiceTunnelIPv4));
> - } else {
> - THROW("unexpected ip type %d", service_ip_msg->virtual_ip.type);
> - }
> - DBG(0, "service_id=%d (%s), virtual_ip=%s", service->id,
> service->name.c_str(),
> - inet_ntoa(service->virtual_ip));
> -#ifdef TUNNEL_CONFIG
> - service->service_src->send_virtual_ip(service->virtual_ip);
> -#endif
> -}
> -
> -void TunnelChannel::handle_socket_open(RedPeer::InMessage* message)
> -{
> - SpiceMsgTunnelSocketOpen* open_msg =
> (SpiceMsgTunnelSocketOpen*)message->data();
> - TunnelSocket* sckt;
> - Message* out_msg;
> -
> - if (_sockets[open_msg->connection_id]) {
> - THROW("%s: attempt to open an already opened connection id=%d",
> __FUNCTION__,
> - open_msg->connection_id);
> - }
> -
> - TunnelService* service = find_service(open_msg->service_id);
> - if (!service) {
> - THROW("%s: attempt to access non-existing service id=%d",
> __FUNCTION__,
> - open_msg->service_id);
> - }
> -
> - sckt = new TunnelSocket(open_msg->connection_id, *service,
> get_process_loop(), *this, _marshallers);
> -
> - if (sckt->connect(open_msg->tokens)) {
> - _sockets[open_msg->connection_id] = sckt;
> - out_msg = new Message(SPICE_MSGC_TUNNEL_SOCKET_OPEN_ACK);
> - sckt->set_num_tokens(0);
> - sckt->set_server_num_tokens(SOCKET_WINDOW_SIZE);
> - SpiceMsgcTunnelSocketOpenAck ack;
> - ack.connection_id = open_msg->connection_id;
> - ack.tokens = SOCKET_WINDOW_SIZE;
> - _marshallers->msgc_tunnel_socket_open_ack(out_msg->marshaller(),
> &ack);
> - } else {
> - out_msg = new Message(SPICE_MSGC_TUNNEL_SOCKET_OPEN_NACK);
> - SpiceMsgcTunnelSocketOpenNack nack;
> - nack.connection_id = open_msg->connection_id;
> - _marshallers->msgc_tunnel_socket_open_nack(out_msg->marshaller(),
> &nack);
> - delete sckt;
> - }
> -
> - post_message(out_msg);
> -}
> -
> -void TunnelChannel::handle_socket_fin(RedPeer::InMessage* message)
> -{
> - SpiceMsgTunnelSocketFin* fin_msg =
> (SpiceMsgTunnelSocketFin*)message->data();
> - TunnelSocket* sckt = _sockets[fin_msg->connection_id];
> -
> - if (!sckt) {
> - THROW("%s: fin connection that doesn't exist id=%d", __FUNCTION__,
> fin_msg->connection_id);
> - }
> -
> - DBG(0, "guest fin connection_id=%d", fin_msg->connection_id);
> - if (sckt->is_connected()) {
> - sckt->push_fin();
> - }
> -}
> -
> -void TunnelChannel::handle_socket_close(RedPeer::InMessage* message)
> -{
> - SpiceMsgTunnelSocketClose* close_msg =
> (SpiceMsgTunnelSocketClose*)message->data();
> - TunnelSocket* sckt = _sockets[close_msg->connection_id];
> -
> - if (!sckt) {
> - THROW("%s: closing connection that doesn't exist id=%d",
> __FUNCTION__,
> - close_msg->connection_id);
> - }
> - DBG(0, "guest closed connection_id=%d", close_msg->connection_id);
> -
> - sckt->set_guest_closed();
> -
> - if (sckt->is_connected()) {
> - sckt->push_disconnect();
> - } else {
> - // close happened in the server side before it received the client
> - // close msg. we should ack the server and free the socket
> - on_socket_disconnect(*sckt);
> - }
> -}
> -
> -void TunnelChannel::handle_socket_closed_ack(RedPeer::InMessage* message)
> -{
> - SpiceMsgTunnelSocketClosedAck* close_ack_msg =
> (SpiceMsgTunnelSocketClosedAck*)message->data();
> - TunnelSocket* sckt = _sockets[close_ack_msg->connection_id];
> - if (!sckt) {
> - THROW("%s: close ack to connection that doesn't exist id=%d",
> __FUNCTION__,
> - close_ack_msg->connection_id);
> - }
> -
> - if (sckt->is_connected()) {
> - THROW("%s: close ack to connection that is not closed id=%d",
> - __FUNCTION__, close_ack_msg->connection_id);
> - }
> - _sockets[sckt->id()] = NULL;
> - DBG(0, "guest Acked closed connection_id=%d",
> close_ack_msg->connection_id);
> - delete sckt;
> -}
> -
> -void TunnelChannel::handle_socket_data(RedPeer::InMessage* message)
> -{
> - SpiceMsgTunnelSocketData* send_msg =
> (SpiceMsgTunnelSocketData*)message->data();
> - TunnelSocket* sckt = _sockets[send_msg->connection_id];
> -
> - if (!sckt) {
> - THROW("%s: sending data to connection that doesn't exist id=%d",
> __FUNCTION__,
> - send_msg->connection_id);
> - }
> -
> - if (!sckt->get_server_num_tokens()) {
> - THROW("%s: token violation connectio_id=%d", __FUNCTION__,
> sckt->id());
> - }
> -
> - sckt->set_server_num_tokens(sckt->get_server_num_tokens() - 1);
> -
> - if (!sckt->is_connected()) {
> - // server hasn't handled the close msg yet
> - return;
> - }
> -
> - InSocketMessage* sckt_msg = new InSocketMessage(*(
> -
> static_cast<RedChannel::CompoundInMessage*>(message)));
> - if (sckt_msg->size() > _max_socket_data_size) {
> - THROW("%s: socket data exceeds size limit %d > %d connection_id=%d",
> __FUNCTION__,
> - sckt_msg->size(), _max_socket_data_size, sckt->id());
> - }
> - sckt->push_send(*sckt_msg);
> - sckt_msg->unref();
> -}
> -
> -void TunnelChannel::handle_socket_token(RedPeer::InMessage* message)
> -{
> - SpiceMsgTunnelSocketTokens* token_msg =
> (SpiceMsgTunnelSocketTokens*)message->data();
> - TunnelSocket* sckt = _sockets[token_msg->connection_id];
> -
> - if (!sckt) {
> - THROW("%s: ack connection that doesn't exist id=%d", __FUNCTION__,
> - token_msg->connection_id);
> - }
> - if (!sckt->is_connected()) {
> - return;
> - }
> - sckt->add_recv_tokens(token_msg->num_tokens);
> -}
> -
> -void TunnelChannel::on_socket_message_recv_done(ClientNetSocket& sckt,
> -
> ClientNetSocket::ReceiveBuffer&
> buf)
> -{
> - OutSocketMessage* out_msg = static_cast<OutSocketMessage*>(&buf);
> -
> - post_message(out_msg);
> -}
> -
> -void TunnelChannel::on_socket_fin_recv(ClientNetSocket& sckt)
> -{
> - TunnelChannel::TunnelSocket* tunnel_sckt =
> static_cast<TunnelChannel::TunnelSocket*>(&sckt);
> - Message* out_msg = new Message(SPICE_MSGC_TUNNEL_SOCKET_FIN);
> - DBG(0, "FIN from client coonection id=%d", tunnel_sckt->id());
> - SpiceMsgcTunnelSocketFin fin;
> - fin.connection_id = tunnel_sckt->id();
> - _marshallers->msgc_tunnel_socket_fin(out_msg->marshaller(), &fin);
> - post_message(out_msg);
> -}
> -
> -void TunnelChannel::on_socket_disconnect(ClientNetSocket& sckt)
> -{
> - TunnelChannel::TunnelSocket* tunnel_sckt =
> static_cast<TunnelChannel::TunnelSocket*>(&sckt);
> - Message* out_msg;
> - // close initiated by server -> needs ack
> - if (tunnel_sckt->get_guest_closed()) {
> - DBG(0, "send close ack connection_id=%d", tunnel_sckt->id());
> - out_msg = new Message(SPICE_MSGC_TUNNEL_SOCKET_CLOSED_ACK);
> - SpiceMsgcTunnelSocketClosedAck ack;
> - ack.connection_id = tunnel_sckt->id();
> - _marshallers->msgc_tunnel_socket_closed_ack(out_msg->marshaller(),
> &ack);
> - _sockets[tunnel_sckt->id()] = NULL;
> - delete &sckt;
> - } else { // close initiated by client
> - DBG(0, "send close coonection_id=%d", tunnel_sckt->id());
> - out_msg = new Message(SPICE_MSGC_TUNNEL_SOCKET_CLOSED);
> - SpiceMsgcTunnelSocketClosed closed;
> - closed.connection_id = tunnel_sckt->id();
> - _marshallers->msgc_tunnel_socket_closed(out_msg->marshaller(),
> &closed);
> - }
> -
> - post_message(out_msg);
> -}
> -
> -void TunnelChannel::on_socket_message_send_done(ClientNetSocket& sckt)
> -{
> - TunnelChannel::TunnelSocket* tunnel_sckt =
> static_cast<TunnelChannel::TunnelSocket*>(&sckt);
> - uint32_t num_tokens = tunnel_sckt->get_num_tokens();
> - num_tokens++;
> -
> - if (num_tokens == SOCKET_TOKENS_TO_SEND) {
> - Message* out_msg = new Message(SPICE_MSGC_TUNNEL_SOCKET_TOKEN);
> - SpiceMsgcTunnelSocketTokens tokens_msg;
> - tokens_msg.connection_id = tunnel_sckt->id();
> - tokens_msg.num_tokens = num_tokens;
> - _marshallers->msgc_tunnel_socket_token(out_msg->marshaller(),
> &tokens_msg);
> - post_message(out_msg);
> -
> - tunnel_sckt->set_num_tokens(0);
> -
> tunnel_sckt->set_server_num_tokens(tunnel_sckt->get_server_num_tokens()
> + num_tokens);
> -
> - ASSERT(tunnel_sckt->get_server_num_tokens() <= SOCKET_WINDOW_SIZE);
> - } else {
> - tunnel_sckt->set_num_tokens(num_tokens);
> - }
> -}
> -
> -TunnelService* TunnelChannel::find_service(uint32_t id)
> -{
> - for (std::list<TunnelService*>::iterator iter = _services.begin();
> - iter != _services.end(); iter++) {
> - if ((*iter)->id == id) {
> - return *iter;
> - }
> - }
> - return NULL;
> -}
> -
> -/* returns the first service with the same ip */
> -TunnelService* TunnelChannel::find_service(struct in_addr& ip)
> -{
> - for (std::list<TunnelService*>::iterator iter = _services.begin();
> - iter != _services.end(); iter++) {
> - if ((*iter)->ip.s_addr == ip.s_addr) {
> - return *iter;
> - }
> - }
> - return NULL;
> -}
> -
> -TunnelService* TunnelChannel::find_service(struct in_addr& ip, uint32_t
> port)
> -{
> - for (std::list<TunnelService*>::iterator iter = _services.begin();
> - iter != _services.end(); iter++) {
> - if (((*iter)->ip.s_addr == ip.s_addr) && ((*iter)->port == port)) {
> - return *iter;
> - }
> - }
> - return NULL;
> -}
> -
> -void TunnelChannel::destroy_sockets()
> -{
> - for (unsigned int i = 0; i < _sockets.size(); i++) {
> - if (_sockets[i]) {
> - delete _sockets[i];
> - _sockets[i] = NULL;
> - }
> - }
> -}
> -
> -#ifdef TUNNEL_CONFIG
> -void TunnelChannel::on_connect()
> -{
> - _config_listener = new TunnelConfigListenerIfc(*this);
> -}
> -#endif
> -
> -void TunnelChannel::on_disconnect()
> -{
> - destroy_sockets();
> - OutSocketMessage::clear_free_messages();
> -#ifdef TUNNEL_CONFIG
> - if (_config_listener) {
> - delete _config_listener;
> - _config_listener = NULL;
> - }
> -#endif
> -}
> -
> -#ifdef TUNNEL_CONFIG
> -void TunnelChannel::add_service(TunnelConfigConnectionIfc& source,
> - uint32_t type, struct in_addr& ip, uint32_t
> port,
> - std::string& name, std::string& description)
> -{
> - if (find_service(ip, port)) {
> - LOG_WARN("service ip=%s port=%d was already added",
> - inet_ntoa(ip), port);
> - return;
> - }
> - TunnelService* new_service = new TunnelService;
> - TunnelService* service_group = find_service(ip);
> - new_service->type = type;
> - new_service->id = _service_id++;
> - if (service_group) {
> - if (name != service_group->name) {
> - LOG_WARN("service ip=%s port=%d was not added because of
> inconsistent name for ip",
> - inet_ntoa(ip), port);
> - delete new_service;
> - return;
> - }
> - new_service->group = service_group->group;
> - } else {
> - new_service->group = _service_group++;
> - }
> - new_service->ip.s_addr = ip.s_addr;
> - new_service->port = port;
> - new_service->name = name;
> - new_service->description = description;
> - new_service->service_src = &source;
> - _services.push_back(new_service);
> - send_service(*new_service);
> -}
> -
> -#endif
> -
> -class TunnelFactory: public ChannelFactory {
> -public:
> - TunnelFactory() : ChannelFactory(SPICE_CHANNEL_TUNNEL) {}
> - virtual RedChannel* construct(RedClient& client, uint32_t id)
> - {
> - return new TunnelChannel(client, id);
> - }
> -};
> -
> -static TunnelFactory factory;
> -
> -ChannelFactory& TunnelChannel::Factory()
> -{
> - return factory;
> -}
> -
> -#ifdef TUNNEL_CONFIG
> -class CreatePipeListenerEvent: public SyncEvent {
> -public:
> - CreatePipeListenerEvent(NamedPipe::ListenerInterface& listener_ifc)
> - : _listener_ifc (listener_ifc)
> - {
> - }
> -
> - virtual void do_response(AbstractProcessLoop& events_loop)
> - {
> - _listener_ref = NamedPipe::create(TUNNEL_CONFIG_PIPE_NAME,
> _listener_ifc);
> - }
> -
> - NamedPipe::ListenerRef get_listener() { return _listener_ref;}
> -private:
> - NamedPipe::ListenerInterface& _listener_ifc;
> - NamedPipe::ListenerRef _listener_ref;
> -};
> -
> -class DestroyPipeListenerEvent: public SyncEvent {
> -public:
> - DestroyPipeListenerEvent(NamedPipe::ListenerRef listener_ref)
> - : _listener_ref (listener_ref)
> - {
> - }
> -
> - virtual void do_response(AbstractProcessLoop& events_loop)
> - {
> - NamedPipe::destroy(_listener_ref);
> - }
> -
> -private:
> - NamedPipe::ListenerRef _listener_ref;
> -};
> -
> -class DestroyPipeConnectionEvent: public SyncEvent {
> -public:
> - DestroyPipeConnectionEvent(NamedPipe::ConnectionRef ref) :
> _conn_ref(ref) {}
> - virtual void do_response(AbstractProcessLoop& events_loop)
> - {
> - NamedPipe::destroy_connection(_conn_ref);
> - }
> -private:
> - NamedPipe::ConnectionRef _conn_ref;
> -};
> -
> -TunnelConfigListenerIfc::TunnelConfigListenerIfc(TunnelChannel& tunnel)
> - : _tunnel (tunnel)
> -{
> - AutoRef<CreatePipeListenerEvent> event(new
> CreatePipeListenerEvent(*this));
> - _tunnel.get_client().push_event(*event);
> - (*event)->wait();
> - _listener_ref = (*event)->get_listener();
> -}
> -
> -TunnelConfigListenerIfc::~TunnelConfigListenerIfc()
> -{
> - AutoRef<DestroyPipeListenerEvent> listen_event(new
> DestroyPipeListenerEvent(_listener_ref));
> - _tunnel.get_client().push_event(*listen_event);
> - (*listen_event)->wait();
> - for (std::list<TunnelConfigConnectionIfc*>::iterator it =
> _connections.begin();
> - it != _connections.end(); ++it) {
> - if ((*it)->get_ref() != NamedPipe::INVALID_CONNECTION) {
> - AutoRef<DestroyPipeConnectionEvent> conn_event(new
> DestroyPipeConnectionEvent(
> -
> (*it)->get_ref()));
> - _tunnel.get_client().push_event(*conn_event);
> - (*conn_event)->wait();
> - }
> - delete (*it);
> - }
> -}
> -
> -NamedPipe::ConnectionInterface& TunnelConfigListenerIfc::create()
> -{
> - DBG(0, "new_connection");
> - TunnelConfigConnectionIfc* new_conn = new
> TunnelConfigConnectionIfc(_tunnel, *this);
> - _connections.push_back(new_conn);
> - return *new_conn;
> -}
> -
> -void TunnelConfigListenerIfc::destroy_connection(TunnelConfigConnectionIfc*
> conn)
> -{
> - if (conn->get_ref() != NamedPipe::INVALID_CONNECTION) {
> - NamedPipe::destroy_connection(conn->get_ref());
> - }
> - _connections.remove(conn);
> - delete conn;
> -}
> -
> -TunnelConfigConnectionIfc::TunnelConfigConnectionIfc(TunnelChannel& tunnel,
> -
> TunnelConfigListenerIfc&
> listener)
> - : _tunnel (tunnel)
> - , _listener (listener)
> - , _in_msg_len (0)
> - , _out_msg ("")
> - , _out_msg_pos (0)
> -{
> -}
> -
> -void TunnelConfigConnectionIfc::bind(NamedPipe::ConnectionRef conn_ref)
> -{
> - _opaque = conn_ref;
> - on_data();
> -}
> -
> -void TunnelConfigConnectionIfc::on_data()
> -{
> - if (!_out_msg.empty()) {
> - int ret = NamedPipe::write(_opaque, (uint8_t*)_out_msg.c_str() +
> _out_msg_pos,
> - _out_msg.length() - _out_msg_pos);
> - if (ret == -1) {
> - _listener.destroy_connection(this);
> - return;
> - }
> - _out_msg_pos += ret;
> - if (_out_msg_pos == _out_msg.length()) {
> - _out_msg = "";
> - _out_msg_pos = 0;
> - }
> - } else {
> - int ret = NamedPipe::read(_opaque, (uint8_t*)_in_msg + _in_msg_len,
> - TUNNEL_CONFIG_MAX_MSG_LEN - _in_msg_len);
> -
> - if (ret == -1) {
> - _listener.destroy_connection(this);
> - return;
> - }
> - _in_msg_len += ret;
> -
> - if (_in_msg[_in_msg_len - 1] != '\n') {
> - return;
> - }
> - handle_msg();
> - _in_msg_len = 0;
> - }
> -}
> -
> -void TunnelConfigConnectionIfc::send_virtual_ip(struct in_addr& ip)
> -{
> - _out_msg = inet_ntoa(ip);
> - _out_msg += "\n";
> - _out_msg_pos = 0;
> - on_data();
> -}
> -
> -void TunnelConfigConnectionIfc::handle_msg()
> -{
> - std::string space = " \t";
> - _in_msg[_in_msg_len - 1] = '\0';
> - std::string msg(_in_msg);
> -
> - uint32_t service_type;
> - struct in_addr ip;
> - uint32_t port;
> - std::string name;
> - std::string desc;
> -
> - DBG(0, "msg=%s", _in_msg);
> - size_t start_token = 0;
> - size_t end_token;
> -
> - start_token = msg.find_first_not_of(space);
> - end_token = msg.find_first_of(space, start_token);
> -
> - if ((end_token - start_token) != 1) {
> - THROW("unexpected service type length");
> - }
> - if (msg[start_token] == '0') {
> - service_type = SPICE_TUNNEL_SERVICE_TYPE_GENERIC;
> - } else if (msg[start_token] == '1') {
> - service_type = SPICE_TUNNEL_SERVICE_TYPE_IPP;
> - } else {
> - THROW("unexpected service type");
> - }
> -
> - start_token = msg.find_first_not_of(space, end_token);
> - end_token = msg.find_first_of(space, start_token);
> -
> - inet_aton(msg.substr(start_token, end_token - start_token).c_str(),
> &ip);
> -
> - start_token = msg.find_first_not_of(space, end_token);
> - end_token = msg.find_first_of(space, start_token);
> -
> - port = atoi(msg.substr(start_token, end_token - start_token).c_str());
> -
> - start_token = msg.find_first_not_of(space, end_token);
> - end_token = msg.find_first_of(space, start_token);
> -
> - name = msg.substr(start_token, end_token - start_token);
> -
> - start_token = msg.find_first_not_of(space, end_token);
> - desc = msg.substr(start_token);
> -
> - _tunnel.add_service(*this, service_type, ip, port, name, desc);
> -}
> -
> -#endif
> diff --git a/client/tunnel_channel.h b/client/tunnel_channel.h
> deleted file mode 100644
> index 63174d8..0000000
> --- a/client/tunnel_channel.h
> +++ /dev/null
> @@ -1,140 +0,0 @@
> -/*
> - Copyright (C) 2009 Red Hat, Inc.
> -
> - This library is free software; you can redistribute it and/or
> - modify it under the terms of the GNU Lesser General Public
> - License as published by the Free Software Foundation; either
> - version 2.1 of the License, or (at your option) any later version.
> -
> - This library is distributed in the hope that it will be useful,
> - but WITHOUT ANY WARRANTY; without even the implied warranty of
> - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> - Lesser General Public License for more details.
> -
> - You should have received a copy of the GNU Lesser General Public
> - License along with this library; if not, see
> <http://www.gnu.org/licenses/>.
> -
> -
> - Author:
> - yhalperi at redhat.com
> -*/
> -
> -#ifndef _H_TUNNEL_CHANNEL
> -#define _H_TUNNEL_CHANNEL
> -
> -#include "common.h"
> -#include "red_channel.h"
> -#include "red_client.h"
> -#include "client_net_socket.h"
> -#include "platform.h"
> -
> -#define TUNNEL_CONFIG
> -
> -#ifdef TUNNEL_CONFIG
> -class TunnelConfigConnectionIfc;
> -class TunnelConfigListenerIfc;
> -#endif
> -
> -/* channel for tunneling tcp from guest to client network */
> -typedef struct TunnelService TunnelService;
> -class TunnelChannel: public RedChannel,
> - public ClientNetSocket::EventHandler {
> -public:
> -
> - TunnelChannel(RedClient& client, uint32_t id);
> - virtual ~TunnelChannel();
> -
> - virtual void on_socket_message_recv_done(ClientNetSocket& sckt,
> - ClientNetSocket::ReceiveBuffer&
> buf);
> - virtual void on_socket_message_send_done(ClientNetSocket& sckt);
> - virtual void on_socket_fin_recv(ClientNetSocket& sckt);
> - virtual void on_socket_disconnect(ClientNetSocket& sckt);
> -
> -#ifdef TUNNEL_CONFIG
> - void add_service(TunnelConfigConnectionIfc& source,
> - uint32_t type, struct in_addr& ip, uint32_t port,
> - std::string& name, std::string& description);
> -#endif
> - static ChannelFactory& Factory();
> -
> -protected:
> - class TunnelSocket;
> -
> - virtual void on_disconnect();
> - virtual void on_connect();
> -
> -private:
> - void handle_init(RedPeer::InMessage* message);
> - void handle_service_ip_map(RedPeer::InMessage* message);
> -
> - void handle_socket_open(RedPeer::InMessage* message);
> - void handle_socket_fin(RedPeer::InMessage* message);
> - void handle_socket_close(RedPeer::InMessage* message);
> - void handle_socket_closed_ack(RedPeer::InMessage* message);
> - void handle_socket_data(RedPeer::InMessage* message);
> - void handle_socket_token(RedPeer::InMessage* message);
> -
> - TunnelService* find_service(uint32_t id);
> - TunnelService* find_service(struct in_addr& ip);
> - TunnelService* find_service(struct in_addr& ip, uint32_t port);
> -
> - void send_service(TunnelService& service);
> - void destroy_sockets();
> -
> -private:
> - std::vector<TunnelSocket*> _sockets;
> - std::list<TunnelService*> _services;
> - uint32_t _max_socket_data_size;
> - uint32_t _service_id;
> - uint32_t _service_group;
> -#ifdef TUNNEL_CONFIG
> - TunnelConfigListenerIfc* _config_listener;
> - friend class TunnelConfigListenerIfc;
> -#endif
> -};
> -
> -#ifdef TUNNEL_CONFIG
> -#ifdef _WIN32
> -#define TUNNEL_CONFIG_PIPE_NAME "tunnel-config.pipe"
> -#else
> -#define TUNNEL_CONFIG_PIPE_NAME "/tmp/tunnel-config.pipe"
> -#endif
> -
> -class TunnelConfigConnectionIfc;
> -
> -class TunnelConfigListenerIfc: public NamedPipe::ListenerInterface {
> -public:
> - TunnelConfigListenerIfc(TunnelChannel& tunnel);
> - virtual ~TunnelConfigListenerIfc();
> - virtual NamedPipe::ConnectionInterface& create();
> - virtual void destroy_connection(TunnelConfigConnectionIfc* conn);
> -
> -private:
> - TunnelChannel& _tunnel;
> - NamedPipe::ListenerRef _listener_ref;
> - std::list<TunnelConfigConnectionIfc*> _connections;
> -};
> -
> -#define TUNNEL_CONFIG_MAX_MSG_LEN 2048
> -class TunnelConfigConnectionIfc: public NamedPipe::ConnectionInterface {
> -public:
> - TunnelConfigConnectionIfc(TunnelChannel& tunnel,
> - TunnelConfigListenerIfc& listener);
> - virtual void bind(NamedPipe::ConnectionRef conn_ref);
> - virtual void on_data();
> - void send_virtual_ip(struct in_addr& ip);
> - NamedPipe::ConnectionRef get_ref() {return _opaque;}
> - void handle_msg();
> -
> -private:
> - TunnelChannel& _tunnel;
> - TunnelConfigListenerIfc& _listener;
> - char _in_msg[TUNNEL_CONFIG_MAX_MSG_LEN]; // <service_type> <ip> <port>
> <name> <desc>\n
> - int _in_msg_len;
> -
> - std::string _out_msg; // <virtual ip>\n
> - unsigned _out_msg_pos;
> -};
> -#endif
> -
> -#endif
> diff --git a/configure.ac b/configure.ac
> index b781d34..7e81329 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -118,16 +118,7 @@ AM_CONDITIONAL(OS_UNIX, test "$os_win32" != "yes")
> AM_CONDITIONAL(OS_LINUX, test "$os_linux" = "yes")
>
> dnl
> =========================================================================
> -dnl Chek optional features
> -AC_ARG_ENABLE(tunnel,
> -[ --enable-tunnel Enable network redirection],,
> -[enable_tunnel="no"])
> -AS_IF([test x"$enable_tunnel" != "xno"], [enable_tunnel="yes"])
> -AM_CONDITIONAL(SUPPORT_TUNNEL, test "x$enable_tunnel" != "xno")
> -if test "x$enable_tunnel" != "xno"; then
> - AC_DEFINE([USE_TUNNEL], [1], [Define if supporting tunnel proxying])
> -fi
> -
> +dnl Check optional features
> AC_ARG_ENABLE(gui,
> [ --enable-gui Enable start dialog with CEGUI],,
> [enable_gui="no"])
> @@ -221,14 +212,6 @@ if test "x$enable_gui" = "xyes" && test
> "x$enable_client" = "xyes" ; then
> ])
> fi
>
> -if test "x$enable_tunnel" = "xyes"; then
> - PKG_CHECK_MODULES(SLIRP, slirp)
> - AC_SUBST(SLIRP_CFLAGS)
> - AC_SUBST(SLIRP_LIBS)
> - SPICE_REQUIRES+=" slirp"
> - AC_DEFINE([HAVE_SLIRP], [], [Define if we have slirp])
> -fi
> -
> if test "x$enable_smartcard" = "xyes"; then
> PKG_CHECK_MODULES(CAC_CARD, libcacard >= 0.1.2)
> SMARTCARD_LIBS="$CAC_CARD_LIBS"
> @@ -535,8 +518,6 @@ echo "
>
> GUI: ${enable_gui}
> " ; fi ; echo "\
> - Support tunneling: ${enable_tunnel}
> -
> Smartcard: ${enable_smartcard}
>
> SASL support: ${enable_sasl}
> diff --git a/server/Makefile.am b/server/Makefile.am
> index 0f8888d..807fbfb 100644
> --- a/server/Makefile.am
> +++ b/server/Makefile.am
> @@ -107,13 +107,6 @@ libspice_server_la_SOURCES = \
> spice_image_cache.c \
> $(NULL)
>
> -if SUPPORT_TUNNEL
> -libspice_server_la_SOURCES += \
> - red_tunnel_worker.c \
> - red_tunnel_worker.h \
> - $(NULL)
> -endif
> -
> if SUPPORT_GL
> libspice_server_la_SOURCES += \
> reds_gl_canvas.c \
> diff --git a/server/red_tunnel_worker.c b/server/red_tunnel_worker.c
> deleted file mode 100644
> index 6781d73..0000000
> --- a/server/red_tunnel_worker.c
> +++ /dev/null
> @@ -1,3481 +0,0 @@
> -/*
> - Copyright (C) 2009 Red Hat, Inc.
> -
> - This library is free software; you can redistribute it and/or
> - modify it under the terms of the GNU Lesser General Public
> - License as published by the Free Software Foundation; either
> - version 2.1 of the License, or (at your option) any later version.
> -
> - This library is distributed in the hope that it will be useful,
> - but WITHOUT ANY WARRANTY; without even the implied warranty of
> - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> - Lesser General Public License for more details.
> -
> - You should have received a copy of the GNU Lesser General Public
> - License along with this library; if not, see
> <http://www.gnu.org/licenses/>.
> -
> -
> - Author:
> - yhalperi at redhat.com
> -*/
> -#ifdef HAVE_CONFIG_H
> -#include <config.h>
> -#endif
> -
> -#include <stdio.h>
> -#include <stdint.h>
> -#include <sys/socket.h>
> -#include <netinet/in.h>
> -#include <arpa/inet.h>
> -#include <netinet/tcp.h>
> -#include <fcntl.h>
> -#include <unistd.h>
> -#include <errno.h>
> -#include "spice.h"
> -#include "spice-experimental.h"
> -#include "red_tunnel_worker.h"
> -#include "red_common.h"
> -#include <spice/protocol.h>
> -#include "reds.h"
> -#include "net_slirp.h"
> -#include "red_channel.h"
> -
> -
> -//#define DEBUG_NETWORK
> -
> -#ifdef DEBUG_NETWORK
> -#define PRINT_SCKT(sckt) spice_printerr("TUNNEL_DBG SOCKET(connection_id=%d
> port=%d, service=%d)",\
> - sckt->connection_id,
> ntohs(sckt->local_port), \
> - sckt->far_service->id)
> -#endif
> -
> -#define MAX_SOCKETS_NUM 20
> -
> -#define MAX_SOCKET_DATA_SIZE (1024 * 2)
> -
> -#define SOCKET_WINDOW_SIZE 80
> -#define SOCKET_TOKENS_TO_SEND 20
> -#define SOCKET_TOKENS_TO_SEND_FOR_PROCESS 5 // sent in case the all the
> tokens were used by
> - // the client but they weren't
> consumed by slirp
> - // due to missing data for
> processing them and
> - // turning them into 'ready
> chunks'
> -
> -/* the number of buffer might exceed the window size when the analysis of
> the buffers in the
> - process queue need more data in order to be able to move them to the
> ready queue */
> -#define MAX_SOCKET_IN_BUFFERS (int)(SOCKET_WINDOW_SIZE * 1.5)
> -#define MAX_SOCKET_OUT_BUFFERS (int)(SOCKET_WINDOW_SIZE * 1.5)
> -
> -#define CONTROL_MSG_RECV_BUF_SIZE 1024
> -
> -typedef struct TunnelWorker TunnelWorker;
> -
> -enum {
> - PIPE_ITEM_TYPE_MIGRATE_DATA = PIPE_ITEM_TYPE_CHANNEL_BASE,
> - PIPE_ITEM_TYPE_TUNNEL_INIT,
> - PIPE_ITEM_TYPE_SERVICE_IP_MAP,
> - PIPE_ITEM_TYPE_SOCKET_OPEN,
> - PIPE_ITEM_TYPE_SOCKET_FIN,
> - PIPE_ITEM_TYPE_SOCKET_CLOSE,
> - PIPE_ITEM_TYPE_SOCKET_CLOSED_ACK,
> - PIPE_ITEM_TYPE_SOCKET_DATA,
> - PIPE_ITEM_TYPE_SOCKET_TOKEN,
> -};
> -
> -typedef struct RawTunneledBuffer RawTunneledBuffer;
> -typedef void (*release_tunneled_buffer_proc_t)(RawTunneledBuffer *buf);
> -
> -struct RawTunneledBuffer {
> - uint8_t *data;
> - int size;
> - int max_size;
> - int refs;
> - RawTunneledBuffer *next;
> - void *usr_opaque;
> - release_tunneled_buffer_proc_t release_proc;
> -};
> -
> -static inline RawTunneledBuffer *tunneled_buffer_ref(RawTunneledBuffer *buf)
> -{
> - buf->refs++;
> - return buf;
> -}
> -
> -static inline void tunneled_buffer_unref(RawTunneledBuffer *buf)
> -{
> - if (!(--buf->refs)) {
> - buf->release_proc(buf);
> - }
> -}
> -
> -typedef struct RedSocket RedSocket;
> -
> -/* data received from the quest through slirp */
> -typedef struct RedSocketRawSndBuf {
> - RawTunneledBuffer base;
> - uint8_t buf[MAX_SOCKET_DATA_SIZE];
> -} RedSocketRawSndBuf;
> -
> -/* data received from the client */
> -typedef struct RedSocketRawRcvBuf {
> - RawTunneledBuffer base;
> - uint8_t buf[MAX_SOCKET_DATA_SIZE + sizeof(SpiceMsgcTunnelSocketData)];
> - SpiceMsgcTunnelSocketData *msg_info;
> -} RedSocketRawRcvBuf;
> -
> -typedef struct ReadyTunneledChunk ReadyTunneledChunk;
> -
> -enum {
> - READY_TUNNELED_CHUNK_TYPE_ORIG,
> - READY_TUNNELED_CHUNK_TYPE_SUB, // substitution
> -};
> -
> -
> -/* A chunk of data from a RawTunneledBuffer (or a substitution for a part of
> it)
> - that was processed and is ready to be consumed (by slirp or by the
> client).
> - Each chunk has a reference to the RawTunneledBuffer it
> - was originated from. When all the reference chunks of one buffer are
> consumed (i.e. they are out
> - of the ready queue and they unrefed the buffer), the buffer is released
> */
> -struct ReadyTunneledChunk {
> - uint32_t type;
> - RawTunneledBuffer *origin;
> - uint8_t *data; // if type == READY_TUNNELED_CHUNK_TYPE_ORIG,
> it points
> - // directly to the tunneled data. Otherwise,
> it is a
> - // newly allocated chunk of data
> - // that should be freed after its
> consumption.
> - int size;
> - ReadyTunneledChunk *next;
> -};
> -
> -typedef struct ReadyTunneledChunkQueue {
> - ReadyTunneledChunk *head;
> - ReadyTunneledChunk *tail;
> - uint32_t offset; // first byte in the ready queue that wasn't
> consumed
> -} ReadyTunneledChunkQueue;
> -
> -static void ready_queue_add_orig_chunk(ReadyTunneledChunkQueue *queue,
> RawTunneledBuffer *origin,
> - uint8_t *data, int size);
> -static void ready_queue_pop_chunk(ReadyTunneledChunkQueue *queue);
> -
> -
> -enum {
> - PROCESS_DIRECTION_TYPE_REQUEST, // guest request
> - PROCESS_DIRECTION_TYPE_REPLY, // reply from the service in the client
> LAN
> -};
> -
> -typedef struct TunneledBufferProcessQueue TunneledBufferProcessQueue;
> -
> -typedef RawTunneledBuffer
> *(*alloc_tunneled_buffer_proc_t)(TunneledBufferProcessQueue *queue);
> -/* processing the data. Notice that the buffers can be empty of
> - * data (see RedSocketRestoreTokensBuf) */
> -typedef void (*analyze_new_data_proc_t)(TunneledBufferProcessQueue *queue,
> - RawTunneledBuffer *start_buf, int
> offset, int len);
> -
> -// migrating specific queue data (not the buffers themselves)
> -typedef int (*get_migrate_data_proc_t)(TunneledBufferProcessQueue *queue,
> void **migrate_data);
> -typedef void (*release_migrate_data_proc_t)(TunneledBufferProcessQueue
> *queue, void *migrate_data);
> -typedef void (*restore_proc_t)(TunneledBufferProcessQueue *queue, uint8_t
> *migrate_data);
> -
> -struct TunneledBufferProcessQueue {
> - uint32_t service_type; // which kind of processing is performed.
> - uint32_t direction; // reply/request
> - RawTunneledBuffer *head;
> - RawTunneledBuffer *tail;
> - int head_offset;
> -
> - ReadyTunneledChunkQueue *ready_chunks_queue; // the queue to push the
> post-process data to
> -
> - void *usr_opaque;
> -
> - alloc_tunneled_buffer_proc_t alloc_buf_proc; // for appending data to
> the queue
> - analyze_new_data_proc_t analysis_proc; // service dependent.
> should create the
> - // post-process chunks and
> remove buffers
> - // from the queue.
> - get_migrate_data_proc_t get_migrate_data_proc;
> - release_migrate_data_proc_t release_migrate_data_proc;
> - restore_proc_t restore_proc;
> -};
> -
> -/* push and append routines are the ones that call to the analysis_proc */
> -static void process_queue_push(TunneledBufferProcessQueue *queue,
> RawTunneledBuffer *buf);
> -static void process_queue_append(TunneledBufferProcessQueue *queue, uint8_t
> *data, size_t size);
> -static void process_queue_pop(TunneledBufferProcessQueue *queue);
> -
> -static void process_queue_clear(TunneledBufferProcessQueue *queue);
> -
> -
> -typedef struct RedSocketOutData {
> - // Note that this pipe items can appear only once in the pipe
> - PipeItem status_pipe_item;
> - PipeItem data_pipe_item;
> - PipeItem token_pipe_item;
> -
> - TunneledBufferProcessQueue *process_queue; // service type dependent
> - ReadyTunneledChunkQueue ready_chunks_queue;
> - ReadyTunneledChunk *push_tail; // last chunk in the ready
> queue that was pushed
> - uint32_t push_tail_size; // the subset of the
> push_tail that was sent
> -
> - uint32_t num_buffers; // total count of buffers in process_queue +
> references from ready queue
> - uint32_t data_size; // total size of data that is waiting to be sent.
> -
> - uint32_t num_tokens;
> - uint32_t window_size;
> -} RedSocketOutData;
> -
> -typedef struct RedSocketInData {
> - TunneledBufferProcessQueue *process_queue; // service type dependent
> - ReadyTunneledChunkQueue ready_chunks_queue;
> -
> - uint32_t num_buffers;
> -
> - int32_t num_tokens; // No. tokens consumed by slirp since the last
> token msg sent to the
> - // client. can be negative if we loaned some to
> the client (when the
> - // ready queue is empty)
> - uint32_t client_total_num_tokens;
> -} RedSocketInData;
> -
> -typedef enum {
> - SLIRP_SCKT_STATUS_OPEN,
> - SLIRP_SCKT_STATUS_SHUTDOWN_SEND, // FIN was issued from guest
> - SLIRP_SCKT_STATUS_SHUTDOWN_RECV, // Triggered when FIN is received from
> client
> - SLIRP_SCKT_STATUS_DELAY_ABORT, // when out buffers overflow, we wait
> for client to
> - // close before we close slirp socket.
> see
> - //tunnel_socket_force_close
> - SLIRP_SCKT_STATUS_WAIT_CLOSE, // when shutdown_send was called after
> shut_recv
> - // and vice versa
> - SLIRP_SCKT_STATUS_CLOSED,
> -} SlirpSocketStatus;
> -
> -typedef enum {
> - CLIENT_SCKT_STATUS_WAIT_OPEN,
> - CLIENT_SCKT_STATUS_OPEN,
> - CLIENT_SCKT_STATUS_SHUTDOWN_SEND, // FIN was issued from client
> - CLIENT_SCKT_STATUS_CLOSED,
> -} ClientSocketStatus;
> -
> -typedef struct TunnelService TunnelService;
> -struct RedSocket {
> - int allocated;
> -
> - TunnelWorker *worker;
> -
> - uint16_t connection_id;
> -
> - uint16_t local_port;
> - TunnelService *far_service;
> -
> - ClientSocketStatus client_status;
> - SlirpSocketStatus slirp_status;
> -
> - int pushed_close;
> - int client_waits_close_ack;
> -
> - SlirpSocket *slirp_sckt;
> -
> - RedSocketOutData out_data;
> - RedSocketInData in_data;
> -
> - int in_slirp_send;
> -
> - uint32_t mig_client_status_msg; // the last status change msg
> that was received from
> - //the client during migration,
> and thus was unhandled.
> - // It is 0 if the status didn't
> change during migration
> - uint32_t mig_open_ack_tokens; // if
> SPICE_MSGC_TUNNEL_SOCKET_OPEN_ACK was received during
> - // migration, we store the
> tokens we received in the
> - // msg.
> -};
> -
> -/********** managing send buffers ***********/
> -static RawTunneledBuffer *tunnel_socket_alloc_snd_buf(RedSocket *sckt);
> -static inline RedSocketRawSndBuf
> *__tunnel_worker_alloc_socket_snd_buf(TunnelWorker *worker);
> -static RawTunneledBuffer *process_queue_alloc_snd_tunneled_buffer(
> -
> TunneledBufferProcessQueue
> *queue);
> -
> -static void tunnel_socket_free_snd_buf(RedSocket *sckt, RedSocketRawSndBuf
> *snd_buf);
> -static inline void __tunnel_worker_free_socket_snd_buf(TunnelWorker *worker,
> - RedSocketRawSndBuf
> *snd_buf);
> -static void snd_tunnled_buffer_release(RawTunneledBuffer *buf);
> -
> -/********** managing recv buffers ***********/
> -// receive buffers are allocated before we know to which socket they are
> directed.
> -static inline void tunnel_socket_assign_rcv_buf(RedSocket *sckt,
> - RedSocketRawRcvBuf
> *recv_buf, int buf_size);
> -static inline RedSocketRawRcvBuf
> *__tunnel_worker_alloc_socket_rcv_buf(TunnelWorker *worker);
> -
> -static void tunnel_socket_free_rcv_buf(RedSocket *sckt, RedSocketRawRcvBuf
> *rcv_buf);
> -static inline void __tunnel_worker_free_socket_rcv_buf(TunnelWorker *worker,
> - RedSocketRawRcvBuf
> *rcv_buf);
> -static void rcv_tunnled_buffer_release(RawTunneledBuffer *buf);
> -
> -/********* managing buffers' queues ***********/
> -
> -static void process_queue_simple_analysis(TunneledBufferProcessQueue *queue,
> - RawTunneledBuffer
> *start_last_added,
> - int offset, int len);
> -static inline TunneledBufferProcessQueue
> *__tunnel_socket_alloc_simple_process_queue(
> -
> RedSocket
> *sckt,
> -
> uint32_t
> service_type,
> -
> uint32_t
> direction_type);
> -static TunneledBufferProcessQueue
> *tunnel_socket_alloc_simple_print_request_process_queue(
> -
> RedSocket
> *sckt);
> -static TunneledBufferProcessQueue
> *tunnel_socket_alloc_simple_print_reply_process_queue(
> -
> RedSocket
> *sckt);
> -static void free_simple_process_queue(TunneledBufferProcessQueue *queue);
> -
> -typedef struct ServiceCallback {
> - /* allocating the queue & setting the analysis proc by service type */
> - TunneledBufferProcessQueue *(*alloc_process_queue)(RedSocket * sckt);
> - void (*free_process_queue)(TunneledBufferProcessQueue *queue);
> -} ServiceCallback;
> -
> -/* Callbacks for process queue manipulation according to the service type
> and
> - the direction of the data.
> - The access is performed by [service_type][direction] */
> -static const ServiceCallback SERVICES_CALLBACKS[3][2] = {
> - {{NULL, NULL},
> - {NULL, NULL}},
> - {{tunnel_socket_alloc_simple_print_request_process_queue,
> free_simple_process_queue},
> - {tunnel_socket_alloc_simple_print_reply_process_queue,
> free_simple_process_queue}},
> - {{tunnel_socket_alloc_simple_print_request_process_queue,
> free_simple_process_queue},
> - {tunnel_socket_alloc_simple_print_reply_process_queue,
> free_simple_process_queue}}
> -};
> -
> -/****************************************************
> -* Migration data
> -****************************************************/
> -typedef struct TunnelChannelClient TunnelChannelClient;
> -
> -#define TUNNEL_MIGRATE_DATA_MAGIC (*(uint32_t *)"TMDA")
> -#define TUNNEL_MIGRATE_DATA_VERSION 1
> -
> -#define TUNNEL_MIGRATE_NULL_OFFSET = ~0;
> -
> -typedef struct __attribute__ ((__packed__)) TunnelMigrateSocketOutData {
> - uint32_t num_tokens;
> - uint32_t window_size;
> -
> - uint32_t process_buf_size;
> - uint32_t process_buf;
> -
> - uint32_t process_queue_size;
> - uint32_t process_queue;
> -
> - uint32_t ready_buf_size;
> - uint32_t ready_buf;
> -} TunnelMigrateSocketOutData;
> -
> -typedef struct __attribute__ ((__packed__)) TunnelMigrateSocketInData {
> - int32_t num_tokens;
> - uint32_t client_total_num_tokens;
> -
> - uint32_t process_buf_size;
> - uint32_t process_buf;
> -
> - uint32_t process_queue_size;
> - uint32_t process_queue;
> -
> - uint32_t ready_buf_size;
> - uint32_t ready_buf;
> -} TunnelMigrateSocketInData;
> -
> -
> -typedef struct __attribute__ ((__packed__)) TunnelMigrateSocket {
> - uint16_t connection_id;
> - uint16_t local_port;
> - uint32_t far_service_id;
> -
> - uint16_t client_status;
> - uint16_t slirp_status;
> -
> - uint8_t pushed_close;
> - uint8_t client_waits_close_ack;
> -
> - TunnelMigrateSocketOutData out_data;
> - TunnelMigrateSocketInData in_data;
> -
> - uint32_t slirp_sckt;
> -
> - uint32_t mig_client_status_msg;
> - uint32_t mig_open_ack_tokens;
> -} TunnelMigrateSocket;
> -
> -typedef struct __attribute__ ((__packed__)) TunnelMigrateSocketList {
> - uint16_t num_sockets;
> - uint32_t sockets[0]; // offsets in TunnelMigrateData.data to
> TunnelMigrateSocket
> -} TunnelMigrateSocketList;
> -
> -typedef struct __attribute__ ((__packed__)) TunnelMigrateService {
> - uint32_t type;
> - uint32_t id;
> - uint32_t group;
> - uint32_t port;
> - uint32_t name;
> - uint32_t description;
> - uint8_t virt_ip[4];
> -} TunnelMigrateService;
> -
> -typedef struct __attribute__ ((__packed__)) TunnelMigratePrintService {
> - TunnelMigrateService base;
> - uint8_t ip[4];
> -} TunnelMigratePrintService;
> -
> -typedef struct __attribute__ ((__packed__)) TunnelMigrateServicesList {
> - uint32_t num_services;
> - uint32_t services[0];
> -} TunnelMigrateServicesList;
> -
> -//todo: add ack_generation
> -typedef struct __attribute__ ((__packed__)) TunnelMigrateData {
> - uint32_t magic;
> - uint32_t version;
> - uint64_t message_serial;
> -
> - uint32_t slirp_state; // offset in data to slirp state
> - uint32_t sockets_list; // offset in data to TunnelMigrateSocketList
> - uint32_t services_list;
> -
> - uint8_t data[0];
> -} TunnelMigrateData;
> -
> -typedef struct TunnelMigrateSocketItem {
> - RedSocket *socket;
> - TunnelMigrateSocket mig_socket;
> - void *out_process_queue;
> - void *in_process_queue; // queue data specific for service
> - void *slirp_socket;
> - uint32_t slirp_socket_size;
> -} TunnelMigrateSocketItem;
> -
> -typedef struct TunnelMigrateServiceItem {
> - TunnelService *service;
> - union {
> - TunnelMigrateService generic_service;
> - TunnelMigratePrintService print_service;
> - } u;
> -} TunnelMigrateServiceItem;
> -
> -typedef struct TunnelMigrateItem {
> - PipeItem base;
> -
> - void *slirp_state;
> - uint64_t slirp_state_size;
> -
> - TunnelMigrateServicesList *services_list;
> - uint32_t services_list_size;
> -
> - TunnelMigrateServiceItem *services;
> -
> - TunnelMigrateSocketList *sockets_list;
> - uint32_t sockets_list_size;
> -
> - TunnelMigrateSocketItem sockets_data[MAX_SOCKETS_NUM];
> -} TunnelMigrateItem;
> -
> -static inline void
> tunnel_channel_activate_migrated_sockets(TunnelChannelClient *channel);
> -
> -/*******************************************************************************************/
> -
> -/* use for signaling that 1) subroutines failed 2)routines in the interface
> for slirp
> - failed (which triggered from a call to slirp) */
> -#define SET_TUNNEL_ERROR(channel,format, ...) { \
> - channel->tunnel_error = TRUE; \
> - spice_printerr(format, ## __VA_ARGS__); \
> -}
> -
> -/* should be checked after each subroutine that may cause error or after
> calls to slirp routines */
> -#define CHECK_TUNNEL_ERROR(channel) (channel->tunnel_error)
> -
> -struct TunnelChannelClient {
> - RedChannelClient base;
> - TunnelWorker *worker;
> - int mig_inprogress;
> -
> - int tunnel_error;
> -
> - /* TODO: this needs to be RCC specific (or bad things will happen) */
> - struct {
> - union {
> - SpiceMsgTunnelInit init;
> - SpiceMsgTunnelServiceIpMap service_ip;
> - SpiceMsgTunnelSocketOpen socket_open;
> - SpiceMsgTunnelSocketFin socket_fin;
> - SpiceMsgTunnelSocketClose socket_close;
> - SpiceMsgTunnelSocketClosedAck socket_close_ack;
> - SpiceMsgTunnelSocketData socket_data;
> - SpiceMsgTunnelSocketTokens socket_token;
> - TunnelMigrateData migrate_data;
> - SpiceMsgMigrate migrate;
> - } u;
> - } send_data;
> -
> - uint8_t control_rcv_buf[CONTROL_MSG_RECV_BUF_SIZE];
> -};
> -
> -typedef struct RedSlirpNetworkInterface {
> - SlirpUsrNetworkInterface base;
> - TunnelWorker *worker;
> -} RedSlirpNetworkInterface;
> -
> -struct TunnelService {
> - RingItem ring_item;
> - PipeItem pipe_item;
> - uint32_t type;
> - uint32_t id;
> - uint32_t group;
> - uint32_t port;
> - char *name;
> - char *description;
> -
> - struct in_addr virt_ip;
> -};
> -
> -typedef struct TunnelPrintService {
> - TunnelService base;
> - uint8_t ip[4];
> -} TunnelPrintService;
> -
> -struct TunnelWorker {
> - RedChannel *channel;
> - TunnelChannelClient *channel_client;
> -
> - SpiceCoreInterface *core_interface;
> - SpiceNetWireInstance *sin;
> - SpiceNetWireInterface *sif;
> - RedSlirpNetworkInterface tunnel_interface;
> - RedSlirpNetworkInterface null_interface;
> -
> - RedSocket sockets[MAX_SOCKETS_NUM]; // the sockets are in the
> worker and not
> - // in the channel since the
> slirp sockets
> - // can be still alive (but
> during close) after
> - // the channel was
> disconnected
> -
> - int num_sockets;
> -
> - RedSocketRawSndBuf *free_snd_buf;
> - RedSocketRawRcvBuf *free_rcv_buf;
> -
> - Ring services;
> - int num_services;
> -};
> -
> -
> -/*********************************************************************
> - * Tunnel interface
> - *********************************************************************/
> -static void tunnel_channel_on_disconnect(RedChannel *channel);
> -
> -/* networking interface for slirp */
> -static int qemu_can_output(SlirpUsrNetworkInterface *usr_interface);
> -static void qemu_output(SlirpUsrNetworkInterface *usr_interface, const
> uint8_t *pkt, int pkt_len);
> -static int null_tunnel_socket_connect(SlirpUsrNetworkInterface
> *usr_interface,
> - struct in_addr src_addr, uint16_t
> src_port,
> - struct in_addr dst_addr, uint16_t
> dst_port,
> - SlirpSocket *slirp_s, UserSocket
> **o_usr_s);
> -static int tunnel_socket_connect(SlirpUsrNetworkInterface *usr_interface,
> - struct in_addr src_addr, uint16_t src_port,
> - struct in_addr dst_addr, uint16_t dst_port,
> - SlirpSocket *slirp_s, UserSocket
> **o_usr_s);
> -static void null_tunnel_socket_close(SlirpUsrNetworkInterface
> *usr_interface, UserSocket *opaque);
> -static void tunnel_socket_close(SlirpUsrNetworkInterface *usr_interface,
> UserSocket *opaque);
> -static int null_tunnel_socket_send(SlirpUsrNetworkInterface *usr_interface,
> UserSocket *opaque,
> - uint8_t *buf, size_t len, uint8_t
> urgent);
> -static int tunnel_socket_send(SlirpUsrNetworkInterface *usr_interface,
> UserSocket *opaque,
> - uint8_t *buf, size_t len, uint8_t urgent);
> -static int null_tunnel_socket_recv(SlirpUsrNetworkInterface *usr_interface,
> UserSocket *opaque,
> - uint8_t *buf, size_t len);
> -static int tunnel_socket_recv(SlirpUsrNetworkInterface *usr_interface,
> UserSocket *opaque,
> - uint8_t *buf, size_t len);
> -static void null_tunnel_socket_shutdown_send(SlirpUsrNetworkInterface
> *usr_interface,
> - UserSocket *opaque);
> -static void tunnel_socket_shutdown_send(SlirpUsrNetworkInterface
> *usr_interface,
> - UserSocket *opaque);
> -static void null_tunnel_socket_shutdown_recv(SlirpUsrNetworkInterface
> *usr_interface,
> - UserSocket *opaque);
> -static void tunnel_socket_shutdown_recv(SlirpUsrNetworkInterface
> *usr_interface,
> - UserSocket *opaque);
> -
> -static UserTimer *create_timer(SlirpUsrNetworkInterface *usr_interface,
> - timer_proc_t proc, void *opaque);
> -static void arm_timer(SlirpUsrNetworkInterface *usr_interface, UserTimer
> *timer, uint32_t ms);
> -
> -
> -/* RedChannel interface */
> -
> -static void handle_tunnel_channel_link(RedChannel *channel, RedClient
> *client,
> - RedsStream *stream, int migration,
> - int num_common_caps,
> - uint32_t *common_caps, int num_caps,
> - uint32_t *caps);
> -static void handle_tunnel_channel_client_migrate(RedChannelClient *rcc);
> -static void red_tunnel_channel_create(TunnelWorker *worker);
> -
> -static void tunnel_shutdown(TunnelWorker *worker)
> -{
> - int i;
> - spice_printerr("");
> - /* shutdown input from channel */
> - if (worker->channel_client) {
> - red_channel_client_shutdown(&worker->channel_client->base);
> - }
> -
> - /* shutdown socket pipe items */
> - for (i = 0; i < MAX_SOCKETS_NUM; i++) {
> - RedSocket *sckt = worker->sockets + i;
> - if (sckt->allocated) {
> - sckt->client_status = CLIENT_SCKT_STATUS_CLOSED;
> - sckt->client_waits_close_ack = FALSE;
> - }
> - }
> -
> - /* shutdown input from slirp */
> - net_slirp_set_net_interface(&worker->null_interface.base);
> -}
> -
> -/*****************************************************************
> -* Managing raw tunneled buffers storage
> -******************************************************************/
> -
> -/********** send buffers ***********/
> -static RawTunneledBuffer *tunnel_socket_alloc_snd_buf(RedSocket *sckt)
> -{
> - RedSocketRawSndBuf *ret =
> __tunnel_worker_alloc_socket_snd_buf(sckt->worker);
> - ret->base.usr_opaque = sckt;
> - ret->base.release_proc = snd_tunnled_buffer_release;
> - sckt->out_data.num_buffers++;
> - return &ret->base;
> -}
> -
> -static inline RedSocketRawSndBuf
> *__tunnel_worker_alloc_socket_snd_buf(TunnelWorker *worker)
> -{
> - RedSocketRawSndBuf *ret;
> - if (worker->free_snd_buf) {
> - ret = worker->free_snd_buf;
> - worker->free_snd_buf = (RedSocketRawSndBuf
> *)worker->free_snd_buf->base.next;
> - } else {
> - ret = spice_new(RedSocketRawSndBuf, 1);
> - }
> - ret->base.data = ret->buf;
> - ret->base.size = 0;
> - ret->base.max_size = MAX_SOCKET_DATA_SIZE;
> - ret->base.usr_opaque = NULL;
> - ret->base.refs = 1;
> - ret->base.next = NULL;
> -
> - return ret;
> -}
> -
> -static void tunnel_socket_free_snd_buf(RedSocket *sckt, RedSocketRawSndBuf
> *snd_buf)
> -{
> - sckt->out_data.num_buffers--;
> - __tunnel_worker_free_socket_snd_buf(sckt->worker, snd_buf);
> -}
> -
> -static inline void __tunnel_worker_free_socket_snd_buf(TunnelWorker *worker,
> - RedSocketRawSndBuf
> *snd_buf)
> -{
> - snd_buf->base.size = 0;
> - snd_buf->base.next = &worker->free_snd_buf->base;
> - worker->free_snd_buf = snd_buf;
> -}
> -
> -static RawTunneledBuffer
> *process_queue_alloc_snd_tunneled_buffer(TunneledBufferProcessQueue *queue)
> -{
> - return tunnel_socket_alloc_snd_buf((RedSocket *)queue->usr_opaque);
> -}
> -
> -static void snd_tunnled_buffer_release(RawTunneledBuffer *buf)
> -{
> - tunnel_socket_free_snd_buf((RedSocket *)buf->usr_opaque,
> (RedSocketRawSndBuf *)buf);
> -}
> -
> -/********** recv buffers ***********/
> -
> -static inline void tunnel_socket_assign_rcv_buf(RedSocket *sckt,
> - RedSocketRawRcvBuf
> *recv_buf, int buf_size)
> -{
> - spice_assert(!recv_buf->base.usr_opaque);
> - // the rcv buffer was allocated by tunnel_channel_alloc_msg_rcv_buf
> - // before we could know which of the sockets it belongs to, so the
> - // assignment to the socket is performed now
> - recv_buf->base.size = buf_size;
> - recv_buf->base.usr_opaque = sckt;
> - recv_buf->base.release_proc = rcv_tunnled_buffer_release;
> - sckt->in_data.num_buffers++;
> - process_queue_push(sckt->in_data.process_queue, &recv_buf->base);
> -}
> -
> -static inline RedSocketRawRcvBuf
> *__tunnel_worker_alloc_socket_rcv_buf(TunnelWorker *worker)
> -{
> - RedSocketRawRcvBuf *ret;
> - if (worker->free_rcv_buf) {
> - ret = worker->free_rcv_buf;
> - worker->free_rcv_buf = (RedSocketRawRcvBuf
> *)worker->free_rcv_buf->base.next;
> - } else {
> - ret = spice_new(RedSocketRawRcvBuf, 1);
> - }
> - ret->msg_info = (SpiceMsgcTunnelSocketData *)ret->buf;
> - ret->base.usr_opaque = NULL;
> - ret->base.data = ret->msg_info->data;
> - ret->base.size = 0;
> - ret->base.max_size = MAX_SOCKET_DATA_SIZE;
> - ret->base.refs = 1;
> - ret->base.next = NULL;
> -
> - return ret;
> -}
> -
> -static inline void __process_rcv_buf_tokens(TunnelChannelClient *channel,
> RedSocket *sckt)
> -{
> - if ((sckt->client_status != CLIENT_SCKT_STATUS_OPEN) ||
> red_channel_client_pipe_item_is_linked(
> - &channel->base, &sckt->out_data.token_pipe_item) ||
> channel->mig_inprogress) {
> - return;
> - }
> -
> - if ((sckt->in_data.num_tokens >= SOCKET_TOKENS_TO_SEND) ||
> - (!sckt->in_data.client_total_num_tokens &&
> !sckt->in_data.ready_chunks_queue.head)) {
> - sckt->out_data.token_pipe_item.type = PIPE_ITEM_TYPE_SOCKET_TOKEN;
> - red_channel_client_pipe_add(&channel->base,
> &sckt->out_data.token_pipe_item);
> - }
> -}
> -
> -static void tunnel_socket_free_rcv_buf(RedSocket *sckt, RedSocketRawRcvBuf
> *rcv_buf)
> -{
> - --sckt->in_data.num_buffers;
> - __tunnel_worker_free_socket_rcv_buf(sckt->worker, rcv_buf);
> - ++sckt->in_data.num_tokens;
> - __process_rcv_buf_tokens(sckt->worker->channel_client, sckt);
> -}
> -
> -static inline void __tunnel_worker_free_socket_rcv_buf(TunnelWorker *worker,
> - RedSocketRawRcvBuf
> *rcv_buf)
> -{
> - rcv_buf->base.next = &worker->free_rcv_buf->base;
> - worker->free_rcv_buf = rcv_buf;
> -}
> -
> -static void rcv_tunnled_buffer_release(RawTunneledBuffer *buf)
> -{
> - tunnel_socket_free_rcv_buf((RedSocket *)buf->usr_opaque,
> - (RedSocketRawRcvBuf *)buf);
> -}
> -
> -/************************
> -* Process & Ready queue
> -*************************/
> -
> -static inline void __process_queue_push(TunneledBufferProcessQueue *queue,
> RawTunneledBuffer *buf)
> -{
> - buf->next = NULL;
> - if (!queue->head) {
> - queue->head = buf;
> - queue->tail = buf;
> - } else {
> - queue->tail->next = buf;
> - queue->tail = buf;
> - }
> -}
> -
> -static void process_queue_push(TunneledBufferProcessQueue *queue,
> RawTunneledBuffer *buf)
> -{
> - __process_queue_push(queue, buf);
> - queue->analysis_proc(queue, buf, 0, buf->size);
> -}
> -
> -static void process_queue_append(TunneledBufferProcessQueue *queue, uint8_t
> *data, size_t size)
> -{
> - RawTunneledBuffer *start_buf = NULL;
> - int start_offset = 0;
> - int copied = 0;
> -
> - if (queue->tail) {
> - RawTunneledBuffer *buf = queue->tail;
> - int space = buf->max_size - buf->size;
> - if (space) {
> - int copy_count = MIN(size, space);
> - start_buf = buf;
> - start_offset = buf->size;
> - memcpy(buf->data + buf->size, data, copy_count);
> - copied += copy_count;
> - buf->size += copy_count;
> - }
> - }
> -
> -
> - while (copied < size) {
> - RawTunneledBuffer *buf = queue->alloc_buf_proc(queue);
> - int copy_count = MIN(size - copied, buf->max_size);
> - memcpy(buf->data, data + copied, copy_count);
> - copied += copy_count;
> - buf->size = copy_count;
> -
> - __process_queue_push(queue, buf);
> -
> - if (!start_buf) {
> - start_buf = buf;
> - start_offset = 0;
> - }
> - }
> -
> - queue->analysis_proc(queue, start_buf, start_offset, size);
> -}
> -
> -static void process_queue_pop(TunneledBufferProcessQueue *queue)
> -{
> - RawTunneledBuffer *prev_head;
> - spice_assert(queue->head && queue->tail);
> - prev_head = queue->head;
> - queue->head = queue->head->next;
> - if (!queue->head) {
> - queue->tail = NULL;
> - }
> -
> - tunneled_buffer_unref(prev_head);
> -}
> -
> -static void process_queue_clear(TunneledBufferProcessQueue *queue)
> -{
> - while (queue->head) {
> - process_queue_pop(queue);
> - }
> -}
> -
> -static void __ready_queue_push(ReadyTunneledChunkQueue *queue,
> ReadyTunneledChunk *chunk)
> -{
> - chunk->next = NULL;
> - if (queue->tail) {
> - queue->tail->next = chunk;
> - queue->tail = chunk;
> - } else {
> - queue->head = chunk;
> - queue->tail = chunk;
> - }
> -}
> -
> -static void ready_queue_add_orig_chunk(ReadyTunneledChunkQueue *queue,
> RawTunneledBuffer *origin,
> - uint8_t *data, int size)
> -{
> - ReadyTunneledChunk *chunk = spice_new(ReadyTunneledChunk, 1);
> - chunk->type = READY_TUNNELED_CHUNK_TYPE_ORIG;
> - chunk->origin = tunneled_buffer_ref(origin);
> - chunk->data = data;
> - chunk->size = size;
> -
> - __ready_queue_push(queue, chunk);
> -}
> -
> -static void ready_queue_pop_chunk(ReadyTunneledChunkQueue *queue)
> -{
> - ReadyTunneledChunk *chunk = queue->head;
> - spice_assert(queue->head);
> - queue->head = queue->head->next;
> -
> - if (!queue->head) {
> - queue->tail = NULL;
> - }
> -
> - tunneled_buffer_unref(chunk->origin);
> - if (chunk->type != READY_TUNNELED_CHUNK_TYPE_ORIG) {
> - free(chunk->data);
> - }
> - free(chunk);
> -}
> -
> -static void ready_queue_clear(ReadyTunneledChunkQueue *queue)
> -{
> - while (queue->head) {
> - ready_queue_pop_chunk(queue);
> - }
> -}
> -
> -static void process_queue_simple_analysis(TunneledBufferProcessQueue *queue,
> - RawTunneledBuffer
> *start_last_added, int offset, int len)
> -{
> - spice_assert(offset == 0);
> - spice_assert(start_last_added == queue->head);
> -
> - while (queue->head) {
> - ready_queue_add_orig_chunk(queue->ready_chunks_queue, queue->head,
> queue->head->data,
> - queue->head->size);
> - process_queue_pop(queue);
> - }
> -}
> -
> -static int process_queue_simple_get_migrate_data(TunneledBufferProcessQueue
> *queue,
> - void **migrate_data)
> -{
> - *migrate_data = NULL;
> - return 0;
> -}
> -
> -static void
> process_queue_simple_release_migrate_data(TunneledBufferProcessQueue *queue,
> - void *migrate_data)
> -{
> - spice_assert(!migrate_data);
> -}
> -
> -static void process_queue_simple_restore(TunneledBufferProcessQueue *queue,
> uint8_t *migrate_data)
> -{
> -}
> -
> -static inline TunneledBufferProcessQueue
> *__tunnel_socket_alloc_simple_process_queue(
> -
> RedSocket
> *sckt,
> -
> uint32_t
> service_type,
> -
> uint32_t
> direction_type)
> -{
> - TunneledBufferProcessQueue *ret_queue =
> spice_new0(TunneledBufferProcessQueue, 1);
> - ret_queue->service_type = service_type;
> - ret_queue->direction = direction_type;
> - ret_queue->usr_opaque = sckt;
> - // NO need for allocations by the process queue when getting replies.
> The buffer is created
> - // when the msg is received
> - if (direction_type == PROCESS_DIRECTION_TYPE_REQUEST) {
> - ret_queue->alloc_buf_proc = process_queue_alloc_snd_tunneled_buffer;
> - ret_queue->ready_chunks_queue = &sckt->out_data.ready_chunks_queue;
> - } else {
> - ret_queue->ready_chunks_queue = &sckt->in_data.ready_chunks_queue;
> - }
> -
> - ret_queue->analysis_proc = process_queue_simple_analysis;
> -
> - ret_queue->get_migrate_data_proc =
> process_queue_simple_get_migrate_data;
> - ret_queue->release_migrate_data_proc =
> process_queue_simple_release_migrate_data;
> - ret_queue->restore_proc = process_queue_simple_restore;
> - return ret_queue;
> -}
> -
> -static void free_simple_process_queue(TunneledBufferProcessQueue *queue)
> -{
> - process_queue_clear(queue);
> - free(queue);
> -}
> -
> -static TunneledBufferProcessQueue
> *tunnel_socket_alloc_simple_print_request_process_queue(
> -
> RedSocket
> *sckt)
> -{
> - return __tunnel_socket_alloc_simple_process_queue(sckt,
> -
> SPICE_TUNNEL_SERVICE_TYPE_IPP,
> -
> PROCESS_DIRECTION_TYPE_REQUEST);
> -}
> -
> -static TunneledBufferProcessQueue
> *tunnel_socket_alloc_simple_print_reply_process_queue(
> -
> RedSocket
> *sckt)
> -{
> - return __tunnel_socket_alloc_simple_process_queue(sckt,
> -
> SPICE_TUNNEL_SERVICE_TYPE_IPP,
> -
> PROCESS_DIRECTION_TYPE_REPLY);
> -}
> -
> -SPICE_GNUC_VISIBLE void
> spice_server_net_wire_recv_packet(SpiceNetWireInstance *sin,
> - const uint8_t
> *pkt, int pkt_len)
> -{
> - TunnelWorker *worker = sin->st->worker;
> - spice_assert(worker);
> -
> - if (worker->channel_client && worker->channel_client->mig_inprogress) {
> - return; // during migration and the tunnel state hasn't been
> restored yet.
> - }
> -
> - net_slirp_input(pkt, pkt_len);
> -}
> -
> -void *red_tunnel_attach(SpiceCoreInterface *core_interface,
> - SpiceNetWireInstance *sin)
> -{
> - TunnelWorker *worker = spice_new0(TunnelWorker, 1);
> -
> - worker->core_interface = core_interface;
> - worker->sin = sin;
> - worker->sin->st->worker = worker;
> - worker->sif = SPICE_CONTAINEROF(sin->base.sif, SpiceNetWireInterface,
> base);
> -
> - worker->tunnel_interface.base.slirp_can_output = qemu_can_output;
> - worker->tunnel_interface.base.slirp_output = qemu_output;
> - worker->tunnel_interface.base.connect = tunnel_socket_connect;
> - worker->tunnel_interface.base.send = tunnel_socket_send;
> - worker->tunnel_interface.base.recv = tunnel_socket_recv;
> - worker->tunnel_interface.base.close = tunnel_socket_close;
> - worker->tunnel_interface.base.shutdown_recv =
> tunnel_socket_shutdown_recv;
> - worker->tunnel_interface.base.shutdown_send =
> tunnel_socket_shutdown_send;
> - worker->tunnel_interface.base.create_timer = create_timer;
> - worker->tunnel_interface.base.arm_timer = arm_timer;
> -
> - worker->tunnel_interface.worker = worker;
> -
> - worker->null_interface.base.slirp_can_output = qemu_can_output;
> - worker->null_interface.base.slirp_output = qemu_output;
> - worker->null_interface.base.connect = null_tunnel_socket_connect;
> - worker->null_interface.base.send = null_tunnel_socket_send;
> - worker->null_interface.base.recv = null_tunnel_socket_recv;
> - worker->null_interface.base.close = null_tunnel_socket_close;
> - worker->null_interface.base.shutdown_recv =
> null_tunnel_socket_shutdown_recv;
> - worker->null_interface.base.shutdown_send =
> null_tunnel_socket_shutdown_send;
> - worker->null_interface.base.create_timer = create_timer;
> - worker->null_interface.base.arm_timer = arm_timer;
> -
> - worker->null_interface.worker = worker;
> -
> - red_tunnel_channel_create(worker);
> -
> - ring_init(&worker->services);
> -
> - net_slirp_init(worker->sif->get_ip(worker->sin),
> - TRUE,
> - &worker->null_interface.base);
> - return worker;
> -}
> -
> -/* returns the first service that has the same group id (NULL if not found)
> */
> -static inline TunnelService
> *__tunnel_worker_find_service_of_group(TunnelWorker *worker,
> - uint32_t
> group)
> -{
> - TunnelService *service;
> - for (service = (TunnelService *)ring_get_head(&worker->services);
> - service;
> - service = (TunnelService *)ring_next(&worker->services,
> &service->ring_item)) {
> - if (service->group == group) {
> - return service;
> - }
> - }
> -
> - return NULL;
> -}
> -
> -static inline TunnelService *__tunnel_worker_add_service(TunnelWorker
> *worker, uint32_t size,
> - uint32_t type,
> uint32_t id,
> - uint32_t group,
> uint32_t port,
> - char *name, char
> *description,
> - struct in_addr
> *virt_ip)
> -{
> - TunnelService *new_service = spice_malloc0(size);
> -
> - if (!virt_ip) {
> - TunnelService *service_of_same_group;
> - if (!(service_of_same_group =
> __tunnel_worker_find_service_of_group(worker, group))) {
> - if (!net_slirp_allocate_virtual_ip(&new_service->virt_ip)) {
> - spice_printerr("failed to allocate virtual ip");
> - free(new_service);
> - return NULL;
> - }
> - } else {
> - if (strcmp(name, service_of_same_group->name) == 0) {
> - new_service->virt_ip.s_addr =
> service_of_same_group->virt_ip.s_addr;
> - } else {
> - spice_printerr("inconsistent name for service group %d",
> group);
> - free(new_service);
> - return NULL;
> - }
> - }
> - } else {
> - new_service->virt_ip.s_addr = virt_ip->s_addr;
> - }
> -
> - ring_item_init(&new_service->ring_item);
> - new_service->type = type;
> - new_service->id = id;
> - new_service->group = group;
> - new_service->port = port;
> -
> - new_service->name = spice_strdup(name);
> - new_service->description = spice_strdup(description);
> -
> - ring_add(&worker->services, &new_service->ring_item);
> - worker->num_services++;
> -
> -#ifdef DEBUG_NETWORK
> - spice_printerr("TUNNEL_DBG: ==>SERVICE ADDED: id=%d virt ip=%s port=%d
> name=%s desc=%s",
> - new_service->id, inet_ntoa(new_service->virt_ip),
> - new_service->port, new_service->name,
> new_service->description);
> -#endif
> - if (!virt_ip) {
> - new_service->pipe_item.type = PIPE_ITEM_TYPE_SERVICE_IP_MAP;
> - red_channel_client_pipe_add(&worker->channel_client->base,
> &new_service->pipe_item);
> - }
> -
> - return new_service;
> -}
> -
> -static TunnelService *tunnel_worker_add_service(TunnelWorker *worker,
> uint32_t size,
> -
> SpiceMsgcTunnelAddGenericService
> *redc_service)
> -{
> - return __tunnel_worker_add_service(worker, size, redc_service->type,
> - redc_service->id,
> redc_service->group,
> - redc_service->port,
> - (char *)(((uint8_t *)redc_service) +
> - redc_service->name),
> - (char *)(((uint8_t *)redc_service) +
> - redc_service->description),
> NULL);
> -}
> -
> -static inline void tunnel_worker_free_service(TunnelWorker *worker,
> TunnelService *service)
> -{
> - ring_remove(&service->ring_item);
> - free(service->name);
> - free(service->description);
> - free(service);
> - worker->num_services--;
> -}
> -
> -static void tunnel_worker_free_print_service(TunnelWorker *worker,
> TunnelPrintService *service)
> -{
> - tunnel_worker_free_service(worker, &service->base);
> -}
> -
> -static TunnelPrintService *tunnel_worker_add_print_service(TunnelWorker
> *worker,
> -
> SpiceMsgcTunnelAddGenericService
> *redc_service)
> -{
> - TunnelPrintService *service;
> -
> - service = (TunnelPrintService *)tunnel_worker_add_service(worker,
> sizeof(TunnelPrintService),
> - redc_service);
> -
> - if (!service) {
> - return NULL;
> - }
> -
> - if (redc_service->type == SPICE_TUNNEL_IP_TYPE_IPv4) {
> - memcpy(service->ip, redc_service->u.ip.data,
> sizeof(SpiceTunnelIPv4));
> - } else {
> - spice_printerr("unexpected ip type=%d", redc_service->type);
> - tunnel_worker_free_print_service(worker, service);
> - return NULL;
> - }
> -#ifdef DEBUG_NETWORK
> - spice_printerr("TUNNEL_DBG: ==>PRINT SERVICE ADDED: ip=%d.%d.%d.%d",
> service->ip[0],
> - service->ip[1], service->ip[2], service->ip[3]);
> -#endif
> - return service;
> -}
> -
> -static int tunnel_channel_handle_service_add(TunnelChannelClient *channel,
> -
> SpiceMsgcTunnelAddGenericService
> *service_msg)
> -{
> - TunnelService *out_service = NULL;
> - if (service_msg->type == SPICE_TUNNEL_SERVICE_TYPE_IPP) {
> - out_service = &tunnel_worker_add_print_service(channel->worker,
> - service_msg)->base;
> - } else if (service_msg->type == SPICE_TUNNEL_SERVICE_TYPE_GENERIC) {
> - out_service = tunnel_worker_add_service(channel->worker,
> sizeof(TunnelService),
> - service_msg);
> - } else {
> - spice_printerr("invalid service type");
> - }
> -
> - free(service_msg);
> - return (out_service != NULL);
> -}
> -
> -static inline TunnelService *tunnel_worker_find_service_by_id(TunnelWorker
> *worker, uint32_t id)
> -{
> - TunnelService *service;
> - for (service = (TunnelService *)ring_get_head(&worker->services);
> - service;
> - service = (TunnelService *)ring_next(&worker->services,
> &service->ring_item)) {
> - if (service->id == id) {
> - return service;
> - }
> - }
> -
> - return NULL;
> -}
> -
> -static inline TunnelService *tunnel_worker_find_service_by_addr(TunnelWorker
> *worker,
> - struct
> in_addr *virt_ip,
> - uint32_t
> port)
> -{
> - TunnelService *service;
> - for (service = (TunnelService *)ring_get_head(&worker->services);
> - service;
> - service = (TunnelService *)ring_next(&worker->services,
> &service->ring_item)) {
> - if ((virt_ip->s_addr == service->virt_ip.s_addr) && (port ==
> service->port)) {
> - return service;
> - }
> - }
> -
> - return NULL;
> -}
> -
> -static inline void tunnel_worker_clear_routed_network(TunnelWorker *worker)
> -{
> - while (!ring_is_empty(&worker->services)) {
> - TunnelService *service = (TunnelService
> *)ring_get_head(&worker->services);
> - if (service->type == SPICE_TUNNEL_SERVICE_TYPE_GENERIC) {
> - tunnel_worker_free_service(worker, service);
> - } else if (service->type == SPICE_TUNNEL_SERVICE_TYPE_IPP) {
> - tunnel_worker_free_print_service(worker, (TunnelPrintService
> *)service);
> - } else {
> - spice_error("unexpected service type");
> - }
> - }
> -
> - net_slirp_clear_virtual_ips();
> -}
> -
> -static inline RedSocket *__tunnel_worker_find_free_socket(TunnelWorker
> *worker)
> -{
> - int i;
> - RedSocket *ret = NULL;
> -
> - if (worker->num_sockets == MAX_SOCKETS_NUM) {
> - return NULL;
> - }
> -
> - for (i = 0; i < MAX_SOCKETS_NUM; i++) {
> - if (!worker->sockets[i].allocated) {
> - ret = worker->sockets + i;
> - ret->connection_id = i;
> - break;
> - }
> - }
> -
> - spice_assert(ret);
> - return ret;
> -}
> -
> -static inline void __tunnel_worker_add_socket(TunnelWorker *worker,
> RedSocket *sckt)
> -{
> - spice_assert(!sckt->allocated);
> - sckt->allocated = TRUE;
> - worker->num_sockets++;
> -}
> -
> -static inline void tunnel_worker_alloc_socket(TunnelWorker *worker,
> RedSocket *sckt,
> - uint16_t local_port,
> TunnelService *far_service,
> - SlirpSocket *slirp_s)
> -{
> - spice_assert(far_service);
> - sckt->worker = worker;
> - sckt->local_port = local_port;
> - sckt->far_service = far_service;
> - sckt->out_data.num_tokens = 0;
> -
> - sckt->slirp_status = SLIRP_SCKT_STATUS_OPEN;
> - sckt->client_status = CLIENT_SCKT_STATUS_WAIT_OPEN;
> - sckt->slirp_sckt = slirp_s;
> -
> - sckt->out_data.process_queue = SERVICES_CALLBACKS[far_service->type][
> - PROCESS_DIRECTION_TYPE_REQUEST].alloc_process_queue(sckt);
> - sckt->in_data.process_queue = SERVICES_CALLBACKS[far_service->type][
> - PROCESS_DIRECTION_TYPE_REPLY].alloc_process_queue(sckt);
> - __tunnel_worker_add_socket(worker, sckt);
> -}
> -
> -static inline void __tunnel_worker_free_socket(TunnelWorker *worker,
> RedSocket *sckt)
> -{
> - memset(sckt, 0, sizeof(*sckt));
> - worker->num_sockets--;
> -}
> -
> -static RedSocket *tunnel_worker_create_socket(TunnelWorker *worker, uint16_t
> local_port,
> - TunnelService *far_service,
> - SlirpSocket *slirp_s)
> -{
> - RedSocket *new_socket;
> - spice_assert(worker);
> - new_socket = __tunnel_worker_find_free_socket(worker);
> -
> - if (!new_socket) {
> - spice_error("creation of RedSocket failed");
> - }
> -
> - tunnel_worker_alloc_socket(worker, new_socket, local_port, far_service,
> slirp_s);
> -
> - return new_socket;
> -}
> -
> -static void tunnel_worker_free_socket(TunnelWorker *worker, RedSocket *sckt)
> -{
> - if (worker->channel_client) {
> - if
> (red_channel_client_pipe_item_is_linked(&worker->channel_client->base,
> - &sckt->out_data.data_pipe_item))
> {
> -
> red_channel_client_pipe_remove_and_release(&worker->channel_client->base,
> - &sckt->out_data.data_pipe_item);
> - return;
> - }
> -
> - if
> (red_channel_client_pipe_item_is_linked(&worker->channel_client->base,
> -
> &sckt->out_data.status_pipe_item))
> {
> -
> red_channel_client_pipe_remove_and_release(&worker->channel_client->base,
> - &sckt->out_data.status_pipe_item);
> - return;
> - }
> -
> - if
> (red_channel_client_pipe_item_is_linked(&worker->channel_client->base,
> -
> &sckt->out_data.token_pipe_item))
> {
> -
> red_channel_client_pipe_remove_and_release(&worker->channel_client->base,
> - &sckt->out_data.token_pipe_item);
> - return;
> - }
> - }
> -
> - SERVICES_CALLBACKS[sckt->far_service->type][
> -
> PROCESS_DIRECTION_TYPE_REQUEST].free_process_queue(sckt->out_data.process_queue);
> - SERVICES_CALLBACKS[sckt->far_service->type][
> -
> PROCESS_DIRECTION_TYPE_REPLY].free_process_queue(sckt->in_data.process_queue);
> -
> - ready_queue_clear(&sckt->out_data.ready_chunks_queue);
> - ready_queue_clear(&sckt->in_data.ready_chunks_queue);
> -
> - __tunnel_worker_free_socket(worker, sckt);
> -}
> -
> -static inline RedSocket *tunnel_worker_find_socket(TunnelWorker *worker,
> - uint16_t local_port,
> - uint32_t far_service_id)
> -{
> - RedSocket *sckt;
> - int allocated = 0;
> -
> - for (sckt = worker->sockets; allocated < worker->num_sockets; sckt++) {
> - if (sckt->allocated) {
> - allocated++;
> - if ((sckt->local_port == local_port) &&
> - (sckt->far_service->id == far_service_id)) {
> - return sckt;
> - }
> - }
> - }
> - return NULL;
> -}
> -
> -static inline void __tunnel_socket_add_fin_to_pipe(TunnelChannelClient
> *channel, RedSocket *sckt)
> -{
> - spice_assert(!red_channel_client_pipe_item_is_linked(&channel->base,
> &sckt->out_data.status_pipe_item));
> - sckt->out_data.status_pipe_item.type = PIPE_ITEM_TYPE_SOCKET_FIN;
> - red_channel_client_pipe_add(&channel->base,
> &sckt->out_data.status_pipe_item);
> -}
> -
> -static inline void __tunnel_socket_add_close_to_pipe(TunnelChannelClient
> *channel, RedSocket *sckt)
> -{
> - spice_assert(!channel->mig_inprogress);
> -
> - if (red_channel_client_pipe_item_is_linked(&channel->base,
> &sckt->out_data.status_pipe_item)) {
> - spice_assert(sckt->out_data.status_pipe_item.type ==
> PIPE_ITEM_TYPE_SOCKET_FIN);
> - // close is stronger than FIN
> - red_channel_client_pipe_remove_and_release(&channel->base,
> - &sckt->out_data.status_pipe_item);
> - }
> - sckt->pushed_close = TRUE;
> - sckt->out_data.status_pipe_item.type = PIPE_ITEM_TYPE_SOCKET_CLOSE;
> - red_channel_client_pipe_add(&channel->base,
> &sckt->out_data.status_pipe_item);
> -}
> -
> -static inline void __tunnel_socket_add_close_ack_to_pipe(TunnelChannelClient
> *channel, RedSocket *sckt)
> -{
> - spice_assert(!channel->mig_inprogress);
> -
> - if (red_channel_client_pipe_item_is_linked(&channel->base,
> &sckt->out_data.status_pipe_item)) {
> - spice_assert(sckt->out_data.status_pipe_item.type ==
> PIPE_ITEM_TYPE_SOCKET_FIN);
> - // close is stronger than FIN
> - red_channel_client_pipe_remove_and_release(&channel->base,
> - &sckt->out_data.status_pipe_item);
> - }
> -
> - sckt->out_data.status_pipe_item.type = PIPE_ITEM_TYPE_SOCKET_CLOSED_ACK;
> - red_channel_client_pipe_add(&channel->base,
> &sckt->out_data.status_pipe_item);
> -}
> -
> -/*
> - Send close msg to the client.
> - If possible, notify slirp to recv data (which will return 0)
> - When close ack is received from client, we notify slirp (maybe again) if
> needed.
> -*/
> -static void tunnel_socket_force_close(TunnelChannelClient *channel,
> RedSocket *sckt)
> -{
> - if (red_channel_client_pipe_item_is_linked(&channel->base,
> &sckt->out_data.token_pipe_item)) {
> - red_channel_client_pipe_remove_and_release(&channel->base,
> &sckt->out_data.token_pipe_item);
> - }
> -
> - if (red_channel_client_pipe_item_is_linked(&channel->base,
> &sckt->out_data.data_pipe_item)) {
> - red_channel_client_pipe_remove_and_release(&channel->base,
> &sckt->out_data.data_pipe_item);
> - }
> -
> -
> - if ((sckt->client_status != CLIENT_SCKT_STATUS_CLOSED) ||
> - !sckt->pushed_close) {
> - __tunnel_socket_add_close_to_pipe(channel, sckt);
> - }
> -
> - // we can't call net_slirp_socket_can_receive_notify if the forced close
> was initiated by
> - // tunnel_socket_send (which was called from slirp). Instead, when
> - // we receive the close ack from the client, we call
> net_slirp_socket_can_receive_notify
> - if (sckt->slirp_status != SLIRP_SCKT_STATUS_CLOSED) {
> - if (!sckt->in_slirp_send) {
> - sckt->slirp_status = SLIRP_SCKT_STATUS_WAIT_CLOSE;
> - net_slirp_socket_abort(sckt->slirp_sckt);
> - } else {
> - sckt->slirp_status = SLIRP_SCKT_STATUS_DELAY_ABORT;
> - }
> - }
> -}
> -
> -static int tunnel_channel_handle_socket_connect_ack(TunnelChannelClient
> *channel, RedSocket *sckt,
> - uint32_t tokens)
> -{
> -#ifdef DEBUG_NETWORK
> - spice_printerr("TUNNEL_DBG");
> -#endif
> - if (channel->mig_inprogress) {
> - sckt->mig_client_status_msg = SPICE_MSGC_TUNNEL_SOCKET_OPEN_ACK;
> - sckt->mig_open_ack_tokens = tokens;
> - return TRUE;
> - }
> -
> - if (sckt->client_status != CLIENT_SCKT_STATUS_WAIT_OPEN) {
> - spice_printerr("unexpected SPICE_MSGC_TUNNEL_SOCKET_OPEN_ACK
> status=%d", sckt->client_status);
> - return FALSE;
> - }
> - sckt->client_status = CLIENT_SCKT_STATUS_OPEN;
> -
> - // SLIRP_SCKT_STATUS_CLOSED is possible after waiting for a connection
> has timed out
> - if (sckt->slirp_status == SLIRP_SCKT_STATUS_CLOSED) {
> - spice_assert(!sckt->pushed_close);
> - __tunnel_socket_add_close_to_pipe(channel, sckt);
> - } else if (sckt->slirp_status == SLIRP_SCKT_STATUS_OPEN) {
> - sckt->out_data.window_size = tokens;
> - sckt->out_data.num_tokens = tokens;
> - net_slirp_socket_connected_notify(sckt->slirp_sckt);
> - } else {
> - spice_printerr("unexpected slirp status status=%d",
> sckt->slirp_status);
> - return FALSE;
> - }
> -
> - return (!CHECK_TUNNEL_ERROR(channel));
> -}
> -
> -static int tunnel_channel_handle_socket_connect_nack(TunnelChannelClient
> *channel, RedSocket *sckt)
> -{
> -#ifdef DEBUG_NETWORK
> - PRINT_SCKT(sckt);
> -#endif
> - if (channel->mig_inprogress) {
> - sckt->mig_client_status_msg = SPICE_MSGC_TUNNEL_SOCKET_OPEN_NACK;
> - return TRUE;
> - }
> -
> - if (sckt->client_status != CLIENT_SCKT_STATUS_WAIT_OPEN) {
> - spice_printerr("unexpected SPICE_MSGC_TUNNEL_SOCKET_OPEN_NACK
> status=%d", sckt->client_status);
> - return FALSE;
> - }
> - sckt->client_status = CLIENT_SCKT_STATUS_CLOSED;
> -
> - if (sckt->slirp_status != SLIRP_SCKT_STATUS_CLOSED) {
> - net_slirp_socket_connect_failed_notify(sckt->slirp_sckt);
> - } else {
> - tunnel_worker_free_socket(channel->worker, sckt);
> - }
> -
> - return (!CHECK_TUNNEL_ERROR(channel));
> -}
> -
> -static int tunnel_channel_handle_socket_fin(TunnelChannelClient *channel,
> RedSocket *sckt)
> -{
> -#ifdef DEBUG_NETWORK
> - PRINT_SCKT(sckt);
> -#endif
> - if (channel->mig_inprogress) {
> - sckt->mig_client_status_msg = SPICE_MSGC_TUNNEL_SOCKET_FIN;
> - return TRUE;
> - }
> -
> - if (sckt->client_status != CLIENT_SCKT_STATUS_OPEN) {
> - spice_printerr("unexpected SPICE_MSGC_TUNNEL_SOCKET_FIN status=%d",
> sckt->client_status);
> - return FALSE;
> - }
> - sckt->client_status = CLIENT_SCKT_STATUS_SHUTDOWN_SEND;
> -
> - if ((sckt->slirp_status == SLIRP_SCKT_STATUS_CLOSED) ||
> - (sckt->slirp_status == SLIRP_SCKT_STATUS_DELAY_ABORT)) {
> - return TRUE;
> - }
> -
> - if ((sckt->slirp_status == SLIRP_SCKT_STATUS_OPEN) ||
> - (sckt->slirp_status == SLIRP_SCKT_STATUS_SHUTDOWN_SEND)) {
> - // After slirp will receive all the data buffers, the next recv
> - // will return an error and shutdown_recv should be called.
> - net_slirp_socket_can_receive_notify(sckt->slirp_sckt);
> - } else if (sckt->slirp_status == SLIRP_SCKT_STATUS_SHUTDOWN_RECV) {
> - // it already received the FIN
> - spice_printerr("unexpected slirp status=%d", sckt->slirp_status);
> - return FALSE;
> - }
> -
> - return (!CHECK_TUNNEL_ERROR(channel));
> -}
> -
> -static int tunnel_channel_handle_socket_closed(TunnelChannelClient *channel,
> RedSocket *sckt)
> -{
> - int prev_client_status = sckt->client_status;
> -
> -#ifdef DEBUG_NETWORK
> - PRINT_SCKT(sckt);
> -#endif
> -
> - if (channel->mig_inprogress) {
> - sckt->mig_client_status_msg = SPICE_MSGC_TUNNEL_SOCKET_CLOSED;
> - return TRUE;
> - }
> -
> - sckt->client_status = CLIENT_SCKT_STATUS_CLOSED;
> -
> - if (sckt->slirp_status == SLIRP_SCKT_STATUS_CLOSED) {
> - // if we already pushed close to the client, we expect it to send us
> ack.
> - // Otherwise, we will send it an ack.
> - if (!sckt->pushed_close) {
> - sckt->client_waits_close_ack = TRUE;
> - __tunnel_socket_add_close_ack_to_pipe(channel, sckt);
> - }
> -
> - return (!CHECK_TUNNEL_ERROR(channel));
> - }
> -
> - // close was initiated by client
> - sckt->client_waits_close_ack = TRUE;
> -
> - if (sckt->slirp_status == SLIRP_SCKT_STATUS_SHUTDOWN_SEND) {
> - // guest waits for fin: after slirp will receive all the data
> buffers,
> - // the next recv will return an error and shutdown_recv should be
> called.
> - net_slirp_socket_can_receive_notify(sckt->slirp_sckt);
> - } else if ((sckt->slirp_status == SLIRP_SCKT_STATUS_OPEN) ||
> - (sckt->slirp_status == SLIRP_SCKT_STATUS_SHUTDOWN_RECV)) {
> - sckt->slirp_status = SLIRP_SCKT_STATUS_WAIT_CLOSE;
> - net_slirp_socket_abort(sckt->slirp_sckt);
> - } else if ((sckt->slirp_status != SLIRP_SCKT_STATUS_WAIT_CLOSE) ||
> - (prev_client_status != CLIENT_SCKT_STATUS_SHUTDOWN_SEND)) {
> - // slirp can be in wait close if both slirp and client sent fin
> previously
> - // otherwise, the prev client status would also have been wait
> close, and this
> - // case was handled above
> - spice_printerr("unexpected slirp_status=%d", sckt->slirp_status);
> - return FALSE;
> - }
> -
> - return (!CHECK_TUNNEL_ERROR(channel));
> -}
> -
> -static int tunnel_channel_handle_socket_closed_ack(TunnelChannelClient
> *channel, RedSocket *sckt)
> -{
> -#ifdef DEBUG_NETWORK
> - PRINT_SCKT(sckt);
> -#endif
> - if (channel->mig_inprogress) {
> - sckt->mig_client_status_msg = SPICE_MSGC_TUNNEL_SOCKET_CLOSED_ACK;
> - return TRUE;
> - }
> -
> - sckt->client_status = CLIENT_SCKT_STATUS_CLOSED;
> - if (sckt->slirp_status == SLIRP_SCKT_STATUS_DELAY_ABORT) {
> - sckt->slirp_status = SLIRP_SCKT_STATUS_WAIT_CLOSE;
> - net_slirp_socket_abort(sckt->slirp_sckt);
> - return (!CHECK_TUNNEL_ERROR(channel));
> - }
> -
> - if (sckt->slirp_status != SLIRP_SCKT_STATUS_CLOSED) {
> - spice_printerr("unexpected SPICE_MSGC_TUNNEL_SOCKET_CLOSED_ACK
> slirp_status=%d",
> - sckt->slirp_status);
> - return FALSE;
> - }
> -
> - tunnel_worker_free_socket(channel->worker, sckt);
> - return (!CHECK_TUNNEL_ERROR(channel));
> -}
> -
> -static int tunnel_channel_handle_socket_receive_data(TunnelChannelClient
> *channel, RedSocket *sckt,
> - RedSocketRawRcvBuf
> *recv_data, int buf_size)
> -{
> - if ((sckt->client_status == CLIENT_SCKT_STATUS_SHUTDOWN_SEND) ||
> - (sckt->client_status == CLIENT_SCKT_STATUS_CLOSED)) {
> - spice_printerr("unexpected SPICE_MSGC_TUNNEL_SOCKET_DATA
> client_status=%d",
> - sckt->client_status);
> - return FALSE;
> - }
> -
> - // handling a case where the client sent data before it received the
> close msg
> - if ((sckt->slirp_status != SLIRP_SCKT_STATUS_OPEN) &&
> - (sckt->slirp_status != SLIRP_SCKT_STATUS_SHUTDOWN_SEND)) {
> - __tunnel_worker_free_socket_rcv_buf(sckt->worker, recv_data);
> - return (!CHECK_TUNNEL_ERROR(channel));
> - } else if ((sckt->in_data.num_buffers == MAX_SOCKET_IN_BUFFERS) &&
> - !channel->mig_inprogress) {
> - spice_printerr("socket in buffers overflow, socket will be closed"
> - " (local_port=%d, service_id=%d)",
> - ntohs(sckt->local_port), sckt->far_service->id);
> - __tunnel_worker_free_socket_rcv_buf(sckt->worker, recv_data);
> - tunnel_socket_force_close(channel, sckt);
> - return (!CHECK_TUNNEL_ERROR(channel));
> - }
> -
> - tunnel_socket_assign_rcv_buf(sckt, recv_data, buf_size);
> - if (!sckt->in_data.client_total_num_tokens) {
> - spice_printerr("token violation");
> - return FALSE;
> - }
> -
> - --sckt->in_data.client_total_num_tokens;
> - __process_rcv_buf_tokens(channel, sckt);
> -
> - if (sckt->in_data.ready_chunks_queue.head && !channel->mig_inprogress) {
> - net_slirp_socket_can_receive_notify(sckt->slirp_sckt);
> - }
> -
> - return (!CHECK_TUNNEL_ERROR(channel));
> -}
> -
> -static inline int __client_socket_can_receive(RedSocket *sckt)
> -{
> - return (((sckt->client_status == CLIENT_SCKT_STATUS_OPEN) ||
> - (sckt->client_status == CLIENT_SCKT_STATUS_SHUTDOWN_SEND)) &&
> - !sckt->worker->channel_client->mig_inprogress);
> -}
> -
> -static int tunnel_channel_handle_socket_token(TunnelChannelClient *channel,
> RedSocket *sckt,
> - SpiceMsgcTunnelSocketTokens
> *message)
> -{
> - sckt->out_data.num_tokens += message->num_tokens;
> -
> - if (__client_socket_can_receive(sckt) &&
> sckt->out_data.ready_chunks_queue.head &&
> - !red_channel_client_pipe_item_is_linked(&channel->base,
> &sckt->out_data.data_pipe_item)) {
> - // data is pending to be sent
> - sckt->out_data.data_pipe_item.type = PIPE_ITEM_TYPE_SOCKET_DATA;
> - red_channel_client_pipe_add(&channel->base,
> &sckt->out_data.data_pipe_item);
> - }
> -
> - return TRUE;
> -}
> -
> -static uint8_t *tunnel_channel_alloc_msg_rcv_buf(RedChannelClient *rcc,
> - uint16_t type, uint32_t
> size)
> -{
> - TunnelChannelClient *tunnel_channel = (TunnelChannelClient
> *)rcc->channel;
> -
> - if (type == SPICE_MSGC_TUNNEL_SOCKET_DATA) {
> - return
> (__tunnel_worker_alloc_socket_rcv_buf(tunnel_channel->worker)->buf);
> - } else if ((type == SPICE_MSGC_MIGRATE_DATA) ||
> - (type == SPICE_MSGC_TUNNEL_SERVICE_ADD)) {
> - return spice_malloc(size);
> - } else {
> - return (tunnel_channel->control_rcv_buf);
> - }
> -}
> -
> -// called by the receive routine of the channel, before the buffer was
> assigned to a socket
> -static void tunnel_channel_release_msg_rcv_buf(RedChannelClient *rcc,
> uint16_t type, uint32_t size,
> - uint8_t *msg)
> -{
> - TunnelChannelClient *tunnel_channel = (TunnelChannelClient
> *)rcc->channel;
> -
> - if (type == SPICE_MSGC_TUNNEL_SOCKET_DATA) {
> - spice_assert(!(SPICE_CONTAINEROF(msg, RedSocketRawRcvBuf,
> buf)->base.usr_opaque));
> - __tunnel_worker_free_socket_rcv_buf(tunnel_channel->worker,
> - SPICE_CONTAINEROF(msg,
> RedSocketRawRcvBuf, buf));
> - }
> -}
> -
> -static void __tunnel_channel_fill_service_migrate_item(TunnelChannelClient
> *channel,
> - TunnelService
> *service,
> -
> TunnelMigrateServiceItem
> *migrate_item)
> -{
> - migrate_item->service = service;
> - TunnelMigrateService *general_data;
> - if (service->type == SPICE_TUNNEL_SERVICE_TYPE_GENERIC) {
> - general_data = &migrate_item->u.generic_service;
> - } else if (service->type == SPICE_TUNNEL_SERVICE_TYPE_IPP) {
> - general_data = &migrate_item->u.print_service.base;
> - memcpy(migrate_item->u.print_service.ip, ((TunnelPrintService
> *)service)->ip, 4);
> - } else {
> - spice_error("unexpected service type");
> - abort();
> - }
> -
> - general_data->type = service->type;
> - general_data->id = service->id;
> - general_data->group = service->group;
> - general_data->port = service->port;
> - memcpy(general_data->virt_ip, &service->virt_ip.s_addr, 4);
> -}
> -
> -static void __tunnel_channel_fill_socket_migrate_item(TunnelChannelClient
> *channel, RedSocket *sckt,
> -
> TunnelMigrateSocketItem
> *migrate_item)
> -{
> - TunnelMigrateSocket *mig_sckt = &migrate_item->mig_socket;
> - migrate_item->socket = sckt;
> - mig_sckt->connection_id = sckt->connection_id;
> - mig_sckt->local_port = sckt->local_port;
> - mig_sckt->far_service_id = sckt->far_service->id;
> - mig_sckt->client_status = sckt->client_status;
> - mig_sckt->slirp_status = sckt->slirp_status;
> -
> - mig_sckt->pushed_close = sckt->pushed_close;
> - mig_sckt->client_waits_close_ack = sckt->client_waits_close_ack;
> -
> - mig_sckt->mig_client_status_msg = sckt->mig_client_status_msg;
> - mig_sckt->mig_open_ack_tokens = sckt->mig_open_ack_tokens;
> -
> - mig_sckt->out_data.num_tokens = sckt->out_data.num_tokens;
> - mig_sckt->out_data.window_size = sckt->out_data.window_size;
> -
> - // checking if there is a need to save the queues
> - if ((sckt->client_status != CLIENT_SCKT_STATUS_CLOSED) &&
> - (sckt->mig_client_status_msg != SPICE_MSGC_TUNNEL_SOCKET_CLOSED) &&
> - (sckt->mig_client_status_msg !=
> SPICE_MSGC_TUNNEL_SOCKET_CLOSED_ACK)) {
> - mig_sckt->out_data.process_queue_size =
> -
> sckt->out_data.process_queue->get_migrate_data_proc(sckt->out_data.process_queue,
> -
> &migrate_item->out_process_queue);
> - }
> -
> - mig_sckt->in_data.num_tokens = sckt->in_data.num_tokens;
> - mig_sckt->in_data.client_total_num_tokens =
> sckt->in_data.client_total_num_tokens;
> -
> - if ((sckt->slirp_status == SLIRP_SCKT_STATUS_OPEN) ||
> - (sckt->slirp_status == SLIRP_SCKT_STATUS_SHUTDOWN_SEND)) {
> - mig_sckt->in_data.process_queue_size =
> -
> sckt->in_data.process_queue->get_migrate_data_proc(sckt->in_data.process_queue,
> -
> &migrate_item->in_process_queue);
> - }
> -
> - if (sckt->slirp_status != SLIRP_SCKT_STATUS_CLOSED) {
> - migrate_item->slirp_socket_size =
> net_slirp_tcp_socket_export(sckt->slirp_sckt,
> -
> &migrate_item->slirp_socket);
> - if (!migrate_item->slirp_socket) {
> - SET_TUNNEL_ERROR(channel, "failed export slirp socket");
> - }
> - } else {
> - migrate_item->slirp_socket_size = 0;
> - migrate_item->slirp_socket = NULL;
> - }
> -}
> -
> -static void release_migrate_item(TunnelMigrateItem *item);
> -static int tunnel_channel_handle_migrate_mark(RedChannelClient *base)
> -{
> - TunnelChannelClient *channel = SPICE_CONTAINEROF(base->channel,
> TunnelChannelClient, base);
> - TunnelMigrateItem *migrate_item = NULL;
> - TunnelService *service;
> - TunnelMigrateServiceItem *mig_service;
> - int num_sockets_saved = 0;
> - RedSocket *sckt;
> -
> - migrate_item = spice_new0(TunnelMigrateItem, 1);
> - migrate_item->base.type = PIPE_ITEM_TYPE_MIGRATE_DATA;
> -
> - migrate_item->slirp_state_size =
> net_slirp_state_export(&migrate_item->slirp_state);
> - if (!migrate_item->slirp_state) {
> - spice_printerr("failed export slirp state");
> - goto error;
> - }
> -
> - migrate_item->services_list_size = sizeof(TunnelMigrateServicesList) +
> - (sizeof(uint32_t)*channel->worker->num_services);
> - migrate_item->services_list =
> - (TunnelMigrateServicesList
> *)spice_malloc(migrate_item->services_list_size);
> - migrate_item->services_list->num_services =
> channel->worker->num_services;
> -
> - migrate_item->services = (TunnelMigrateServiceItem *)spice_malloc(
> - channel->worker->num_services *
> sizeof(TunnelMigrateServiceItem));
> -
> - for (mig_service = migrate_item->services,
> - service = (TunnelService
> *)ring_get_head(&channel->worker->services);
> - service;
> - mig_service++,
> - service = (TunnelService *)ring_next(&channel->worker->services,
> &service->ring_item)) {
> - __tunnel_channel_fill_service_migrate_item(channel, service,
> mig_service);
> - if (CHECK_TUNNEL_ERROR(channel)) {
> - goto error;
> - }
> - }
> -
> - migrate_item->sockets_list_size = sizeof(TunnelMigrateSocketList) +
> - (sizeof(uint32_t)*channel->worker->num_sockets);
> - migrate_item->sockets_list =
> - (TunnelMigrateSocketList *)
> spice_malloc(migrate_item->sockets_list_size);
> -
> - migrate_item->sockets_list->num_sockets = channel->worker->num_sockets;
> -
> - for (sckt = channel->worker->sockets; num_sockets_saved <
> channel->worker->num_sockets;
> -
> sckt++)
> {
> - if (sckt->allocated) {
> - __tunnel_channel_fill_socket_migrate_item(channel, sckt,
> -
> &migrate_item->sockets_data[
> -
> num_sockets_saved++]);
> - if (CHECK_TUNNEL_ERROR(channel)) {
> - goto error;
> - }
> - }
> - }
> -
> - red_channel_client_pipe_add(&channel->base, &migrate_item->base);
> -
> - return TRUE;
> -error:
> - release_migrate_item(migrate_item);
> - return FALSE;
> -}
> -
> -static void release_migrate_item(TunnelMigrateItem *item)
> -{
> - if (!item) {
> - return;
> - }
> -
> - int i;
> - if (item->sockets_list) {
> - int num_sockets = item->sockets_list->num_sockets;
> - for (i = 0; i < num_sockets; i++) {
> - if (item->sockets_data[i].socket) { // handling errors in the
> middle of
> - //
> __tunnel_channel_fill_socket_migrate_item
> - if (item->sockets_data[i].out_process_queue) {
> -
> item->sockets_data[i].socket->out_data.process_queue->release_migrate_data_proc(
> -
> item->sockets_data[i].socket->out_data.process_queue,
> - item->sockets_data[i].out_process_queue);
> - }
> - if (item->sockets_data[i].in_process_queue) {
> -
> item->sockets_data[i].socket->in_data.process_queue->release_migrate_data_proc(
> - item->sockets_data[i].socket->in_data.process_queue,
> - item->sockets_data[i].in_process_queue);
> - }
> - }
> -
> - free(item->sockets_data[i].slirp_socket);
> - }
> - free(item->sockets_list);
> - }
> -
> - free(item->services);
> - free(item->services_list);
> - free(item->slirp_state);
> - free(item);
> -}
> -
> -typedef RawTunneledBuffer *(*socket_alloc_buffer_proc_t)(RedSocket *sckt);
> -
> -typedef struct RedSocketRestoreTokensBuf {
> - RedSocketRawRcvBuf base;
> - int num_tokens;
> -} RedSocketRestoreTokensBuf;
> -
> -// not updating tokens
> -static void restored_rcv_buf_release(RawTunneledBuffer *buf)
> -{
> - RedSocket *sckt = (RedSocket *)buf->usr_opaque;
> - --sckt->in_data.num_buffers;
> - __tunnel_worker_free_socket_rcv_buf(sckt->worker, (RedSocketRawRcvBuf
> *)buf);
> - // for case that ready queue is empty and the client has no tokens
> - __process_rcv_buf_tokens(sckt->worker->channel_client, sckt);
> -}
> -
> -RawTunneledBuffer *tunnel_socket_alloc_restored_rcv_buf(RedSocket *sckt)
> -{
> - RedSocketRawRcvBuf *buf =
> __tunnel_worker_alloc_socket_rcv_buf(sckt->worker);
> - buf->base.usr_opaque = sckt;
> - buf->base.release_proc = restored_rcv_buf_release;
> -
> - sckt->in_data.num_buffers++;
> - return &buf->base;
> -}
> -
> -static void restore_tokens_buf_release(RawTunneledBuffer *buf)
> -{
> - RedSocketRestoreTokensBuf *tokens_buf = (RedSocketRestoreTokensBuf
> *)buf;
> - RedSocket *sckt = (RedSocket *)buf->usr_opaque;
> -
> - sckt->in_data.num_tokens += tokens_buf->num_tokens;
> - __process_rcv_buf_tokens(sckt->worker->channel_client, sckt);
> -
> - free(tokens_buf);
> -}
> -
> -RawTunneledBuffer *__tunnel_socket_alloc_restore_tokens_buf(RedSocket *sckt,
> int num_tokens)
> -{
> - RedSocketRestoreTokensBuf *buf = spice_new0(RedSocketRestoreTokensBuf,
> 1);
> -
> - buf->base.base.usr_opaque = sckt;
> - buf->base.base.refs = 1;
> - buf->base.base.release_proc = restore_tokens_buf_release;
> - buf->num_tokens = num_tokens;
> -#ifdef DEBUG_NETWORK
> - spice_printerr("TUNNEL DBG: num_tokens=%d", num_tokens);
> -#endif
> - return &buf->base.base;
> -}
> -
> -static void __restore_ready_chunks_queue(RedSocket *sckt,
> ReadyTunneledChunkQueue *queue,
> - uint8_t *data, int size,
> - socket_alloc_buffer_proc_t
> alloc_buf)
> -{
> - int copied = 0;
> -
> - while (copied < size) {
> - RawTunneledBuffer *buf = alloc_buf(sckt);
> - int copy_count = MIN(size - copied, buf->max_size);
> - memcpy(buf->data, data + copied, copy_count);
> - copied += copy_count;
> - buf->size = copy_count;
> - ready_queue_add_orig_chunk(queue, buf, buf->data, buf->size);
> - tunneled_buffer_unref(buf);
> - }
> -}
> -
> -// not using the alloc_buf cb of the queue, since we may want to create the
> migrated buffers
> -// with other properties (e.g., not releasing token)
> -static void __restore_process_queue(RedSocket *sckt,
> TunneledBufferProcessQueue *queue,
> - uint8_t *data, int size,
> - socket_alloc_buffer_proc_t alloc_buf)
> -{
> - int copied = 0;
> -
> - while (copied < size) {
> - RawTunneledBuffer *buf = alloc_buf(sckt);
> - int copy_count = MIN(size - copied, buf->max_size);
> - memcpy(buf->data, data + copied, copy_count);
> - copied += copy_count;
> - buf->size = copy_count;
> - __process_queue_push(queue, buf);
> - }
> -}
> -
> -static void tunnel_channel_restore_migrated_service(TunnelChannelClient
> *channel,
> - TunnelMigrateService
> *mig_service,
> - uint8_t *data_buf)
> -{
> - int service_size;
> - TunnelService *service;
> - struct in_addr virt_ip;
> - if (mig_service->type == SPICE_TUNNEL_SERVICE_TYPE_GENERIC) {
> - service_size = sizeof(TunnelService);
> - } else if (mig_service->type == SPICE_TUNNEL_SERVICE_TYPE_IPP) {
> - service_size = sizeof(TunnelPrintService);
> - } else {
> - SET_TUNNEL_ERROR(channel, "unexpected service type");
> - return;
> - }
> -
> - memcpy(&virt_ip.s_addr, mig_service->virt_ip, 4);
> - service = __tunnel_worker_add_service(channel->worker, service_size,
> - mig_service->type,
> mig_service->id,
> - mig_service->group,
> mig_service->port,
> - (char *)(data_buf +
> mig_service->name),
> - (char *)(data_buf +
> mig_service->description), &virt_ip);
> - if (!service) {
> - SET_TUNNEL_ERROR(channel, "failed creating service");
> - return;
> - }
> -
> - if (service->type == SPICE_TUNNEL_SERVICE_TYPE_IPP) {
> - TunnelMigratePrintService *mig_print_service =
> (TunnelMigratePrintService *)mig_service;
> - TunnelPrintService *print_service = (TunnelPrintService *)service;
> -
> - memcpy(print_service->ip, mig_print_service->ip, 4);
> - }
> -}
> -
> -static void tunnel_channel_restore_migrated_socket(TunnelChannelClient
> *channel,
> - TunnelMigrateSocket
> *mig_socket,
> - uint8_t *data_buf)
> -{
> - RedSocket *sckt;
> - SlirpSocket *slirp_sckt;
> - RawTunneledBuffer *tokens_buf;
> - TunnelService *service;
> - sckt = channel->worker->sockets + mig_socket->connection_id;
> - sckt->connection_id = mig_socket->connection_id;
> - spice_assert(!sckt->allocated);
> -
> - /* Services must be restored before sockets */
> - service = tunnel_worker_find_service_by_id(channel->worker,
> mig_socket->far_service_id);
> - if (!service) {
> - SET_TUNNEL_ERROR(channel, "service not found");
> - return;
> - }
> -
> - tunnel_worker_alloc_socket(channel->worker, sckt,
> mig_socket->local_port, service, NULL);
> -
> - sckt->client_status = mig_socket->client_status;
> - sckt->slirp_status = mig_socket->slirp_status;
> -
> - sckt->mig_client_status_msg = mig_socket->mig_client_status_msg;
> - sckt->mig_open_ack_tokens = mig_socket->mig_open_ack_tokens;
> -
> - sckt->pushed_close = mig_socket->pushed_close;
> - sckt->client_waits_close_ack = mig_socket->client_waits_close_ack;
> -
> - if (sckt->slirp_status != SLIRP_SCKT_STATUS_CLOSED) {
> - slirp_sckt = net_slirp_tcp_socket_restore(data_buf +
> mig_socket->slirp_sckt, sckt);
> - if (!slirp_sckt) {
> - SET_TUNNEL_ERROR(channel, "failed restoring slirp socket");
> - return;
> - }
> - sckt->slirp_sckt = slirp_sckt;
> - }
> - // out data
> - sckt->out_data.num_tokens = mig_socket->out_data.num_tokens;
> - sckt->out_data.window_size = mig_socket->out_data.window_size;
> - sckt->out_data.data_size = mig_socket->out_data.process_buf_size +
> - mig_socket->out_data.ready_buf_size;
> -
> - __restore_ready_chunks_queue(sckt, &sckt->out_data.ready_chunks_queue,
> - data_buf + mig_socket->out_data.ready_buf,
> - mig_socket->out_data.ready_buf_size,
> - tunnel_socket_alloc_snd_buf);
> -
> - sckt->out_data.process_queue->restore_proc(sckt->out_data.process_queue,
> - data_buf +
> mig_socket->out_data.process_queue);
> -
> - __restore_process_queue(sckt, sckt->out_data.process_queue,
> - data_buf + mig_socket->out_data.process_buf,
> - mig_socket->out_data.process_buf_size,
> - tunnel_socket_alloc_snd_buf);
> -
> - sckt->in_data.client_total_num_tokens =
> mig_socket->in_data.client_total_num_tokens;
> - sckt->in_data.num_tokens = mig_socket->in_data.num_tokens;
> -
> - __restore_ready_chunks_queue(sckt, &sckt->in_data.ready_chunks_queue,
> - data_buf + mig_socket->in_data.ready_buf,
> - mig_socket->in_data.ready_buf_size,
> - tunnel_socket_alloc_restored_rcv_buf);
> -
> - sckt->in_data.process_queue->restore_proc(sckt->in_data.process_queue,
> - data_buf +
> mig_socket->in_data.process_queue);
> -
> - __restore_process_queue(sckt, sckt->in_data.process_queue,
> - data_buf + mig_socket->in_data.process_buf,
> - mig_socket->in_data.process_buf_size,
> - tunnel_socket_alloc_restored_rcv_buf);
> -
> - tokens_buf = __tunnel_socket_alloc_restore_tokens_buf(sckt,
> - SOCKET_WINDOW_SIZE
> -
> -
> (sckt->in_data.client_total_num_tokens
> +
> -
> sckt->in_data.num_tokens));
> - if (sckt->in_data.process_queue->head) {
> - __process_queue_push(sckt->in_data.process_queue, tokens_buf);
> - } else {
> - ready_queue_add_orig_chunk(&sckt->in_data.ready_chunks_queue,
> tokens_buf,
> - tokens_buf->data, tokens_buf->size);
> - tunneled_buffer_unref(tokens_buf);
> - }
> -}
> -
> -static void tunnel_channel_restore_socket_state(TunnelChannelClient
> *channel, RedSocket *sckt)
> -{
> - int ret = TRUE;
> - spice_printerr("");
> - // handling client status msgs that were received during migration
> - switch (sckt->mig_client_status_msg) {
> - case 0:
> - break;
> - case SPICE_MSGC_TUNNEL_SOCKET_OPEN_ACK:
> - ret = tunnel_channel_handle_socket_connect_ack(channel, sckt,
> -
> sckt->mig_open_ack_tokens);
> - break;
> - case SPICE_MSGC_TUNNEL_SOCKET_OPEN_NACK:
> - ret = tunnel_channel_handle_socket_connect_nack(channel, sckt);
> - break;
> - case SPICE_MSGC_TUNNEL_SOCKET_FIN:
> - if (sckt->client_status == CLIENT_SCKT_STATUS_WAIT_OPEN) {
> - ret = tunnel_channel_handle_socket_connect_ack(channel, sckt,
> -
> sckt->mig_open_ack_tokens);
> - }
> - if (ret) {
> - ret = tunnel_channel_handle_socket_fin(channel, sckt);
> - }
> - break;
> - case SPICE_MSGC_TUNNEL_SOCKET_CLOSED:
> - // can't just send nack since we need to send close ack to client
> - if (sckt->client_status == CLIENT_SCKT_STATUS_WAIT_OPEN) {
> - ret = tunnel_channel_handle_socket_connect_ack(channel, sckt,
> -
> sckt->mig_open_ack_tokens);
> - }
> - ret = ret & tunnel_channel_handle_socket_closed(channel, sckt);
> -
> - break;
> - case SPICE_MSGC_TUNNEL_SOCKET_CLOSED_ACK:
> - ret = tunnel_channel_handle_socket_closed_ack(channel, sckt);
> - break;
> - default:
> - SET_TUNNEL_ERROR(channel, "invalid message type %u",
> sckt->mig_client_status_msg);
> - return;
> - }
> -
> - if (!ret) {
> - SET_TUNNEL_ERROR(channel, "failed restoring socket state");
> - return;
> - }
> - sckt->mig_client_status_msg = 0;
> - sckt->mig_open_ack_tokens = 0;
> -
> - // handling data transfer
> - if (__client_socket_can_receive(sckt) &&
> sckt->out_data.ready_chunks_queue.head) {
> - if (!red_channel_client_pipe_item_is_linked(
> - &channel->base, &sckt->out_data.data_pipe_item)) {
> - sckt->out_data.data_pipe_item.type = PIPE_ITEM_TYPE_SOCKET_DATA;
> - red_channel_client_pipe_add(&channel->base,
> &sckt->out_data.data_pipe_item);
> - }
> - }
> -
> - if (((sckt->slirp_status == SLIRP_SCKT_STATUS_OPEN) ||
> - (sckt->slirp_status == SLIRP_SCKT_STATUS_SHUTDOWN_SEND)) &&
> - sckt->in_data.ready_chunks_queue.head) {
> - net_slirp_socket_can_receive_notify(sckt->slirp_sckt);
> - }
> -
> - if (CHECK_TUNNEL_ERROR(channel)) {
> - return;
> - }
> -
> - if ((sckt->slirp_status == SLIRP_SCKT_STATUS_OPEN) ||
> - (sckt->slirp_status == SLIRP_SCKT_STATUS_SHUTDOWN_RECV)) {
> - net_slirp_socket_can_send_notify(sckt->slirp_sckt);
> - }
> -
> - if (CHECK_TUNNEL_ERROR(channel)) {
> - return;
> - }
> - // for cases where the client has no tokens left, but all the data is in
> the process queue.
> - __process_rcv_buf_tokens(channel, sckt);
> -}
> -
> -static inline void
> tunnel_channel_activate_migrated_sockets(TunnelChannelClient *channel)
> -{
> - // if we are overgoing migration again, no need to restore the state, we
> will wait
> - // for the next host.
> - if (!channel->mig_inprogress) {
> - int num_activated = 0;
> - RedSocket *sckt = channel->worker->sockets;
> -
> - for (; num_activated < channel->worker->num_sockets; sckt++) {
> - if (sckt->allocated) {
> - tunnel_channel_restore_socket_state(channel, sckt);
> -
> - if (CHECK_TUNNEL_ERROR(channel)) {
> - return;
> - }
> -
> - num_activated++;
> - }
> - }
> - net_slirp_unfreeze();
> - }
> -}
> -
> -static uint64_t
> tunnel_channel_handle_migrate_data_get_serial(RedChannelClient *base,
> - uint32_t size, void *msg)
> -{
> - TunnelMigrateData *migrate_data = msg;
> -
> - if (size < sizeof(TunnelMigrateData)
> - || migrate_data->magic != TUNNEL_MIGRATE_DATA_MAGIC
> - || migrate_data->version != TUNNEL_MIGRATE_DATA_VERSION) {
> - return 0;
> - }
> - return migrate_data->message_serial;
> -}
> -
> -static int tunnel_channel_handle_migrate_data(RedChannelClient *base,
> - uint32_t size, void *msg)
> -{
> - TunnelChannelClient *channel = SPICE_CONTAINEROF(base,
> TunnelChannelClient, base);
> - TunnelMigrateSocketList *sockets_list;
> - TunnelMigrateServicesList *services_list;
> - TunnelMigrateData *migrate_data = msg;
> - int i;
> -
> - if (size < sizeof(TunnelMigrateData)) {
> - spice_printerr("bad message size");
> - goto error;
> - }
> -
> - if (migrate_data->magic != TUNNEL_MIGRATE_DATA_MAGIC ||
> - migrate_data->version != TUNNEL_MIGRATE_DATA_VERSION) {
> - spice_printerr("invalid content");
> - goto error;
> - }
> -
> - net_slirp_state_restore(migrate_data->data + migrate_data->slirp_state);
> -
> - services_list = (TunnelMigrateServicesList *)(migrate_data->data +
> -
> migrate_data->services_list);
> - for (i = 0; i < services_list->num_services; i++) {
> - tunnel_channel_restore_migrated_service(channel,
> - (TunnelMigrateService
> *)(migrate_data->data +
> -
> services_list->services[i]),
> - migrate_data->data);
> - if (CHECK_TUNNEL_ERROR(channel)) {
> - spice_printerr("failed restoring service");
> - goto error;
> - }
> - }
> -
> - sockets_list = (TunnelMigrateSocketList *)(migrate_data->data +
> migrate_data->sockets_list);
> -
> - for (i = 0; i < sockets_list->num_sockets; i++) {
> - tunnel_channel_restore_migrated_socket(channel,
> - (TunnelMigrateSocket
> *)(migrate_data->data +
> -
> sockets_list->sockets[i]),
> - migrate_data->data);
> - if (CHECK_TUNNEL_ERROR(channel)) {
> - spice_printerr("failed restoring socket");
> - goto error;
> - }
> - }
> -
> - // activate channel
> - channel->mig_inprogress = FALSE;
> - red_channel_init_outgoing_messages_window(channel->base.channel);
> -
> - tunnel_channel_activate_migrated_sockets(channel);
> -
> - if (CHECK_TUNNEL_ERROR(channel)) {
> - goto error;
> - }
> - free(migrate_data);
> - return TRUE;
> -error:
> - free(migrate_data);
> - return FALSE;
> -}
> -
> -// msg was allocated by tunnel_channel_alloc_msg_rcv_buf
> -static int tunnel_channel_handle_message(RedChannelClient *rcc, uint16_t
> type,
> - uint32_t size, uint8_t *msg)
> -{
> - TunnelChannelClient *tunnel_channel = (TunnelChannelClient
> *)rcc->channel;
> - RedSocket *sckt = NULL;
> - // retrieve the sckt
> - switch (type) {
> - case SPICE_MSGC_MIGRATE_FLUSH_MARK:
> - case SPICE_MSGC_MIGRATE_DATA:
> - case SPICE_MSGC_TUNNEL_SERVICE_ADD:
> - case SPICE_MSGC_TUNNEL_SERVICE_REMOVE:
> - break;
> - case SPICE_MSGC_TUNNEL_SOCKET_OPEN_ACK:
> - case SPICE_MSGC_TUNNEL_SOCKET_OPEN_NACK:
> - case SPICE_MSGC_TUNNEL_SOCKET_DATA:
> - case SPICE_MSGC_TUNNEL_SOCKET_FIN:
> - case SPICE_MSGC_TUNNEL_SOCKET_CLOSED:
> - case SPICE_MSGC_TUNNEL_SOCKET_CLOSED_ACK:
> - case SPICE_MSGC_TUNNEL_SOCKET_TOKEN:
> - // the first field in these messages is connection id
> - sckt = tunnel_channel->worker->sockets + (*((uint16_t *)msg));
> - if (!sckt->allocated) {
> - spice_printerr("red socket not found");
> - return FALSE;
> - }
> - break;
> - default:
> - return red_channel_client_handle_message(rcc, size, type, msg);
> - }
> -
> - switch (type) {
> - case SPICE_MSGC_TUNNEL_SERVICE_ADD:
> - if (size < sizeof(SpiceMsgcTunnelAddGenericService)) {
> - spice_printerr("bad message size");
> - free(msg);
> - return FALSE;
> - }
> - return tunnel_channel_handle_service_add(tunnel_channel,
> -
> (SpiceMsgcTunnelAddGenericService
> *)msg);
> - case SPICE_MSGC_TUNNEL_SERVICE_REMOVE:
> - spice_printerr("REDC_TUNNEL_REMOVE_SERVICE not supported yet");
> - return FALSE;
> - case SPICE_MSGC_TUNNEL_SOCKET_OPEN_ACK:
> - if (size != sizeof(SpiceMsgcTunnelSocketOpenAck)) {
> - spice_printerr("bad message size");
> - return FALSE;
> - }
> -
> - return tunnel_channel_handle_socket_connect_ack(tunnel_channel,
> sckt,
> -
> ((SpiceMsgcTunnelSocketOpenAck
> *)msg)->tokens);
> -
> - case SPICE_MSGC_TUNNEL_SOCKET_OPEN_NACK:
> - if (size != sizeof(SpiceMsgcTunnelSocketOpenNack)) {
> - spice_printerr("bad message size");
> - return FALSE;
> - }
> -
> - return tunnel_channel_handle_socket_connect_nack(tunnel_channel,
> sckt);
> - case SPICE_MSGC_TUNNEL_SOCKET_DATA:
> - {
> - if (size < sizeof(SpiceMsgcTunnelSocketData)) {
> - spice_printerr("bad message size");
> - return FALSE;
> - }
> -
> - return tunnel_channel_handle_socket_receive_data(tunnel_channel,
> sckt,
> - SPICE_CONTAINEROF(msg,
> RedSocketRawRcvBuf, buf),
> - size -
> sizeof(SpiceMsgcTunnelSocketData));
> - }
> - case SPICE_MSGC_TUNNEL_SOCKET_FIN:
> - if (size != sizeof(SpiceMsgcTunnelSocketFin)) {
> - spice_printerr("bad message size");
> - return FALSE;
> - }
> - return tunnel_channel_handle_socket_fin(tunnel_channel, sckt);
> - case SPICE_MSGC_TUNNEL_SOCKET_CLOSED:
> - if (size != sizeof(SpiceMsgcTunnelSocketClosed)) {
> - spice_printerr("bad message size");
> - return FALSE;
> - }
> - return tunnel_channel_handle_socket_closed(tunnel_channel, sckt);
> - case SPICE_MSGC_TUNNEL_SOCKET_CLOSED_ACK:
> - if (size != sizeof(SpiceMsgcTunnelSocketClosedAck)) {
> - spice_printerr("bad message size");
> - return FALSE;
> - }
> - return tunnel_channel_handle_socket_closed_ack(tunnel_channel,
> sckt);
> - case SPICE_MSGC_TUNNEL_SOCKET_TOKEN:
> - if (size != sizeof(SpiceMsgcTunnelSocketTokens)) {
> - spice_printerr("bad message size");
> - return FALSE;
> - }
> -
> - return tunnel_channel_handle_socket_token(tunnel_channel, sckt,
> -
> (SpiceMsgcTunnelSocketTokens
> *)msg);
> - default:
> - return red_channel_client_handle_message(rcc, size, type, msg);
> - }
> - return TRUE;
> -}
> -
> -/********************************/
> -/* outgoing msgs
> -********************************/
> -
> -static int
> __tunnel_channel_marshall_process_bufs_migrate_data(TunnelChannelClient
> *channel,
> - SpiceMarshaller *m,
> TunneledBufferProcessQueue *queue)
> -{
> - int buf_offset = queue->head_offset;
> - RawTunneledBuffer *buf = queue->head;
> - int size = 0;
> -
> - while (buf) {
> - spice_marshaller_add_ref(m, (uint8_t*)buf->data + buf_offset,
> buf->size - buf_offset);
> - size += buf->size - buf_offset;
> - buf_offset = 0;
> - buf = buf->next;
> - }
> -
> - return size;
> -}
> -
> -static int
> __tunnel_channel_marshall_ready_bufs_migrate_data(TunnelChannelClient
> *channel,
> - SpiceMarshaller *m,
> ReadyTunneledChunkQueue *queue)
> -{
> - int offset = queue->offset;
> - ReadyTunneledChunk *chunk = queue->head;
> - int size = 0;
> -
> - while (chunk) {
> - spice_marshaller_add_ref(m, (uint8_t*)chunk->data + offset,
> chunk->size - offset);
> - size += chunk->size - offset;
> - offset = 0;
> - chunk = chunk->next;
> - }
> - return size;
> -}
> -
> -// returns the size to send
> -static int
> __tunnel_channel_marshall_service_migrate_data(TunnelChannelClient *channel,
> - SpiceMarshaller *m,
> -
> TunnelMigrateServiceItem
> *item,
> - int offset)
> -{
> - TunnelService *service = item->service;
> - int cur_offset = offset;
> - TunnelMigrateService *generic_data;
> -
> - if (service->type == SPICE_TUNNEL_SERVICE_TYPE_GENERIC) {
> - generic_data = &item->u.generic_service;
> - spice_marshaller_add_ref(m, (uint8_t*)&item->u.generic_service,
> - sizeof(item->u.generic_service));
> - cur_offset += sizeof(item->u.generic_service);
> - } else if (service->type == SPICE_TUNNEL_SERVICE_TYPE_IPP) {
> - generic_data = &item->u.print_service.base;
> - spice_marshaller_add_ref(m, (uint8_t*)&item->u.print_service,
> - sizeof(item->u.print_service));
> - cur_offset += sizeof(item->u.print_service);
> - } else {
> - spice_error("unexpected service type");
> - abort();
> - }
> -
> - generic_data->name = cur_offset;
> - spice_marshaller_add_ref(m, (uint8_t*)service->name,
> strlen(service->name) + 1);
> - cur_offset += strlen(service->name) + 1;
> -
> - generic_data->description = cur_offset;
> - spice_marshaller_add_ref(m, (uint8_t*)service->description,
> strlen(service->description) + 1);
> - cur_offset += strlen(service->description) + 1;
> -
> - return (cur_offset - offset);
> -}
> -
> -// returns the size to send
> -static int __tunnel_channel_marshall_socket_migrate_data(TunnelChannelClient
> *channel,
> - SpiceMarshaller *m, TunnelMigrateSocketItem
> *item, int offset)
> -{
> - RedSocket *sckt = item->socket;
> - TunnelMigrateSocket *mig_sckt = &item->mig_socket;
> - int cur_offset = offset;
> - spice_marshaller_add_ref(m, (uint8_t*)mig_sckt, sizeof(*mig_sckt));
> - cur_offset += sizeof(*mig_sckt);
> -
> - if ((sckt->client_status != CLIENT_SCKT_STATUS_CLOSED) &&
> - (sckt->mig_client_status_msg != SPICE_MSGC_TUNNEL_SOCKET_CLOSED) &&
> - (sckt->mig_client_status_msg !=
> SPICE_MSGC_TUNNEL_SOCKET_CLOSED_ACK)) {
> - mig_sckt->out_data.process_buf = cur_offset;
> - mig_sckt->out_data.process_buf_size =
> - __tunnel_channel_marshall_process_bufs_migrate_data(channel, m,
> -
> sckt->out_data.process_queue);
> - cur_offset += mig_sckt->out_data.process_buf_size;
> - if (mig_sckt->out_data.process_queue_size) {
> - mig_sckt->out_data.process_queue = cur_offset;
> - spice_marshaller_add_ref(m, (uint8_t*)item->out_process_queue,
> - mig_sckt->out_data.process_queue_size);
> - cur_offset += mig_sckt->out_data.process_queue_size;
> - }
> - mig_sckt->out_data.ready_buf = cur_offset;
> - mig_sckt->out_data.ready_buf_size =
> - __tunnel_channel_marshall_ready_bufs_migrate_data(channel, m,
> -
> &sckt->out_data.ready_chunks_queue);
> - cur_offset += mig_sckt->out_data.ready_buf_size;
> - } else {
> - mig_sckt->out_data.process_buf_size = 0;
> - mig_sckt->out_data.ready_buf_size = 0;
> - }
> -
> - // notice that we migrate the received buffers without the msg headers.
> - if ((sckt->slirp_status == SLIRP_SCKT_STATUS_OPEN) ||
> - (sckt->slirp_status == SLIRP_SCKT_STATUS_SHUTDOWN_SEND)) {
> - mig_sckt->in_data.process_buf = cur_offset;
> - mig_sckt->in_data.process_buf_size =
> - __tunnel_channel_marshall_process_bufs_migrate_data(channel, m,
> -
> sckt->in_data.process_queue);
> - cur_offset += mig_sckt->in_data.process_buf_size;
> - if (mig_sckt->in_data.process_queue_size) {
> - mig_sckt->in_data.process_queue = cur_offset;
> - spice_marshaller_add_ref(m, (uint8_t*)item->in_process_queue,
> - mig_sckt->in_data.process_queue_size);
> - cur_offset += mig_sckt->in_data.process_queue_size;
> - }
> - mig_sckt->in_data.ready_buf = cur_offset;
> - mig_sckt->in_data.ready_buf_size =
> - __tunnel_channel_marshall_ready_bufs_migrate_data(channel, m,
> -
> &sckt->in_data.ready_chunks_queue);
> - cur_offset += mig_sckt->in_data.ready_buf_size;
> - } else {
> - mig_sckt->in_data.process_buf_size = 0;
> - mig_sckt->in_data.ready_buf_size = 0;
> - }
> -
> - if (item->slirp_socket_size) { // zero if socket is closed
> - spice_marshaller_add_ref(m, (uint8_t*)item->slirp_socket,
> item->slirp_socket_size);
> - mig_sckt->slirp_sckt = cur_offset;
> - cur_offset += item->slirp_socket_size;
> - }
> - return (cur_offset - offset);
> -}
> -
> -static void tunnel_channel_marshall_migrate_data(RedChannelClient *rcc,
> - SpiceMarshaller *m, PipeItem *item)
> -{
> - TunnelChannelClient *tunnel_channel;
> - TunnelMigrateData *migrate_data;
> - TunnelMigrateItem *migrate_item = (TunnelMigrateItem *)item;
> - int i;
> -
> - uint32_t data_buf_offset = 0; // current location in data[0] field
> - spice_assert(rcc);
> - tunnel_channel = SPICE_CONTAINEROF(rcc->channel, TunnelChannelClient,
> base);
> - migrate_data = &tunnel_channel->send_data.u.migrate_data;
> -
> - migrate_data->magic = TUNNEL_MIGRATE_DATA_MAGIC;
> - migrate_data->version = TUNNEL_MIGRATE_DATA_VERSION;
> - migrate_data->message_serial =
> red_channel_client_get_message_serial(rcc);
> - red_channel_client_init_send_data(rcc, SPICE_MSG_MIGRATE_DATA, item);
> - spice_marshaller_add_ref(m, (uint8_t*)migrate_data,
> sizeof(*migrate_data));
> -
> - migrate_data->slirp_state = data_buf_offset;
> - spice_marshaller_add_ref(m, (uint8_t*)migrate_item->slirp_state,
> migrate_item->slirp_state_size);
> - data_buf_offset += migrate_item->slirp_state_size;
> -
> - migrate_data->services_list = data_buf_offset;
> - spice_marshaller_add_ref(m, (uint8_t*)migrate_item->services_list,
> - migrate_item->services_list_size);
> - data_buf_offset += migrate_item->services_list_size;
> -
> - for (i = 0; i < migrate_item->services_list->num_services; i++) {
> - migrate_item->services_list->services[i] = data_buf_offset;
> - data_buf_offset +=
> __tunnel_channel_marshall_service_migrate_data(tunnel_channel, m,
> -
> migrate_item->services
> + i,
> -
> data_buf_offset);
> - }
> -
> -
> - migrate_data->sockets_list = data_buf_offset;
> - spice_marshaller_add_ref(m, (uint8_t*)migrate_item->sockets_list,
> - migrate_item->sockets_list_size);
> - data_buf_offset += migrate_item->sockets_list_size;
> -
> - for (i = 0; i < migrate_item->sockets_list->num_sockets; i++) {
> - migrate_item->sockets_list->sockets[i] = data_buf_offset;
> - data_buf_offset +=
> __tunnel_channel_marshall_socket_migrate_data(tunnel_channel, m,
> -
> migrate_item->sockets_data
> + i,
> -
> data_buf_offset);
> - }
> -}
> -
> -static void tunnel_channel_marshall_init(RedChannelClient *rcc,
> SpiceMarshaller *m, PipeItem *item)
> -{
> - TunnelChannelClient *channel;
> -
> - spice_assert(rcc);
> - channel = SPICE_CONTAINEROF(rcc->channel, TunnelChannelClient, base);
> - channel->send_data.u.init.max_socket_data_size = MAX_SOCKET_DATA_SIZE;
> - channel->send_data.u.init.max_num_of_sockets = MAX_SOCKETS_NUM;
> -
> - red_channel_client_init_send_data(rcc, SPICE_MSG_TUNNEL_INIT, item);
> - spice_marshaller_add_ref(m, (uint8_t*)&channel->send_data.u.init,
> sizeof(SpiceMsgTunnelInit));
> -}
> -
> -static void tunnel_channel_marshall_service_ip_map(RedChannelClient *rcc,
> SpiceMarshaller *m, PipeItem *item)
> -{
> - TunnelChannelClient *tunnel_channel;
> - TunnelService *service = SPICE_CONTAINEROF(item, TunnelService,
> pipe_item);
> -
> - tunnel_channel = SPICE_CONTAINEROF(rcc->channel, TunnelChannelClient,
> base);
> - tunnel_channel->send_data.u.service_ip.service_id = service->id;
> - tunnel_channel->send_data.u.service_ip.virtual_ip.type =
> SPICE_TUNNEL_IP_TYPE_IPv4;
> -
> - red_channel_client_init_send_data(rcc, SPICE_MSG_TUNNEL_SERVICE_IP_MAP,
> item);
> - spice_marshaller_add_ref(m,
> (uint8_t*)&tunnel_channel->send_data.u.service_ip,
> - sizeof(SpiceMsgTunnelServiceIpMap));
> - spice_marshaller_add_ref(m, (uint8_t*)&service->virt_ip.s_addr,
> sizeof(SpiceTunnelIPv4));
> -}
> -
> -static void tunnel_channel_marshall_socket_open(RedChannelClient *rcc,
> SpiceMarshaller *m, PipeItem *item)
> -{
> - TunnelChannelClient *tunnel_channel;
> - RedSocketOutData *sckt_out_data = SPICE_CONTAINEROF(item,
> RedSocketOutData, status_pipe_item);
> - RedSocket *sckt = SPICE_CONTAINEROF(sckt_out_data, RedSocket, out_data);
> -
> - tunnel_channel = SPICE_CONTAINEROF(rcc->channel, TunnelChannelClient,
> base);
> - tunnel_channel->send_data.u.socket_open.connection_id =
> sckt->connection_id;
> - tunnel_channel->send_data.u.socket_open.service_id =
> sckt->far_service->id;
> - tunnel_channel->send_data.u.socket_open.tokens = SOCKET_WINDOW_SIZE;
> -
> - sckt->in_data.client_total_num_tokens = SOCKET_WINDOW_SIZE;
> - sckt->in_data.num_tokens = 0;
> - red_channel_client_init_send_data(rcc, SPICE_MSG_TUNNEL_SOCKET_OPEN,
> item);
> - spice_marshaller_add_ref(m,
> (uint8_t*)&tunnel_channel->send_data.u.socket_open,
> - sizeof(tunnel_channel->send_data.u.socket_open));
> -#ifdef DEBUG_NETWORK
> - PRINT_SCKT(sckt);
> -#endif
> -}
> -
> -static void tunnel_channel_marshall_socket_fin(RedChannelClient *rcc,
> SpiceMarshaller *m, PipeItem *item)
> -{
> - TunnelChannelClient *tunnel_channel;
> - RedSocketOutData *sckt_out_data = SPICE_CONTAINEROF(item,
> RedSocketOutData, status_pipe_item);
> - RedSocket *sckt = SPICE_CONTAINEROF(sckt_out_data, RedSocket, out_data);
> -
> - spice_assert(!sckt->out_data.ready_chunks_queue.head);
> -
> - tunnel_channel = SPICE_CONTAINEROF(rcc->channel, TunnelChannelClient,
> base);
> - if (sckt->out_data.process_queue->head) {
> - spice_printerr("socket sent FIN but there are still buffers in
> outgoing process queue"
> - "(local_port=%d, service_id=%d)",
> - ntohs(sckt->local_port), sckt->far_service->id);
> - }
> -
> - tunnel_channel->send_data.u.socket_fin.connection_id =
> sckt->connection_id;
> -
> - red_channel_client_init_send_data(rcc, SPICE_MSG_TUNNEL_SOCKET_FIN,
> item);
> - spice_marshaller_add_ref(m,
> (uint8_t*)&tunnel_channel->send_data.u.socket_fin,
> - sizeof(tunnel_channel->send_data.u.socket_fin));
> -#ifdef DEBUG_NETWORK
> - PRINT_SCKT(sckt);
> -#endif
> -}
> -
> -static void tunnel_channel_marshall_socket_close(RedChannelClient *rcc,
> SpiceMarshaller *m, PipeItem *item)
> -{
> - TunnelChannelClient *tunnel_channel;
> - RedSocketOutData *sckt_out_data = SPICE_CONTAINEROF(item,
> RedSocketOutData, status_pipe_item);
> - RedSocket *sckt = SPICE_CONTAINEROF(sckt_out_data, RedSocket, out_data);
> -
> - tunnel_channel = SPICE_CONTAINEROF(rcc->channel, TunnelChannelClient,
> base);
> - // can happen when it is a forced close
> - if (sckt->out_data.ready_chunks_queue.head) {
> - spice_printerr("socket closed but there are still buffers in
> outgoing ready queue"
> - "(local_port=%d, service_id=%d)",
> - ntohs(sckt->local_port),
> - sckt->far_service->id);
> - }
> -
> - if (sckt->out_data.process_queue->head) {
> - spice_printerr("socket closed but there are still buffers in
> outgoing process queue"
> - "(local_port=%d, service_id=%d)",
> - ntohs(sckt->local_port), sckt->far_service->id);
> - }
> -
> - tunnel_channel->send_data.u.socket_close.connection_id =
> sckt->connection_id;
> -
> - red_channel_client_init_send_data(rcc, SPICE_MSG_TUNNEL_SOCKET_CLOSE,
> item);
> - spice_marshaller_add_ref(m,
> (uint8_t*)&tunnel_channel->send_data.u.socket_close,
> - sizeof(tunnel_channel->send_data.u.socket_close));
> -#ifdef DEBUG_NETWORK
> - PRINT_SCKT(sckt);
> -#endif
> -}
> -
> -static void tunnel_channel_marshall_socket_closed_ack(RedChannelClient *rcc,
> SpiceMarshaller *m, PipeItem *item)
> -{
> - TunnelChannelClient *tunnel_channel;
> - RedSocketOutData *sckt_out_data = SPICE_CONTAINEROF(item,
> RedSocketOutData, status_pipe_item);
> - RedSocket *sckt = SPICE_CONTAINEROF(sckt_out_data, RedSocket, out_data);
> -
> - tunnel_channel = SPICE_CONTAINEROF(rcc->channel, TunnelChannelClient,
> base);
> - tunnel_channel->send_data.u.socket_close_ack.connection_id =
> sckt->connection_id;
> -
> - // pipe item is null because we free the sckt.
> - red_channel_client_init_send_data(rcc,
> SPICE_MSG_TUNNEL_SOCKET_CLOSED_ACK, NULL);
> - spice_marshaller_add_ref(m,
> (uint8_t*)&tunnel_channel->send_data.u.socket_close_ack,
> -
> sizeof(tunnel_channel->send_data.u.socket_close_ack));
> -#ifdef DEBUG_NETWORK
> - PRINT_SCKT(sckt);
> -#endif
> -
> - spice_assert(sckt->client_waits_close_ack && (sckt->client_status ==
> CLIENT_SCKT_STATUS_CLOSED));
> - tunnel_worker_free_socket(tunnel_channel->worker, sckt);
> - if (CHECK_TUNNEL_ERROR(tunnel_channel)) {
> - tunnel_shutdown(tunnel_channel->worker);
> - }
> -}
> -
> -static void tunnel_channel_marshall_socket_token(RedChannelClient *rcc,
> SpiceMarshaller *m, PipeItem *item)
> -{
> - TunnelChannelClient *tunnel_channel;
> - RedSocketOutData *sckt_out_data = SPICE_CONTAINEROF(item,
> RedSocketOutData, token_pipe_item);
> - RedSocket *sckt = SPICE_CONTAINEROF(sckt_out_data, RedSocket, out_data);
> -
> - /* notice that the num of tokens sent can be > SOCKET_TOKENS_TO_SEND,
> since
> - the sending is performed after the pipe item was pushed */
> -
> - tunnel_channel = SPICE_CONTAINEROF(rcc->channel, TunnelChannelClient,
> base);
> - tunnel_channel->send_data.u.socket_token.connection_id =
> sckt->connection_id;
> -
> - if (sckt->in_data.num_tokens > 0) {
> - tunnel_channel->send_data.u.socket_token.num_tokens =
> sckt->in_data.num_tokens;
> - } else {
> - spice_assert(!sckt->in_data.client_total_num_tokens &&
> !sckt->in_data.ready_chunks_queue.head);
> - tunnel_channel->send_data.u.socket_token.num_tokens =
> SOCKET_TOKENS_TO_SEND_FOR_PROCESS;
> - }
> - sckt->in_data.num_tokens -=
> tunnel_channel->send_data.u.socket_token.num_tokens;
> - sckt->in_data.client_total_num_tokens +=
> tunnel_channel->send_data.u.socket_token.num_tokens;
> - spice_assert(sckt->in_data.client_total_num_tokens <=
> SOCKET_WINDOW_SIZE);
> -
> - red_channel_client_init_send_data(rcc, SPICE_MSG_TUNNEL_SOCKET_TOKEN,
> item);
> - spice_marshaller_add_ref(m,
> (uint8_t*)&tunnel_channel->send_data.u.socket_token,
> - sizeof(tunnel_channel->send_data.u.socket_token));
> -}
> -
> -static void tunnel_channel_marshall_socket_out_data(RedChannelClient *rcc,
> SpiceMarshaller *m, PipeItem *item)
> -{
> - TunnelChannelClient *tunnel_channel;
> - tunnel_channel = SPICE_CONTAINEROF(rcc->channel, TunnelChannelClient,
> base);
> - RedSocketOutData *sckt_out_data = SPICE_CONTAINEROF(item,
> RedSocketOutData, data_pipe_item);
> - RedSocket *sckt = SPICE_CONTAINEROF(sckt_out_data, RedSocket, out_data);
> - ReadyTunneledChunk *chunk;
> - uint32_t total_push_size = 0;
> - uint32_t pushed_bufs_num = 0;
> -
> - spice_assert(!sckt->pushed_close);
> - if (sckt->client_status == CLIENT_SCKT_STATUS_CLOSED) {
> - return;
> - }
> -
> - if (!sckt->out_data.num_tokens) {
> - return; // only when an we will receive tokens, data will be sent
> again.
> - }
> -
> - spice_assert(sckt->out_data.ready_chunks_queue.head);
> - spice_assert(!sckt->out_data.push_tail);
> - spice_assert(sckt->out_data.ready_chunks_queue.head->size <=
> MAX_SOCKET_DATA_SIZE);
> -
> - tunnel_channel->send_data.u.socket_data.connection_id =
> sckt->connection_id;
> -
> - red_channel_client_init_send_data(rcc, SPICE_MSG_TUNNEL_SOCKET_DATA,
> item);
> - spice_marshaller_add_ref(m,
> (uint8_t*)&tunnel_channel->send_data.u.socket_data,
> - sizeof(tunnel_channel->send_data.u.socket_data));
> - pushed_bufs_num++;
> -
> - // the first chunk is in a valid size
> - chunk = sckt->out_data.ready_chunks_queue.head;
> - total_push_size = chunk->size -
> sckt->out_data.ready_chunks_queue.offset;
> - spice_marshaller_add_ref(m, (uint8_t*)chunk->data +
> sckt->out_data.ready_chunks_queue.offset,
> - total_push_size);
> - pushed_bufs_num++;
> - sckt->out_data.push_tail = chunk;
> - sckt->out_data.push_tail_size = chunk->size; // all the chunk was sent
> -
> - chunk = chunk->next;
> -
> - while (chunk && (total_push_size < MAX_SOCKET_DATA_SIZE) &&
> (pushed_bufs_num < MAX_SEND_BUFS)) {
> - uint32_t cur_push_size = MIN(chunk->size, MAX_SOCKET_DATA_SIZE -
> total_push_size);
> - spice_marshaller_add_ref(m, (uint8_t*)chunk->data, cur_push_size);
> - pushed_bufs_num++;
> -
> - sckt->out_data.push_tail = chunk;
> - sckt->out_data.push_tail_size = cur_push_size;
> - total_push_size += cur_push_size;
> -
> - chunk = chunk->next;
> - }
> -
> - sckt->out_data.num_tokens--;
> -}
> -
> -static void tunnel_worker_release_socket_out_data(TunnelWorker *worker,
> PipeItem *item)
> -{
> - RedSocketOutData *sckt_out_data = SPICE_CONTAINEROF(item,
> RedSocketOutData, data_pipe_item);
> - RedSocket *sckt = SPICE_CONTAINEROF(sckt_out_data, RedSocket, out_data);
> -
> - spice_assert(sckt_out_data->ready_chunks_queue.head);
> -
> - while (sckt_out_data->ready_chunks_queue.head !=
> sckt_out_data->push_tail) {
> - sckt_out_data->data_size -=
> sckt_out_data->ready_chunks_queue.head->size;
> - ready_queue_pop_chunk(&sckt_out_data->ready_chunks_queue);
> - }
> -
> - sckt_out_data->data_size -= sckt_out_data->push_tail_size;
> -
> - // compensation. was subtracted in the previous lines
> - sckt_out_data->data_size += sckt_out_data->ready_chunks_queue.offset;
> -
> - if (sckt_out_data->push_tail_size == sckt_out_data->push_tail->size) {
> - ready_queue_pop_chunk(&sckt_out_data->ready_chunks_queue);
> - sckt_out_data->ready_chunks_queue.offset = 0;
> - } else {
> - sckt_out_data->ready_chunks_queue.offset =
> sckt_out_data->push_tail_size;
> - }
> -
> - sckt_out_data->push_tail = NULL;
> - sckt_out_data->push_tail_size = 0;
> -
> - if (worker->channel_client) {
> - // can still send data to socket
> - if (__client_socket_can_receive(sckt)) {
> - if (sckt_out_data->ready_chunks_queue.head) {
> - // the pipe item may already be linked, if for example the
> send was
> - // blocked and before it finished and called release,
> tunnel_socket_send was called
> - if (!red_channel_client_pipe_item_is_linked(
> - &worker->channel_client->base,
> &sckt_out_data->data_pipe_item)) {
> - sckt_out_data->data_pipe_item.type =
> PIPE_ITEM_TYPE_SOCKET_DATA;
> -
> red_channel_client_pipe_add(&worker->channel_client->base,
> &sckt_out_data->data_pipe_item);
> - }
> - } else if ((sckt->slirp_status ==
> SLIRP_SCKT_STATUS_SHUTDOWN_SEND) ||
> - (sckt->slirp_status == SLIRP_SCKT_STATUS_WAIT_CLOSE))
> {
> - __tunnel_socket_add_fin_to_pipe(worker->channel_client,
> sckt);
> - } else if (sckt->slirp_status == SLIRP_SCKT_STATUS_CLOSED) {
> - __tunnel_socket_add_close_to_pipe(worker->channel_client,
> sckt);
> - }
> - }
> - }
> -
> -
> - if (((sckt->slirp_status == SLIRP_SCKT_STATUS_OPEN) ||
> - (sckt->slirp_status == SLIRP_SCKT_STATUS_SHUTDOWN_RECV)) &&
> - !sckt->in_slirp_send && !worker->channel_client->mig_inprogress) {
> - // for cases that slirp couldn't write whole it data to our socket
> buffer
> - net_slirp_socket_can_send_notify(sckt->slirp_sckt);
> - }
> -}
> -
> -static void tunnel_channel_send_item(RedChannelClient *rcc, PipeItem *item)
> -{
> - SpiceMarshaller *m = red_channel_client_get_marshaller(rcc);
> -
> - switch (item->type) {
> - case PIPE_ITEM_TYPE_TUNNEL_INIT:
> - tunnel_channel_marshall_init(rcc, m, item);
> - break;
> - case PIPE_ITEM_TYPE_SERVICE_IP_MAP:
> - tunnel_channel_marshall_service_ip_map(rcc, m, item);
> - break;
> - case PIPE_ITEM_TYPE_SOCKET_OPEN:
> - tunnel_channel_marshall_socket_open(rcc, m, item);
> - break;
> - case PIPE_ITEM_TYPE_SOCKET_DATA:
> - tunnel_channel_marshall_socket_out_data(rcc, m, item);
> - break;
> - case PIPE_ITEM_TYPE_SOCKET_FIN:
> - tunnel_channel_marshall_socket_fin(rcc, m, item);
> - break;
> - case PIPE_ITEM_TYPE_SOCKET_CLOSE:
> - tunnel_channel_marshall_socket_close(rcc, m, item);
> - break;
> - case PIPE_ITEM_TYPE_SOCKET_CLOSED_ACK:
> - tunnel_channel_marshall_socket_closed_ack(rcc, m, item);
> - break;
> - case PIPE_ITEM_TYPE_SOCKET_TOKEN:
> - tunnel_channel_marshall_socket_token(rcc, m, item);
> - break;
> - case PIPE_ITEM_TYPE_MIGRATE_DATA:
> - tunnel_channel_marshall_migrate_data(rcc, m, item);
> - break;
> - default:
> - spice_error("invalid pipe item type");
> - }
> - red_channel_client_begin_send_message(rcc);
> -}
> -
> -/* param item_pushed: distinguishes between a pipe item that was pushed for
> sending, and
> - a pipe item that is still in the pipe and is released due to
> disconnection.
> - see red_pipe_item_clear */
> -static void tunnel_channel_release_pipe_item(RedChannelClient *rcc, PipeItem
> *item, int item_pushed)
> -{
> - if (!item) { // e.g. when acking closed socket
> - return;
> - }
> - switch (item->type) {
> - case PIPE_ITEM_TYPE_TUNNEL_INIT:
> - free(item);
> - break;
> - case PIPE_ITEM_TYPE_SERVICE_IP_MAP:
> - case PIPE_ITEM_TYPE_SOCKET_OPEN:
> - case PIPE_ITEM_TYPE_SOCKET_CLOSE:
> - case PIPE_ITEM_TYPE_SOCKET_FIN:
> - case PIPE_ITEM_TYPE_SOCKET_TOKEN:
> - break;
> - case PIPE_ITEM_TYPE_SOCKET_DATA:
> - if (item_pushed) {
> - tunnel_worker_release_socket_out_data(
> - SPICE_CONTAINEROF(rcc, TunnelChannelClient, base)->worker,
> item);
> - }
> - break;
> - case PIPE_ITEM_TYPE_MIGRATE:
> - free(item);
> - break;
> - case PIPE_ITEM_TYPE_MIGRATE_DATA:
> - release_migrate_item((TunnelMigrateItem *)item);
> - break;
> - default:
> - spice_error("invalid pipe item type");
> - }
> -}
> -
> -/***********************************************************
> -* interface for slirp
> -************************************************************/
> -
> -static int qemu_can_output(SlirpUsrNetworkInterface *usr_interface)
> -{
> - TunnelWorker *worker = ((RedSlirpNetworkInterface
> *)usr_interface)->worker;
> - return worker->sif->can_send_packet(worker->sin);
> -}
> -
> -static void qemu_output(SlirpUsrNetworkInterface *usr_interface, const
> uint8_t *pkt, int pkt_len)
> -{
> - TunnelWorker *worker = ((RedSlirpNetworkInterface
> *)usr_interface)->worker;
> - worker->sif->send_packet(worker->sin, pkt, pkt_len);
> -}
> -
> -static int null_tunnel_socket_connect(SlirpUsrNetworkInterface
> *usr_interface,
> - struct in_addr src_addr, uint16_t
> src_port,
> - struct in_addr dst_addr, uint16_t
> dst_port,
> - SlirpSocket *slirp_s, UserSocket
> **o_usr_s)
> -{
> - errno = ENETUNREACH;
> - return -1;
> -}
> -
> -static int tunnel_socket_connect(SlirpUsrNetworkInterface *usr_interface,
> - struct in_addr src_addr, uint16_t src_port,
> - struct in_addr dst_addr, uint16_t dst_port,
> - SlirpSocket *slirp_s, UserSocket **o_usr_s)
> -{
> - TunnelWorker *worker;
> - RedSocket *sckt;
> - TunnelService *far_service;
> -
> - spice_assert(usr_interface);
> -
> -#ifdef DEBUG_NETWORK
> - spice_printerr("TUNNEL_DBG");
> -#endif
> - worker = ((RedSlirpNetworkInterface *)usr_interface)->worker;
> - spice_assert(worker->channel_client);
> - spice_assert(!worker->channel_client->mig_inprogress);
> -
> - far_service = tunnel_worker_find_service_by_addr(worker, &dst_addr,
> (uint32_t)ntohs(dst_port));
> -
> - if (!far_service) {
> - errno = EADDRNOTAVAIL;
> - return -1;
> - }
> -
> - if (tunnel_worker_find_socket(worker, src_port, far_service->id)) {
> - spice_printerr("slirp tried to open a socket that is still opened");
> - errno = EADDRINUSE;
> - return -1;
> - }
> -
> - if (worker->num_sockets == MAX_SOCKETS_NUM) {
> - spice_printerr("number of tunneled sockets exceeds the limit");
> - errno = ENFILE;
> - return -1;
> - }
> -
> - sckt = tunnel_worker_create_socket(worker, src_port, far_service,
> slirp_s);
> -
> -#ifdef DEBUG_NETWORK
> - PRINT_SCKT(sckt);
> -#endif
> - *o_usr_s = sckt;
> - sckt->out_data.status_pipe_item.type = PIPE_ITEM_TYPE_SOCKET_OPEN;
> - red_channel_client_pipe_add(&worker->channel_client->base,
> &sckt->out_data.status_pipe_item);
> -
> - errno = EINPROGRESS;
> - return -1;
> -}
> -
> -static int null_tunnel_socket_send(SlirpUsrNetworkInterface *usr_interface,
> UserSocket *opaque,
> - uint8_t *buf, size_t len, uint8_t urgent)
> -{
> - errno = ECONNRESET;
> - return -1;
> -}
> -
> -static int tunnel_socket_send(SlirpUsrNetworkInterface *usr_interface,
> UserSocket *opaque,
> - uint8_t *buf, size_t len, uint8_t urgent)
> -{
> - TunnelWorker *worker;
> - RedSocket *sckt;
> - size_t size_to_send;
> -
> - spice_assert(usr_interface);
> - spice_assert(opaque);
> -
> - worker = ((RedSlirpNetworkInterface *)usr_interface)->worker;
> -
> - spice_assert(!worker->channel_client->mig_inprogress);
> -
> - sckt = (RedSocket *)opaque;
> -
> - if (sckt->slirp_status == SLIRP_SCKT_STATUS_DELAY_ABORT) {
> - errno = EAGAIN;
> - return -1;
> - }
> -
> - if ((sckt->client_status != CLIENT_SCKT_STATUS_OPEN) &&
> - (sckt->client_status != CLIENT_SCKT_STATUS_SHUTDOWN_SEND)) {
> - spice_printerr("client socket is unable to receive data");
> - errno = ECONNRESET;
> - return -1;
> - }
> -
> -
> - if ((sckt->slirp_status == SLIRP_SCKT_STATUS_SHUTDOWN_SEND) ||
> - (sckt->slirp_status == SLIRP_SCKT_STATUS_WAIT_CLOSE)) {
> - spice_printerr("send was shutdown");
> - errno = EPIPE;
> - return -1;
> - }
> -
> - if (urgent) {
> - SET_TUNNEL_ERROR(worker->channel_client, "urgent msgs not
> supported");
> - tunnel_shutdown(worker);
> - errno = ECONNRESET;
> - return -1;
> - }
> -
> - sckt->in_slirp_send = TRUE;
> -
> - if (sckt->out_data.data_size < (sckt->out_data.window_size) *
> MAX_SOCKET_DATA_SIZE) {
> - // the current data in the queues doesn't fill all the tokens
> - size_to_send = len;
> - } else {
> - if (sckt->out_data.ready_chunks_queue.head) {
> - // there are no tokens for future data, but once the data will
> be sent
> - // and buffers will be released, we will try to send again.
> - size_to_send = 0;
> - } else {
> - spice_assert(sckt->out_data.process_queue->head);
> - if ((sckt->out_data.data_size + len) >
> - (MAX_SOCKET_OUT_BUFFERS *
> MAX_SOCKET_DATA_SIZE)) {
> - spice_printerr("socket out buffers overflow, socket will be
> closed"
> - " (local_port=%d, service_id=%d)",
> - ntohs(sckt->local_port), sckt->far_service->id);
> - tunnel_socket_force_close(worker->channel_client, sckt);
> - size_to_send = 0;
> - } else {
> - size_to_send = len;
> - }
> - }
> - }
> -
> - if (size_to_send) {
> - process_queue_append(sckt->out_data.process_queue, buf,
> size_to_send);
> - sckt->out_data.data_size += size_to_send;
> -
> - if (sckt->out_data.ready_chunks_queue.head &&
> -
> !red_channel_client_pipe_item_is_linked(&worker->channel_client->base,
> -
> &sckt->out_data.data_pipe_item))
> {
> - sckt->out_data.data_pipe_item.type = PIPE_ITEM_TYPE_SOCKET_DATA;
> - red_channel_client_pipe_add(&worker->channel_client->base,
> &sckt->out_data.data_pipe_item);
> - }
> - }
> -
> - sckt->in_slirp_send = FALSE;
> -
> - if (!size_to_send) {
> - errno = EAGAIN;
> - return -1;
> - } else {
> - return size_to_send;
> - }
> -}
> -
> -static inline int __should_send_fin_to_guest(RedSocket *sckt)
> -{
> - return (((sckt->client_status == CLIENT_SCKT_STATUS_SHUTDOWN_SEND) ||
> - ((sckt->client_status == CLIENT_SCKT_STATUS_CLOSED) &&
> - (sckt->slirp_status == SLIRP_SCKT_STATUS_SHUTDOWN_SEND))) &&
> - !sckt->in_data.ready_chunks_queue.head);
> -}
> -
> -static int null_tunnel_socket_recv(SlirpUsrNetworkInterface *usr_interface,
> UserSocket *opaque,
> - uint8_t *buf, size_t len)
> -{
> - errno = ECONNRESET;
> - return -1;
> -}
> -
> -static int tunnel_socket_recv(SlirpUsrNetworkInterface *usr_interface,
> UserSocket *opaque,
> - uint8_t *buf, size_t len)
> -{
> - TunnelWorker *worker;
> - RedSocket *sckt;
> - int copied = 0;
> -
> - spice_assert(usr_interface);
> - spice_assert(opaque);
> - worker = ((RedSlirpNetworkInterface *)usr_interface)->worker;
> -
> - spice_assert(!worker->channel_client->mig_inprogress);
> -
> - sckt = (RedSocket *)opaque;
> -
> - if (sckt->slirp_status == SLIRP_SCKT_STATUS_DELAY_ABORT) {
> - errno = EAGAIN;
> - return -1;
> - }
> -
> - if ((sckt->slirp_status == SLIRP_SCKT_STATUS_SHUTDOWN_RECV) ||
> - (sckt->slirp_status == SLIRP_SCKT_STATUS_WAIT_CLOSE)) {
> - SET_TUNNEL_ERROR(worker->channel_client, "receive was shutdown");
> - tunnel_shutdown(worker);
> - errno = ECONNRESET;
> - return -1;
> - }
> -
> - if (sckt->slirp_status == SLIRP_SCKT_STATUS_CLOSED) {
> - SET_TUNNEL_ERROR(worker->channel_client, "slirp socket not
> connected");
> - tunnel_shutdown(worker);
> - errno = ECONNRESET;
> - return -1;
> - }
> -
> - spice_assert((sckt->client_status == CLIENT_SCKT_STATUS_OPEN) ||
> - (sckt->client_status == CLIENT_SCKT_STATUS_SHUTDOWN_SEND) ||
> - ((sckt->client_status == CLIENT_SCKT_STATUS_CLOSED) &&
> - (sckt->slirp_status == SLIRP_SCKT_STATUS_SHUTDOWN_SEND)));
> -
> -
> - // if there is data in ready queue, when it is acked, slirp will call
> recv and get 0
> - if (__should_send_fin_to_guest(sckt)) {
> - if (sckt->in_data.process_queue->head) {
> - spice_printerr("client socket sent FIN but there are still
> buffers in incoming process"
> - "queue (local_port=%d, service_id=%d)",
> - ntohs(sckt->local_port), sckt->far_service->id);
> - }
> - return 0; // slirp will call shutdown recv now and it will also send
> FIN to the guest.
> - }
> -
> - while (sckt->in_data.ready_chunks_queue.head && (copied < len)) {
> - ReadyTunneledChunk *cur_chunk =
> sckt->in_data.ready_chunks_queue.head;
> - int copy_count = MIN(cur_chunk->size -
> sckt->in_data.ready_chunks_queue.offset,
> - len - copied);
> -
> - memcpy(buf + copied, cur_chunk->data +
> sckt->in_data.ready_chunks_queue.offset, copy_count);
> - copied += copy_count;
> - if ((sckt->in_data.ready_chunks_queue.offset + copy_count) ==
> cur_chunk->size) {
> - ready_queue_pop_chunk(&sckt->in_data.ready_chunks_queue);
> - sckt->in_data.ready_chunks_queue.offset = 0;
> - } else {
> - spice_assert(copied == len);
> - sckt->in_data.ready_chunks_queue.offset += copy_count;
> - }
> - }
> -
> - if (!copied) {
> - errno = EAGAIN;
> - return -1;
> - } else {
> - return copied;
> - }
> -}
> -
> -static void null_tunnel_socket_shutdown_send(SlirpUsrNetworkInterface
> *usr_interface,
> - UserSocket *opaque)
> -{
> -}
> -
> -// can be called : 1) when a FIN is requested from the guest 2) after
> shutdown rcv that was called
> -// after received failed because the client socket was sent
> FIN
> -static void tunnel_socket_shutdown_send(SlirpUsrNetworkInterface
> *usr_interface, UserSocket *opaque)
> -{
> - TunnelWorker *worker;
> - RedSocket *sckt;
> -
> - spice_assert(usr_interface);
> - spice_assert(opaque);
> - worker = ((RedSlirpNetworkInterface *)usr_interface)->worker;
> - sckt = (RedSocket *)opaque;
> -
> -#ifdef DEBUG_NETWORK
> - PRINT_SCKT(sckt);
> -#endif
> - spice_assert(!worker->channel_client->mig_inprogress);
> -
> - if (sckt->slirp_status == SLIRP_SCKT_STATUS_DELAY_ABORT) {
> - return;
> - }
> -
> - if (sckt->slirp_status == SLIRP_SCKT_STATUS_OPEN) {
> - sckt->slirp_status = SLIRP_SCKT_STATUS_SHUTDOWN_SEND;
> - } else if (sckt->slirp_status == SLIRP_SCKT_STATUS_SHUTDOWN_RECV) {
> - spice_assert(sckt->client_status ==
> CLIENT_SCKT_STATUS_SHUTDOWN_SEND);
> - sckt->slirp_status = SLIRP_SCKT_STATUS_WAIT_CLOSE;
> - } else {
> - SET_TUNNEL_ERROR(worker->channel_client, "unexpected
> tunnel_socket_shutdown_send slirp_status=%d",
> - sckt->slirp_status);
> - tunnel_shutdown(worker);
> - return;
> - }
> -
> - if ((sckt->client_status == CLIENT_SCKT_STATUS_OPEN) ||
> - (sckt->client_status == CLIENT_SCKT_STATUS_SHUTDOWN_SEND)) {
> - // check if there is still data to send. the fin will be sent after
> data is released
> - // channel is alive, otherwise the sockets would have been aborted
> - if (!sckt->out_data.ready_chunks_queue.head) {
> - __tunnel_socket_add_fin_to_pipe(worker->channel_client, sckt);
> - }
> - } else { // if client is closed, it means the connection was aborted
> since we didn't
> - // received fin from guest
> - SET_TUNNEL_ERROR(worker->channel_client,
> - "unexpected tunnel_socket_shutdown_send
> client_status=%d",
> - sckt->client_status);
> - tunnel_shutdown(worker);
> - }
> -}
> -
> -static void null_tunnel_socket_shutdown_recv(SlirpUsrNetworkInterface
> *usr_interface,
> - UserSocket *opaque)
> -{
> -}
> -
> -static void tunnel_socket_shutdown_recv(SlirpUsrNetworkInterface
> *usr_interface, UserSocket *opaque)
> -{
> - TunnelWorker *worker;
> - RedSocket *sckt;
> -
> - spice_assert(usr_interface);
> - spice_assert(opaque);
> - worker = ((RedSlirpNetworkInterface *)usr_interface)->worker;
> - sckt = (RedSocket *)opaque;
> -
> -#ifdef DEBUG_NETWORK
> - PRINT_SCKT(sckt);
> -#endif
> - spice_assert(!worker->channel_client->mig_inprogress);
> -
> - /* failure in recv can happen after the client sckt was shutdown
> - (after client sent FIN, or after slirp sent FIN and client socket was
> closed */
> - if (!__should_send_fin_to_guest(sckt)) {
> - SET_TUNNEL_ERROR(worker->channel_client,
> - "unexpected tunnel_socket_shutdown_recv
> client_status=%d slirp_status=%d",
> - sckt->client_status, sckt->slirp_status);
> - tunnel_shutdown(worker);
> - return;
> - }
> -
> - if (sckt->slirp_status == SLIRP_SCKT_STATUS_OPEN) {
> - sckt->slirp_status = SLIRP_SCKT_STATUS_SHUTDOWN_RECV;
> - } else if (sckt->slirp_status == SLIRP_SCKT_STATUS_SHUTDOWN_SEND) {
> - sckt->slirp_status = SLIRP_SCKT_STATUS_WAIT_CLOSE;
> - } else {
> - SET_TUNNEL_ERROR(worker->channel_client,
> - "unexpected tunnel_socket_shutdown_recv
> slirp_status=%d",
> - sckt->slirp_status);
> - tunnel_shutdown(worker);
> - }
> -}
> -
> -static void null_tunnel_socket_close(SlirpUsrNetworkInterface
> *usr_interface, UserSocket *opaque)
> -{
> - TunnelWorker *worker;
> - RedSocket *sckt;
> -
> - spice_assert(usr_interface);
> - spice_assert(opaque);
> -
> - worker = ((RedSlirpNetworkInterface *)usr_interface)->worker;
> -
> - sckt = (RedSocket *)opaque;
> -#ifdef DEBUG_NETWORK
> - PRINT_SCKT(sckt);
> -#endif
> - sckt->slirp_status = SLIRP_SCKT_STATUS_CLOSED;
> -
> - if (sckt->client_status == CLIENT_SCKT_STATUS_CLOSED) {
> - tunnel_worker_free_socket(worker, sckt);
> - } // else, it will be closed when disconnect will be called (because
> this callback is
> - // set if the channel is disconnect or when we are in the middle of
> disconnection that
> - // was caused by an error
> -}
> -
> -// can be called during migration due to the channel disconnect. But it does
> not affect the
> -// migrate data
> -static void tunnel_socket_close(SlirpUsrNetworkInterface *usr_interface,
> UserSocket *opaque)
> -{
> - TunnelWorker *worker;
> - RedSocket *sckt;
> -
> - spice_assert(usr_interface);
> - spice_assert(opaque);
> -
> - worker = ((RedSlirpNetworkInterface *)usr_interface)->worker;
> -
> - sckt = (RedSocket *)opaque;
> -
> -#ifdef DEBUG_NETWORK
> - PRINT_SCKT(sckt);
> -#endif
> -
> - sckt->slirp_status = SLIRP_SCKT_STATUS_CLOSED;
> -
> - // if sckt is not opened yet, close will be sent when we receive connect
> ack
> - if ((sckt->client_status == CLIENT_SCKT_STATUS_OPEN) ||
> - (sckt->client_status == CLIENT_SCKT_STATUS_SHUTDOWN_SEND)) {
> - // check if there is still data to send. the close will be sent
> after data is released.
> - // close may already been pushed if it is a forced close
> - if (!sckt->out_data.ready_chunks_queue.head && !sckt->pushed_close)
> {
> - __tunnel_socket_add_close_to_pipe(worker->channel_client, sckt);
> - }
> - } else if (sckt->client_status == CLIENT_SCKT_STATUS_CLOSED) {
> - if (sckt->client_waits_close_ack) {
> - __tunnel_socket_add_close_ack_to_pipe(worker->channel_client,
> sckt);
> - } else {
> - tunnel_worker_free_socket(worker, sckt);
> - }
> - }
> -}
> -
> -static UserTimer *create_timer(SlirpUsrNetworkInterface *usr_interface,
> - timer_proc_t proc, void *opaque)
> -{
> - TunnelWorker *worker;
> -
> - spice_assert(usr_interface);
> -
> - worker = ((RedSlirpNetworkInterface *)usr_interface)->worker;
> -
> - return (void *)worker->core_interface->timer_add(proc, opaque);
> -}
> -
> -static void arm_timer(SlirpUsrNetworkInterface *usr_interface, UserTimer
> *timer, uint32_t ms)
> -{
> - TunnelWorker *worker;
> -
> - spice_assert(usr_interface);
> -
> - worker = ((RedSlirpNetworkInterface *)usr_interface)->worker;
> -#ifdef DEBUG_NETWORK
> - if (!worker->channel_client) {
> - spice_printerr("channel not connected");
> - }
> -#endif
> - if (worker->channel_client && worker->channel_client->mig_inprogress) {
> - SET_TUNNEL_ERROR(worker->channel_client, "during migration");
> - tunnel_shutdown(worker);
> - return;
> - }
> -
> - worker->core_interface->timer_start((SpiceTimer*)timer, ms);
> -}
> -
> -/***********************************************
> -* channel interface and other related procedures
> -************************************************/
> -
> -static int tunnel_channel_config_socket(RedChannelClient *rcc)
> -{
> - int flags;
> - int delay_val;
> - RedsStream *stream = red_channel_client_get_stream(rcc);
> -
> - if ((flags = fcntl(stream->socket, F_GETFL)) == -1) {
> - spice_printerr("accept failed, %s", strerror(errno)); // can't we
> just use spice_error?
> - return FALSE;
> - }
> -
> - if (fcntl(stream->socket, F_SETFL, flags | O_NONBLOCK) == -1) {
> - spice_printerr("accept failed, %s", strerror(errno));
> - return FALSE;
> - }
> -
> - delay_val = 1;
> -
> - if (setsockopt(stream->socket, IPPROTO_TCP, TCP_NODELAY, &delay_val,
> - sizeof(delay_val)) == -1) {
> - if (errno != ENOTSUP) {
> - spice_printerr("setsockopt failed, %s", strerror(errno));
> - }
> - }
> -
> - return TRUE;
> -}
> -
> -static void tunnel_worker_disconnect_slirp(TunnelWorker *worker)
> -{
> - int i;
> -
> - net_slirp_set_net_interface(&worker->null_interface.base);
> - for (i = 0; i < MAX_SOCKETS_NUM; i++) {
> - RedSocket *sckt = worker->sockets + i;
> - if (sckt->allocated) {
> - sckt->client_status = CLIENT_SCKT_STATUS_CLOSED;
> - sckt->client_waits_close_ack = FALSE;
> - if (sckt->slirp_status == SLIRP_SCKT_STATUS_CLOSED) {
> - tunnel_worker_free_socket(worker, sckt);
> - } else {
> - sckt->slirp_status = SLIRP_SCKT_STATUS_WAIT_CLOSE;
> - net_slirp_socket_abort(sckt->slirp_sckt);
> - }
> - }
> - }
> -}
> -
> -/* don't call disconnect from functions that might be called by slirp
> - since it closes all its sockets and slirp is not aware of it */
> -static void tunnel_channel_on_disconnect(RedChannel *channel)
> -{
> - TunnelWorker *worker;
> - if (!channel) {
> - return;
> - }
> - spice_printerr("");
> - worker = (TunnelWorker *)channel->data;
> -
> - tunnel_worker_disconnect_slirp(worker);
> -
> - tunnel_worker_clear_routed_network(worker);
> - worker->channel_client = NULL;
> -}
> -
> -// TODO - not MC friendly, remove
> -static void tunnel_channel_client_on_disconnect(RedChannelClient *rcc)
> -{
> - tunnel_channel_on_disconnect(rcc->channel);
> -}
> -
> -/* interface for reds */
> -
> -static void on_new_tunnel_channel(TunnelChannelClient *tcc, int migration)
> -{
> - red_channel_client_push_set_ack(&tcc->base);
> -
> - if (!migration) {
> - red_channel_init_outgoing_messages_window(tcc->base.channel);
> - red_channel_client_pipe_add_type(&tcc->base,
> PIPE_ITEM_TYPE_TUNNEL_INIT);
> - }
> -}
> -
> -static void tunnel_channel_hold_pipe_item(RedChannelClient *rcc, PipeItem
> *item)
> -{
> -}
> -
> -static void handle_tunnel_channel_link(RedChannel *channel, RedClient
> *client,
> - RedsStream *stream, int migration,
> - int num_common_caps,
> - uint32_t *common_caps, int num_caps,
> - uint32_t *caps)
> -{
> - TunnelChannelClient *tcc;
> - TunnelWorker *worker = (TunnelWorker *)channel->data;
> -
> - if (worker->channel_client) {
> - spice_error("tunnel does not support multiple clients");
> - }
> -
> - tcc =
> (TunnelChannelClient*)red_channel_client_create(sizeof(TunnelChannelClient),
> - channel, client,
> stream, FALSE,
> - 0, NULL, 0, NULL);
> - if (!tcc) {
> - return;
> - }
> - tcc->worker = worker;
> - tcc->worker->channel_client = tcc;
> - net_slirp_set_net_interface(&worker->tunnel_interface.base);
> -
> - on_new_tunnel_channel(tcc, migration);
> -}
> -
> -static void handle_tunnel_channel_client_migrate(RedChannelClient *rcc)
> -{
> - TunnelChannelClient *tunnel_channel;
> -
> -#ifdef DEBUG_NETWORK
> - spice_printerr("TUNNEL_DBG: MIGRATE STARTED");
> -#endif
> - tunnel_channel = (TunnelChannelClient *)rcc;
> - spice_assert(tunnel_channel == tunnel_channel->worker->channel_client);
> - tunnel_channel->mig_inprogress = TRUE;
> - net_slirp_freeze();
> - red_channel_client_default_migrate(rcc);
> -}
> -
> -static void red_tunnel_channel_create(TunnelWorker *worker)
> -{
> - RedChannel *channel;
> - ChannelCbs channel_cbs = { NULL, };
> - ClientCbs client_cbs = { NULL, };
> -
> - channel_cbs.config_socket = tunnel_channel_config_socket;
> - channel_cbs.on_disconnect = tunnel_channel_client_on_disconnect;
> - channel_cbs.alloc_recv_buf = tunnel_channel_alloc_msg_rcv_buf;
> - channel_cbs.release_recv_buf = tunnel_channel_release_msg_rcv_buf;
> - channel_cbs.hold_item = tunnel_channel_hold_pipe_item;
> - channel_cbs.send_item = tunnel_channel_send_item;
> - channel_cbs.release_item = tunnel_channel_release_pipe_item;
> - channel_cbs.handle_migrate_flush_mark =
> tunnel_channel_handle_migrate_mark;
> - channel_cbs.handle_migrate_data = tunnel_channel_handle_migrate_data;
> - channel_cbs.handle_migrate_data_get_serial =
> tunnel_channel_handle_migrate_data_get_serial;
> -
> - channel = red_channel_create(sizeof(RedChannel),
> - worker->core_interface,
> - SPICE_CHANNEL_TUNNEL, 0,
> - TRUE,
> - tunnel_channel_handle_message,
> - &channel_cbs,
> - SPICE_MIGRATE_NEED_FLUSH |
> SPICE_MIGRATE_NEED_DATA_TRANSFER);
> - if (!channel) {
> - return;
> - }
> -
> - client_cbs.connect = handle_tunnel_channel_link;
> - client_cbs.migrate = handle_tunnel_channel_client_migrate;
> - red_channel_register_client_cbs(channel, &client_cbs);
> -
> - worker->channel = channel;
> - red_channel_set_data(channel, worker);
> - reds_register_channel(worker->channel);
> -}
> diff --git a/server/red_tunnel_worker.h b/server/red_tunnel_worker.h
> deleted file mode 100644
> index 3df4aea..0000000
> --- a/server/red_tunnel_worker.h
> +++ /dev/null
> @@ -1,27 +0,0 @@
> -/*
> - Copyright (C) 2009 Red Hat, Inc.
> -
> - This library is free software; you can redistribute it and/or
> - modify it under the terms of the GNU Lesser General Public
> - License as published by the Free Software Foundation; either
> - version 2.1 of the License, or (at your option) any later version.
> -
> - This library is distributed in the hope that it will be useful,
> - but WITHOUT ANY WARRANTY; without even the implied warranty of
> - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> - Lesser General Public License for more details.
> -
> - You should have received a copy of the GNU Lesser General Public
> - License along with this library; if not, see
> <http://www.gnu.org/licenses/>.
> -
> -
> - Author:
> - yhalperi at redhat.com
> -*/
> -
> -#ifndef _H_RED_TUNNEL_WORKER
> -#define _H_RED_TUNNEL_WORKER
> -
> -void *red_tunnel_attach(SpiceCoreInterface *core_interface,
> SpiceNetWireInstance *sin);
> -
> -#endif
> diff --git a/server/reds.c b/server/reds.c
> index a98b02b..892d247 100644
> --- a/server/reds.c
> +++ b/server/reds.c
> @@ -70,9 +70,6 @@
> #include "demarshallers.h"
> #include "char_device.h"
> #include "migration_protocol.h"
> -#ifdef USE_TUNNEL
> -#include "red_tunnel_worker.h"
> -#endif
> #ifdef USE_SMARTCARD
> #include "smartcard.h"
> #endif
> @@ -120,9 +117,6 @@ uint32_t streaming_video = STREAM_VIDEO_FILTER;
> spice_image_compression_t image_compression = SPICE_IMAGE_COMPRESS_AUTO_GLZ;
> spice_wan_compression_t jpeg_state = SPICE_WAN_COMPRESSION_AUTO;
> spice_wan_compression_t zlib_glz_state = SPICE_WAN_COMPRESSION_AUTO;
> -#ifdef USE_TUNNEL
> -void *red_tunnel = NULL;
> -#endif
> int agent_mouse = TRUE;
> int agent_copypaste = TRUE;
> int agent_file_xfer = TRUE;
> @@ -3782,25 +3776,8 @@ SPICE_GNUC_VISIBLE int
> spice_server_add_interface(SpiceServer *s,
> spice_server_char_device_add_interface(s, sin);
>
> } else if (strcmp(interface->type, SPICE_INTERFACE_NET_WIRE) == 0) {
> -#ifdef USE_TUNNEL
> - SpiceNetWireInstance *net;
> - spice_info("SPICE_INTERFACE_NET_WIRE");
> - if (red_tunnel) {
> - spice_warning("net wire already attached");
> - return -1;
> - }
> - if (interface->major_version != SPICE_INTERFACE_NET_WIRE_MAJOR ||
> - interface->minor_version > SPICE_INTERFACE_NET_WIRE_MINOR) {
> - spice_warning("unsupported net wire interface");
> - return -1;
> - }
> - net = SPICE_CONTAINEROF(sin, SpiceNetWireInstance, base);
> - net->st = spice_new0(SpiceNetWireState, 1);
> - red_tunnel = red_tunnel_attach(core, net);
> -#else
> spice_warning("unsupported net wire interface");
> return -1;
> -#endif
> } else if (strcmp(interface->type, SPICE_INTERFACE_MIGRATION) == 0) {
> spice_info("SPICE_INTERFACE_MIGRATION");
> if (migration_interface) {
> @@ -4205,9 +4182,6 @@ SPICE_GNUC_VISIBLE int
> spice_server_set_channel_security(SpiceServer *s, const c
> [ SPICE_CHANNEL_CURSOR ] = "cursor",
> [ SPICE_CHANNEL_PLAYBACK ] = "playback",
> [ SPICE_CHANNEL_RECORD ] = "record",
> -#ifdef USE_TUNNEL
> - [ SPICE_CHANNEL_TUNNEL ] = "tunnel",
> -#endif
> #ifdef USE_SMARTCARD
> [ SPICE_CHANNEL_SMARTCARD] = "smartcard",
> #endif
> --
> 1.8.3.1
>
> _______________________________________________
> Spice-devel mailing list
> Spice-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/spice-devel
>
More information about the Spice-devel
mailing list