// // Socket.cpp // libraries/networking/src/udt // // Created by Stephen Birarda on 2015-07-20. // Copyright 2015 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // #include "Socket.h" #include #include "../NetworkLogging.h" #include "ControlSender.h" #include "Packet.h" using namespace udt; Socket::Socket(QObject* parent) : QObject(parent) { connect(&_udpSocket, &QUdpSocket::readyRead, this, &Socket::readPendingDatagrams); // make a QThread for the ControlSender to live on QThread* controlThread = new QThread(this); // setup the ControlSender and parent it _controlSender = new ControlSender; // move the ControlSender to its thread _controlSender->moveToThread(controlThread); // start the ControlSender once the thread is started connect(controlThread, &QThread::started, _controlSender, &ControlSender::loop); // make sure the control thread is named so we can identify it controlThread->setObjectName("UDT Control Thread"); // start the control thread controlThread->start(); } Socket::~Socket() { if (_controlSender) { QThread* controlThread = _controlSender->thread(); // tell the control sender to stop and be deleted so we can wait on its thread QMetaObject::invokeMethod(_controlSender, "stop"); _controlSender->deleteLater(); // make sure the control thread goes down controlThread->quit(); controlThread->wait(); } } void Socket::rebind() { quint16 oldPort = _udpSocket.localPort(); _udpSocket.close(); _udpSocket.bind(QHostAddress::AnyIPv4, oldPort); } void Socket::setBufferSizes(int numBytes) { for (int i = 0; i < 2; i++) { QAbstractSocket::SocketOption bufferOpt; QString bufferTypeString; if (i == 0) { bufferOpt = QAbstractSocket::SendBufferSizeSocketOption; bufferTypeString = "send"; } else { bufferOpt = QAbstractSocket::ReceiveBufferSizeSocketOption; bufferTypeString = "receive"; } int oldBufferSize = _udpSocket.socketOption(bufferOpt).toInt(); if (oldBufferSize < numBytes) { int newBufferSize = _udpSocket.socketOption(bufferOpt).toInt(); qCDebug(networking) << "Changed socket" << bufferTypeString << "buffer size from" << oldBufferSize << "to" << newBufferSize << "bytes"; } else { // don't make the buffer smaller qCDebug(networking) << "Did not change socket" << bufferTypeString << "buffer size from" << oldBufferSize << "since it is larger than desired size of" << numBytes; } } } qint64 Socket::writeUnreliablePacket(const Packet& packet, const HifiSockAddr& sockAddr) { return writeDatagram(packet.getData(), packet.getDataSize(), sockAddr); } qint64 Socket::writeDatagram(const QByteArray& datagram, const HifiSockAddr& sockAddr) { qint64 bytesWritten = _udpSocket.writeDatagram(datagram, sockAddr.getAddress(), sockAddr.getPort()); // TODO: write the correct sequence number to the Packet here // const_cast(packet).writeSequenceNumber(sequenceNumber); if (bytesWritten < 0) { qCDebug(networking) << "ERROR in writeDatagram:" << _udpSocket.error() << "-" << _udpSocket.errorString(); } return bytesWritten; } void Socket::readPendingDatagrams() { while (_udpSocket.hasPendingDatagrams()) { // setup a HifiSockAddr to read into HifiSockAddr senderSockAddr; // setup a buffer to read the packet into int packetSizeWithHeader = _udpSocket.pendingDatagramSize(); std::unique_ptr buffer = std::unique_ptr(new char[packetSizeWithHeader]); // pull the datagram _udpSocket.readDatagram(buffer.get(), packetSizeWithHeader, senderSockAddr.getAddressPointer(), senderSockAddr.getPortPointer()); auto it = _unfilteredHandlers.find(senderSockAddr); if (it != _unfilteredHandlers.end()) { // we have a registered unfiltered handler for this HifiSockAddr - call that and return if (it->second) { auto basePacket = BasePacket::fromReceivedPacket(std::move(buffer), packetSizeWithHeader, senderSockAddr); it->second(std::move(basePacket)); } return; } // setup a Packet from the data we just read auto packet = Packet::fromReceivedPacket(std::move(buffer), packetSizeWithHeader, senderSockAddr); // call our verification operator to see if this packet is verified if (!_packetFilterOperator || _packetFilterOperator(*packet)) { if (_packetHandler) { // call the verified packet callback to let it handle this packet return _packetHandler(std::move(packet)); } } } }