void AudioReceiver::initClient() { quint16 port = (quint16) (set->getAudioPort() + (io->audio_rx * 2)); QUdpSocket *socket = new QUdpSocket(); socket->setSocketOption(QAbstractSocket::LowDelayOption, 1); if (socket->bind(port, QUdpSocket::ReuseAddressHint | QUdpSocket::ShareAddress)) { CHECKED_CONNECT( socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(displayAudioRcvrSocketError(QAbstractSocket::SocketError))); CHECKED_CONNECT( socket, SIGNAL(readyRead()), this, SLOT(readPendingAudioRcvrData())); clientConnections.append(socket); AUDIO_RECEIVER << "client socket binding successful."; m_message = tr("[server]: listening for rx %1 audio on port %2."); emit messageEvent(m_message.arg(io->audio_rx).arg(port)); //m_dataEngine->clientConnected = true; // need to implement connection in dataEngine !!!! emit clientConnectedEvent(true); //rcveIQ_toggle = false; } else { m_message = tr("[server]: bind socket failed for socket on port %1."); emit messageEvent(m_message.arg(port)); } }
void UdpRelay::onServerUdpSocketReadyRead() { if (listenSocket.pendingDatagramSize() > RecvSize) { emit info("[UDP] Datagram is too large. discarded."); return; } QByteArray data; data.resize(listenSocket.pendingDatagramSize()); QHostAddress r_addr; quint16 r_port; qint64 readSize = listenSocket.readDatagram(data.data(), RecvSize, &r_addr, &r_port); emit bytesRead(readSize); if (isLocal) { if (static_cast<int>(data[2]) != 0) { emit info("[UDP] Drop a message since frag is not 0"); return; } data.remove(0, 3); } else { if (autoBan && Common::isAddressBanned(r_addr)) { emit debug(QString("[UDP] A banned IP %1 " "attempted to access this server") .arg(r_addr.toString())); return; } data = encryptor->decryptAll(data); } Address destAddr, remoteAddr(r_addr, r_port);//remote == client int header_length = 0; bool at_auth = false; Common::parseHeader(data, destAddr, header_length, at_auth); if (header_length == 0) { emit info("[UDP] Can't parse header. " "Wrong encryption method or password?"); if (!isLocal && autoBan) { Common::banAddress(r_addr); } return; } QUdpSocket *client = cache.value(remoteAddr, nullptr); QString dbg; if (!client) { client = new QUdpSocket(this); client->setReadBufferSize(RecvSize); client->setSocketOption(QAbstractSocket::LowDelayOption, 1); cache.insert(remoteAddr, client); connect(client, &QUdpSocket::readyRead, this, &UdpRelay::onClientUdpSocketReadyRead); connect(client, &QUdpSocket::disconnected, this, &UdpRelay::onClientDisconnected); QDebug(&dbg) << "[UDP] cache miss:" << destAddr << "<->" << remoteAddr; } else { QDebug(&dbg) << "[UDP] cache hit:" << destAddr << "<->" << remoteAddr; } emit debug(dbg); if (isLocal) { if (auth || at_auth) { /* * shadowsocks UDP Request (OTA-enabled, unencrypted) * +------+----------+----------+----------+-------------+ * | ATYP | DST.ADDR | DST.PORT | DATA | HMAC-SHA1 | * +------+----------+----------+----------+-------------+ * | 1 | Variable | 2 | Variable | 10 | * +------+----------+----------+----------+-------------+ */ encryptor->addHeaderAuth(data); } data = encryptor->encryptAll(data); destAddr = serverAddress; } else { if (auth || at_auth) { if (!encryptor->verifyHeaderAuth(data, data.length() - Cipher::AUTH_LEN)) { emit info("[UDP] One-time message authentication " "for header failed."); if (autoBan) { Common::banAddress(r_addr); } return; } } data = data.mid(header_length, data.length() - header_length - Cipher::AUTH_LEN); } if (!destAddr.isIPValid()) {//TODO async dns destAddr.blockingLookUp(); } client->writeDatagram(data, destAddr.getFirstIP(), destAddr.getPort()); }
void Discover::announceRecords () { // Reset timer timer->start(announcePeriodMsec); if (not running) return; // Servers don't announce periodically or send departure messages if (mServerMode) return; // Start building a list of records to send in each scope QList<Record> recordsToSend; /////////////////////////////////////////////////////////////////////// // Global scope first /////////////////////////////////////////////////////////////////////// for (Record record : ownedRecords) if (record["Scope"] == "Global") { recordsToSend.push_back(record); } if (not recordsToSend.empty() or defaultScope=="Global") { // This is a discovery request which should be responded to QByteArray datagram("DSDR"); if (departure) datagram = "DSDD"; datagram += makeDatagram(recordsToSend, false); // Send to each Global server for (QPair<QHostAddress,quint16> globalServer : globalServers) { globalSocket->writeDatagram(datagram, globalServer.first, globalServer.second); } } /////////////////////////////////////////////////////////////////////// // Local scope next /////////////////////////////////////////////////////////////////////// for (Record record : ownedRecords) if (record["Scope"] == "Local") { recordsToSend.push_back(record); } if (not recordsToSend.empty() or defaultScope=="Global" or defaultScope=="Local") { QByteArray datagram("DSDA"); if (announceNeedsResponse) datagram = "DSDR"; if (departure) datagram = "DSDD"; datagram += makeDatagram(recordsToSend, true); // For each interface for (auto iface : QNetworkInterface::allInterfaces()) { // For each IPv4 address on this interface for (auto entry : iface.addressEntries()) { if (entry.ip().protocol() != QAbstractSocket::IPv4Protocol) continue; // Add it to addressEntryCache if necessary for local scope testing if (not addressEntryCache.contains(entry)) addressEntryCache.push_back(entry); // Multicast if (iface.flags().testFlag(QNetworkInterface::CanMulticast) and !entry.ip().isNull() and !entry.ip().isLoopback()) { // Create the socket if it doesn't exit yet if (not multiSocket.contains(entry.ip().toString())) { logDebug(QString("New multicast socket: %1 %2").arg(entry.ip().toString(), entry.netmask().toString())); // Add it, create and bind the socket QUdpSocket* socket = new QUdpSocket(this); connect(socket, SIGNAL(readyRead()), this, SLOT(readDatagrams())); socket->setSocketOption(QAbstractSocket::MulticastTtlOption, 1); if (not socket->bind(QHostAddress::AnyIPv4, port, QAbstractSocket::ShareAddress | QAbstractSocket::ReuseAddressHint)) { logWarning(QString("Error binding to iface %1: %2").arg(entry.ip().toString(), socket->errorString())); } socket->setMulticastInterface(iface); socket->joinMulticastGroup(groupAddress, iface); multiSocket.insert(entry.ip().toString(), socket); } // Send datagram multiSocket[entry.ip().toString()]->writeDatagram(datagram, groupAddress, port); } } } } /////////////////////////////////////////////////////////////////////// // Loopback scope last /////////////////////////////////////////////////////////////////////// for (Record record : ownedRecords) if (record["Scope"] == "Loopback") { recordsToSend.push_back(record); } if (not recordsToSend.empty() or true) // Any scope is above or equivalent to loopback { QByteArray datagram("DSDA"); if (announceNeedsResponse) datagram = "DSDR"; if (departure) datagram = "DSDD"; datagram += makeDatagram(recordsToSend, true); // Loopback //loopbackSocket->writeDatagram(datagram, QHostAddress::LocalHost, port); } // Reset announceNeedsResponse = false; departure = false; }