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@xxxxxxxxxx > -*/ > -#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@xxxxxxxxxx > -*/ > - > -#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@xxxxxxxxxx > -*/ > -#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@xxxxxxxxxx > -*/ > - > -#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@xxxxxxxxxxxxxxxxxxxxx > http://lists.freedesktop.org/mailman/listinfo/spice-devel > _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/spice-devel