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