コード例 #1
0
QHostAddress CameraTcpServer::getHostAddress() const
{
	QHostAddress hostAddress;

	QList<QHostAddress> ipAddressesList = QNetworkInterface::allAddresses();
	// use the first non-localhost IPv4 address
	for (int i = 0; i < ipAddressesList.size(); ++i)
	{
		if (ipAddressesList.at(i) != QHostAddress::LocalHost && ipAddressesList.at(i).toIPv4Address())
		{
			hostAddress = ipAddressesList.at(i).toString();
			break;
		}
	}

	// if we did not find one, use IPv4 localhost
	if (hostAddress.isNull())
	{
		hostAddress = QHostAddress(QHostAddress::LocalHost);
	}

	return hostAddress;
}
コード例 #2
0
void tst_QHostAddress::setAddress_QString()
{
    QFETCH(QString, address);
    QFETCH(bool, ok);
    QFETCH(int, protocol);

    QHostAddress hostAddr;
    QVERIFY(hostAddr.setAddress(address) == ok);

    if (ok)
        QTEST(hostAddr.toString(), "resAddr");

    if ( protocol == 4 ) {
        QVERIFY( hostAddr.protocol() == QAbstractSocket::IPv4Protocol || hostAddr.protocol() == QAbstractSocket::UnknownNetworkLayerProtocol );
        QVERIFY( hostAddr.protocol() != QAbstractSocket::IPv6Protocol );
    } else if ( protocol == 6 ) {
        QVERIFY( hostAddr.protocol() != QAbstractSocket::IPv4Protocol && hostAddr.protocol() != QAbstractSocket::UnknownNetworkLayerProtocol );
        QVERIFY( hostAddr.protocol() == QAbstractSocket::IPv6Protocol );
    } else {
        QVERIFY( hostAddr.isNull() );
        QVERIFY( hostAddr.protocol() == QAbstractSocket::UnknownNetworkLayerProtocol );
    }
}
コード例 #3
0
void ServerDiscoveryModel::addService(KDNSSD::RemoteService::Ptr service)
{
	QUrl url;
	url.setScheme("drawpile");
	QHostAddress hostname = KDNSSD::ServiceBrowser::resolveHostName(service->hostName());
	url.setHost(hostname.isNull() ? service->hostName() : hostname.toString());
	if(service->port() != DRAWPILE_PROTO_DEFAULT_PORT)
		url.setPort(service->port());

	QDateTime started = QDateTime::fromString(service->textData()["started"], Qt::ISODate);
	started.setTimeSpec(Qt::UTC);

	DiscoveredServer s {
		url,
		service->serviceName(),
		service->textData()["title"],
		service->textData()["protocol"],
		started
	};

	beginInsertRows(QModelIndex(), _servers.size(), _servers.size());
	_servers.append(s);
	endInsertRows();
}
コード例 #4
0
ファイル: UDTTest.cpp プロジェクト: cozza13/hifi
UDTTest::UDTTest(int& argc, char** argv) :
    QCoreApplication(argc, argv)
{
    qInstallMessageHandler(LogHandler::verboseMessageHandler);
    
    parseArguments();
    
    // randomize the seed for packet size randomization
    srand(time(NULL));

    _socket.bind(QHostAddress::AnyIPv4, _argumentParser.value(PORT_OPTION).toUInt());
    qDebug() << "Test socket is listening on" << _socket.localPort();
    
    if (_argumentParser.isSet(TARGET_OPTION)) {
        // parse the IP and port combination for this target
        QString hostnamePortString = _argumentParser.value(TARGET_OPTION);
        
        QHostAddress address { hostnamePortString.left(hostnamePortString.indexOf(':')) };
        quint16 port { (quint16) hostnamePortString.mid(hostnamePortString.indexOf(':') + 1).toUInt() };
        
        if (address.isNull() || port == 0) {
            qCritical() << "Could not parse an IP address and port combination from" << hostnamePortString << "-" <<
                "The parsed IP was" << address.toString() << "and the parsed port was" << port;
            
            QMetaObject::invokeMethod(this, "quit", Qt::QueuedConnection);
        } else {
            _target = HifiSockAddr(address, port);
            qDebug() << "Packets will be sent to" << _target;
        }
    }
    
    if (_argumentParser.isSet(PACKET_SIZE)) {
        // parse the desired packet size
        _minPacketSize = _maxPacketSize = _argumentParser.value(PACKET_SIZE).toInt();
        
        if (_argumentParser.isSet(MIN_PACKET_SIZE) || _argumentParser.isSet(MAX_PACKET_SIZE)) {
            qCritical() << "Cannot set a min packet size or max packet size AND a specific packet size.";
            QMetaObject::invokeMethod(this, "quit", Qt::QueuedConnection);
        }
    } else {
        
        bool customMinSize = false;
        
        if (_argumentParser.isSet(MIN_PACKET_SIZE)) {
            _minPacketSize = _argumentParser.value(MIN_PACKET_SIZE).toInt();
            customMinSize = true;
        }
        
        if (_argumentParser.isSet(MAX_PACKET_SIZE)) {
            _maxPacketSize = _argumentParser.value(MAX_PACKET_SIZE).toInt();
            
            // if we don't have a min packet size we should make it 1, because we have a max
            if (customMinSize) {
                _minPacketSize = 1;
            }
        }
        
        if (_maxPacketSize < _minPacketSize) {
            qCritical() << "Cannot set a max packet size that is smaller than the min packet size.";
            QMetaObject::invokeMethod(this, "quit", Qt::QueuedConnection);
        }
    }
    
    if (_argumentParser.isSet(MAX_SEND_BYTES)) {
        _maxSendBytes = _argumentParser.value(MAX_SEND_BYTES).toInt();
    }
    
    if (_argumentParser.isSet(MAX_SEND_PACKETS)) {
        _maxSendPackets = _argumentParser.value(MAX_SEND_PACKETS).toInt();
    }
    
    if (_argumentParser.isSet(UNRELIABLE_PACKETS)) {
        _sendReliable = false;
    }

    if (_argumentParser.isSet(ORDERED_PACKETS)) {
        _sendOrdered = true;
    }
    
    if (_argumentParser.isSet(MESSAGE_SIZE)) {
        if (_argumentParser.isSet(ORDERED_PACKETS)) {
            static const double BYTES_PER_MEGABYTE = 1000000;
            _messageSize = (int) _argumentParser.value(MESSAGE_SIZE).toInt() * BYTES_PER_MEGABYTE;
            
            qDebug() << "Message size for ordered packet sending is" << QString("%1MB").arg(_messageSize / BYTES_PER_MEGABYTE);
        } else {
            qWarning() << "message-size has no effect if not sending ordered - it will be ignored";
        }
    }
    
    
    // in case we're an ordered sender or receiver setup our random number generator now
    static const int FIRST_MESSAGE_SEED = 742272;
    
    int messageSeed = FIRST_MESSAGE_SEED;
    
    if (_argumentParser.isSet(MESSAGE_SEED)) {
        messageSeed = _argumentParser.value(MESSAGE_SEED).toInt();
    }
    
    // seed the generator with a value that the receiver will also use when verifying the ordered message
    _generator.seed(messageSeed);
    
    if (!_target.isNull()) {
        sendInitialPackets();
    } else {
        // this is a receiver - in case there are ordered packets (messages) being sent to us make sure that we handle them
        // so that they can be verified
        _socket.setMessageHandler(
            [this](std::unique_ptr<udt::Packet> packet) {
                auto messageNumber = packet->getMessageNumber();
                auto it = _pendingMessages.find(messageNumber);

                if (it == _pendingMessages.end()) {
                    auto message = std::unique_ptr<Message>(new Message { messageNumber, packet->readAll() });
                    message->data.reserve(_messageSize);
                    if (packet->getPacketPosition() == udt::Packet::ONLY) {
                        handleMessage(std::move(message));
                    } else {
                        _pendingMessages[messageNumber] = std::move(message);
                    }
                } else {
                    auto& message = it->second;
                    message->data.append(packet->readAll());

                    if (packet->getPacketPosition() == udt::Packet::LAST) {
                        handleMessage(std::move(message));
                        _pendingMessages.erase(it);
                    }
                }

        });
    }
    _socket.setMessageFailureHandler(
        [this](HifiSockAddr from, udt::Packet::MessageNumber messageNumber) {
            _pendingMessages.erase(messageNumber);
        }
    );
    
    // the sender reports stats every 100 milliseconds, unless passed a custom value
    
    if (_argumentParser.isSet(STATS_INTERVAL)) {
        _statsInterval = _argumentParser.value(STATS_INTERVAL).toInt();
    }
    
    QTimer* statsTimer = new QTimer(this);
    connect(statsTimer, &QTimer::timeout, this, &UDTTest::sampleStats);
    statsTimer->start(_statsInterval);
}
コード例 #5
0
QT_BEGIN_NAMESPACE

