2012-12-31 23:37:39 +01:00
|
|
|
/* This file is part of Clementine.
|
|
|
|
Copyright 2012, Andreas Muttscheller <asfa194@gmail.com>
|
|
|
|
|
|
|
|
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 <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2013-01-16 14:56:31 +01:00
|
|
|
#include "networkremote.h"
|
|
|
|
|
2013-01-03 21:40:47 +01:00
|
|
|
#include <QDataStream>
|
2013-02-18 18:06:56 +01:00
|
|
|
#include <QHostInfo>
|
2013-07-31 17:28:11 +02:00
|
|
|
#include <QNetworkProxy>
|
2020-09-18 16:15:19 +02:00
|
|
|
#include <QSettings>
|
2016-02-11 16:11:31 +01:00
|
|
|
#include <QTcpServer>
|
|
|
|
|
|
|
|
#include "core/logging.h"
|
|
|
|
#include "covers/currentartloader.h"
|
|
|
|
#include "networkremote/incomingdataparser.h"
|
|
|
|
#include "networkremote/outgoingdatacreator.h"
|
|
|
|
#include "networkremote/zeroconf.h"
|
|
|
|
#include "playlist/playlistmanager.h"
|
2012-12-31 23:37:39 +01:00
|
|
|
|
|
|
|
const char* NetworkRemote::kSettingsGroup = "NetworkRemote";
|
2013-01-14 17:18:24 +01:00
|
|
|
const quint16 NetworkRemote::kDefaultServerPort = 5500;
|
2014-11-13 22:31:49 +01:00
|
|
|
const char* NetworkRemote::kTranscoderSettingPostfix = "/NetworkRemote";
|
2012-12-31 23:37:39 +01:00
|
|
|
|
2013-01-14 17:18:24 +01:00
|
|
|
NetworkRemote::NetworkRemote(Application* app, QObject* parent)
|
2020-05-27 07:36:26 +02:00
|
|
|
: QObject(parent), signals_connected_(false), app_(app) {
|
|
|
|
setObjectName("Network remote");
|
|
|
|
}
|
2012-12-31 23:37:39 +01:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
NetworkRemote::~NetworkRemote() { StopServer(); }
|
2012-12-31 23:37:39 +01:00
|
|
|
|
|
|
|
void NetworkRemote::ReadSettings() {
|
|
|
|
QSettings s;
|
|
|
|
|
|
|
|
s.beginGroup(NetworkRemote::kSettingsGroup);
|
2013-01-14 17:18:24 +01:00
|
|
|
use_remote_ = s.value("use_remote", false).toBool();
|
2014-02-07 16:34:20 +01:00
|
|
|
port_ = s.value("port", kDefaultServerPort).toInt();
|
2013-01-10 21:21:55 +01:00
|
|
|
|
|
|
|
// Use only non public ips must be true be default
|
2013-01-14 17:18:24 +01:00
|
|
|
only_non_public_ip_ = s.value("only_non_public_ip", true).toBool();
|
2013-01-10 21:21:55 +01:00
|
|
|
|
2012-12-31 23:37:39 +01:00
|
|
|
s.endGroup();
|
|
|
|
}
|
|
|
|
|
|
|
|
void NetworkRemote::SetupServer() {
|
2013-01-14 17:18:24 +01:00
|
|
|
server_.reset(new QTcpServer());
|
|
|
|
server_ipv6_.reset(new QTcpServer());
|
|
|
|
incoming_data_parser_.reset(new IncomingDataParser(app_));
|
|
|
|
outgoing_data_creator_.reset(new OutgoingDataCreator(app_));
|
2012-12-31 23:37:39 +01:00
|
|
|
|
2013-01-09 20:07:28 +01:00
|
|
|
outgoing_data_creator_->SetClients(&clients_);
|
|
|
|
|
2012-12-31 23:37:39 +01:00
|
|
|
connect(app_->current_art_loader(),
|
|
|
|
SIGNAL(ArtLoaded(const Song&, const QString&, const QImage&)),
|
2013-01-14 17:18:24 +01:00
|
|
|
outgoing_data_creator_.get(),
|
2012-12-31 23:37:39 +01:00
|
|
|
SLOT(CurrentSongChanged(const Song&, const QString&, const QImage&)));
|
2013-01-23 20:02:12 +01:00
|
|
|
|
|
|
|
// Only connect the signals once
|
2014-02-07 16:34:20 +01:00
|
|
|
connect(server_.get(), SIGNAL(newConnection()), this,
|
|
|
|
SLOT(AcceptConnection()));
|
|
|
|
connect(server_ipv6_.get(), SIGNAL(newConnection()), this,
|
|
|
|
SLOT(AcceptConnection()));
|
2020-11-27 13:05:53 +01:00
|
|
|
|
|
|
|
connect(incoming_data_parser_.get(), SIGNAL(AddToPlaylistSignal(QMimeData*)),
|
|
|
|
SIGNAL(AddToPlaylistSignal(QMimeData*)));
|
|
|
|
connect(incoming_data_parser_.get(), SIGNAL(SetCurrentPlaylist(int)),
|
|
|
|
SIGNAL(SetCurrentPlaylist(int)));
|
2012-12-31 23:37:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void NetworkRemote::StartServer() {
|
|
|
|
if (!app_) {
|
2013-01-03 21:40:47 +01:00
|
|
|
qLog(Error) << "Start Server called without having an application!";
|
2012-12-31 23:37:39 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
// Check if user desires to start a network remote server
|
|
|
|
ReadSettings();
|
|
|
|
if (!use_remote_) {
|
|
|
|
qLog(Info) << "Network Remote deactivated";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
qLog(Info) << "Starting network remote";
|
|
|
|
|
2013-07-31 17:28:11 +02:00
|
|
|
server_->setProxy(QNetworkProxy::NoProxy);
|
|
|
|
server_ipv6_->setProxy(QNetworkProxy::NoProxy);
|
|
|
|
|
2012-12-31 23:37:39 +01:00
|
|
|
server_->listen(QHostAddress::Any, port_);
|
2013-01-10 21:21:55 +01:00
|
|
|
server_ipv6_->listen(QHostAddress::AnyIPv6, port_);
|
2012-12-31 23:37:39 +01:00
|
|
|
|
|
|
|
qLog(Info) << "Listening on port " << port_;
|
2013-01-16 14:56:31 +01:00
|
|
|
|
|
|
|
if (Zeroconf::GetZeroconf()) {
|
2013-02-19 16:29:45 +01:00
|
|
|
QString name = QString("Clementine on %1").arg(QHostInfo::localHostName());
|
2014-02-07 16:34:20 +01:00
|
|
|
Zeroconf::GetZeroconf()->Publish("local", "_clementine._tcp", name, port_);
|
2013-01-16 14:56:31 +01:00
|
|
|
}
|
2012-12-31 23:37:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void NetworkRemote::StopServer() {
|
|
|
|
if (server_->isListening()) {
|
2013-01-23 20:02:12 +01:00
|
|
|
outgoing_data_creator_.get()->DisconnectAllClients();
|
2012-12-31 23:37:39 +01:00
|
|
|
server_->close();
|
2013-01-10 21:21:55 +01:00
|
|
|
server_ipv6_->close();
|
2013-02-18 14:53:37 +01:00
|
|
|
qDeleteAll(clients_);
|
2013-01-09 20:07:28 +01:00
|
|
|
clients_.clear();
|
2012-12-31 23:37:39 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void NetworkRemote::ReloadSettings() {
|
2013-01-03 21:40:47 +01:00
|
|
|
StopServer();
|
2012-12-31 23:37:39 +01:00
|
|
|
StartServer();
|
|
|
|
}
|
|
|
|
|
|
|
|
void NetworkRemote::AcceptConnection() {
|
2013-01-09 20:07:28 +01:00
|
|
|
if (!signals_connected_) {
|
|
|
|
signals_connected_ = true;
|
2012-12-31 23:37:39 +01:00
|
|
|
|
|
|
|
// Setting up the signals, but only once
|
2013-01-15 14:24:59 +01:00
|
|
|
connect(incoming_data_parser_.get(), SIGNAL(SendClementineInfo()),
|
|
|
|
outgoing_data_creator_.get(), SLOT(SendClementineInfo()));
|
2013-03-27 16:54:02 +01:00
|
|
|
connect(incoming_data_parser_.get(), SIGNAL(SendFirstData(bool)),
|
|
|
|
outgoing_data_creator_.get(), SLOT(SendFirstData(bool)));
|
2013-01-14 17:18:24 +01:00
|
|
|
connect(incoming_data_parser_.get(), SIGNAL(SendAllPlaylists()),
|
|
|
|
outgoing_data_creator_.get(), SLOT(SendAllPlaylists()));
|
2013-04-16 13:57:04 +02:00
|
|
|
connect(incoming_data_parser_.get(), SIGNAL(SendAllActivePlaylists()),
|
|
|
|
outgoing_data_creator_.get(), SLOT(SendAllActivePlaylists()));
|
2013-01-14 17:18:24 +01:00
|
|
|
connect(incoming_data_parser_.get(), SIGNAL(SendPlaylistSongs(int)),
|
|
|
|
outgoing_data_creator_.get(), SLOT(SendPlaylistSongs(int)));
|
2012-12-31 23:37:39 +01:00
|
|
|
|
|
|
|
connect(app_->playlist_manager(), SIGNAL(ActiveChanged(Playlist*)),
|
2013-01-14 17:18:24 +01:00
|
|
|
outgoing_data_creator_.get(), SLOT(ActiveChanged(Playlist*)));
|
2012-12-31 23:37:39 +01:00
|
|
|
connect(app_->playlist_manager(), SIGNAL(PlaylistChanged(Playlist*)),
|
2013-01-14 17:18:24 +01:00
|
|
|
outgoing_data_creator_.get(), SLOT(PlaylistChanged(Playlist*)));
|
2014-02-07 16:34:20 +01:00
|
|
|
connect(app_->playlist_manager(), SIGNAL(PlaylistAdded(int, QString, bool)),
|
|
|
|
outgoing_data_creator_.get(),
|
|
|
|
SLOT(PlaylistAdded(int, QString, bool)));
|
|
|
|
connect(app_->playlist_manager(), SIGNAL(PlaylistRenamed(int, QString)),
|
|
|
|
outgoing_data_creator_.get(), SLOT(PlaylistRenamed(int, QString)));
|
2013-02-07 21:34:04 +01:00
|
|
|
connect(app_->playlist_manager(), SIGNAL(PlaylistClosed(int)),
|
|
|
|
outgoing_data_creator_.get(), SLOT(PlaylistClosed(int)));
|
|
|
|
connect(app_->playlist_manager(), SIGNAL(PlaylistDeleted(int)),
|
|
|
|
outgoing_data_creator_.get(), SLOT(PlaylistDeleted(int)));
|
2012-12-31 23:37:39 +01:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
connect(app_->player(), SIGNAL(VolumeChanged(int)),
|
|
|
|
outgoing_data_creator_.get(), SLOT(VolumeChanged(int)));
|
2012-12-31 23:37:39 +01:00
|
|
|
connect(app_->player()->engine(), SIGNAL(StateChanged(Engine::State)),
|
2013-01-14 17:18:24 +01:00
|
|
|
outgoing_data_creator_.get(), SLOT(StateChanged(Engine::State)));
|
2013-01-15 14:43:02 +01:00
|
|
|
|
|
|
|
connect(app_->playlist_manager()->sequence(),
|
|
|
|
SIGNAL(RepeatModeChanged(PlaylistSequence::RepeatMode)),
|
|
|
|
outgoing_data_creator_.get(),
|
|
|
|
SLOT(SendRepeatMode(PlaylistSequence::RepeatMode)));
|
|
|
|
connect(app_->playlist_manager()->sequence(),
|
|
|
|
SIGNAL(ShuffleModeChanged(PlaylistSequence::ShuffleMode)),
|
|
|
|
outgoing_data_creator_.get(),
|
|
|
|
SLOT(SendShuffleMode(PlaylistSequence::ShuffleMode)));
|
2013-07-10 13:24:23 +02:00
|
|
|
|
|
|
|
connect(incoming_data_parser_.get(), SIGNAL(GetLyrics()),
|
|
|
|
outgoing_data_creator_.get(), SLOT(GetLyrics()));
|
2013-07-12 12:31:27 +02:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
connect(incoming_data_parser_.get(), SIGNAL(SendLibrary(RemoteClient*)),
|
|
|
|
outgoing_data_creator_.get(), SLOT(SendLibrary(RemoteClient*)));
|
2014-10-21 17:59:02 +02:00
|
|
|
|
|
|
|
connect(incoming_data_parser_.get(),
|
|
|
|
SIGNAL(DoGlobalSearch(QString, RemoteClient*)),
|
|
|
|
outgoing_data_creator_.get(),
|
|
|
|
SLOT(DoGlobalSearch(QString, RemoteClient*)));
|
2020-11-27 13:05:53 +01:00
|
|
|
|
|
|
|
connect(incoming_data_parser_.get(),
|
|
|
|
SIGNAL(SendListFiles(QString, RemoteClient*)),
|
|
|
|
outgoing_data_creator_.get(),
|
|
|
|
SLOT(SendListFiles(QString, RemoteClient*)));
|
|
|
|
connect(incoming_data_parser_.get(), SIGNAL(SendSavedRadios(RemoteClient*)),
|
|
|
|
outgoing_data_creator_.get(), SLOT(SendSavedRadios(RemoteClient*)));
|
2012-12-31 23:37:39 +01:00
|
|
|
}
|
|
|
|
|
2013-01-14 17:18:24 +01:00
|
|
|
QTcpServer* server = qobject_cast<QTcpServer*>(sender());
|
|
|
|
QTcpSocket* client_socket = server->nextPendingConnection();
|
|
|
|
// Check if our ip is in private scope
|
|
|
|
if (only_non_public_ip_ && !IpIsPrivate(client_socket->peerAddress())) {
|
2014-02-07 16:34:20 +01:00
|
|
|
qLog(Info) << "Got a connection from public ip"
|
|
|
|
<< client_socket->peerAddress().toString();
|
2013-01-15 20:20:31 +01:00
|
|
|
client_socket->close();
|
2015-03-24 10:18:20 +01:00
|
|
|
client_socket->deleteLater();
|
2013-01-10 21:21:55 +01:00
|
|
|
} else {
|
2013-01-14 17:18:24 +01:00
|
|
|
CreateRemoteClient(client_socket);
|
2013-01-09 17:38:24 +01:00
|
|
|
}
|
2013-01-09 20:07:28 +01:00
|
|
|
}
|
2013-01-09 17:38:24 +01:00
|
|
|
|
2013-01-12 17:22:40 +01:00
|
|
|
bool NetworkRemote::IpIsPrivate(const QHostAddress& address) {
|
|
|
|
return
|
2013-07-27 07:27:08 +02:00
|
|
|
// Localhost v4
|
|
|
|
address.isInSubnet(QHostAddress::parseSubnet("127.0.0.0/8")) ||
|
2013-01-14 17:18:24 +01:00
|
|
|
// Link Local v4
|
2013-07-27 07:27:08 +02:00
|
|
|
address.isInSubnet(QHostAddress::parseSubnet("169.254.1.0/16")) ||
|
2013-01-12 17:22:40 +01:00
|
|
|
// Link Local v6
|
|
|
|
address.isInSubnet(QHostAddress::parseSubnet("::1/128")) ||
|
2013-01-15 20:20:31 +01:00
|
|
|
address.isInSubnet(QHostAddress::parseSubnet("fe80::/10")) ||
|
2013-01-14 17:18:24 +01:00
|
|
|
// Private v4 range
|
2013-01-12 17:22:40 +01:00
|
|
|
address.isInSubnet(QHostAddress::parseSubnet("192.168.0.0/16")) ||
|
|
|
|
address.isInSubnet(QHostAddress::parseSubnet("172.16.0.0/12")) ||
|
|
|
|
address.isInSubnet(QHostAddress::parseSubnet("10.0.0.0/8")) ||
|
2017-12-15 03:10:02 +01:00
|
|
|
// Private v4 range translated to v6
|
|
|
|
address.isInSubnet(QHostAddress::parseSubnet("::ffff:192.168.0.0/112")) ||
|
|
|
|
address.isInSubnet(QHostAddress::parseSubnet("::ffff:172.16.0.0/108")) ||
|
|
|
|
address.isInSubnet(QHostAddress::parseSubnet("::ffff:10.0.0.0/104")) ||
|
2013-01-12 17:22:40 +01:00
|
|
|
// Private v6 range
|
|
|
|
address.isInSubnet(QHostAddress::parseSubnet("fc00::/7"));
|
2013-01-10 21:21:55 +01:00
|
|
|
}
|
2013-01-09 17:38:24 +01:00
|
|
|
|
2013-07-27 07:27:08 +02:00
|
|
|
void NetworkRemote::CreateRemoteClient(QTcpSocket* client_socket) {
|
2013-01-10 21:21:55 +01:00
|
|
|
if (client_socket) {
|
|
|
|
// Add the client to the list
|
|
|
|
RemoteClient* client = new RemoteClient(app_, client_socket);
|
|
|
|
clients_.push_back(client);
|
2013-01-09 17:38:24 +01:00
|
|
|
|
2020-11-27 13:05:53 +01:00
|
|
|
// Update the Remote Root Files for the latest Client
|
|
|
|
outgoing_data_creator_->SetMusicExtensions(
|
|
|
|
client->files_music_extensions());
|
|
|
|
outgoing_data_creator_->SetRemoteRootFiles(client->files_root_folder());
|
|
|
|
incoming_data_parser_->SetRemoteRootFiles(client->files_root_folder());
|
|
|
|
// update OutgoingDataCreator with latest allow_downloads setting
|
|
|
|
outgoing_data_creator_->SetAllowDownloads(client->allow_downloads());
|
|
|
|
|
2013-01-10 21:21:55 +01:00
|
|
|
// Connect the signal to parse data
|
2021-02-20 22:20:04 +01:00
|
|
|
connect(client, SIGNAL(Parse(cpb::remote::Message)),
|
|
|
|
incoming_data_parser_.get(), SLOT(Parse(cpb::remote::Message)));
|
2013-01-10 21:21:55 +01:00
|
|
|
}
|
2012-12-31 23:37:39 +01:00
|
|
|
}
|
2013-12-22 15:16:42 +01:00
|
|
|
|
|
|
|
void NetworkRemote::EnableKittens(bool aww) {
|
2014-02-07 16:34:20 +01:00
|
|
|
if (outgoing_data_creator_.get()) outgoing_data_creator_->EnableKittens(aww);
|
2013-12-22 15:16:42 +01:00
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
void NetworkRemote::SendKitten(quint64 id, const QImage& kitten) {
|
|
|
|
if (outgoing_data_creator_.get()) outgoing_data_creator_->SendKitten(kitten);
|
2013-12-22 15:16:42 +01:00
|
|
|
}
|