File: tcpserverdevice.cpp

package info (click to toggle)
gammaray 3.3.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 21,612 kB
  • sloc: cpp: 94,643; ansic: 2,227; sh: 336; python: 164; yacc: 90; lex: 82; xml: 61; makefile: 26
file content (122 lines) | stat: -rw-r--r-- 3,865 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
/*
  tcpserverdevice.cpp

  This file is part of GammaRay, the Qt application inspection and manipulation tool.

  SPDX-FileCopyrightText: 2014 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
  Author: Volker Krause <volker.krause@kdab.com>

  SPDX-License-Identifier: GPL-2.0-or-later

  Contact KDAB at <info@kdab.com> for commercial licensing options.
*/

#include "tcpserverdevice.h"
#include "server.h"

#include <QHostAddress>
#include <QNetworkInterface>
#include <QUdpSocket>

using namespace GammaRay;

TcpServerDevice::TcpServerDevice(QObject *parent)
    : ServerDeviceImpl<QTcpServer>(parent)
    , m_broadcastSocket(new QUdpSocket(this))
{
    m_server = new QTcpServer(this);
    connect(m_server, &QTcpServer::newConnection, this, &ServerDevice::newConnection);
}

TcpServerDevice::~TcpServerDevice() = default;

bool TcpServerDevice::listen()
{
    const QHostAddress address(m_address.host());
    // try the requested port first, and fall back to a random port otherwise
    auto result = m_server->listen(address, m_address.port());
    if (!result) {
        result = m_server->listen(address, 0);
    }
    emit externalAddressChanged();
    return result;
}

bool TcpServerDevice::isListening() const
{
    return m_server->isListening();
}

QString TcpServerDevice::bestAvailableIP(const QHostAddress &address) const
{
    QString firstHostFound;
    foreach (const QNetworkInterface &inter, QNetworkInterface::allInterfaces()) {
        if (!(inter.flags() & QNetworkInterface::IsUp)
            || !(inter.flags() & QNetworkInterface::IsRunning)
            || (inter.flags() & QNetworkInterface::IsLoopBack))
            continue;

        foreach (const QNetworkAddressEntry &addrEntry, inter.addressEntries()) {
            const QHostAddress addr = addrEntry.ip();

            // Return the ip according to the listening server protocol.
            if (addr.protocol() != m_server->serverAddress().protocol()
                || !addr.scopeId().isEmpty())
                continue;

            // If its our desired IP (e.g. from --listen) return early
            if (addr == address)
                return addr.toString();
            if (firstHostFound.isEmpty())
                firstHostFound = addr.toString();
        }
    }
    return firstHostFound;
}

QUrl TcpServerDevice::externalAddress() const
{
    const QHostAddress address(m_server->serverAddress());
    QString myHost;

    if (address.isLoopback()) {
        myHost = address.toString();
    } else {
        // scan Interfaces for available IPs, use requested address if we can find it.
        myHost = bestAvailableIP(address);
    }

    // if localhost is all we got, use that rather than nothing
    if (myHost.isEmpty()) {
        switch (m_server->serverAddress().protocol()) {
        case QAbstractSocket::IPv4Protocol:
        case QAbstractSocket::AnyIPProtocol:
            myHost = QHostAddress(QHostAddress::LocalHost).toString();
            break;
        case QAbstractSocket::IPv6Protocol:
            myHost = QHostAddress(QHostAddress::LocalHostIPv6).toString();
            break;
        case QAbstractSocket::UnknownNetworkLayerProtocol:
            qWarning() << "TcpServerDevice::externalAddress - unknown TCP protocol";
            return m_address;
        }
    }

    QUrl url;
    url.setScheme(QStringLiteral("tcp"));
    url.setHost(myHost);
    url.setPort(m_server->serverPort());
    return url;
}

void TcpServerDevice::broadcast(const QByteArray &data)
{
    const QHostAddress address = m_server->serverAddress();

    // broadcast announcement only if we are actually listinging to remote connections
    if (address.isLoopback())
        return;

    m_broadcastSocket->writeDatagram(data.data(),
                                     data.size(), QHostAddress::Broadcast, Server::broadcastPort());
}