void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestName, const QHostAddress &nameserver, QDnsLookupReply *reply)
{
    // Perform DNS query.
    PDNS_RECORD dns_records = 0;
    const QString requestNameUtf16 = QString::fromUtf8(requestName.data(), requestName.size());
    IP4_ARRAY srvList;
    memset(&srvList, 0, sizeof(IP4_ARRAY));
    if (!nameserver.isNull()) {
        if (nameserver.protocol() == QAbstractSocket::IPv4Protocol) {
            // The below code is referenced from: http://support.microsoft.com/kb/831226
            srvList.AddrCount = 1;
            srvList.AddrArray[0] = htonl(nameserver.toIPv4Address());
        } else if (nameserver.protocol() == QAbstractSocket::IPv6Protocol) {
            // For supoprting IPv6 nameserver addresses, we'll need to switch
            // from DnsQuey() to DnsQueryEx() as it supports passing an IPv6
            // address in the nameserver list
            qWarning() << Q_FUNC_INFO << "IPv6 addresses for nameservers is currently not supported";
            reply->error = QDnsLookup::ResolverError;
            reply->errorString = tr("IPv6 addresses for nameservers is currently not supported");
            return;
        }
    }
    const DNS_STATUS status = DnsQuery_W(reinterpret_cast<const wchar_t*>(requestNameUtf16.utf16()), requestType, DNS_QUERY_STANDARD, &srvList, &dns_records, NULL);
    switch (status) {
    case ERROR_SUCCESS:
        break;
    case DNS_ERROR_RCODE_FORMAT_ERROR:
        reply->error = QDnsLookup::InvalidRequestError;
        reply->errorString = tr("Server could not process query");
        return;
    case DNS_ERROR_RCODE_SERVER_FAILURE:
        reply->error = QDnsLookup::ServerFailureError;
        reply->errorString = tr("Server failure");
        return;
    case DNS_ERROR_RCODE_NAME_ERROR:
        reply->error = QDnsLookup::NotFoundError;
        reply->errorString = tr("Non existent domain");
        return;
    case DNS_ERROR_RCODE_REFUSED:
        reply->error = QDnsLookup::ServerRefusedError;
        reply->errorString = tr("Server refused to answer");
        return;
    default:
        reply->error = QDnsLookup::InvalidReplyError;
        reply->errorString = QSystemError(status, QSystemError::NativeError).toString();
        return;
    }

    // Extract results.
    for (PDNS_RECORD ptr = dns_records; ptr != NULL; ptr = ptr->pNext) {
        const QString name = QUrl::fromAce( QString::fromWCharArray( ptr->pName ).toLatin1() );
        if (ptr->wType == QDnsLookup::A) {
            QDnsHostAddressRecord record;
            record.d->name = name;
            record.d->timeToLive = ptr->dwTtl;
            record.d->value = QHostAddress(ntohl(ptr->Data.A.IpAddress));
            reply->hostAddressRecords.append(record);
        } else if (ptr->wType == QDnsLookup::AAAA) {
            Q_IPV6ADDR addr;
            memcpy(&addr, &ptr->Data.AAAA.Ip6Address, sizeof(Q_IPV6ADDR));

            QDnsHostAddressRecord record;
            record.d->name = name;
            record.d->timeToLive = ptr->dwTtl;
            record.d->value = QHostAddress(addr);
            reply->hostAddressRecords.append(record);
        } else if (ptr->wType == QDnsLookup::CNAME) {
            QDnsDomainNameRecord record;
            record.d->name = name;
            record.d->timeToLive = ptr->dwTtl;
            record.d->value = QUrl::fromAce(QString::fromWCharArray(ptr->Data.Cname.pNameHost).toLatin1());
            reply->canonicalNameRecords.append(record);
        } else if (ptr->wType == QDnsLookup::MX) {
            QDnsMailExchangeRecord record;
            record.d->name = name;
            record.d->exchange = QUrl::fromAce(QString::fromWCharArray(ptr->Data.Mx.pNameExchange).toLatin1());
            record.d->preference = ptr->Data.Mx.wPreference;
            record.d->timeToLive = ptr->dwTtl;
            reply->mailExchangeRecords.append(record);
        } else if (ptr->wType == QDnsLookup::NS) {
            QDnsDomainNameRecord record;
            record.d->name = name;
            record.d->timeToLive = ptr->dwTtl;
            record.d->value = QUrl::fromAce(QString::fromWCharArray(ptr->Data.Ns.pNameHost).toLatin1());
            reply->nameServerRecords.append(record);
        } else if (ptr->wType == QDnsLookup::PTR) {
            QDnsDomainNameRecord record;
            record.d->name = name;
            record.d->timeToLive = ptr->dwTtl;
            record.d->value = QUrl::fromAce(QString::fromWCharArray(ptr->Data.Ptr.pNameHost).toLatin1());
            reply->pointerRecords.append(record);
        } else if (ptr->wType == QDnsLookup::SRV) {
            QDnsServiceRecord record;
            record.d->name = name;
            record.d->target = QUrl::fromAce(QString::fromWCharArray(ptr->Data.Srv.pNameTarget).toLatin1());
            record.d->port = ptr->Data.Srv.wPort;
            record.d->priority = ptr->Data.Srv.wPriority;
            record.d->timeToLive = ptr->dwTtl;
            record.d->weight = ptr->Data.Srv.wWeight;
            reply->serviceRecords.append(record);
        } else if (ptr->wType == QDnsLookup::TXT) {
            QDnsTextRecord record;
            record.d->name = name;
            record.d->timeToLive = ptr->dwTtl;
            for (unsigned int i = 0; i < ptr->Data.Txt.dwStringCount; ++i) {
                record.d->values << QString::fromWCharArray((ptr->Data.Txt.pStringArray[i])).toLatin1();;
            }
            reply->textRecords.append(record);
        }
    }

    DnsRecordListFree(dns_records, DnsFreeRecordList);
}
コード例 #6
0
QT_BEGIN_NAMESPACE

