/* * QCMA: Cross-platform content manager assistant for the PS Vita * * Copyright (C) 2013 Codestation * * This program 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. * * This program 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 this program. If not, see . */ #include "cmabroadcast.h" #include "cmautils.h" #include #include #include #include #include #include #include const QString CmaBroadcast::broadcast_reply = "%1\r\n" "host-id:%2\r\n" "host-type:%3\r\n" "host-name:%4\r\n" "host-mtp-protocol-version:%5\r\n" "host-request-port:%6\r\n" "host-wireless-protocol-version:%7\r\n" "host-supported-device:PS Vita, PS Vita TV\r\n"; const char *CmaBroadcast::broadcast_query_start = "SRCH"; const char *CmaBroadcast::broadcast_query_end = " * HTTP/1.1\r\n"; const char *CmaBroadcast::broadcast_ok = "HTTP/1.1 200 OK"; const char *CmaBroadcast::broadcast_unavailable = "HTTP/1.1 503 NG"; CmaBroadcast::CmaBroadcast(QObject *obj_parent) : QObject(obj_parent) { QSettings settings; // generate a GUID if doesn't exist yet in settings uuid = settings.value("guid").toString(); if(uuid.isEmpty()) { uuid = QUuid::createUuid().toString().mid(1,36); settings.setValue("guid", uuid); } hostname = settings.value("hostName", QHostInfo::localHostName()).toString(); setAvailable(); socket = new QUdpSocket(this); connect(socket, SIGNAL(readyRead()), this, SLOT(readPendingDatagrams())); QHostAddress host_address(QHostAddress::AnyIPv4); if(!socket->bind(host_address, QCMA_REQUEST_PORT, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint)) { qCritical() << "Failed to bind address for UDP broadcast"; } } void CmaBroadcast::readPendingDatagrams() { if(socket->hasPendingDatagrams()) { QByteArray datagram; datagram.resize(socket->pendingDatagramSize()); QHostAddress cma_sender; quint16 senderPort; socket->readDatagram(datagram.data(), datagram.size(), &cma_sender, &senderPort); if(datagram.startsWith(broadcast_query_start) && datagram.contains(broadcast_query_end)) { QMutexLocker locker(&mutex); socket->writeDatagram(reply, cma_sender, senderPort); } else { qWarning() << "Unknown request, length: " << datagram.length() << "data: " << datagram.constData(); } } } void CmaBroadcast::setAvailable() { QMutexLocker locker(&mutex); int protocol_version = ::getVitaProtocolVersion(); reply.clear(); reply.insert(0, broadcast_reply .arg(broadcast_ok, uuid, "win", hostname) .arg(protocol_version, 8, 10, QChar('0')) .arg(QCMA_REQUEST_PORT) .arg(VITAMTP_WIRELESS_MAX_VERSION, 8, 10, QChar('0')).toStdString()); reply.append('\0'); } void CmaBroadcast::setUnavailable() { QMutexLocker locker(&mutex); int protocol_version = ::getVitaProtocolVersion(); reply.clear(); reply.insert(0, broadcast_reply .arg(broadcast_unavailable, uuid, "win", hostname) .arg(protocol_version, 8, 10, QChar('0')) .arg(QCMA_REQUEST_PORT) .arg(VITAMTP_WIRELESS_MAX_VERSION, 8, 10, QChar('0')).toStdString()); reply.append('\0'); }