Commit e0f537c521d3dace44e222e1d29546ed9b58f988
- Diff rendering mode:
- inline
- side by side
include/Uuid.h
(55 / 0)
|   | |||
| 1 | /* | ||
| 2 | * libMendeley: Assorted classes used by Mendeley Desktop | ||
| 3 | * Copyright (C) 2009 Mendeley Limited <copyright@mendeley.com> | ||
| 4 | |||
| 5 | * Mendeley contact: Mendeley Copyright (copyrightmendeley.com) | ||
| 6 | * | ||
| 7 | * This library is free software; you can redistribute it and/or | ||
| 8 | * modify it under the terms of the GNU Lesser General Public | ||
| 9 | * License as published by the Free Software Foundation; version 2.1. | ||
| 10 | * | ||
| 11 | * This library is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 14 | * Lesser General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU Lesser General Public | ||
| 17 | * License along with this library; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 19 | */ | ||
| 20 | #ifndef _MENDELEY_UUID_H | ||
| 21 | #define _MENDELEY_UUID_H | ||
| 22 | |||
| 23 | #include <QAtomicInt> | ||
| 24 | |||
| 25 | namespace Mendeley | ||
| 26 | { | ||
| 27 | /** Alternative to QUuid which makes UUIDs that are less likely to have collisions. | ||
| 28 | * | ||
| 29 | * QUuid is purely based on date and time. | ||
| 30 | * | ||
| 31 | * This class takes into account: | ||
| 32 | * - The current date and time | ||
| 33 | * - The application PID | ||
| 34 | * - The current thread | ||
| 35 | * - The MAC addresses of all interfaces on the local host | ||
| 36 | * | ||
| 37 | * Not as fast, but safer if you have multiple clients which need to have non-colliding UUIDs. | ||
| 38 | * | ||
| 39 | * @author Fred Emmott <fred.emmott@mendeley.com> | ||
| 40 | */ | ||
| 41 | class Uuid | ||
| 42 | { | ||
| 43 | public: | ||
| 44 | /** Alternative to QUuid::createUuid() which works when used across | ||
| 45 | * multiple threads simultaneously. | ||
| 46 | */ | ||
| 47 | static QString createUuid(); | ||
| 48 | private: | ||
| 49 | /// Random seed for the first call to this function per thread. | ||
| 50 | static void randomSeed(char* seed, int bytes); | ||
| 51 | static void nextValue(char* value, int bytes); | ||
| 52 | }; | ||
| 53 | } | ||
| 54 | |||
| 55 | #endif |
src/core/CMakeLists.txt
(1 / 0)
|   | |||
| 9 | 9 | TagReader | |
| 10 | 10 | ToolBar | |
| 11 | 11 | TrackData | |
| 12 | Uuid | ||
| 12 | 13 | Utilities | |
| 13 | 14 | WizardPage | |
| 14 | 15 | ) |
src/core/Uuid.cpp
(128 / 0)
|   | |||
| 1 | /* | ||
| 2 | * libMendeley: Assorted classes used by Mendeley Desktop | ||
| 3 | * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies) | ||
| 4 | * Copyright (C) 2009 Mendeley Limited | ||
| 5 | * | ||
| 6 | * This version is maintained by Mendeley Limited, and most queries should | ||
| 7 | * be directed to them. | ||
| 8 | * | ||
| 9 | * Nokia contact: Qt Software Information (qt-info@nokia.com) | ||
| 10 | * Mendeley contact: Mendeley Copyright (copyright@mendeley.com) | ||
| 11 | * | ||
| 12 | * This library is free software; you can redistribute it and/or | ||
| 13 | * modify it under the terms of the GNU Lesser General Public | ||
| 14 | * License as published by the Free Software Foundation, version 2.1. | ||
| 15 | * | ||
| 16 | * This library is distributed in the hope that it will be useful, | ||
| 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 19 | * Lesser General Public License for more details. | ||
| 20 | * | ||
| 21 | * You should have received a copy of the GNU Lesser General Public | ||
| 22 | * License along with this library; if not, write to the Free Software | ||
| 23 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1161 USA | ||
| 24 | */ | ||
| 25 | #include "Uuid.h" | ||
| 26 | #include "memcpy_safe.h" | ||
| 27 | |||
| 28 | // This needs to be included before QNetworkInterface to work around a bug | ||
| 29 | // in the Qt 4.5 headers. | ||
| 30 | #include <QPair> | ||
| 31 | |||
| 32 | #include <QByteArray> | ||
| 33 | #include <QCoreApplication> | ||
| 34 | #include <QCryptographicHash> | ||
| 35 | #include <QDataStream> | ||
| 36 | #include <QDateTime> | ||
| 37 | #include <QNetworkInterface> | ||
| 38 | #include <QString> | ||
| 39 | #include <QThread> | ||
| 40 | #include <QThreadStorage> | ||
| 41 | #include <QUuid> | ||
| 42 | |||
| 43 | #include <cstdlib> | ||
| 44 | |||
| 45 | namespace Mendeley | ||
| 46 | { | ||
| 47 | void Uuid::nextValue(char* value, int bytes) | ||
| 48 | { | ||
| 49 | // progress by md5 | ||
| 50 | const QByteArray hash(QCryptographicHash::hash(QByteArray(value, bytes), QCryptographicHash::Md5)); | ||
| 51 | ::memcpy_safe(value, bytes, hash.constData(), qMin(bytes, hash.count())); | ||
| 52 | } | ||
| 53 | |||
| 54 | // wrap seed inside a struct because QThreadStorage<> uses delete rather than | ||
| 55 | // delete[] to free the stored value | ||
| 56 | struct UuidSeed | ||
| 57 | { | ||
| 58 | char seed[16]; | ||
| 59 | }; | ||
| 60 | |||
| 61 | QString Uuid::createUuid() | ||
| 62 | { | ||
| 63 | // Begin section lifted from QUuid::createUuid(), modified to set a | ||
| 64 | // different random seed for each thread - otherwise qrand() always returns the same | ||
| 65 | // sequence of random numbers for each thread and the resulting uuids will be the same | ||
| 66 | // when called from different threads | ||
| 67 | // | ||
| 68 | // See Qt Software Task Tracker Bug #171206 | ||
| 69 | // (http://www.qtsoftware.com/developer/task-tracker/index_html?method=entry&id=171206) | ||
| 70 | static QThreadStorage<UuidSeed*> threadStorage; | ||
| 71 | if(!threadStorage.hasLocalData()) | ||
| 72 | { | ||
| 73 | UuidSeed* seedValue = new UuidSeed; | ||
| 74 | randomSeed(seedValue->seed, 16); | ||
| 75 | threadStorage.setLocalData(seedValue); | ||
| 76 | } | ||
| 77 | |||
| 78 | char* value = threadStorage.localData()->seed; | ||
| 79 | nextValue(value, 16); | ||
| 80 | |||
| 81 | struct | ||
| 82 | { | ||
| 83 | uint data1; | ||
| 84 | ushort data2; | ||
| 85 | ushort data3; | ||
| 86 | uchar data4[8]; | ||
| 87 | } parts; | ||
| 88 | |||
| 89 | uint *data = &(parts.data1); | ||
| 90 | ::memcpy_safe(data, sizeof(parts), value, 16); | ||
| 91 | |||
| 92 | parts.data4[0] = (parts.data4[0] & 0x3F) | 0x80; // UV_DCE | ||
| 93 | parts.data3 = (parts.data3 & 0x0FFF) | 0x4000; // UV_Random | ||
| 94 | // End Section lifted from QUuid::createUuid() | ||
| 95 | |||
| 96 | QUuid uuid(parts.data1,parts.data2,parts.data3, | ||
| 97 | parts.data4[0],parts.data4[1],parts.data4[2], | ||
| 98 | parts.data4[3],parts.data4[4],parts.data4[5], | ||
| 99 | parts.data4[6],parts.data4[7]); | ||
| 100 | |||
| 101 | return uuid.toString(); | ||
| 102 | } | ||
| 103 | |||
| 104 | void Uuid::randomSeed(char* seed, int bytes) | ||
| 105 | { | ||
| 106 | Q_ASSERT(bytes == 16); | ||
| 107 | // Seed based on: | ||
| 108 | // - 'mendeley' (salt) | ||
| 109 | // - date and time | ||
| 110 | // - PID | ||
| 111 | // - thread | ||
| 112 | // - all MAC addresses | ||
| 113 | QByteArray data; | ||
| 114 | { | ||
| 115 | QDataStream stream(&data, QIODevice::WriteOnly); | ||
| 116 | stream << "mendeley"; | ||
| 117 | stream << QDateTime::currentDateTime(); | ||
| 118 | stream << QCoreApplication::applicationPid(); | ||
| 119 | stream << reinterpret_cast<qint64>(QThread::currentThread()); | ||
| 120 | Q_FOREACH(const QNetworkInterface& interface, QNetworkInterface::allInterfaces()) | ||
| 121 | { | ||
| 122 | stream << interface.hardwareAddress() << interface.name(); | ||
| 123 | } | ||
| 124 | } | ||
| 125 | const QByteArray hash(QCryptographicHash::hash(data, QCryptographicHash::Md5)); | ||
| 126 | ::memcpy_safe(seed, bytes, hash.constData(), qMin(bytes, hash.count())); | ||
| 127 | } | ||
| 128 | } |
src/core/memcpy_safe.h
(30 / 0)
|   | |||
| 1 | /* LICENSE NOTICE | ||
| 2 | Copyright (c) 2009, Frederick Emmott <mail@fredemmott.co.uk> | ||
| 3 | |||
| 4 | Permission to use, copy, modify, and/or distribute this software for any | ||
| 5 | purpose with or without fee is hereby granted, provided that the above | ||
| 6 | copyright notice and this permission notice appear in all copies. | ||
| 7 | |||
| 8 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
| 9 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
| 10 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
| 11 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
| 12 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
| 13 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
| 14 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
| 15 | */ | ||
| 16 | #pragma once | ||
| 17 | |||
| 18 | #include <string.h> | ||
| 19 | |||
| 20 | // TODO: use the windows function on windows | ||
| 21 | |||
| 22 | inline void* memcpy_safe(void* destination, size_t destinationSize, const void* source, size_t count) | ||
| 23 | { | ||
| 24 | Q_ASSERT(destinationSize >= count); | ||
| 25 | if(destinationSize < count) | ||
| 26 | { | ||
| 27 | return 0; | ||
| 28 | } | ||
| 29 | return ::memcpy(destination, source, count); | ||
| 30 | } |
|   | |||
| 1 | SET( | ||
| 2 | CLASSES | ||
| 3 | NetworkClient | ||
| 4 | ) | ||
| 5 | |||
| 6 | SET(SOURCES) | ||
| 7 | SET(HEADERS) | ||
| 8 | FOREACH(class ${CLASSES}) | ||
| 9 | LIST(APPEND SOURCES ${class}.cpp) | ||
| 10 | LIST(APPEND HEADERS ${class}.h) | ||
| 11 | ENDFOREACH() | ||
| 12 | |||
| 13 | INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) | ||
| 14 | QT4_WRAP_CPP(MOC_SOURCES ${HEADERS}) | ||
| 15 | ADD_LIBRARY( | ||
| 16 | NetworkClient | ||
| 17 | ${SOURCES} | ||
| 18 | ${MOC_SOURCES} | ||
| 19 | ) |
|   | |||
| 1 | #include "NetworkClient.h" | ||
| 2 | |||
| 3 | #include <QApplication> | ||
| 4 | #include <QDebug> | ||
| 5 | #include <QtPlugin> | ||
| 6 | |||
| 7 | NetworkClient::NetworkClient() | ||
| 8 | : QObject(0) | ||
| 9 | { | ||
| 10 | } | ||
| 11 | |||
| 12 | QString NetworkClient::pluginName() const | ||
| 13 | { | ||
| 14 | return tr("Network Client"); | ||
| 15 | } | ||
| 16 | |||
| 17 | QString NetworkClient::pluginAuthor() const | ||
| 18 | { | ||
| 19 | return QString::fromLatin1("Fred Emmott"); | ||
| 20 | } | ||
| 21 | |||
| 22 | QString NetworkClient::uniqueId() const | ||
| 23 | { | ||
| 24 | return "org.jerboaplayer.NetworkClient"; | ||
| 25 | } | ||
| 26 | |||
| 27 | Q_EXPORT_PLUGIN2(Jerboa_NetworkClient, NetworkClient); |
|   | |||
| 1 | #pragma once | ||
| 2 | |||
| 3 | #include "Plugin.h" | ||
| 4 | |||
| 5 | #include <QObject> | ||
| 6 | |||
| 7 | class NetworkClient : public QObject, public Jerboa::Plugin | ||
| 8 | { | ||
| 9 | Q_OBJECT; | ||
| 10 | Q_INTERFACES(Jerboa::Plugin); | ||
| 11 | public: | ||
| 12 | NetworkClient(); | ||
| 13 | QString pluginName() const; | ||
| 14 | QString pluginAuthor() const; | ||
| 15 | QString uniqueId() const; | ||
| 16 | private: | ||
| 17 | class Implementation; | ||
| 18 | }; |
|   | |||
| 1 | SET( | ||
| 2 | CLASSES | ||
| 3 | NetworkServer | ||
| 4 | NetworkServer_Implementation | ||
| 5 | ) | ||
| 6 | |||
| 7 | SET(SOURCES) | ||
| 8 | SET(HEADERS) | ||
| 9 | FOREACH(class ${CLASSES}) | ||
| 10 | LIST(APPEND SOURCES ${class}.cpp) | ||
| 11 | LIST(APPEND HEADERS ${class}.h) | ||
| 12 | ENDFOREACH() | ||
| 13 | |||
| 14 | INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) | ||
| 15 | QT4_WRAP_CPP(MOC_SOURCES ${HEADERS}) | ||
| 16 | ADD_LIBRARY( | ||
| 17 | NetworkServer | ||
| 18 | ${SOURCES} | ||
| 19 | ${MOC_SOURCES} | ||
| 20 | ) |
|   | |||
| 1 | #include "NetworkServer.h" | ||
| 2 | #include "NetworkServer_Implementation.h" | ||
| 3 | |||
| 4 | #include "CollectionInterface.h" | ||
| 5 | #include "PlayerInterface.h" | ||
| 6 | #include "PlaylistInterface.h" | ||
| 7 | |||
| 8 | #include <QApplication> | ||
| 9 | #include <QDebug> | ||
| 10 | #include <QtPlugin> | ||
| 11 | |||
| 12 | NetworkServer::NetworkServer() | ||
| 13 | : QObject(0) | ||
| 14 | , m_collection(0) | ||
| 15 | , m_player(0) | ||
| 16 | , m_playlist(0) | ||
| 17 | { | ||
| 18 | } | ||
| 19 | |||
| 20 | QString NetworkServer::pluginName() const | ||
| 21 | { | ||
| 22 | return tr("Network Server"); | ||
| 23 | } | ||
| 24 | |||
| 25 | QString NetworkServer::pluginAuthor() const | ||
| 26 | { | ||
| 27 | return QString::fromLatin1("Fred Emmott"); | ||
| 28 | } | ||
| 29 | |||
| 30 | QString NetworkServer::uniqueId() const | ||
| 31 | { | ||
| 32 | return "org.jerboaplayer.NetworkServer"; | ||
| 33 | } | ||
| 34 | |||
| 35 | void NetworkServer::initialize() const | ||
| 36 | { | ||
| 37 | if(m_collection && m_player && m_playlist) | ||
| 38 | { | ||
| 39 | new Implementation(m_collection, m_player, m_playlist); | ||
| 40 | } | ||
| 41 | } | ||
| 42 | |||
| 43 | void NetworkServer::addComponent(ComponentType type, QObject* component) | ||
| 44 | { | ||
| 45 | switch(type) | ||
| 46 | { | ||
| 47 | case CollectionSource: | ||
| 48 | Q_ASSERT(qobject_cast<Jerboa::CollectionInterface*>(component)); | ||
| 49 | m_collection = static_cast<Jerboa::CollectionInterface*>(component); | ||
| 50 | initialize(); | ||
| 51 | break; | ||
| 52 | case Player: | ||
| 53 | Q_ASSERT(qobject_cast<Jerboa::PlayerInterface*>(component)); | ||
| 54 | m_player = static_cast<Jerboa::PlayerInterface*>(component); | ||
| 55 | initialize(); | ||
| 56 | break; | ||
| 57 | case PlaylistSource: | ||
| 58 | Q_ASSERT(qobject_cast<Jerboa::PlaylistInterface*>(component)); | ||
| 59 | m_playlist = static_cast<Jerboa::PlaylistInterface*>(component); | ||
| 60 | initialize(); | ||
| 61 | break; | ||
| 62 | default: | ||
| 63 | Plugin::addComponent(type, component); | ||
| 64 | break; | ||
| 65 | } | ||
| 66 | } | ||
| 67 | |||
| 68 | Q_EXPORT_PLUGIN2(Jerboa_NetworkServer, NetworkServer); |
|   | |||
| 1 | #pragma once | ||
| 2 | |||
| 3 | #include "Plugin.h" | ||
| 4 | |||
| 5 | #include <QObject> | ||
| 6 | |||
| 7 | namespace Jerboa | ||
| 8 | { | ||
| 9 | class CollectionInterface; | ||
| 10 | class PlayerInterface; | ||
| 11 | class PlaylistInterface; | ||
| 12 | }; | ||
| 13 | |||
| 14 | class NetworkServer : public QObject, public Jerboa::Plugin | ||
| 15 | { | ||
| 16 | Q_OBJECT; | ||
| 17 | Q_INTERFACES(Jerboa::Plugin); | ||
| 18 | public: | ||
| 19 | NetworkServer(); | ||
| 20 | QString pluginName() const; | ||
| 21 | QString pluginAuthor() const; | ||
| 22 | QString uniqueId() const; | ||
| 23 | void addComponent(ComponentType type, QObject* component); | ||
| 24 | private: | ||
| 25 | class Implementation; | ||
| 26 | |||
| 27 | void initialize() const; | ||
| 28 | |||
| 29 | Jerboa::CollectionInterface* m_collection; | ||
| 30 | Jerboa::PlayerInterface* m_player; | ||
| 31 | Jerboa::PlaylistInterface* m_playlist; | ||
| 32 | }; |
|   | |||
| 1 | #include "NetworkServer_Implementation.h" | ||
| 2 | |||
| 3 | #include "Uuid.h" | ||
| 4 | |||
| 5 | #include <QDebug> | ||
| 6 | #include <QHostInfo> | ||
| 7 | #include <QSettings> | ||
| 8 | #include <QTcpServer> | ||
| 9 | #include <QUdpSocket> | ||
| 10 | |||
| 11 | const quint16 PORT_NUMBER = 61719; // pseudo-random from private range | ||
| 12 | const QByteArray DISCOVERY_MESSAGE = "Jerboa Network Discovery/1.0\n"; | ||
| 13 | |||
| 14 | NetworkServer::Implementation::Implementation(Jerboa::CollectionInterface* collection, Jerboa::PlayerInterface* player, Jerboa::PlaylistInterface* playlist) | ||
| 15 | : QObject(0) | ||
| 16 | , m_collection(collection) | ||
| 17 | , m_player(player) | ||
| 18 | , m_playlist(playlist) | ||
| 19 | , m_discoverySocket(new QUdpSocket(this)) | ||
| 20 | , m_server(new QTcpServer(this)) | ||
| 21 | { | ||
| 22 | const bool startedDiscovery = m_discoverySocket->bind(QHostAddress::Any, PORT_NUMBER); | ||
| 23 | if(!startedDiscovery) | ||
| 24 | { | ||
| 25 | qDebug() << "Failed to start network discovery:" << m_discoverySocket->errorString(); | ||
| 26 | return; | ||
| 27 | } | ||
| 28 | |||
| 29 | if(!m_server->listen()) | ||
| 30 | { | ||
| 31 | qDebug() << "Failed to bind network socket:" << m_server->errorString(); | ||
| 32 | return; | ||
| 33 | } | ||
| 34 | |||
| 35 | qDebug() << "Network server started."; | ||
| 36 | |||
| 37 | connect(m_discoverySocket, SIGNAL(readyRead()), SLOT(sendDiscoveryResponses())); | ||
| 38 | |||
| 39 | |||
| 40 | QSettings settings; | ||
| 41 | |||
| 42 | // Deal with strings in QSettings so the saved values are more human-readable | ||
| 43 | QString serverUuid = settings.value("network/serverUuid").toString(); | ||
| 44 | if(serverUuid.isEmpty()) | ||
| 45 | { | ||
| 46 | serverUuid = Mendeley::Uuid::createUuid(); | ||
| 47 | settings.setValue("network/serverUuid", serverUuid); | ||
| 48 | } | ||
| 49 | |||
| 50 | m_serverUuid = serverUuid.toLatin1(); | ||
| 51 | |||
| 52 | // Load up the response | ||
| 53 | { | ||
| 54 | QByteArray payload; | ||
| 55 | payload = QString::number(m_serverUuid.length()).toLatin1(); | ||
| 56 | payload.append(','); | ||
| 57 | payload.append(m_serverUuid); | ||
| 58 | payload.append(','); | ||
| 59 | const QByteArray host = QHostInfo::localHostName().toUtf8(); | ||
| 60 | payload.append(QString::number(host.length()).toLatin1()); | ||
| 61 | payload.append(','); | ||
| 62 | payload.append(host); | ||
| 63 | payload.append(','); | ||
| 64 | const QByteArray port = QString::number(m_server->serverPort()).toLatin1(); | ||
| 65 | payload.append(QString::number(port.length()).toLatin1()); | ||
| 66 | payload.append(','); | ||
| 67 | payload.append(port); | ||
| 68 | payload.append(','); | ||
| 69 | |||
| 70 | m_discoveryResponse = createMessage("ANNOUNCE", payload, UnsignedMessage); | ||
| 71 | } | ||
| 72 | } | ||
| 73 | |||
| 74 | QByteArray NetworkServer::Implementation::createMessage(const QByteArray& command, const QByteArray& payload, MessageType messageType) const | ||
| 75 | { | ||
| 76 | // netstrings-influenced | ||
| 77 | // CommandLength,Command,PayloadLength,Payload,{U|S,timestamp-length,timestamp,message-uuid,signature}; | ||
| 78 | // | ||
| 79 | // Examples: | ||
| 80 | // 3,foo,0,,U; | ||
| 81 | // 3,bar,3,baz,S,10,1266356591,{fc8d8c6c-2ede-4bb8-8685-2cc47cdd8b2b},0000000000000000000000000000000000000000 | ||
| 82 | // | ||
| 83 | // Where: | ||
| 84 | // - timestamp is the number of seconds since 1970-01-01T00:00:00 UTC | ||
| 85 | // - message-uuid is a per-message UUID to prevent replays | ||
| 86 | // - signature is an HMAC-SHA1 of everything up to and including the previous comma | ||
| 87 | QByteArray out; | ||
| 88 | Q_ASSERT(messageType == UnsignedMessage); | ||
| 89 | Q_UNUSED(messageType); | ||
| 90 | |||
| 91 | out.append(QString::number(command.length()).toLatin1()); | ||
| 92 | out.append(','); | ||
| 93 | out.append(command); | ||
| 94 | out.append(','); | ||
| 95 | out.append(QString::number(payload.length()).toLatin1()); | ||
| 96 | out.append(','); | ||
| 97 | out.append(payload); | ||
| 98 | out.append(",U;"); | ||
| 99 | return out; | ||
| 100 | } | ||
| 101 | |||
| 102 | void NetworkServer::Implementation::sendDiscoveryResponses() | ||
| 103 | { | ||
| 104 | while(m_discoverySocket->hasPendingDatagrams()) | ||
| 105 | { | ||
| 106 | // don't worry about overflow, UDP packets have reasonable maximum size | ||
| 107 | QByteArray payload; | ||
| 108 | payload.resize(m_discoverySocket->pendingDatagramSize()); | ||
| 109 | QHostAddress source; | ||
| 110 | quint16 sourcePort; | ||
| 111 | m_discoverySocket->readDatagram(payload.data(), payload.size(), &source, &sourcePort); | ||
| 112 | if(payload == DISCOVERY_MESSAGE) | ||
| 113 | { | ||
| 114 | qDebug() << "Received a discovery message from" << QString("%1:%2").arg(source.toString()).arg(sourcePort); | ||
| 115 | // send a response | ||
| 116 | m_discoverySocket->writeDatagram(m_discoveryResponse, source, sourcePort); | ||
| 117 | } | ||
| 118 | } | ||
| 119 | } |
|   | |||
| 1 | #include "NetworkServer.h" | ||
| 2 | |||
| 3 | #include <QByteArray> | ||
| 4 | |||
| 5 | class QTcpServer; | ||
| 6 | class QUdpSocket; | ||
| 7 | |||
| 8 | namespace Jerboa | ||
| 9 | { | ||
| 10 | class CollectionInterface; | ||
| 11 | class PlayerInterface; | ||
| 12 | class PlaylistInterface; | ||
| 13 | }; | ||
| 14 | |||
| 15 | class NetworkServer::Implementation : public QObject | ||
| 16 | { | ||
| 17 | Q_OBJECT; | ||
| 18 | public: | ||
| 19 | Implementation(Jerboa::CollectionInterface* collection, Jerboa::PlayerInterface* player, Jerboa::PlaylistInterface* playlist); | ||
| 20 | private slots: | ||
| 21 | void sendDiscoveryResponses(); | ||
| 22 | private: | ||
| 23 | enum MessageType | ||
| 24 | { | ||
| 25 | UnsignedMessage, | ||
| 26 | SignedMessage | ||
| 27 | }; | ||
| 28 | QByteArray createMessage(const QByteArray& command, const QByteArray& payload, MessageType messageType) const; | ||
| 29 | |||
| 30 | Jerboa::CollectionInterface* m_collection; | ||
| 31 | Jerboa::PlayerInterface* m_player; | ||
| 32 | Jerboa::PlaylistInterface* m_playlist; | ||
| 33 | |||
| 34 | QByteArray m_serverUuid; | ||
| 35 | QByteArray m_discoveryResponse; | ||
| 36 | |||
| 37 | QUdpSocket* m_discoverySocket; | ||
| 38 | QTcpServer* m_server; | ||
| 39 | }; |