void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestName, const QHostAddress &nameserver, QDnsLookupReply *reply)
{
    // TODO: Add nameserver support for winRT
    if (!nameserver.isNull())
        qWarning() << "Ignoring nameserver as its currently not supported on WinRT";

    // TODO: is there any way to do "proper" dns lookup?
    if (requestType != QDnsLookup::A && requestType != QDnsLookup::AAAA
            && requestType != QDnsLookup::ANY) {
        reply->error = QDnsLookup::InvalidRequestError;
        reply->errorString = QLatin1String("WinRT only supports IPv4 and IPv6 requests");
        return;
    }

    QString aceHostname = QUrl::fromAce(requestName);
    if (aceHostname.isEmpty()) {
        reply->error = QDnsLookup::InvalidRequestError;
        reply->errorString = requestName.isEmpty() ? tr("No hostname given") : tr("Invalid hostname");
        return;
    }

    ComPtr<IHostNameFactory> hostnameFactory;
    HRESULT hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Networking_HostName).Get(),
                                        IID_PPV_ARGS(&hostnameFactory));
    if (FAILED(hr)) {
        reply->error = QDnsLookup::ResolverError;
        reply->errorString = QLatin1String("Could not obtain hostname factory");
        return;
    }
    ComPtr<IHostName> host;
    HStringReference hostNameRef((const wchar_t*)aceHostname.utf16());
    hostnameFactory->CreateHostName(hostNameRef.Get(), &host);

    ComPtr<IDatagramSocketStatics> datagramSocketStatics;
    GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Networking_Sockets_DatagramSocket).Get(), &datagramSocketStatics);

    ComPtr<IAsyncOperation<IVectorView<EndpointPair *> *>> op;
    datagramSocketStatics->GetEndpointPairsAsync(host.Get(),
                                                 HString::MakeReference(L"0").Get(),
                                                 &op);

    ComPtr<IVectorView<EndpointPair *>> endpointPairs;
    hr = op->GetResults(&endpointPairs);
    int waitCount = 0;
    while (hr == E_ILLEGAL_METHOD_CALL) {
        WaitForSingleObjectEx(GetCurrentThread(), 50, FALSE);
        hr = op->GetResults(&endpointPairs);
        if (++waitCount > 1200) // Wait for 1 minute max
            return;
    }

    if (!endpointPairs)
        return;

    unsigned int size;
    endpointPairs->get_Size(&size);
    // endpoint pairs might contain duplicates so we temporarily store addresses in a QSet
    QSet<QHostAddress> addresses;
    for (unsigned int i = 0; i < size; ++i) {
        ComPtr<IEndpointPair> endpointpair;
        endpointPairs->GetAt(i, &endpointpair);
        ComPtr<IHostName> remoteHost;
        endpointpair->get_RemoteHostName(&remoteHost);
        HostNameType type;
        remoteHost->get_Type(&type);
        if (type == HostNameType_Bluetooth || type == HostNameType_DomainName
                || (requestType != QDnsLookup::ANY
                && ((type == HostNameType_Ipv4 && requestType == QDnsLookup::AAAA)
                || (type == HostNameType_Ipv6 && requestType == QDnsLookup::A))))
            continue;

        HString name;
        remoteHost->get_CanonicalName(name.GetAddressOf());
        UINT32 length;
        PCWSTR rawString = name.GetRawBuffer(&length);
        addresses.insert(QHostAddress(QString::fromWCharArray(rawString, length)));
    }
    foreach (const QHostAddress &address, addresses) {
        QDnsHostAddressRecord record;
        record.d->name = aceHostname;
        record.d->value = address;
        reply->hostAddressRecords.append(record);
    }
コード例 #7
0
/**
 * Accept an incoming stream tube as a TCP socket.
 *
 * This method accepts an incoming connection request for a stream tube. It can be called
 * only if the tube is in the #TubeStateLocalPending state.
 *
 * The connection manager will open a TCP socket for the application to connect to. The address of
 * the socket will be returned in PendingStreamTubeConnection::ipAddress() once the operation has
 * finished successfully.
 *
 * This overload lets you specify an allowed address/port combination for connecting to the CM
 * socket. Connections with other source addresses won't be accepted. The accessors
 * supportsIPv4SocketsWithSpecifiedAddress() and supportsIPv6SocketsWithSpecifiedAddress() can be
 * used to verify that the connection manager supports this kind of access control; otherwise, this
 * method will always fail unless QHostAddress::Any (or QHostAddress::AnyIPv4 in Qt5) or
 * QHostAddress::AnyIPv6 is passed, in which case the behavior is identical to the always supported
 * acceptTubeAsTcpSocket() overload.
 *
 * Note that when using QHostAddress::Any (or QHostAddress::AnyIPv4 in Qt5) or
 * QHostAddress::AnyIPv6, \a allowedPort is ignored.
 *
 * This method requires IncomingStreamTubeChannel::FeatureCore to be ready.
 *
 * \param allowedAddress An allowed address for connecting to the socket.
 * \param allowedPort An allowed port for connecting to the socket.
 * \return A PendingStreamTubeConnection which will emit PendingStreamTubeConnection::finished
 *         when the stream tube is ready to be used
 *         (hence in the #TubeStateOpen state).
 */
