From 7187e2440f4cfeb3862908911436c41ea67d61a0 Mon Sep 17 00:00:00 2001 From: Andreas Date: Wed, 9 Jan 2013 17:38:24 +0100 Subject: [PATCH 1/3] removed base64 encoding --- src/networkremote/incomingdataparser.cpp | 5 +- src/networkremote/networkremote.cpp | 56 ++++++++++++++++++++--- src/networkremote/networkremote.h | 3 ++ src/networkremote/outgoingdatacreator.cpp | 10 +++- 4 files changed, 63 insertions(+), 11 deletions(-) diff --git a/src/networkremote/incomingdataparser.cpp b/src/networkremote/incomingdataparser.cpp index 3bd41f121..b0fe45e55 100644 --- a/src/networkremote/incomingdataparser.cpp +++ b/src/networkremote/incomingdataparser.cpp @@ -52,13 +52,12 @@ bool IncomingDataParser::close_connection() { return close_connection_; } -void IncomingDataParser::Parse(const QByteArray& b64_data) { +void IncomingDataParser::Parse(const QByteArray& data) { close_connection_ = false; - QByteArray pb_data = QByteArray::fromBase64(b64_data); // Parse the incoming data pb::remote::Message msg; - if (!msg.ParseFromArray(pb_data.constData(), pb_data.size())) { + if (!msg.ParseFromArray(data.constData(), data.size())) { qLog(Info) << "Couldn't parse data"; return; } diff --git a/src/networkremote/networkremote.cpp b/src/networkremote/networkremote.cpp index abb20938c..c3a6beaec 100644 --- a/src/networkremote/networkremote.cpp +++ b/src/networkremote/networkremote.cpp @@ -30,6 +30,7 @@ const int NetworkRemote::kDefaultServerPort = 5500; NetworkRemote::NetworkRemote(Application* app) : app_(app) { + buffer_.open(QIODevice::ReadWrite); } @@ -133,12 +134,55 @@ void NetworkRemote::AcceptConnection() { void NetworkRemote::IncomingData() { QTcpSocket* client = static_cast(QObject::sender()); - // Now read all the data from the socket - QByteArray data; - data = client->readAll(); - incoming_data_parser_->Parse(data); + while (client->bytesAvailable()) { + if (!reading_protobuf_) { + // Read the length of the next message + QDataStream s(client); + s >> expected_length_; - if (incoming_data_parser_->close_connection()) { - client->close(); + reading_protobuf_ = true; + } + + // Read some of the message + buffer_.write(client->read(expected_length_ - buffer_.size())); + + // Did we get everything? + if (buffer_.size() == expected_length_) { + // Parse the message + qLog(Debug) << "Parsing message"; + incoming_data_parser_->Parse(buffer_.data()); + + // Clear the buffer + buffer_.close(); + buffer_.setData(QByteArray()); + buffer_.open(QIODevice::ReadWrite); + reading_protobuf_ = false; + } } +/* + // Now read all the data from the socket + QDataStream s(client); + qint32 expected_length; + + while (client->bytesAvailable()) { + QBuffer buf; + buf.setData(); + buf.open(QIODevice::ReadWrite); + s >> expected_length; + + buf.write(client->read(expected_length - buf.size())); + qLog(Debug) << "Length:" << buf.size() << "/" << expected_length; + + + if (buf.size() == expected_length) { + qLog(Debug) << "Buf:" << buf.data(); + incoming_data_parser_->Parse(buf.data()); + } + + if (incoming_data_parser_->close_connection()) { + client->close(); + } + + buf.close(); + }*/ } diff --git a/src/networkremote/networkremote.h b/src/networkremote/networkremote.h index 381e2a1ad..e9eae1a6b 100644 --- a/src/networkremote/networkremote.h +++ b/src/networkremote/networkremote.h @@ -34,6 +34,9 @@ private: int port_; bool use_remote_; Application* app_; + bool reading_protobuf_; + quint32 expected_length_; + QBuffer buffer_; void StopServer(); void ReadSettings(); diff --git a/src/networkremote/outgoingdatacreator.cpp b/src/networkremote/outgoingdatacreator.cpp index fa5ac4599..b00e4bd27 100644 --- a/src/networkremote/outgoingdatacreator.cpp +++ b/src/networkremote/outgoingdatacreator.cpp @@ -49,10 +49,16 @@ void OutgoingDataCreator::SendDataToClients(pb::remote::Message* msg) { // Check if the client is still active if (sock->state() == QTcpSocket::ConnectedState) { std::string data = msg->SerializeAsString(); - QByteArray b64_data = QByteArray::fromRawData(data.data(), data.length()); + /*QByteArray b64_data = QByteArray::fromRawData(data.data(), data.length()); sock->write(b64_data.toBase64()); - sock->write("\n"); + sock->write("\n");*/ + + QDataStream s(sock); + s << qint32(data.length()); + s.writeRawData(data.data(), data.length()); + sock->flush(); + } else { clients_->removeAt(clients_->indexOf(sock)); } From c732e70511b7bd0a5a9833b5cf273638ab182981 Mon Sep 17 00:00:00 2001 From: Andreas Date: Wed, 9 Jan 2013 20:07:28 +0100 Subject: [PATCH 2/3] multiclient support and shuffle feature --- .../remotecontrolmessages.proto | 1 + src/networkremote/incomingdataparser.cpp | 4 + src/networkremote/incomingdataparser.h | 1 + src/networkremote/networkremote.cpp | 97 ++++++++++--------- src/networkremote/networkremote.h | 14 ++- src/networkremote/outgoingdatacreator.cpp | 8 +- 6 files changed, 70 insertions(+), 55 deletions(-) diff --git a/ext/libclementine-remote/remotecontrolmessages.proto b/ext/libclementine-remote/remotecontrolmessages.proto index 5a700a3ee..7cf35c0ef 100644 --- a/ext/libclementine-remote/remotecontrolmessages.proto +++ b/ext/libclementine-remote/remotecontrolmessages.proto @@ -16,6 +16,7 @@ enum MsgType { STOP = 23; NEXT = 24; PREV = 25; + TOOGLE_SHUFFLE = 26; // Messages send from server to client INFOS = 40; diff --git a/src/networkremote/incomingdataparser.cpp b/src/networkremote/incomingdataparser.cpp index b0fe45e55..34e6a0115 100644 --- a/src/networkremote/incomingdataparser.cpp +++ b/src/networkremote/incomingdataparser.cpp @@ -43,6 +43,8 @@ IncomingDataParser::IncomingDataParser(Application* app) app_->player(), SLOT(PlayAt(int,Engine::TrackChangeFlags,bool))); connect(this, SIGNAL(SetActivePlaylist(int)), app_->playlist_manager(), SLOT(SetActivePlaylist(int))); + connect(this, SIGNAL(ShuffleCurrent()), + app_->playlist_manager(), SLOT(ShuffleCurrent())); } IncomingDataParser::~IncomingDataParser() { @@ -89,6 +91,8 @@ void IncomingDataParser::Parse(const QByteArray& data) { break; case pb::remote::CHANGE_SONG: ChangeSong(&msg); break; + case pb::remote::TOOGLE_SHUFFLE: emit ShuffleCurrent(); + break; default: break; } } diff --git a/src/networkremote/incomingdataparser.h b/src/networkremote/incomingdataparser.h index b9c80571c..588f5df34 100644 --- a/src/networkremote/incomingdataparser.h +++ b/src/networkremote/incomingdataparser.h @@ -29,6 +29,7 @@ signals: void SetVolume(int volume); void PlayAt(int i, Engine::TrackChangeFlags change, bool reshuffle); void SetActivePlaylist(int id); + void ShuffleCurrent(); private: Application* app_; diff --git a/src/networkremote/networkremote.cpp b/src/networkremote/networkremote.cpp index c3a6beaec..6339859fa 100644 --- a/src/networkremote/networkremote.cpp +++ b/src/networkremote/networkremote.cpp @@ -30,12 +30,12 @@ const int NetworkRemote::kDefaultServerPort = 5500; NetworkRemote::NetworkRemote(Application* app) : app_(app) { - buffer_.open(QIODevice::ReadWrite); + signals_connected_ = false; } NetworkRemote::~NetworkRemote() { - server_->close(); + StopServer(); delete incoming_data_parser_; delete outgoing_data_creator_; } @@ -57,6 +57,8 @@ void NetworkRemote::SetupServer() { incoming_data_parser_ = new IncomingDataParser(app_); outgoing_data_creator_ = new OutgoingDataCreator(app_); + outgoing_data_creator_->SetClients(&clients_); + connect(app_->current_art_loader(), SIGNAL(ArtLoaded(const Song&, const QString&, const QImage&)), outgoing_data_creator_, @@ -77,8 +79,6 @@ void NetworkRemote::StartServer() { qLog(Info) << "Starting network remote"; - clients_ = NULL; - connect(server_, SIGNAL(newConnection()), this, SLOT(AcceptConnection())); server_->listen(QHostAddress::Any, port_); @@ -89,6 +89,15 @@ void NetworkRemote::StartServer() { void NetworkRemote::StopServer() { if (server_->isListening()) { server_->close(); + clients_.clear(); + expected_length_.clear(); + reading_protobuf_.clear(); + + // Delete all QBuffers + foreach (QBuffer* b, buffer_) { + delete b; + } + buffer_.clear(); } } @@ -98,10 +107,8 @@ void NetworkRemote::ReloadSettings() { } void NetworkRemote::AcceptConnection() { - if (!clients_) { - // Create a new QList with clients - clients_ = new QList(); - outgoing_data_creator_->SetClients(clients_); + if (!signals_connected_) { + signals_connected_ = true; // Setting up the signals, but only once connect(incoming_data_parser_, SIGNAL(SendClementineInfos()), @@ -125,7 +132,12 @@ void NetworkRemote::AcceptConnection() { } QTcpSocket* client = server_->nextPendingConnection(); - clients_->push_back(client); + clients_.push_back(client); + reading_protobuf_.append(false); + expected_length_.append(0); + QBuffer* buf = new QBuffer(); + buf->open(QIODevice::ReadWrite); + buffer_.push_back(buf); // Connect to the slot IncomingData when receiving data connect(client, SIGNAL(readyRead()), this, SLOT(IncomingData())); @@ -134,55 +146,48 @@ void NetworkRemote::AcceptConnection() { void NetworkRemote::IncomingData() { QTcpSocket* client = static_cast(QObject::sender()); + int which = clients_.indexOf(client); + qDebug() << "Which:" << which; + while (client->bytesAvailable()) { - if (!reading_protobuf_) { + if (!reading_protobuf_[which]) { // Read the length of the next message QDataStream s(client); - s >> expected_length_; + s >> expected_length_[which]; - reading_protobuf_ = true; + reading_protobuf_[which] = true; } // Read some of the message - buffer_.write(client->read(expected_length_ - buffer_.size())); + buffer_[which]->write( + client->read(expected_length_[which] - buffer_[which]->size())); // Did we get everything? - if (buffer_.size() == expected_length_) { + if (buffer_[which]->size() == expected_length_[which]) { // Parse the message - qLog(Debug) << "Parsing message"; - incoming_data_parser_->Parse(buffer_.data()); + incoming_data_parser_->Parse(buffer_[which]->data()); // Clear the buffer - buffer_.close(); - buffer_.setData(QByteArray()); - buffer_.open(QIODevice::ReadWrite); - reading_protobuf_ = false; + buffer_[which]->close(); + buffer_[which]->setData(QByteArray()); + buffer_[which]->open(QIODevice::ReadWrite); + reading_protobuf_[which] = false; } } -/* - // Now read all the data from the socket - QDataStream s(client); - qint32 expected_length; - - while (client->bytesAvailable()) { - QBuffer buf; - buf.setData(); - buf.open(QIODevice::ReadWrite); - s >> expected_length; - - buf.write(client->read(expected_length - buf.size())); - qLog(Debug) << "Length:" << buf.size() << "/" << expected_length; - - - if (buf.size() == expected_length) { - qLog(Debug) << "Buf:" << buf.data(); - incoming_data_parser_->Parse(buf.data()); - } - - if (incoming_data_parser_->close_connection()) { - client->close(); - } - - buf.close(); - }*/ +} + +void NetworkRemote::RemoveClient(int index) { + // Remove client + QTcpSocket* client = clients_[index]; + delete client; + clients_.removeAt(index); + + // Remove QBuffer + QBuffer* buf = buffer_[index]; + delete buf; + buffer_.removeAt(index); + + // Remove other QList entries + reading_protobuf_.removeAt(index); + expected_length_.removeAt(index); } diff --git a/src/networkremote/networkremote.h b/src/networkremote/networkremote.h index e9eae1a6b..27cf2df55 100644 --- a/src/networkremote/networkremote.h +++ b/src/networkremote/networkremote.h @@ -10,6 +10,8 @@ #include "incomingdataparser.h" #include "outgoingdatacreator.h" +class Application; + class NetworkRemote : public QThread { Q_OBJECT public: @@ -19,6 +21,8 @@ public: NetworkRemote(Application* app); ~NetworkRemote(); + void RemoveClient(int index); + public slots: void SetupServer(); void StartServer(); @@ -28,15 +32,17 @@ public slots: private: QTcpServer* server_; - QList* clients_; IncomingDataParser* incoming_data_parser_; OutgoingDataCreator* outgoing_data_creator_; int port_; bool use_remote_; + bool signals_connected_; Application* app_; - bool reading_protobuf_; - quint32 expected_length_; - QBuffer buffer_; + + QList clients_; + QList reading_protobuf_; + QList expected_length_; + QList buffer_; void StopServer(); void ReadSettings(); diff --git a/src/networkremote/outgoingdatacreator.cpp b/src/networkremote/outgoingdatacreator.cpp index b00e4bd27..09d1a418a 100644 --- a/src/networkremote/outgoingdatacreator.cpp +++ b/src/networkremote/outgoingdatacreator.cpp @@ -16,6 +16,7 @@ */ #include "outgoingdatacreator.h" +#include "networkremote.h" #include "core/logging.h" OutgoingDataCreator::OutgoingDataCreator(Application* app) @@ -40,7 +41,7 @@ void OutgoingDataCreator::SetClients(QList* clients) { void OutgoingDataCreator::SendDataToClients(pb::remote::Message* msg) { // Check if we have clients to send data to - if (!clients_ || clients_->size() == 0) { + if (!clients_ || clients_->empty()) { return; } @@ -49,9 +50,6 @@ void OutgoingDataCreator::SendDataToClients(pb::remote::Message* msg) { // Check if the client is still active if (sock->state() == QTcpSocket::ConnectedState) { std::string data = msg->SerializeAsString(); - /*QByteArray b64_data = QByteArray::fromRawData(data.data(), data.length()); - sock->write(b64_data.toBase64()); - sock->write("\n");*/ QDataStream s(sock); s << qint32(data.length()); @@ -60,7 +58,7 @@ void OutgoingDataCreator::SendDataToClients(pb::remote::Message* msg) { sock->flush(); } else { - clients_->removeAt(clients_->indexOf(sock)); + app_->network_remote()->RemoveClient(clients_->indexOf(sock)); } } } From 04ccdbbf0884a17db2d8d51971f160703aa5abda Mon Sep 17 00:00:00 2001 From: Andreas Date: Thu, 10 Jan 2013 21:21:55 +0100 Subject: [PATCH 3/3] added version to protocol buffer message changed client handling only non public ips can connect (can change that in options) --- .../remotecontrolmessages.proto | 13 +- src/CMakeLists.txt | 2 + src/networkremote/incomingdataparser.h | 4 +- src/networkremote/networkremote.cpp | 113 ++++++++---------- src/networkremote/networkremote.h | 17 ++- src/networkremote/outgoingdatacreator.cpp | 30 ++--- src/networkremote/outgoingdatacreator.h | 5 +- src/networkremote/remoteclient.cpp | 83 +++++++++++++ src/networkremote/remoteclient.h | 35 ++++++ src/ui/networkremotesettingspage.cpp | 8 ++ src/ui/networkremotesettingspage.ui | 24 +++- 11 files changed, 235 insertions(+), 99 deletions(-) create mode 100644 src/networkremote/remoteclient.cpp create mode 100644 src/networkremote/remoteclient.h diff --git a/ext/libclementine-remote/remotecontrolmessages.proto b/ext/libclementine-remote/remotecontrolmessages.proto index 7cf35c0ef..3a9f6f71c 100644 --- a/ext/libclementine-remote/remotecontrolmessages.proto +++ b/ext/libclementine-remote/remotecontrolmessages.proto @@ -34,13 +34,14 @@ enum EngineState { } message Message { - required MsgType msgType = 1; + required int32 version = 1; + required MsgType msgType = 2; - optional EngineState state = 2; - optional ClementineInfos infos = 3; - optional SongMetadata currentSong = 4; - optional int32 volume = 5; - repeated Playlist playlists = 6; + optional EngineState state = 3; + optional ClementineInfos infos = 4; + optional SongMetadata currentSong = 5; + optional int32 volume = 6; + repeated Playlist playlists = 7; } message ClementineInfos { diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8d35283b5..3b6284203 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -218,6 +218,7 @@ set(SOURCES networkremote/networkremote.cpp networkremote/incomingdataparser.cpp networkremote/outgoingdatacreator.cpp + networkremote/remoteclient.cpp playlist/dynamicplaylistcontrols.cpp playlist/playlist.cpp @@ -496,6 +497,7 @@ set(HEADERS networkremote/networkremote.h networkremote/incomingdataparser.h networkremote/outgoingdatacreator.h + networkremote/remoteclient.h playlist/dynamicplaylistcontrols.h playlist/playlist.h diff --git a/src/networkremote/incomingdataparser.h b/src/networkremote/incomingdataparser.h index 588f5df34..c930ef5b8 100644 --- a/src/networkremote/incomingdataparser.h +++ b/src/networkremote/incomingdataparser.h @@ -11,9 +11,11 @@ public: IncomingDataParser(Application* app); ~IncomingDataParser(); - void Parse(const QByteArray& pb_data); bool close_connection(); +public slots: + void Parse(const QByteArray& pb_data); + signals: void SendClementineInfos(); void SendFirstData(); diff --git a/src/networkremote/networkremote.cpp b/src/networkremote/networkremote.cpp index 6339859fa..8cf887b24 100644 --- a/src/networkremote/networkremote.cpp +++ b/src/networkremote/networkremote.cpp @@ -26,6 +26,7 @@ const char* NetworkRemote::kSettingsGroup = "NetworkRemote"; const int NetworkRemote::kDefaultServerPort = 5500; +const int NetworkRemote::kProtocolBufferVersion = 1; NetworkRemote::NetworkRemote(Application* app) : app_(app) @@ -46,6 +47,14 @@ void NetworkRemote::ReadSettings() { s.beginGroup(NetworkRemote::kSettingsGroup); use_remote_ = s.value("use_remote").toBool(); port_ = s.value("port").toInt(); + + // Use only non public ips must be true be default + if (s.contains("only_non_public_ip")) { + only_non_public_ip_ = s.value("only_non_public_ip").toBool(); + } else { + only_non_public_ip_ = true; + } + if (port_ == 0) { port_ = kDefaultServerPort; } @@ -54,6 +63,7 @@ void NetworkRemote::ReadSettings() { void NetworkRemote::SetupServer() { server_ = new QTcpServer(); + server_ipv6_ = new QTcpServer(); incoming_data_parser_ = new IncomingDataParser(app_); outgoing_data_creator_ = new OutgoingDataCreator(app_); @@ -80,8 +90,10 @@ void NetworkRemote::StartServer() { qLog(Info) << "Starting network remote"; connect(server_, SIGNAL(newConnection()), this, SLOT(AcceptConnection())); + connect(server_ipv6_, SIGNAL(newConnection()), this, SLOT(AcceptConnection())); server_->listen(QHostAddress::Any, port_); + server_ipv6_->listen(QHostAddress::AnyIPv6, port_); qLog(Info) << "Listening on port " << port_; } @@ -89,15 +101,8 @@ void NetworkRemote::StartServer() { void NetworkRemote::StopServer() { if (server_->isListening()) { server_->close(); + server_ipv6_->close(); clients_.clear(); - expected_length_.clear(); - reading_protobuf_.clear(); - - // Delete all QBuffers - foreach (QBuffer* b, buffer_) { - delete b; - } - buffer_.clear(); } } @@ -130,64 +135,50 @@ void NetworkRemote::AcceptConnection() { connect(app_->player()->engine(), SIGNAL(StateChanged(Engine::State)), outgoing_data_creator_, SLOT(StateChanged(Engine::State))); } - QTcpSocket* client = server_->nextPendingConnection(); - clients_.push_back(client); - reading_protobuf_.append(false); - expected_length_.append(0); - QBuffer* buf = new QBuffer(); - buf->open(QIODevice::ReadWrite); - buffer_.push_back(buf); - - // Connect to the slot IncomingData when receiving data - connect(client, SIGNAL(readyRead()), this, SLOT(IncomingData())); -} - -void NetworkRemote::IncomingData() { - QTcpSocket* client = static_cast(QObject::sender()); - - int which = clients_.indexOf(client); - qDebug() << "Which:" << which; - - while (client->bytesAvailable()) { - if (!reading_protobuf_[which]) { - // Read the length of the next message - QDataStream s(client); - s >> expected_length_[which]; - - reading_protobuf_[which] = true; + if (server_->hasPendingConnections()) { + QTcpSocket* client_socket = server_->nextPendingConnection(); + // Check if our ip is in private scope + if (only_non_public_ip_ + && !IpIsPrivate(client_socket->peerAddress().toIPv4Address())) { + qLog(Info) << "Got a connection from public ip" << + client_socket->peerAddress().toString(); + } else { + CreateRemoteClient(client_socket); + // TODO: Check private ips for ipv6 } - // Read some of the message - buffer_[which]->write( - client->read(expected_length_[which] - buffer_[which]->size())); - - // Did we get everything? - if (buffer_[which]->size() == expected_length_[which]) { - // Parse the message - incoming_data_parser_->Parse(buffer_[which]->data()); - - // Clear the buffer - buffer_[which]->close(); - buffer_[which]->setData(QByteArray()); - buffer_[which]->open(QIODevice::ReadWrite); - reading_protobuf_[which] = false; - } + } else { + // No checks on ipv6 + CreateRemoteClient(server_ipv6_->nextPendingConnection()); } } -void NetworkRemote::RemoveClient(int index) { - // Remove client - QTcpSocket* client = clients_[index]; - delete client; - clients_.removeAt(index); +bool NetworkRemote::IpIsPrivate(int ip) { + int private_local = QHostAddress("127.0.0.1").toIPv4Address(); + int private_a = QHostAddress("10.0.0.0").toIPv4Address(); + int private_b = QHostAddress("172.16.0.0").toIPv4Address(); + int private_c = QHostAddress("192.168.0.0").toIPv4Address(); - // Remove QBuffer - QBuffer* buf = buffer_[index]; - delete buf; - buffer_.removeAt(index); - - // Remove other QList entries - reading_protobuf_.removeAt(index); - expected_length_.removeAt(index); + // Check if we have a private ip address + if (ip == private_local + || (ip >= private_a && ip < private_a + 16777216) + || (ip >= private_b && ip < private_b + 1048576) + || (ip >= private_c && ip < private_c + 65536)) { + return true; + } else { + return false; + } +} + +void NetworkRemote::CreateRemoteClient(QTcpSocket *client_socket) { + if (client_socket) { + // Add the client to the list + RemoteClient* client = new RemoteClient(app_, client_socket); + clients_.push_back(client); + + // Connect the signal to parse data + connect(client, SIGNAL(Parse(QByteArray)), + incoming_data_parser_, SLOT(Parse(QByteArray))); + } } diff --git a/src/networkremote/networkremote.h b/src/networkremote/networkremote.h index 27cf2df55..87e3bd4a1 100644 --- a/src/networkremote/networkremote.h +++ b/src/networkremote/networkremote.h @@ -1,7 +1,6 @@ #ifndef NETWORKREMOTE_H #define NETWORKREMOTE_H -#include #include #include @@ -9,43 +8,41 @@ #include "core/application.h" #include "incomingdataparser.h" #include "outgoingdatacreator.h" - -class Application; +#include "remoteclient.h" class NetworkRemote : public QThread { Q_OBJECT public: static const char* kSettingsGroup; static const int kDefaultServerPort; + static const int kProtocolBufferVersion; NetworkRemote(Application* app); ~NetworkRemote(); - void RemoveClient(int index); - public slots: void SetupServer(); void StartServer(); void ReloadSettings(); void AcceptConnection(); - void IncomingData(); private: QTcpServer* server_; + QTcpServer* server_ipv6_; IncomingDataParser* incoming_data_parser_; OutgoingDataCreator* outgoing_data_creator_; int port_; bool use_remote_; + bool only_non_public_ip_; bool signals_connected_; Application* app_; - QList clients_; - QList reading_protobuf_; - QList expected_length_; - QList buffer_; + QList clients_; void StopServer(); void ReadSettings(); + void CreateRemoteClient(QTcpSocket* client_socket); + bool IpIsPrivate(int ip); }; #endif // NETWORKREMOTE_H diff --git a/src/networkremote/outgoingdatacreator.cpp b/src/networkremote/outgoingdatacreator.cpp index 09d1a418a..21c90018a 100644 --- a/src/networkremote/outgoingdatacreator.cpp +++ b/src/networkremote/outgoingdatacreator.cpp @@ -20,8 +20,7 @@ #include "core/logging.h" OutgoingDataCreator::OutgoingDataCreator(Application* app) - : app_(app), - clients_(NULL) + : app_(app) { // Create Keep Alive Timer keep_alive_timer_ = new QTimer(this); @@ -32,7 +31,7 @@ OutgoingDataCreator::OutgoingDataCreator(Application* app) OutgoingDataCreator::~OutgoingDataCreator() { } -void OutgoingDataCreator::SetClients(QList* clients) { +void OutgoingDataCreator::SetClients(QList* clients) { clients_ = clients; // After we got some clients, start the keep alive timer // Default: every 10 seconds @@ -41,24 +40,21 @@ void OutgoingDataCreator::SetClients(QList* clients) { void OutgoingDataCreator::SendDataToClients(pb::remote::Message* msg) { // Check if we have clients to send data to - if (!clients_ || clients_->empty()) { + if (clients_->empty()) { return; } - QTcpSocket* sock; - foreach(sock, *clients_) { + // Add the Version number + msg->set_version(NetworkRemote::kProtocolBufferVersion); + + RemoteClient* client; + foreach(client, *clients_) { // Check if the client is still active - if (sock->state() == QTcpSocket::ConnectedState) { - std::string data = msg->SerializeAsString(); - - QDataStream s(sock); - s << qint32(data.length()); - s.writeRawData(data.data(), data.length()); - - sock->flush(); - + if (client->State() == QTcpSocket::ConnectedState) { + client->SendData(msg); } else { - app_->network_remote()->RemoveClient(clients_->indexOf(sock)); + clients_->removeAt(clients_->indexOf(client)); + delete client; } } } @@ -141,7 +137,7 @@ void OutgoingDataCreator::CurrentSongChanged(const Song& song, const QString& ur current_uri_ = uri; current_image_ = img; - if (clients_) { + if (!clients_->empty()) { // Create the message pb::remote::Message msg; msg.set_msgtype(pb::remote::CURRENT_METAINFOS); diff --git a/src/networkremote/outgoingdatacreator.h b/src/networkremote/outgoingdatacreator.h index 7a3a8277d..9ec9280e1 100644 --- a/src/networkremote/outgoingdatacreator.h +++ b/src/networkremote/outgoingdatacreator.h @@ -13,6 +13,7 @@ #include "playlist/playlist.h" #include "playlist/playlistmanager.h" #include "remotecontrolmessages.pb.h" +#include "remoteclient.h" class OutgoingDataCreator : public QObject { Q_OBJECT @@ -20,7 +21,7 @@ public: OutgoingDataCreator(Application* app); ~OutgoingDataCreator(); - void SetClients(QList* clients); + void SetClients(QList* clients); public slots: void SendClementineInfos(); @@ -36,7 +37,7 @@ public slots: private: Application* app_; - QList* clients_; + QList* clients_; Song current_song_; QString current_uri_; QImage current_image_; diff --git a/src/networkremote/remoteclient.cpp b/src/networkremote/remoteclient.cpp new file mode 100644 index 000000000..0732395bd --- /dev/null +++ b/src/networkremote/remoteclient.cpp @@ -0,0 +1,83 @@ +/* This file is part of Clementine. + Copyright 2013, Andreas Muttscheller + + Clementine is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Clementine 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Clementine. If not, see . +*/ + +#include "core/logging.h" + +#include "remoteclient.h" + +#include + +RemoteClient::RemoteClient(Application* app, QTcpSocket* client) + : app_(app), + client_(client) +{ + // Open the buffer + buffer_.setData(QByteArray()); + buffer_.open(QIODevice::ReadWrite); + reading_protobuf_ = false; + + // Connect to the slot IncomingData when receiving data + connect(client, SIGNAL(readyRead()), this, SLOT(IncomingData())); +} + + +RemoteClient::~RemoteClient() { +} + +void RemoteClient::IncomingData() { + while (client_->bytesAvailable()) { + if (!reading_protobuf_) { + // Read the length of the next message + QDataStream s(client_); + s >> expected_length_; + reading_protobuf_ = true; + } + + // Read some of the message + buffer_.write( + client_->read(expected_length_ - buffer_.size())); + + // Did we get everything? + if (buffer_.size() == expected_length_) { + // Parse the message + emit Parse(buffer_.data()); + + // Clear the buffer + buffer_.close(); + buffer_.setData(QByteArray()); + buffer_.open(QIODevice::ReadWrite); + reading_protobuf_ = false; + } + } +} + +void RemoteClient::SendData(pb::remote::Message *msg) { + // Serialize the message + std::string data = msg->SerializeAsString(); + + // write the length of the data first + QDataStream s(client_); + s << qint32(data.length()); + s.writeRawData(data.data(), data.length()); + + // Flush data + client_->flush(); +} + +QAbstractSocket::SocketState RemoteClient::State() { + return client_->state(); +} diff --git a/src/networkremote/remoteclient.h b/src/networkremote/remoteclient.h new file mode 100644 index 000000000..f283b4145 --- /dev/null +++ b/src/networkremote/remoteclient.h @@ -0,0 +1,35 @@ +#ifndef REMOTECLIENT_H +#define REMOTECLIENT_H + +#include +#include +#include + +#include "core/application.h" +#include "incomingdataparser.h" + +class RemoteClient : public QObject { + Q_OBJECT +public: + RemoteClient(Application* app, QTcpSocket* client); + ~RemoteClient(); + + void SendData(pb::remote::Message* msg); + QAbstractSocket::SocketState State(); + +private slots: + void IncomingData(); + +signals: + void Parse(const QByteArray& pb_data); + +private: + Application* app_; + + QTcpSocket* client_; + bool reading_protobuf_; + quint32 expected_length_; + QBuffer buffer_; +}; + +#endif // REMOTECLIENT_H diff --git a/src/ui/networkremotesettingspage.cpp b/src/ui/networkremotesettingspage.cpp index 16a5266c0..d67ad2e25 100644 --- a/src/ui/networkremotesettingspage.cpp +++ b/src/ui/networkremotesettingspage.cpp @@ -51,6 +51,13 @@ void NetworkRemoteSettingsPage::Load() { } ui_->use_remote->setChecked(s.value("use_remote").toBool()); + if (s.contains("only_non_public_ip")) { + ui_->only_non_public_ip->setChecked(s.value("only_non_public_ip").toBool()); + } else { + // Default yes + ui_->only_non_public_ip->setChecked(true); + s.setValue("only_non_public_ip", true); + } s.endGroup(); } @@ -61,6 +68,7 @@ void NetworkRemoteSettingsPage::Save() { s.beginGroup(NetworkRemote::kSettingsGroup); s.setValue("port", ui_->remote_port->value()); s.setValue("use_remote", ui_->use_remote->isChecked()); + s.setValue("only_non_public_ip", ui_->only_non_public_ip->isChecked()); s.endGroup(); diff --git a/src/ui/networkremotesettingspage.ui b/src/ui/networkremotesettingspage.ui index c9577164e..2e605de03 100644 --- a/src/ui/networkremotesettingspage.ui +++ b/src/ui/networkremotesettingspage.ui @@ -6,7 +6,7 @@ 0 0 - 400 + 475 300 @@ -33,7 +33,7 @@ - + 171 @@ -63,6 +63,26 @@ + + + + + + Only accept connections from clients within the ip ranges: +10.x.x.x +172.16.0.0 - 172.31.255.255 +192.168.x.x + + + Accept non public clients only + + + true + + + + +