PendingStreamTubeConnection *IncomingStreamTubeChannel::acceptTubeAsTcpSocket(
        const QHostAddress &allowedAddress,
        quint16 allowedPort)
{
    if (!isReady(IncomingStreamTubeChannel::FeatureCore)) {
        warning() << "IncomingStreamTubeChannel::FeatureCore must be ready before "
                "calling acceptTubeAsTcpSocket";
        return new PendingStreamTubeConnection(TP_QT_ERROR_NOT_AVAILABLE,
                QLatin1String("Channel not ready"),
                IncomingStreamTubeChannelPtr(this));
    }

    // The tube must be in local pending state
    if (state() != TubeChannelStateLocalPending) {
        warning() << "You can accept tubes only when they are in LocalPending state";
        return new PendingStreamTubeConnection(TP_QT_ERROR_NOT_AVAILABLE,
                QLatin1String("Channel not ready"),
                IncomingStreamTubeChannelPtr(this));
    }

    QVariant controlParameter;
    SocketAccessControl accessControl;
    QHostAddress hostAddress = allowedAddress;

#if QT_VERSION >= 0x050000
    if (hostAddress == QHostAddress::Any) {
        hostAddress = QHostAddress::AnyIPv4;
    }
#endif

    // Now, let's check what we need to do with accessControl. There is just one special case, Port.
    if (hostAddress != QHostAddress::Any &&
#if QT_VERSION >= 0x050000
        hostAddress != QHostAddress::AnyIPv4 &&
#endif
        hostAddress != QHostAddress::AnyIPv6) {
        // We need to have a valid QHostAddress AND Port.
        if (hostAddress.isNull() || allowedPort == 0) {
            warning() << "You have to set a valid allowed address+port to use Port access control";
            return new PendingStreamTubeConnection(TP_QT_ERROR_INVALID_ARGUMENT,
                    QLatin1String("The supplied allowed address and/or port was invalid"),
                    IncomingStreamTubeChannelPtr(this));
        }

        accessControl = SocketAccessControlPort;

        // IPv4 or IPv6?
        if (hostAddress.protocol() == QAbstractSocket::IPv4Protocol) {
            // IPv4 case
            SocketAddressIPv4 addr;
            addr.address = hostAddress.toString();
            addr.port = allowedPort;

            controlParameter = QVariant::fromValue(addr);
        } else if (hostAddress.protocol() == QAbstractSocket::IPv6Protocol) {
            // IPv6 case
            SocketAddressIPv6 addr;
            addr.address = hostAddress.toString();
            addr.port = allowedPort;

            controlParameter = QVariant::fromValue(addr);
        } else {
            // We're handling an IPv4/IPv6 socket only
            warning() << "acceptTubeAsTcpSocket can be called only with a QHostAddress "
                    "representing an IPv4 or IPv6 address";
            return new PendingStreamTubeConnection(TP_QT_ERROR_INVALID_ARGUMENT,
                    QLatin1String("Invalid host given"),
                    IncomingStreamTubeChannelPtr(this));
        }
    } else {
        // We have to do no special stuff here
        accessControl = SocketAccessControlLocalhost;
        // Since QDBusMarshaller does not like null variants, just add an empty string.
        controlParameter = QVariant(QString());
    }

    // Set the correct address type and access control
    setAddressType(hostAddress.protocol() == QAbstractSocket::IPv4Protocol ?
            SocketAddressTypeIPv4 :
            SocketAddressTypeIPv6);
    setAccessControl(accessControl);

    // Fail early if the combination is not supported
    if ((accessControl == SocketAccessControlLocalhost &&
            addressType() == SocketAddressTypeIPv4 &&
            !supportsIPv4SocketsOnLocalhost()) ||
        (accessControl == SocketAccessControlPort &&
            addressType() == SocketAddressTypeIPv4 &&
            !supportsIPv4SocketsWithSpecifiedAddress()) ||
        (accessControl == SocketAccessControlLocalhost &&
            addressType() == SocketAddressTypeIPv6 &&
            !supportsIPv6SocketsOnLocalhost()) ||
        (accessControl == SocketAccessControlPort &&
            addressType() == SocketAddressTypeIPv6 &&
            !supportsIPv6SocketsWithSpecifiedAddress())) {
        warning() << "You requested an address type/access control combination "
                "not supported by this channel";
        return new PendingStreamTubeConnection(TP_QT_ERROR_NOT_IMPLEMENTED,
                QLatin1String("The requested address type/access control "
                              "combination is not supported"),
                IncomingStreamTubeChannelPtr(this));
    }

    // Perform the actual call
    PendingVariant *pv = new PendingVariant(
            interface<Client::ChannelTypeStreamTubeInterface>()->Accept(
                    addressType(),
                    accessControl,
                    QDBusVariant(controlParameter)),
            IncomingStreamTubeChannelPtr(this));

    PendingStreamTubeConnection *op = new PendingStreamTubeConnection(pv, addressType(),
            false, 0, IncomingStreamTubeChannelPtr(this));
    return op;
}
コード例 #8
0
void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestName, const QHostAddress &nameserver, QDnsLookupReply *reply)
{
    // Load dn_expand, res_ninit and res_nquery on demand.
    static QBasicAtomicInt triedResolve = Q_BASIC_ATOMIC_INITIALIZER(false);
    if (!triedResolve.loadAcquire()) {
        QMutexLocker locker(QMutexPool::globalInstanceGet(&local_res_ninit));
        if (!triedResolve.load()) {
            resolveLibrary();
            triedResolve.storeRelease(true);
        }
    }

    // If dn_expand, res_ninit or res_nquery is missing, fail.
    if (!local_dn_expand || !local_res_nclose || !local_res_ninit || !local_res_nquery) {
        reply->error = QDnsLookup::ResolverError;
        reply->errorString = tr("Resolver functions not found");
        return;
    }

    // Initialize state.
    struct __res_state state;
    memset(&state, 0, sizeof(state));
    if (local_res_ninit(&state) < 0) {
        reply->error = QDnsLookup::ResolverError;
        reply->errorString = tr("Resolver initialization failed");
        return;
    }

    //Check if a nameserver was set. If so, use it
    if (!nameserver.isNull()) {
        if (nameserver.protocol() == QAbstractSocket::IPv4Protocol) {
            state.nsaddr_list[0].sin_addr.s_addr = htonl(nameserver.toIPv4Address());
            state.nscount = 1;
        } else if (nameserver.protocol() == QAbstractSocket::IPv6Protocol) {
#if defined(Q_OS_LINUX)
            struct sockaddr_in6 *ns;
            ns = state._u._ext.nsaddrs[0];
            // nsaddrs will be NULL if no nameserver is set in /etc/resolv.conf
            if (!ns) {
                // Memory allocated here will be free'd in res_close() as we
                // have done res_init() above.
                ns = (struct sockaddr_in6*) calloc(1, sizeof(struct sockaddr_in6));
                Q_CHECK_PTR(ns);
                state._u._ext.nsaddrs[0] = ns;
            }
            // Set nsmap[] to indicate that nsaddrs[0] is an IPv6 address
            // See: https://sourceware.org/ml/libc-hacker/2002-05/msg00035.html
            state._u._ext.nsmap[0] = MAXNS + 1;
            state._u._ext.nscount6 = 1;
            ns->sin6_family = AF_INET6;
            ns->sin6_port = htons(53);

            Q_IPV6ADDR ipv6Address = nameserver.toIPv6Address();
            for (int i=0; i<16; i++) {
                ns->sin6_addr.s6_addr[i] = ipv6Address[i];
            }
#else
            qWarning() << Q_FUNC_INFO << "IPv6 addresses for nameservers is currently not supported";
            reply->error = QDnsLookup::ResolverError;
            reply->errorString = tr("IPv6 addresses for nameservers is currently not supported");
            return;
#endif
        }
    }
#ifdef QDNSLOOKUP_DEBUG
    state.options |= RES_DEBUG;
#endif
    QScopedPointer<struct __res_state, QDnsLookupStateDeleter> state_ptr(&state);

    // Perform DNS query.
    unsigned char response[PACKETSZ];
    memset(response, 0, sizeof(response));
    const int responseLength = local_res_nquery(&state, requestName, C_IN, requestType, response, sizeof(response));

    // Check the response header.
    HEADER *header = (HEADER*)response;
    const int answerCount = ntohs(header->ancount);
    switch (header->rcode) {
    case NOERROR:
        break;
    case FORMERR:
        reply->error = QDnsLookup::InvalidRequestError;
        reply->errorString = tr("Server could not process query");
        return;
    case SERVFAIL:
        reply->error = QDnsLookup::ServerFailureError;
        reply->errorString = tr("Server failure");
        return;
    case NXDOMAIN:
        reply->error = QDnsLookup::NotFoundError;
        reply->errorString = tr("Non existent domain");
        return;
    case REFUSED:
        reply->error = QDnsLookup::ServerRefusedError;
        reply->errorString = tr("Server refused to answer");
        return;
    default:
        reply->error = QDnsLookup::InvalidReplyError;
        reply->errorString = tr("Invalid reply received");
        return;
    }

    // Check the reply is valid.
    if (responseLength < int(sizeof(HEADER))) {
        reply->error = QDnsLookup::InvalidReplyError;
        reply->errorString = tr("Invalid reply received");
        return;
    }

    // Skip the query host, type (2 bytes) and class (2 bytes).
    char host[PACKETSZ], answer[PACKETSZ];
    unsigned char *p = response + sizeof(HEADER);
    int status = local_dn_expand(response, response + responseLength, p, host, sizeof(host));
    if (status < 0) {
        reply->error = QDnsLookup::InvalidReplyError;
        reply->errorString = tr("Could not expand domain name");
        return;
    }
    p += status + 4;

    // Extract results.
    int answerIndex = 0;
    while ((p < response + responseLength) && (answerIndex < answerCount)) {
        status = local_dn_expand(response, response + responseLength, p, host, sizeof(host));
        if (status < 0) {
            reply->error = QDnsLookup::InvalidReplyError;
            reply->errorString = tr("Could not expand domain name");
            return;
        }
        const QString name = QUrl::fromAce(host);

        p += status;
        const quint16 type = (p[0] << 8) | p[1];
        p += 2; // RR type
        p += 2; // RR class
        const quint32 ttl = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
        p += 4;
        const quint16 size = (p[0] << 8) | p[1];
        p += 2;

        if (type == QDnsLookup::A) {
            if (size != 4) {
                reply->error = QDnsLookup::InvalidReplyError;
                reply->errorString = tr("Invalid IPv4 address record");
                return;
            }
            const quint32 addr = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
            QDnsHostAddressRecord record;
            record.d->name = name;
            record.d->timeToLive = ttl;
            record.d->value = QHostAddress(addr);
            reply->hostAddressRecords.append(record);
        } else if (type == QDnsLookup::AAAA) {
            if (size != 16) {
                reply->error = QDnsLookup::InvalidReplyError;
                reply->errorString = tr("Invalid IPv6 address record");
                return;
            }
            QDnsHostAddressRecord record;
            record.d->name = name;
            record.d->timeToLive = ttl;
            record.d->value = QHostAddress(p);
            reply->hostAddressRecords.append(record);
        } else if (type == QDnsLookup::CNAME) {
            status = local_dn_expand(response, response + responseLength, p, answer, sizeof(answer));
            if (status < 0) {
                reply->error = QDnsLookup::InvalidReplyError;
                reply->errorString = tr("Invalid canonical name record");
                return;
            }
            QDnsDomainNameRecord record;
            record.d->name = name;
            record.d->timeToLive = ttl;
            record.d->value = QUrl::fromAce(answer);
            reply->canonicalNameRecords.append(record);
        } else if (type == QDnsLookup::NS) {
            status = local_dn_expand(response, response + responseLength, p, answer, sizeof(answer));
            if (status < 0) {
                reply->error = QDnsLookup::InvalidReplyError;
                reply->errorString = tr("Invalid name server record");
                return;
            }
            QDnsDomainNameRecord record;
            record.d->name = name;
            record.d->timeToLive = ttl;
            record.d->value = QUrl::fromAce(answer);
            reply->nameServerRecords.append(record);
        } else if (type == QDnsLookup::PTR) {
            status = local_dn_expand(response, response + responseLength, p, answer, sizeof(answer));
            if (status < 0) {
                reply->error = QDnsLookup::InvalidReplyError;
                reply->errorString = tr("Invalid pointer record");
                return;
            }
            QDnsDomainNameRecord record;
            record.d->name = name;
            record.d->timeToLive = ttl;
            record.d->value = QUrl::fromAce(answer);
            reply->pointerRecords.append(record);
        } else if (type == QDnsLookup::MX) {
            const quint16 preference = (p[0] << 8) | p[1];
            status = local_dn_expand(response, response + responseLength, p + 2, answer, sizeof(answer));
            if (status < 0) {
                reply->error = QDnsLookup::InvalidReplyError;
                reply->errorString = tr("Invalid mail exchange record");
                return;
            }
            QDnsMailExchangeRecord record;
            record.d->exchange = QUrl::fromAce(answer);
            record.d->name = name;
            record.d->preference = preference;
            record.d->timeToLive = ttl;
            reply->mailExchangeRecords.append(record);
        } else if (type == QDnsLookup::SRV) {
            const quint16 priority = (p[0] << 8) | p[1];
            const quint16 weight = (p[2] << 8) | p[3];
            const quint16 port = (p[4] << 8) | p[5];
            status = local_dn_expand(response, response + responseLength, p + 6, answer, sizeof(answer));
            if (status < 0) {
                reply->error = QDnsLookup::InvalidReplyError;
                reply->errorString = tr("Invalid service record");
                return;
            }
            QDnsServiceRecord record;
            record.d->name = name;
            record.d->target = QUrl::fromAce(answer);
            record.d->port = port;
            record.d->priority = priority;
            record.d->timeToLive = ttl;
            record.d->weight = weight;
            reply->serviceRecords.append(record);
        } else if (type == QDnsLookup::TXT) {
            unsigned char *txt = p;
            QDnsTextRecord record;
            record.d->name = name;
            record.d->timeToLive = ttl;
            while (txt < p + size) {
                const unsigned char length = *txt;
                txt++;
                if (txt + length > p + size) {
                    reply->error = QDnsLookup::InvalidReplyError;
                    reply->errorString = tr("Invalid text record");
                    return;
                }
                record.d->values << QByteArray((char*)txt, length);
                txt += length;
            }
            reply->textRecords.append(record);
        }
        p += size;
        answerIndex++;
    }
}
コード例 #9
0
void CDatagrams::onQKA(CEndPoint& addr, G2Packet* pPacket)
{
	if ( !pPacket->m_bCompound )
	{
		return;
	}

	quint32 nKey = 0;
	QHostAddress nKeyHost;

	char szType[9];
	quint32 nLength = 0, nNext = 0;

	while(pPacket->readPacket(&szType[0], nLength))
	{
		nNext = pPacket->m_nPosition + nLength;

		if(strcmp("QK", szType) == 0 && nLength >= 4)
		{
			nKey = pPacket->readIntLE<quint32>();
		}
		else if(strcmp("SNA", szType) == 0 && nLength >= 4)
		{
			if(nLength >= 16)
			{
				Q_IPV6ADDR ip;
				pPacket->read(&ip, 16);
				nKeyHost.setAddress(ip);
			}
			else
			{
				quint32 nIp = pPacket->readIntBE<quint32>();
				nKeyHost.setAddress(nIp);
			}
		}
		pPacket->m_nPosition = nNext;
	}

	hostCache.m_pSection.lock();
	CHostCacheHost* pCache = hostCache.add( addr, common::getTNowUTC() );
	if ( pCache )
	{
		if( !nKey ) // null QK means a hub does not want to be queried or just downgraded
		{
			hostCache.remove( pCache );
		}
		else
		{
			pCache->setKey( nKey );
		}
	}
	hostCache.m_pSection.unlock();

#if LOG_QUERY_HANDLING
	systemLog.postLog(LogSeverity::Debug, QString("Got a query key for %1 = 0x%2").arg(addr.toString().toLocal8Bit().constData()).arg(nKey));
	//qDebug("Got a query key for %s = 0x%x", addr.toString().toLocal8Bit().constData(), nKey);
#endif // LOG_QUERY_HANDLING

	if(Neighbours.isG2Hub() && !nKeyHost.isNull() && nKeyHost != ((QHostAddress)Network.m_oAddress))
	{
		G2Packet* pQNA = G2Packet::newPacket("QNA");
		pQNA->writeHostAddress(&addr);
		pPacket->prependPacket(pQNA);

		Neighbours.m_pSection.lock();
		CNeighbour* pNode = Neighbours.find(nKeyHost, dpG2);
		if( pNode )
		{
			((CG2Node*)pNode)->sendPacket(pPacket, true, false);
		}
		Neighbours.m_pSection.unlock();
	}
}
コード例 #10
0
ファイル: Discover.cpp プロジェクト: dustyco/Drone
void Discover::acceptRecords (QList<Record> records, bool removeThem, QString senderScope, QString senderAddress, QString senderPort)
{
	// TODO
	
	// This function gets its own copy of records
	// This loop edits each item so it can be used after
	for (Record& record : records)
	{
		// Preprocess the record before considering it
		Record::decompressReserved(record);

		// Set the scope based on the address if included, otherwise scope of sender
		QHostAddress recordAddress;
		if (record.has("Address")) recordAddress.setAddress(record["Address"]);
		if (recordAddress.protocol()!=QAbstractSocket::IPv4Protocol) recordAddress = QHostAddress::Null;
		if (recordAddress==QHostAddress::Broadcast) recordAddress = QHostAddress::Null;
		if (recordAddress==QHostAddress::AnyIPv4) recordAddress = QHostAddress::Null;
		if (recordAddress.isNull())
		{
			record["Scope"] = senderScope;
		}
		else
		{
				 if (recordAddress.isLoopback())    record["Scope"] = "Loopback";
			else if (addressIsLocal(recordAddress)) record["Scope"] = "Local";
			else                                    record["Scope"] = "Global";
		}

		if (record["Address"].isEmpty()) record["Address"] = senderAddress; // Sender may override these
		if (record["Port"].isEmpty()) record["Port"] = senderPort; // Sender may override these
		// TODO Extract a custom expiration duration so each record can have its own


		if (removeThem)
		{
			// See if it's new
			if (foundRecords.contains(record))
			{
				logDebug(QString("Record Departed: %1").arg(record.toString()));
				foundRecords.remove(record);
				emit recordLost(record);
			}
		}
		else
		{
			// See if it's new
			if (not foundRecords.contains(record) and passesFilters(record))
			{
				logDebug(QString("Found Record: %1").arg(record.toString()));
				emit recordFound(record);
			}

			// Reset the timer
			foundRecords[record] = QDateTime::currentMSecsSinceEpoch() + 2500; // Set the expire time
		}

		expireTimer->start(0); // In case the next expiration time was changed
	}
	
	// Server: Forward global departures to other global peers
	if (mServerMode and removeThem and senderScope == "Global")
	{
		QByteArray datagram("DSDD");
		datagram += makeDatagram(records, false);
		
		for (Record& record : foundRecords.keys())
		if (record["Scope"] == "Global")
		{
			bool ok;
			globalSocket->writeDatagram(datagram, QHostAddress(record["Address"]), record["Port"].toUInt(&ok, 10));
		}
	}
}
コード例 #11
0
void ConnectThread::run()
{
	QHostInfo addr = QHostInfo::fromName(mAddress);
	if (addr.error() != QHostInfo::NoError) {
		Q_EMIT error(addr.errorString());
		return;
	}

	QHostAddress actualAddr;
	QList<QHostAddress> addresses = addr.addresses();
	for (QList<QHostAddress>::const_iterator iter = addresses.begin();
			iter != addresses.end(); ++ iter) {
		if (iter->protocol() == QAbstractSocket::IPv4Protocol) {
			actualAddr = *iter;
			break;
		}
	}

	if (actualAddr.isNull()) {
		Q_EMIT error(tr("无法解析域名: 找不到'%1'的IPv4地址").arg(mAddress));
		return;
	}

	// Begin connection
	{
		std::string addr = actualAddr.toString().toStdString();
		TCPSocketAddress remote (addr,mPort);
		IOVideoSource *src = 0;

		Error rc;
		TCPSocket *ctrl = new TCPSocket (::socket(AF_INET, SOCK_STREAM, 0));
		TCPSocket *data = new TCPSocket (::socket(AF_INET, SOCK_STREAM, 0));

		ctrl->setBlockingMode(false);
		data->setBlockingMode(false);

		ctrl->connect(&remote);
		do {
			rc = ctrl->poll(IODevice::POLL_WRITE,200);
			if (rc.isSuccess()) break;
			else if (rc.getErrorType() == Error::ERR_TIMEOUT) continue;
			else {
				rc.setErrorString("无法连接到远端服务器");
				goto connect_ctrl_failed;
			}
		}while(!mShouldStop);

		data->connect(&remote);
		do {
			rc = data->poll(IODevice::POLL_WRITE,200);
			if (rc.isSuccess()) break;
			else if (rc.getErrorType() == Error::ERR_TIMEOUT) continue;
			else {
				rc.setErrorString("无法连接到远端服务器");
				goto connect_data_failed;
			}
		}while(!mShouldStop);

		ctrl->setBlockingMode(true);
		data->setBlockingMode(true);


		src = new IOVideoSource(ctrl,data);
		rc = src->init();
		if (rc.isError()) {
			rc.setErrorString("初始化视频源失败,原因为:" + rc.getErrorString());
			goto init_video_source_failed;
		}


		mVideoSource = src;
		Q_EMIT success();
		return;

		init_video_source_failed:
		delete src;
		connect_data_failed:
		connect_ctrl_failed:
		ctrl->close();
		data->close();
		delete ctrl;
		delete data;

		Q_EMIT error(QString::fromStdString(rc.getErrorString()));

	}
}
コード例 #12
0
ファイル: worker.cpp プロジェクト: sjinks/repwatch_proxy
/**
 * @see http://tools.ietf.org/html/rfc1928
 *
 * The SOCKS request is formed as follows:
 *
 *      +----+-----+-------+------+----------+----------+
 *      |VER | CMD |  RSV  | ATYP | DST.ADDR | DST.PORT |
 *      +----+-----+-------+------+----------+----------+
 *      | 1  |  1  | X'00' |  1   | Variable |    2     |
 *      +----+-----+-------+------+----------+----------+
 *
 * Where:
 *
 *    o  VER    protocol version: X'05'
 *    o  CMD
 *       o  CONNECT X'01'
 *       o  BIND X'02'
 *       o  UDP ASSOCIATE X'03'
 *    o  RSV    RESERVED
 *    o  ATYP   address type of following address
 *       o  IP V4 address: X'01'
 *       o  DOMAINNAME: X'03'
 *       o  IP V6 address: X'04'
 *    o  DST.ADDR       desired destination address
 *    o  DST.PORT desired destination port in network octet order
 *
 * The SOCKS server will typically evaluate the request based on source
 * and destination addresses, and return one or more reply messages, as
 * appropriate for the request type.
 *
 * In an address field (DST.ADDR, BND.ADDR), the ATYP field specifies
 * the type of address contained within the field:
 *
 *    o  X'01'
 *
 * the address is a version-4 IP address, with a length of 4 octets
 *
 *    o  X'03'
 *
 * the address field contains a fully-qualified domain name.  The first
 * octet of the address field contains the number of octets of name that
 * follow, there is no terminating NUL octet.
 *
 *    o  X'04'
 *
 * the address is a version-6 IP address, with a length of 16 octets.
 */
void Worker::parseRequest(void)
{
	int size = this->m_buf.size();
	if (-1 == this->m_expected_length) {
		if (size > 4) {
			quint8 ver  = static_cast<quint8>(this->m_buf.at(0));
			quint8 rsv  = static_cast<quint8>(this->m_buf.at(2));
			quint8 atyp = static_cast<quint8>(this->m_buf.at(3));

			if (ver != 5) {
				this->m_state = Worker::FatalErrorState;
				Q_EMIT this->error(Worker::ProtocolVersionMismatch);
				return;
			}

			if (rsv != 0) {
				this->m_state = Worker::FatalErrorState;
				Q_EMIT this->error(Worker::UnknownError);
				return;
			}

			switch (atyp) {
				case 1: // IPv4 address
					this->m_expected_length = 10;
					break;

				case 4: // IPv6 address
					this->m_expected_length = 22;
					break;

				case 3: // Domain name
					this->m_expected_length = 7 + static_cast<quint8>(this->m_buf.at(4));
					break;

				default:
					this->m_state = Worker::FatalErrorState;
					Q_EMIT this->error(Worker::UnknownError);
					return;
			}
		}
	}

	if (this->m_expected_length != -1 && size > this->m_expected_length) {
		this->m_state = Worker::FatalErrorState;
		Q_EMIT this->error(Worker::TooMuchData);
		return;
	}

	QString address;
	quint16 port = 0;
	quint8 cmd  = static_cast<quint8>(this->m_buf.at(1));
	quint8 atyp = static_cast<quint8>(this->m_buf.at(3));
	switch (atyp) {
		case 1: {
			QHostAddress a;
			quint32 addr;
			memcpy(&addr, this->m_buf.constData() + 4, sizeof(quint32));
			memcpy(&port, this->m_buf.constData() + 8, sizeof(quint16));
			a.setAddress(qFromBigEndian(addr));
			address = a.toString();
			break;
		}

		case 4: {
			QHostAddress a;
			quint8 addr[16];
			memcpy(addr, this->m_buf.constData() + 4, 16);
			memcpy(&port, this->m_buf.constData() + 20, sizeof(quint16));
			a.setAddress(addr);
			address = a.toString();
			break;
		}

		case 3: {
			int len = static_cast<quint8>(this->m_buf.at(4));
			QByteArray tmp = QByteArray(this->m_buf.constData() + 5, len);

			if (tmp.endsWith('.')) {
				tmp.chop(1);
				--len;
			}

			address = QString::fromLocal8Bit(tmp.constData(), len);
			memcpy(&port, this->m_buf.constData() + this->m_expected_length - 2, sizeof(quint16));
			break;
		}

		default:
			Q_ASSERT(false);
			break;
	}

	this->m_expected_length = -1;
	this->m_buf.clear();

	port = qFromBigEndian(port);

	if (cmd != 1) { // Connect
		char response[] = "\x05\x07\x00\x01\x00\x00\x00\x00\x00\x00"; // Command not supported
		this->writeAndFlush(this->m_peer, response, 10);
		this->m_state = Worker::FatalErrorState;
		return;
	}

	this->m_connector = new SocketConnector(this);
	QHostAddress a;
	if (qobject_cast<QAbstractSocket*>(this->m_peer)) {
		a = (qobject_cast<QAbstractSocket*>(this->m_peer))->localAddress();
	}

	if (!this->m_connector->createTcpSocket() || (!a.isNull() && !this->m_connector->bindTo(a))) {
		char response[] = "\x05\x01\x00\x01\x00\x00\x00\x00\x00\x00"; // General SOCKS server failure
		this->writeAndFlush(this->m_peer, response, 10);
		this->m_state = Worker::FatalErrorState;
		return;
	}

	this->m_state = Worker::RequestReceivedState;
	QObject::connect(this->m_connector, SIGNAL(connected()), this, SLOT(targetConnectedHandler()));
	QObject::connect(this->m_connector, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(targetConnectFailureHandler(QAbstractSocket::SocketError)));
	this->m_connector->connectToHost(address, port);
}
コード例 #13
0
ファイル: srvresolver.cpp プロジェクト: hummbl/psi
void SrvResolver::ndns_done()
{
#ifndef NO_NDNS
	SafeDeleteLock s(&d->sd);

	QHostAddress r = d->ndns.result();
	int port = d->servers.first().port;
	d->servers.remove(d->servers.begin());

	if(!r.isNull()) {
		d->resultAddress = r;
		d->resultPort = port;
		resultsReady();
	}
	else {
		// failed?  bail if last one
		if(d->servers.isEmpty()) {
			stop();
			resultsReady();
			return;
		}

		// otherwise try the next
		tryNext();
	}
#else
	if(!d->qdns)
		return;

	// apparently we sometimes get this signal even though the results aren't ready
	if(d->qdns->isWorking())
		return;

	SafeDeleteLock s(&d->sd);

	// grab the address list and destroy the qdns object
	QList<QHostAddress> list;
	if(d->qdns->recordType() == Q3Dns::A || d->qdns->recordType() == Q3Dns::Aaaa)
		list = d->qdns->addresses();
	d->qdns->disconnect(this);
	d->sd.deleteLater(d->qdns);
	d->qdns = 0;

	if(!list.isEmpty()) {
		int port = d->servers.first().port;
		d->servers.remove(d->servers.begin());
		d->aaaa = true;

		d->resultAddress = list.first();
		d->resultPort = port;
		resultsReady();
	}
	else {
		if(!d->aaaa)
			d->servers.remove(d->servers.begin());
		d->aaaa = !d->aaaa;

		// failed?  bail if last one
		if(d->servers.isEmpty()) {
			stop();
			resultsReady();
			return;
		}

		// otherwise try the next
		tryNext();
	}
#endif
}
コード例 #14
0
void Dispatcher::sendUnicastRawDatagram(QHostAddress dstAddress, QByteArray *datagram)
{
    // moontlike aborsie wat wag hier:
    //Warning: Calling this function on a connected UDP socket may result in an error and no packet being sent.
    //If you are using a connected socket, use write() to send datagrams.
    // ...maar write() vat nie dstAddress en dstPort nie...
    // split hom toe maar in 'n bound socket vir read en 'n unbound socket vir write.
    // hoop dit werk.

    //quint32 dst = dstAddress.toIPv4Address();  // watch in debugger

    //if (senderUdpSocket->writeDatagram(*datagram, dstAddress, dispatchPort) == -1)
    //    emit writeUdpUnicastFailed();


    // **************************************
    /* man 7 socket:
       SO_SNDBUF
              Sets or gets the maximum socket send buffer in bytes.  The  ker‐
              nel doubles this value (to allow space for bookkeeping overhead)
              when it is set using setsockopt(2), and this  doubled  value  is
              returned  by  getsockopt(2).   The  default  value is set by the
              /proc/sys/net/core/wmem_default file  and  the  maximum  allowed
              value is set by the /proc/sys/net/core/wmem_max file.  The mini‐
              mum (doubled) value for this option is 2048.
    */
    if (dstAddress.isNull())
    {
        delete datagram;
        return;
    }

    /*if (senderUdpSocket->peerAddress() != dstAddress)
    {
        senderUdpSocket->disconnectFromHost();
        senderUdpSocket->connectToHost(dstAddress, dispatchPort);
    }*/

    QAbstractSocket::SocketState state = senderUdpSocket->state();
    int size = 0;
    int maxSize = getMaximumSendBufferSize();
    socklen_t *s = new socklen_t(sizeof(size));
    if (::getsockopt(senderUdpSocket->socketDescriptor(), SOL_SOCKET, SO_SNDBUF, (char *)&size, s) != -1) //successfully read
    {
        if (size != maxSize) //set if not already set
        {
            size = maxSize;
            if (::setsockopt(senderUdpSocket->socketDescriptor(), SOL_SOCKET, SO_SNDBUF, (char *)&size, sizeof(size)) == -1) //couldn't write
            {
                qDebug() << "Dispatcher::sendUnicastRawDatagram: Could not set sending buffer size";
            }
#ifndef Q_OS_LINUX
            else
            {
                //verify if set correctly
                if (::getsockopt(senderUdpSocket->socketDescriptor(), SOL_SOCKET, SO_SNDBUF, (char *)&size, s) != -1) //successfully read
                {
                    if (size != maxSize)
                        qDebug() << "Dispatcher::sendUnicastRawDatagram: Value returned inconsistent with value set " << size << maxSize;
                }
            }
#endif
        }
    }
    delete s;

    int res;
    //if ((res = senderUdpSocket->write(*datagram)) == -1)
    //    emit writeUdpUnicastFailed();

    if (res = senderUdpSocket->writeDatagram(*datagram, dstAddress, dispatchPort) == -1)
        emit writeUdpUnicastFailed();

    delete datagram;
}