Introduce SCTP sockets support
Add protocol-specific code and the QSctpServer, QSctpSocket classes. Change-Id: Ie9a1d87bd1fda866a2405043d1c15c12ded5a96e Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
parent
c5a4b093d0
commit
75a9bd2a4f
60
config.tests/unix/sctp/sctp.cpp
Normal file
60
config.tests/unix/sctp/sctp.cpp
Normal file
@ -0,0 +1,60 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 Alex Trotsenko <alex1973tr@gmail.com>
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the config.tests of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or any later version approved by the KDE Free
|
||||
** Qt Foundation. The licenses are as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
/* Sample program for configure to test for SCTP sockets support
|
||||
on target platforms. */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/sctp.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
int fd;
|
||||
sctp_initmsg sctpInitMsg;
|
||||
socklen_t sctpInitMsgSize = sizeof(sctpInitMsg);
|
||||
|
||||
fd = socket(PF_INET, SOCK_STREAM, IPPROTO_SCTP);
|
||||
if (fd == -1 || getsockopt(fd, SOL_SCTP, SCTP_INITMSG, &sctpInitMsg,
|
||||
&sctpInitMsgSize) != 0)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
4
config.tests/unix/sctp/sctp.pro
Normal file
4
config.tests/unix/sctp/sctp.pro
Normal file
@ -0,0 +1,4 @@
|
||||
SOURCES = sctp.cpp
|
||||
CONFIG -= qt
|
||||
QT =
|
||||
LIBS += $$QMAKE_LIBS_NETWORK
|
@ -365,6 +365,9 @@ Additional options:
|
||||
-no-system-proxies ... Do not use system network proxies by default.
|
||||
* -system-proxies ...... Use system network proxies by default.
|
||||
|
||||
* -no-sctp ............. Do not compile SCTP network protocol support.
|
||||
-sctp ................ Compile SCTP support.
|
||||
|
||||
-no-warnings-are-errors Make warnings be treated normally
|
||||
-warnings-are-errors Make warnings be treated as errors
|
||||
(enabled if -developer-build is active)
|
||||
|
@ -130,6 +130,7 @@
|
||||
"release": { "type": "enum", "name": "debug", "values": { "yes": "no", "no": "yes" } },
|
||||
"rpath": "boolean",
|
||||
"sanitize": "sanitize",
|
||||
"sctp": "boolean",
|
||||
"sdk": "string",
|
||||
"securetransport": "boolean",
|
||||
"separate-debug-info": { "type": "boolean", "name": "separate_debug_info" },
|
||||
@ -596,6 +597,11 @@
|
||||
"type": "openssl",
|
||||
"libs": "-lssl -lcrypto"
|
||||
},
|
||||
"sctp": {
|
||||
"description": "SCTP support",
|
||||
"type": "compile",
|
||||
"test": "unix/sctp"
|
||||
},
|
||||
"icu": {
|
||||
"description": "ICU",
|
||||
"type": "compile",
|
||||
@ -1625,6 +1631,12 @@
|
||||
"condition": "features.securetransport || features.openssl",
|
||||
"output": [ "feature" ]
|
||||
},
|
||||
"sctp": {
|
||||
"description": "SCTP",
|
||||
"autoDetect": false,
|
||||
"condition": "tests.sctp",
|
||||
"output": [ "feature" ]
|
||||
},
|
||||
"accessibility": {
|
||||
"description": "Accessibility",
|
||||
"output": [ "feature" ]
|
||||
@ -2462,6 +2474,7 @@ Please apply the patch corresponding to your Standard Library vendor, found in
|
||||
},
|
||||
"openssl",
|
||||
"openssl-linked",
|
||||
"sctp",
|
||||
"system-proxies"
|
||||
]
|
||||
},
|
||||
|
83
examples/network/multistreamclient/chatconsumer.cpp
Normal file
83
examples/network/multistreamclient/chatconsumer.cpp
Normal file
@ -0,0 +1,83 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 Alex Trotsenko <alex1973tr@gmail.com>
|
||||
** Contact: http://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the examples of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:BSD$
|
||||
** You may use this file under the terms of the BSD license as follows:
|
||||
**
|
||||
** "Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in
|
||||
** the documentation and/or other materials provided with the
|
||||
** distribution.
|
||||
** * Neither the name of The Qt Company Ltd nor the names of its
|
||||
** contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "chatconsumer.h"
|
||||
#include <QWidget>
|
||||
#include <QTextEdit>
|
||||
#include <QLineEdit>
|
||||
#include <QVBoxLayout>
|
||||
#include <QString>
|
||||
|
||||
ChatConsumer::ChatConsumer(QObject *parent)
|
||||
: Consumer(parent)
|
||||
{
|
||||
frameWidget = new QWidget;
|
||||
frameWidget->setFocusPolicy(Qt::TabFocus);
|
||||
|
||||
textEdit = new QTextEdit;
|
||||
textEdit->setFocusPolicy(Qt::NoFocus);
|
||||
textEdit->setReadOnly(true);
|
||||
|
||||
lineEdit = new QLineEdit;
|
||||
frameWidget->setFocusProxy(lineEdit);
|
||||
|
||||
connect(lineEdit, &QLineEdit::returnPressed, this, &ChatConsumer::returnPressed);
|
||||
|
||||
QVBoxLayout *layout = new QVBoxLayout(frameWidget);
|
||||
layout->setContentsMargins( 0, 0, 0, 0);
|
||||
layout->addWidget(textEdit);
|
||||
layout->addWidget(lineEdit);
|
||||
}
|
||||
|
||||
QWidget *ChatConsumer::widget()
|
||||
{
|
||||
return frameWidget;
|
||||
}
|
||||
|
||||
void ChatConsumer::readDatagram(const QByteArray &ba)
|
||||
{
|
||||
textEdit->append(QString::fromUtf8(ba));
|
||||
}
|
||||
|
||||
void ChatConsumer::returnPressed()
|
||||
{
|
||||
emit writeDatagram(lineEdit->text().toUtf8());
|
||||
lineEdit->clear();
|
||||
}
|
69
examples/network/multistreamclient/chatconsumer.h
Normal file
69
examples/network/multistreamclient/chatconsumer.h
Normal file
@ -0,0 +1,69 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 Alex Trotsenko <alex1973tr@gmail.com>
|
||||
** Contact: http://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the examples of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:BSD$
|
||||
** You may use this file under the terms of the BSD license as follows:
|
||||
**
|
||||
** "Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in
|
||||
** the documentation and/or other materials provided with the
|
||||
** distribution.
|
||||
** * Neither the name of The Qt Company Ltd nor the names of its
|
||||
** contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef CHATCONSUMER_H
|
||||
#define CHATCONSUMER_H
|
||||
|
||||
#include "consumer.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QTextEdit;
|
||||
class QLineEdit;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class ChatConsumer : public Consumer
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ChatConsumer(QObject *parent = nullptr);
|
||||
|
||||
QWidget *widget() Q_DECL_OVERRIDE;
|
||||
void readDatagram(const QByteArray &ba) Q_DECL_OVERRIDE;
|
||||
|
||||
private slots:
|
||||
void returnPressed();
|
||||
|
||||
private:
|
||||
QWidget *frameWidget;
|
||||
QTextEdit *textEdit;
|
||||
QLineEdit *lineEdit;
|
||||
};
|
||||
|
||||
#endif
|
207
examples/network/multistreamclient/client.cpp
Normal file
207
examples/network/multistreamclient/client.cpp
Normal file
@ -0,0 +1,207 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 Alex Trotsenko <alex1973tr@gmail.com>
|
||||
** Contact: http://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the examples of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:BSD$
|
||||
** You may use this file under the terms of the BSD license as follows:
|
||||
**
|
||||
** "Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in
|
||||
** the documentation and/or other materials provided with the
|
||||
** distribution.
|
||||
** * Neither the name of The Qt Company Ltd nor the names of its
|
||||
** contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include <QtWidgets>
|
||||
#include <QtNetwork>
|
||||
|
||||
#include "client.h"
|
||||
#include "movieconsumer.h"
|
||||
#include "timeconsumer.h"
|
||||
#include "chatconsumer.h"
|
||||
|
||||
Client::Client(QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, consumers(NumberOfChannels)
|
||||
{
|
||||
setWindowTitle(tr("Multi-stream Client"));
|
||||
|
||||
sctpSocket = new QSctpSocket(this);
|
||||
|
||||
QLabel *hostLabel = new QLabel(tr("&Server name:"));
|
||||
QLabel *portLabel = new QLabel(tr("S&erver port:"));
|
||||
|
||||
hostCombo = new QComboBox;
|
||||
hostCombo->setEditable(true);
|
||||
// find out name of this machine
|
||||
QString name = QHostInfo::localHostName();
|
||||
if (!name.isEmpty()) {
|
||||
hostCombo->addItem(name);
|
||||
QString domain = QHostInfo::localDomainName();
|
||||
if (!domain.isEmpty())
|
||||
hostCombo->addItem(name + QChar('.') + domain);
|
||||
}
|
||||
if (name != QString("localhost"))
|
||||
hostCombo->addItem(QString("localhost"));
|
||||
// find out IP addresses of this machine
|
||||
QList<QHostAddress> ipAddressesList = QNetworkInterface::allAddresses();
|
||||
// add non-localhost addresses
|
||||
for (int i = 0; i < ipAddressesList.size(); ++i) {
|
||||
if (!ipAddressesList.at(i).isLoopback())
|
||||
hostCombo->addItem(ipAddressesList.at(i).toString());
|
||||
}
|
||||
// add localhost addresses
|
||||
for (int i = 0; i < ipAddressesList.size(); ++i) {
|
||||
if (ipAddressesList.at(i).isLoopback())
|
||||
hostCombo->addItem(ipAddressesList.at(i).toString());
|
||||
}
|
||||
|
||||
portLineEdit = new QLineEdit;
|
||||
portLineEdit->setValidator(new QIntValidator(1, 65535, this));
|
||||
|
||||
hostLabel->setBuddy(hostCombo);
|
||||
portLabel->setBuddy(portLineEdit);
|
||||
|
||||
connectButton = new QPushButton(tr("Connect"));
|
||||
connectButton->setDefault(true);
|
||||
connectButton->setEnabled(false);
|
||||
|
||||
QPushButton *quitButton = new QPushButton(tr("Quit"));
|
||||
quitButton->setAutoDefault(false);
|
||||
|
||||
QDialogButtonBox *buttonBox = new QDialogButtonBox;
|
||||
buttonBox->addButton(connectButton, QDialogButtonBox::ActionRole);
|
||||
buttonBox->addButton(quitButton, QDialogButtonBox::AcceptRole);
|
||||
|
||||
QLabel *movieLabel = new QLabel(tr("Movie stream:"));
|
||||
consumers[Movie] = new MovieConsumer(this);
|
||||
QLabel *timeLabel = new QLabel(tr("Time stream:"));
|
||||
consumers[Time] = new TimeConsumer(this);
|
||||
QLabel *chatLabel = new QLabel(tr("&Chat:"));
|
||||
consumers[Chat] = new ChatConsumer(this);
|
||||
chatLabel->setBuddy(consumers[Chat]->widget());
|
||||
|
||||
connect(hostCombo, &QComboBox::editTextChanged, this, &Client::enableConnectButton);
|
||||
connect(portLineEdit, &QLineEdit::textChanged, this, &Client::enableConnectButton);
|
||||
connect(connectButton, &QPushButton::clicked, this, &Client::requestConnect);
|
||||
connect(buttonBox, &QDialogButtonBox::accepted, this, &Client::accept);
|
||||
connect(sctpSocket, &QSctpSocket::connected, this, &Client::connected);
|
||||
connect(sctpSocket, &QSctpSocket::disconnected, this, &Client::disconnected);
|
||||
connect(sctpSocket, &QSctpSocket::channelReadyRead, this, &Client::readDatagram);
|
||||
connect(sctpSocket, SIGNAL(error(QAbstractSocket::SocketError)),
|
||||
this, SLOT(displayError(QAbstractSocket::SocketError)));
|
||||
connect(consumers[Time], &Consumer::writeDatagram, this, &Client::writeDatagram);
|
||||
connect(consumers[Chat], &Consumer::writeDatagram, this, &Client::writeDatagram);
|
||||
|
||||
QGridLayout *mainLayout = new QGridLayout;
|
||||
mainLayout->addWidget(hostLabel, 0, 0);
|
||||
mainLayout->addWidget(hostCombo, 0, 1);
|
||||
mainLayout->addWidget(portLabel, 1, 0);
|
||||
mainLayout->addWidget(portLineEdit, 1, 1);
|
||||
mainLayout->addWidget(buttonBox, 2, 0, 1, 2);
|
||||
mainLayout->addWidget(movieLabel, 3, 0);
|
||||
mainLayout->addWidget(timeLabel, 3, 1);
|
||||
mainLayout->addWidget(consumers[Movie]->widget(), 4, 0);
|
||||
mainLayout->addWidget(consumers[Time]->widget(), 4, 1);
|
||||
mainLayout->addWidget(chatLabel, 5, 0);
|
||||
mainLayout->addWidget(consumers[Chat]->widget(), 6, 0, 1, 2);
|
||||
setLayout(mainLayout);
|
||||
|
||||
portLineEdit->setFocus();
|
||||
}
|
||||
|
||||
Client::~Client()
|
||||
{
|
||||
delete sctpSocket;
|
||||
}
|
||||
|
||||
void Client::connected()
|
||||
{
|
||||
consumers[Chat]->widget()->setFocus();
|
||||
}
|
||||
|
||||
void Client::disconnected()
|
||||
{
|
||||
for (Consumer *consumer : consumers)
|
||||
consumer->serverDisconnected();
|
||||
|
||||
sctpSocket->close();
|
||||
}
|
||||
|
||||
void Client::requestConnect()
|
||||
{
|
||||
connectButton->setEnabled(false);
|
||||
sctpSocket->abort();
|
||||
sctpSocket->connectToHost(hostCombo->currentText(),
|
||||
portLineEdit->text().toInt());
|
||||
}
|
||||
|
||||
void Client::readDatagram(int channel)
|
||||
{
|
||||
sctpSocket->setCurrentReadChannel(channel);
|
||||
consumers[channel]->readDatagram(sctpSocket->readDatagram().data());
|
||||
}
|
||||
|
||||
void Client::displayError(QAbstractSocket::SocketError socketError)
|
||||
{
|
||||
switch (socketError) {
|
||||
case QAbstractSocket::HostNotFoundError:
|
||||
QMessageBox::information(this, tr("Multi-stream Client"),
|
||||
tr("The host was not found. Please check the "
|
||||
"host name and port settings."));
|
||||
break;
|
||||
case QAbstractSocket::ConnectionRefusedError:
|
||||
QMessageBox::information(this, tr("Multi-stream Client"),
|
||||
tr("The connection was refused by the peer. "
|
||||
"Make sure the multi-stream server is running, "
|
||||
"and check that the host name and port "
|
||||
"settings are correct."));
|
||||
break;
|
||||
default:
|
||||
QMessageBox::information(this, tr("Multi-stream Client"),
|
||||
tr("The following error occurred: %1.")
|
||||
.arg(sctpSocket->errorString()));
|
||||
}
|
||||
|
||||
connectButton->setEnabled(true);
|
||||
}
|
||||
|
||||
void Client::enableConnectButton()
|
||||
{
|
||||
connectButton->setEnabled(!hostCombo->currentText().isEmpty() &&
|
||||
!portLineEdit->text().isEmpty());
|
||||
}
|
||||
|
||||
void Client::writeDatagram(const QByteArray &ba)
|
||||
{
|
||||
if (sctpSocket->isValid() && sctpSocket->state() == QAbstractSocket::ConnectedState) {
|
||||
sctpSocket->setCurrentWriteChannel(consumers.indexOf(static_cast<Consumer *>(sender())));
|
||||
sctpSocket->writeDatagram(ba);
|
||||
}
|
||||
}
|
90
examples/network/multistreamclient/client.h
Normal file
90
examples/network/multistreamclient/client.h
Normal file
@ -0,0 +1,90 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 Alex Trotsenko <alex1973tr@gmail.com>
|
||||
** Contact: http://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the examples of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:BSD$
|
||||
** You may use this file under the terms of the BSD license as follows:
|
||||
**
|
||||
** "Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in
|
||||
** the documentation and/or other materials provided with the
|
||||
** distribution.
|
||||
** * Neither the name of The Qt Company Ltd nor the names of its
|
||||
** contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef CLIENT_H
|
||||
#define CLIENT_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QVector>
|
||||
#include <QSctpSocket>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QComboBox;
|
||||
class QLineEdit;
|
||||
class QPushButton;
|
||||
class QByteArray;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class Consumer;
|
||||
|
||||
class Client : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit Client(QWidget *parent = nullptr);
|
||||
virtual ~Client();
|
||||
|
||||
private slots:
|
||||
void connected();
|
||||
void disconnected();
|
||||
void requestConnect();
|
||||
void readDatagram(int channel);
|
||||
void displayError(QAbstractSocket::SocketError socketError);
|
||||
void enableConnectButton();
|
||||
void writeDatagram(const QByteArray &ba);
|
||||
|
||||
private:
|
||||
enum ChannelNumber {
|
||||
Movie = 0,
|
||||
Time = 1,
|
||||
Chat = 2,
|
||||
|
||||
NumberOfChannels = 3
|
||||
};
|
||||
|
||||
QVector<Consumer *> consumers;
|
||||
QSctpSocket *sctpSocket;
|
||||
|
||||
QComboBox *hostCombo;
|
||||
QLineEdit *portLineEdit;
|
||||
QPushButton *connectButton;
|
||||
};
|
||||
|
||||
#endif
|
65
examples/network/multistreamclient/consumer.h
Normal file
65
examples/network/multistreamclient/consumer.h
Normal file
@ -0,0 +1,65 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 Alex Trotsenko <alex1973tr@gmail.com>
|
||||
** Contact: http://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the examples of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:BSD$
|
||||
** You may use this file under the terms of the BSD license as follows:
|
||||
**
|
||||
** "Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in
|
||||
** the documentation and/or other materials provided with the
|
||||
** distribution.
|
||||
** * Neither the name of The Qt Company Ltd nor the names of its
|
||||
** contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef CONSUMER_H
|
||||
#define CONSUMER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QByteArray>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QWidget;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class Consumer : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit inline Consumer(QObject *parent = nullptr) : QObject(parent) { }
|
||||
|
||||
virtual QWidget *widget() = 0;
|
||||
virtual void readDatagram(const QByteArray &ba) = 0;
|
||||
virtual void serverDisconnected() { }
|
||||
|
||||
signals:
|
||||
void writeDatagram(const QByteArray &ba);
|
||||
};
|
||||
|
||||
#endif
|
50
examples/network/multistreamclient/main.cpp
Normal file
50
examples/network/multistreamclient/main.cpp
Normal file
@ -0,0 +1,50 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 Alex Trotsenko <alex1973tr@gmail.com>
|
||||
** Contact: http://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the examples of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:BSD$
|
||||
** You may use this file under the terms of the BSD license as follows:
|
||||
**
|
||||
** "Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in
|
||||
** the documentation and/or other materials provided with the
|
||||
** distribution.
|
||||
** * Neither the name of The Qt Company Ltd nor the names of its
|
||||
** contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include <QApplication>
|
||||
#include "client.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
Client client;
|
||||
|
||||
return (client.exec() == QDialog::Accepted) ? 0 : -1;
|
||||
}
|
73
examples/network/multistreamclient/movieconsumer.cpp
Normal file
73
examples/network/multistreamclient/movieconsumer.cpp
Normal file
@ -0,0 +1,73 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 Alex Trotsenko <alex1973tr@gmail.com>
|
||||
** Contact: http://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the examples of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:BSD$
|
||||
** You may use this file under the terms of the BSD license as follows:
|
||||
**
|
||||
** "Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in
|
||||
** the documentation and/or other materials provided with the
|
||||
** distribution.
|
||||
** * Neither the name of The Qt Company Ltd nor the names of its
|
||||
** contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "movieconsumer.h"
|
||||
#include <QLabel>
|
||||
#include <QDataStream>
|
||||
#include <QImage>
|
||||
#include <QPixmap>
|
||||
|
||||
MovieConsumer::MovieConsumer(QObject *parent)
|
||||
: Consumer(parent)
|
||||
{
|
||||
label = new QLabel;
|
||||
label->setFrameStyle(QFrame::Box | QFrame::Raised);
|
||||
label->setFixedSize(128 + label->frameWidth() * 2,
|
||||
64 + label->frameWidth() * 2);
|
||||
}
|
||||
|
||||
QWidget *MovieConsumer::widget()
|
||||
{
|
||||
return label;
|
||||
}
|
||||
|
||||
void MovieConsumer::readDatagram(const QByteArray &ba)
|
||||
{
|
||||
QDataStream ds(ba);
|
||||
QImage image;
|
||||
|
||||
ds >> image;
|
||||
label->setPixmap(QPixmap::fromImage(image));
|
||||
}
|
||||
|
||||
void MovieConsumer::serverDisconnected()
|
||||
{
|
||||
label->setPixmap(QPixmap());
|
||||
}
|
64
examples/network/multistreamclient/movieconsumer.h
Normal file
64
examples/network/multistreamclient/movieconsumer.h
Normal file
@ -0,0 +1,64 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 Alex Trotsenko <alex1973tr@gmail.com>
|
||||
** Contact: http://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the examples of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:BSD$
|
||||
** You may use this file under the terms of the BSD license as follows:
|
||||
**
|
||||
** "Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in
|
||||
** the documentation and/or other materials provided with the
|
||||
** distribution.
|
||||
** * Neither the name of The Qt Company Ltd nor the names of its
|
||||
** contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef MOVIECONSUMER_H
|
||||
#define MOVIECONSUMER_H
|
||||
|
||||
#include "consumer.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QLabel;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class MovieConsumer : public Consumer
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit MovieConsumer(QObject *parent = nullptr);
|
||||
|
||||
QWidget *widget() Q_DECL_OVERRIDE;
|
||||
void readDatagram(const QByteArray &ba) Q_DECL_OVERRIDE;
|
||||
void serverDisconnected() Q_DECL_OVERRIDE;
|
||||
|
||||
private:
|
||||
QLabel *label;
|
||||
};
|
||||
|
||||
#endif
|
16
examples/network/multistreamclient/multistreamclient.pro
Normal file
16
examples/network/multistreamclient/multistreamclient.pro
Normal file
@ -0,0 +1,16 @@
|
||||
QT += network widgets
|
||||
|
||||
HEADERS = client.h \
|
||||
consumer.h \
|
||||
movieconsumer.h \
|
||||
timeconsumer.h \
|
||||
chatconsumer.h
|
||||
SOURCES = client.cpp \
|
||||
movieconsumer.cpp \
|
||||
timeconsumer.cpp \
|
||||
chatconsumer.cpp \
|
||||
main.cpp
|
||||
|
||||
# install
|
||||
target.path = $$[QT_INSTALL_EXAMPLES]/network/multistreamclient
|
||||
INSTALLS += target
|
84
examples/network/multistreamclient/timeconsumer.cpp
Normal file
84
examples/network/multistreamclient/timeconsumer.cpp
Normal file
@ -0,0 +1,84 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 Alex Trotsenko <alex1973tr@gmail.com>
|
||||
** Contact: http://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the examples of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:BSD$
|
||||
** You may use this file under the terms of the BSD license as follows:
|
||||
**
|
||||
** "Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in
|
||||
** the documentation and/or other materials provided with the
|
||||
** distribution.
|
||||
** * Neither the name of The Qt Company Ltd nor the names of its
|
||||
** contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "timeconsumer.h"
|
||||
#include <QLCDNumber>
|
||||
#include <QString>
|
||||
#include <QDataStream>
|
||||
#include <QTimer>
|
||||
|
||||
TimeConsumer::TimeConsumer(QObject *parent)
|
||||
: Consumer(parent)
|
||||
{
|
||||
lcdNumber = new QLCDNumber(8);
|
||||
|
||||
QTimer *timer = new QTimer(this);
|
||||
connect(timer, &QTimer::timeout, this, &TimeConsumer::timerTick);
|
||||
timer->start(100);
|
||||
|
||||
serverDisconnected();
|
||||
}
|
||||
|
||||
QWidget *TimeConsumer::widget()
|
||||
{
|
||||
return lcdNumber;
|
||||
}
|
||||
|
||||
void TimeConsumer::readDatagram(const QByteArray &ba)
|
||||
{
|
||||
QDataStream ds(ba);
|
||||
|
||||
ds >> lastTime;
|
||||
lcdNumber->display(lastTime.toString("hh:mm:ss"));
|
||||
}
|
||||
|
||||
void TimeConsumer::timerTick()
|
||||
{
|
||||
QByteArray buf;
|
||||
QDataStream ds(&buf, QIODevice::WriteOnly);
|
||||
|
||||
ds << lastTime;
|
||||
emit writeDatagram(buf);
|
||||
}
|
||||
|
||||
void TimeConsumer::serverDisconnected()
|
||||
{
|
||||
lcdNumber->display(QLatin1String("--:--:--"));
|
||||
}
|
69
examples/network/multistreamclient/timeconsumer.h
Normal file
69
examples/network/multistreamclient/timeconsumer.h
Normal file
@ -0,0 +1,69 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 Alex Trotsenko <alex1973tr@gmail.com>
|
||||
** Contact: http://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the examples of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:BSD$
|
||||
** You may use this file under the terms of the BSD license as follows:
|
||||
**
|
||||
** "Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in
|
||||
** the documentation and/or other materials provided with the
|
||||
** distribution.
|
||||
** * Neither the name of The Qt Company Ltd nor the names of its
|
||||
** contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef TIMECONSUMER_H
|
||||
#define TIMECONSUMER_H
|
||||
|
||||
#include "consumer.h"
|
||||
#include <QTime>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QLCDNumber;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class TimeConsumer : public Consumer
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit TimeConsumer(QObject *parent = nullptr);
|
||||
|
||||
QWidget *widget() Q_DECL_OVERRIDE;
|
||||
void readDatagram(const QByteArray &ba) Q_DECL_OVERRIDE;
|
||||
void serverDisconnected() Q_DECL_OVERRIDE;
|
||||
|
||||
private slots:
|
||||
void timerTick();
|
||||
|
||||
private:
|
||||
QTime lastTime;
|
||||
QLCDNumber *lcdNumber;
|
||||
};
|
||||
|
||||
#endif
|
BIN
examples/network/multistreamserver/animation.gif
Normal file
BIN
examples/network/multistreamserver/animation.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 42 KiB |
67
examples/network/multistreamserver/chatprovider.cpp
Normal file
67
examples/network/multistreamserver/chatprovider.cpp
Normal file
@ -0,0 +1,67 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 Alex Trotsenko <alex1973tr@gmail.com>
|
||||
** Contact: http://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the examples of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:BSD$
|
||||
** You may use this file under the terms of the BSD license as follows:
|
||||
**
|
||||
** "Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in
|
||||
** the documentation and/or other materials provided with the
|
||||
** distribution.
|
||||
** * Neither the name of The Qt Company Ltd nor the names of its
|
||||
** contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "chatprovider.h"
|
||||
#include <QString>
|
||||
#include <QSctpSocket>
|
||||
#include <QHostAddress>
|
||||
|
||||
ChatProvider::ChatProvider(QObject *parent)
|
||||
: Provider(parent)
|
||||
{
|
||||
}
|
||||
|
||||
void ChatProvider::readDatagram(QSctpSocket &from, const QByteArray &ba)
|
||||
{
|
||||
emit writeDatagram(0, QString(QLatin1String("<%1:%2> %3"))
|
||||
.arg(from.peerAddress().toString())
|
||||
.arg(QString::number(from.peerPort()))
|
||||
.arg(QString::fromUtf8(ba)).toUtf8());
|
||||
}
|
||||
|
||||
void ChatProvider::newConnection(QSctpSocket &client)
|
||||
{
|
||||
readDatagram(client, QString(tr("has joined")).toUtf8());
|
||||
}
|
||||
|
||||
void ChatProvider::clientDisconnected(QSctpSocket &client)
|
||||
{
|
||||
readDatagram(client, QString(tr("has left")).toUtf8());
|
||||
}
|
57
examples/network/multistreamserver/chatprovider.h
Normal file
57
examples/network/multistreamserver/chatprovider.h
Normal file
@ -0,0 +1,57 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 Alex Trotsenko <alex1973tr@gmail.com>
|
||||
** Contact: http://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the examples of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:BSD$
|
||||
** You may use this file under the terms of the BSD license as follows:
|
||||
**
|
||||
** "Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in
|
||||
** the documentation and/or other materials provided with the
|
||||
** distribution.
|
||||
** * Neither the name of The Qt Company Ltd nor the names of its
|
||||
** contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef CHATPROVIDER_H
|
||||
#define CHATPROVIDER_H
|
||||
|
||||
#include "provider.h"
|
||||
|
||||
class ChatProvider : public Provider
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ChatProvider(QObject *parent = nullptr);
|
||||
|
||||
void readDatagram(QSctpSocket &from, const QByteArray &ba) Q_DECL_OVERRIDE;
|
||||
void newConnection(QSctpSocket &client) Q_DECL_OVERRIDE;
|
||||
void clientDisconnected(QSctpSocket &client) Q_DECL_OVERRIDE;
|
||||
};
|
||||
|
||||
#endif
|
51
examples/network/multistreamserver/main.cpp
Normal file
51
examples/network/multistreamserver/main.cpp
Normal file
@ -0,0 +1,51 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 Alex Trotsenko <alex1973tr@gmail.com>
|
||||
** Contact: http://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the examples of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:BSD$
|
||||
** You may use this file under the terms of the BSD license as follows:
|
||||
**
|
||||
** "Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in
|
||||
** the documentation and/or other materials provided with the
|
||||
** distribution.
|
||||
** * Neither the name of The Qt Company Ltd nor the names of its
|
||||
** contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
#include "server.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
Server server;
|
||||
|
||||
return (server.exec() == QDialog::Accepted) ? 0 : -1;
|
||||
}
|
63
examples/network/multistreamserver/movieprovider.cpp
Normal file
63
examples/network/multistreamserver/movieprovider.cpp
Normal file
@ -0,0 +1,63 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 Alex Trotsenko <alex1973tr@gmail.com>
|
||||
** Contact: http://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the examples of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:BSD$
|
||||
** You may use this file under the terms of the BSD license as follows:
|
||||
**
|
||||
** "Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in
|
||||
** the documentation and/or other materials provided with the
|
||||
** distribution.
|
||||
** * Neither the name of The Qt Company Ltd nor the names of its
|
||||
** contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "movieprovider.h"
|
||||
#include <QMovie>
|
||||
#include <QString>
|
||||
#include <QDataStream>
|
||||
|
||||
MovieProvider::MovieProvider(QObject *parent)
|
||||
: Provider(parent)
|
||||
{
|
||||
movie = new QMovie(this);
|
||||
movie->setCacheMode(QMovie::CacheAll);
|
||||
movie->setFileName(QLatin1String("animation.gif"));
|
||||
connect(movie, &QMovie::frameChanged, this, &MovieProvider::frameChanged);
|
||||
movie->start();
|
||||
}
|
||||
|
||||
void MovieProvider::frameChanged()
|
||||
{
|
||||
QByteArray buf;
|
||||
QDataStream ds(&buf, QIODevice::WriteOnly);
|
||||
|
||||
ds << movie->currentImage();
|
||||
emit writeDatagram(0, buf);
|
||||
}
|
63
examples/network/multistreamserver/movieprovider.h
Normal file
63
examples/network/multistreamserver/movieprovider.h
Normal file
@ -0,0 +1,63 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 Alex Trotsenko <alex1973tr@gmail.com>
|
||||
** Contact: http://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the examples of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:BSD$
|
||||
** You may use this file under the terms of the BSD license as follows:
|
||||
**
|
||||
** "Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in
|
||||
** the documentation and/or other materials provided with the
|
||||
** distribution.
|
||||
** * Neither the name of The Qt Company Ltd nor the names of its
|
||||
** contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef MOVIEPROVIDER_H
|
||||
#define MOVIEPROVIDER_H
|
||||
|
||||
#include "provider.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QMovie;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class MovieProvider : public Provider
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit MovieProvider(QObject *parent = nullptr);
|
||||
|
||||
private slots:
|
||||
void frameChanged();
|
||||
|
||||
private:
|
||||
QMovie *movie;
|
||||
};
|
||||
|
||||
#endif
|
24
examples/network/multistreamserver/multistreamserver.pro
Normal file
24
examples/network/multistreamserver/multistreamserver.pro
Normal file
@ -0,0 +1,24 @@
|
||||
QT += network widgets
|
||||
|
||||
HEADERS = server.h \
|
||||
provider.h \
|
||||
movieprovider.h \
|
||||
timeprovider.h \
|
||||
chatprovider.h
|
||||
SOURCES = server.cpp \
|
||||
movieprovider.cpp \
|
||||
timeprovider.cpp \
|
||||
chatprovider.cpp \
|
||||
main.cpp
|
||||
|
||||
EXAMPLE_FILES = animation.gif
|
||||
|
||||
# install
|
||||
target.path = $$[QT_INSTALL_EXAMPLES]/network/multistreamserver
|
||||
INSTALLS += target
|
||||
|
||||
wince*: {
|
||||
addFiles.files += *.gif
|
||||
addFiles.path = .
|
||||
DEPLOYMENT += addFiles
|
||||
}
|
66
examples/network/multistreamserver/provider.h
Normal file
66
examples/network/multistreamserver/provider.h
Normal file
@ -0,0 +1,66 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 Alex Trotsenko <alex1973tr@gmail.com>
|
||||
** Contact: http://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the examples of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:BSD$
|
||||
** You may use this file under the terms of the BSD license as follows:
|
||||
**
|
||||
** "Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in
|
||||
** the documentation and/or other materials provided with the
|
||||
** distribution.
|
||||
** * Neither the name of The Qt Company Ltd nor the names of its
|
||||
** contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef PROVIDER_H
|
||||
#define PROVIDER_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QSctpSocket;
|
||||
class QByteArray;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class Provider : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit inline Provider(QObject *parent = nullptr) : QObject(parent) { }
|
||||
|
||||
virtual void readDatagram(QSctpSocket &, const QByteArray &) { }
|
||||
virtual void newConnection(QSctpSocket &) { }
|
||||
virtual void clientDisconnected(QSctpSocket &) { }
|
||||
|
||||
signals:
|
||||
void writeDatagram(QSctpSocket *to, const QByteArray &ba);
|
||||
};
|
||||
|
||||
#endif
|
159
examples/network/multistreamserver/server.cpp
Normal file
159
examples/network/multistreamserver/server.cpp
Normal file
@ -0,0 +1,159 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2015 Alex Trotsenko <alex1973tr@gmail.com>
|
||||
** Contact: http://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the examples of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:BSD$
|
||||
** You may use this file under the terms of the BSD license as follows:
|
||||
**
|
||||
** "Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in
|
||||
** the documentation and/or other materials provided with the
|
||||
** distribution.
|
||||
** * Neither the name of The Qt Company Ltd nor the names of its
|
||||
** contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include <QtWidgets>
|
||||
#include <QtNetwork>
|
||||
#include <QtAlgorithms>
|
||||
|
||||
#include "server.h"
|
||||
#include "movieprovider.h"
|
||||
#include "timeprovider.h"
|
||||
#include "chatprovider.h"
|
||||
|
||||
Server::Server(QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, providers(NumberOfChannels)
|
||||
{
|
||||
setWindowTitle(tr("Multi-stream Server"));
|
||||
|
||||
sctpServer = new QSctpServer(this);
|
||||
sctpServer->setMaxChannelCount(NumberOfChannels);
|
||||
|
||||
statusLabel = new QLabel;
|
||||
QPushButton *quitButton = new QPushButton(tr("Quit"));
|
||||
|
||||
providers[Movie] = new MovieProvider(this);
|
||||
providers[Time] = new TimeProvider(this);
|
||||
providers[Chat] = new ChatProvider(this);
|
||||
|
||||
connect(sctpServer, &QSctpServer::newConnection, this, &Server::newConnection);
|
||||
connect(quitButton, &QPushButton::clicked, this, &Server::accept);
|
||||
connect(providers[Movie], &Provider::writeDatagram, this, &Server::writeDatagram);
|
||||
connect(providers[Time], &Provider::writeDatagram, this, &Server::writeDatagram);
|
||||
connect(providers[Chat], &Provider::writeDatagram, this, &Server::writeDatagram);
|
||||
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout;
|
||||
mainLayout->addWidget(statusLabel);
|
||||
mainLayout->addWidget(quitButton);
|
||||
setLayout(mainLayout);
|
||||
}
|
||||
|
||||
Server::~Server()
|
||||
{
|
||||
qDeleteAll(connections.begin(), connections.end());
|
||||
}
|
||||
|
||||
int Server::exec()
|
||||
{
|
||||
if (!sctpServer->listen()) {
|
||||
QMessageBox::critical(this, windowTitle(),
|
||||
tr("Unable to start the server: %1.")
|
||||
.arg(sctpServer->errorString()));
|
||||
return QDialog::Rejected;
|
||||
}
|
||||
|
||||
QString ipAddress;
|
||||
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()) {
|
||||
ipAddress = ipAddressesList.at(i).toString();
|
||||
break;
|
||||
}
|
||||
}
|
||||
// if we did not find one, use IPv4 localhost
|
||||
if (ipAddress.isEmpty())
|
||||
ipAddress = QHostAddress(QHostAddress::LocalHost).toString();
|
||||
statusLabel->setText(tr("The server is running on\n\nIP: %1\nport: %2\n\n"
|
||||
"Run the Multi-stream Client example now.")
|
||||
.arg(ipAddress).arg(sctpServer->serverPort()));
|
||||
|
||||
return QDialog::exec();
|
||||
}
|
||||
|
||||
void Server::newConnection()
|
||||
{
|
||||
QSctpSocket *connection = sctpServer->nextPendingDatagramConnection();
|
||||
|
||||
connections.append(connection);
|
||||
connect(connection, &QSctpSocket::channelReadyRead, this, &Server::readDatagram);
|
||||
connect(connection, &QSctpSocket::disconnected, this, &Server::clientDisconnected);
|
||||
|
||||
for (Provider *provider : providers)
|
||||
provider->newConnection(*connection);
|
||||
}
|
||||
|
||||
void Server::clientDisconnected()
|
||||
{
|
||||
QSctpSocket *connection = static_cast<QSctpSocket *>(sender());
|
||||
|
||||
connections.removeOne(connection);
|
||||
connection->disconnect();
|
||||
|
||||
for (Provider *provider : providers)
|
||||
provider->clientDisconnected(*connection);
|
||||
|
||||
connection->deleteLater();
|
||||
}
|
||||
|
||||
void Server::readDatagram(int channel)
|
||||
{
|
||||
QSctpSocket *connection = static_cast<QSctpSocket *>(sender());
|
||||
|
||||
connection->setCurrentReadChannel(channel);
|
||||
providers[channel]->readDatagram(*connection, connection->readDatagram().data());
|
||||
}
|
||||
|
||||
void Server::writeDatagram(QSctpSocket *to, const QByteArray &ba)
|
||||
{
|
||||
int channel = providers.indexOf(static_cast<Provider *>(sender()));
|
||||
|
||||
if (to) {
|
||||
to->setCurrentWriteChannel(channel);
|
||||
to->writeDatagram(ba);
|
||||
return;
|
||||
}
|
||||
|
||||
for (QSctpSocket *connection : connections) {
|
||||
connection->setCurrentWriteChannel(channel);
|
||||
connection->writeDatagram(ba);
|
||||
}
|
||||
}
|
89
examples/network/multistreamserver/server.h
Normal file
89
examples/network/multistreamserver/server.h
Normal file
@ -0,0 +1,89 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 Alex Trotsenko <alex1973tr@gmail.com>
|
||||
** Contact: http://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the examples of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:BSD$
|
||||
** You may use this file under the terms of the BSD license as follows:
|
||||
**
|
||||
** "Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in
|
||||
** the documentation and/or other materials provided with the
|
||||
** distribution.
|
||||
** * Neither the name of The Qt Company Ltd nor the names of its
|
||||
** contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef SERVER_H
|
||||
#define SERVER_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QVector>
|
||||
#include <QList>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QSctpServer;
|
||||
class QSctpSocket;
|
||||
class QLabel;
|
||||
class QByteArray;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class Provider;
|
||||
|
||||
class Server : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit Server(QWidget *parent = nullptr);
|
||||
virtual ~Server();
|
||||
|
||||
public slots:
|
||||
int exec() Q_DECL_OVERRIDE;
|
||||
|
||||
private slots:
|
||||
void newConnection();
|
||||
void clientDisconnected();
|
||||
void readDatagram(int channel);
|
||||
void writeDatagram(QSctpSocket *to, const QByteArray &ba);
|
||||
|
||||
private:
|
||||
enum ChannelNumber {
|
||||
Movie = 0,
|
||||
Time = 1,
|
||||
Chat = 2,
|
||||
|
||||
NumberOfChannels = 3
|
||||
};
|
||||
|
||||
QVector<Provider *> providers;
|
||||
QSctpServer *sctpServer;
|
||||
QList<QSctpSocket *> connections;
|
||||
|
||||
QLabel *statusLabel;
|
||||
};
|
||||
|
||||
#endif
|
67
examples/network/multistreamserver/timeprovider.cpp
Normal file
67
examples/network/multistreamserver/timeprovider.cpp
Normal file
@ -0,0 +1,67 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 Alex Trotsenko <alex1973tr@gmail.com>
|
||||
** Contact: http://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the examples of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:BSD$
|
||||
** You may use this file under the terms of the BSD license as follows:
|
||||
**
|
||||
** "Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in
|
||||
** the documentation and/or other materials provided with the
|
||||
** distribution.
|
||||
** * Neither the name of The Qt Company Ltd nor the names of its
|
||||
** contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "timeprovider.h"
|
||||
#include <QDataStream>
|
||||
#include <QTime>
|
||||
#include <QByteArray>
|
||||
|
||||
TimeProvider::TimeProvider(QObject *parent)
|
||||
: Provider(parent)
|
||||
{
|
||||
}
|
||||
|
||||
void TimeProvider::readDatagram(QSctpSocket &from, const QByteArray &ba)
|
||||
{
|
||||
QDataStream in_ds(ba);
|
||||
QTime curTime = QTime::currentTime();
|
||||
QTime clientTime;
|
||||
|
||||
in_ds >> clientTime;
|
||||
if (!clientTime.isValid() || curTime.second() != clientTime.second()
|
||||
|| curTime.minute() != clientTime.minute()
|
||||
|| curTime.hour() != clientTime.hour()) {
|
||||
QByteArray buf;
|
||||
QDataStream out_ds(&buf, QIODevice::WriteOnly);
|
||||
|
||||
out_ds << curTime;
|
||||
emit writeDatagram(&from, buf);
|
||||
}
|
||||
}
|
55
examples/network/multistreamserver/timeprovider.h
Normal file
55
examples/network/multistreamserver/timeprovider.h
Normal file
@ -0,0 +1,55 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 Alex Trotsenko <alex1973tr@gmail.com>
|
||||
** Contact: http://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the examples of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:BSD$
|
||||
** You may use this file under the terms of the BSD license as follows:
|
||||
**
|
||||
** "Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in
|
||||
** the documentation and/or other materials provided with the
|
||||
** distribution.
|
||||
** * Neither the name of The Qt Company Ltd nor the names of its
|
||||
** contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef TIMEPROVIDER_H
|
||||
#define TIMEPROVIDER_H
|
||||
|
||||
#include "provider.h"
|
||||
|
||||
class TimeProvider : public Provider
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit TimeProvider(QObject *parent = nullptr);
|
||||
|
||||
void readDatagram(QSctpSocket &from, const QByteArray &ba) Q_DECL_OVERRIDE;
|
||||
};
|
||||
|
||||
#endif
|
@ -32,4 +32,5 @@ qtHaveModule(widgets) {
|
||||
|
||||
contains(QT_CONFIG, openssl):SUBDIRS += securesocketclient
|
||||
contains(QT_CONFIG, openssl-linked):SUBDIRS += securesocketclient
|
||||
contains(QT_CONFIG, sctp):SUBDIRS += multistreamserver multistreamclient
|
||||
}
|
||||
|
@ -738,6 +738,18 @@ void QIODevicePrivate::setWriteChannelCount(int count)
|
||||
setCurrentWriteChannel(currentWriteChannel);
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal
|
||||
*/
|
||||
bool QIODevicePrivate::allWriteBuffersEmpty() const
|
||||
{
|
||||
for (const QRingBuffer &ringBuffer : writeBuffers) {
|
||||
if (!ringBuffer.isEmpty())
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
Opens the device and sets its OpenMode to \a mode. Returns \c true if successful;
|
||||
otherwise returns \c false. This function should be called from any
|
||||
|
@ -154,6 +154,8 @@ public:
|
||||
return buffer.isEmpty() || (transactionStarted && isSequential()
|
||||
&& transactionPos == buffer.size());
|
||||
}
|
||||
bool allWriteBuffersEmpty() const;
|
||||
|
||||
void seekBuffer(qint64 newPos);
|
||||
|
||||
inline void setCurrentReadChannel(int channel)
|
||||
|
@ -0,0 +1,53 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 Alex Trotsenko <alex1973tr@gmail.com>
|
||||
** Contact: http://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the documentation of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:BSD$
|
||||
** You may use this file under the terms of the BSD license as follows:
|
||||
**
|
||||
** "Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in
|
||||
** the documentation and/or other materials provided with the
|
||||
** distribution.
|
||||
** * Neither the name of The Qt Company Ltd nor the names of its
|
||||
** contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
//! [0]
|
||||
QSctpSocket *socket = new QSctpSocket(this);
|
||||
|
||||
socket->setMaxChannelCount(16);
|
||||
socket->connectToHost(QHostAddress::LocalHost, 1973);
|
||||
|
||||
if (socket->waitForConnected(1000)) {
|
||||
int inputChannels = socket->readChannelCount();
|
||||
int outputChannels = socket->writeChannelCount();
|
||||
|
||||
....
|
||||
}
|
||||
//! [0]
|
@ -104,6 +104,7 @@ public:
|
||||
private:
|
||||
QNetworkDatagramPrivate *d;
|
||||
friend class QUdpSocket;
|
||||
friend class QSctpSocket;
|
||||
|
||||
explicit QNetworkDatagram(QNetworkDatagramPrivate &dd);
|
||||
QNetworkDatagram makeReply_helper(const QByteArray &data) const;
|
||||
|
@ -54,7 +54,8 @@ class QIpPacketHeader
|
||||
{
|
||||
public:
|
||||
QIpPacketHeader(const QHostAddress &dstAddr = QHostAddress(), quint16 port = 0)
|
||||
: destinationAddress(dstAddr), ifindex(0), hopLimit(-1), destinationPort(port)
|
||||
: destinationAddress(dstAddr), ifindex(0), hopLimit(-1), streamNumber(-1),
|
||||
destinationPort(port), endOfRecord(false)
|
||||
{}
|
||||
|
||||
void clear()
|
||||
@ -63,6 +64,8 @@ public:
|
||||
destinationAddress.clear();
|
||||
ifindex = 0;
|
||||
hopLimit = -1;
|
||||
streamNumber = -1;
|
||||
endOfRecord = false;
|
||||
}
|
||||
|
||||
QHostAddress senderAddress;
|
||||
@ -70,8 +73,10 @@ public:
|
||||
|
||||
uint ifindex;
|
||||
int hopLimit;
|
||||
int streamNumber;
|
||||
quint16 senderPort;
|
||||
quint16 destinationPort;
|
||||
bool endOfRecord;
|
||||
};
|
||||
|
||||
class QNetworkDatagramPrivate
|
||||
@ -81,6 +86,9 @@ public:
|
||||
const QHostAddress &dstAddr = QHostAddress(), quint16 port = 0)
|
||||
: data(data), header(dstAddr, port)
|
||||
{}
|
||||
QNetworkDatagramPrivate(const QByteArray &data, const QIpPacketHeader &header)
|
||||
: data(data), header(header)
|
||||
{}
|
||||
|
||||
QByteArray data;
|
||||
QIpPacketHeader header;
|
||||
|
@ -212,6 +212,12 @@
|
||||
lookup on a remote host name and connect to it, as opposed to
|
||||
requiring the application to perform the name lookup and request
|
||||
connection to IP addresses only.
|
||||
|
||||
\value SctpTunnelingCapability Ability to open transparent, tunneled
|
||||
SCTP connections to a remote host.
|
||||
|
||||
\value SctpListeningCapability Ability to create a listening socket
|
||||
and wait for an incoming SCTP connection from a remote host.
|
||||
*/
|
||||
|
||||
#include "qnetworkproxy.h"
|
||||
@ -369,7 +375,9 @@ static QNetworkProxy::Capabilities defaultCapabilitiesForType(QNetworkProxy::Pro
|
||||
/* [QNetworkProxy::DefaultProxy] = */
|
||||
(int(QNetworkProxy::ListeningCapability) |
|
||||
int(QNetworkProxy::TunnelingCapability) |
|
||||
int(QNetworkProxy::UdpTunnelingCapability)),
|
||||
int(QNetworkProxy::UdpTunnelingCapability) |
|
||||
int(QNetworkProxy::SctpTunnelingCapability) |
|
||||
int(QNetworkProxy::SctpListeningCapability)),
|
||||
/* [QNetworkProxy::Socks5Proxy] = */
|
||||
(int(QNetworkProxy::TunnelingCapability) |
|
||||
int(QNetworkProxy::ListeningCapability) |
|
||||
@ -379,7 +387,9 @@ static QNetworkProxy::Capabilities defaultCapabilitiesForType(QNetworkProxy::Pro
|
||||
/* [QNetworkProxy::NoProxy] = */
|
||||
(int(QNetworkProxy::ListeningCapability) |
|
||||
int(QNetworkProxy::TunnelingCapability) |
|
||||
int(QNetworkProxy::UdpTunnelingCapability)),
|
||||
int(QNetworkProxy::UdpTunnelingCapability) |
|
||||
int(QNetworkProxy::SctpTunnelingCapability) |
|
||||
int(QNetworkProxy::SctpListeningCapability)),
|
||||
/* [QNetworkProxy::HttpProxy] = */
|
||||
(int(QNetworkProxy::TunnelingCapability) |
|
||||
int(QNetworkProxy::CachingCapability) |
|
||||
@ -965,6 +975,14 @@ template<> void QSharedDataPointer<QNetworkProxyQueryPrivate>::detach()
|
||||
can all be used or be left unused, depending on the
|
||||
characteristics of the socket. The URL component is not used.
|
||||
|
||||
\row
|
||||
\li SctpSocket
|
||||
\li Message-oriented sockets requesting a connection to a remote
|
||||
server. The peer hostname and peer port match the values passed
|
||||
to QSctpSocket::connectToHost(). The local port is usually -1,
|
||||
indicating the socket has no preference in which port should be
|
||||
used. The URL component is not used.
|
||||
|
||||
\row
|
||||
\li TcpServer
|
||||
\li Passive server sockets that listen on a port and await
|
||||
@ -981,6 +999,14 @@ template<> void QSharedDataPointer<QNetworkProxyQueryPrivate>::detach()
|
||||
indicate that more detailed information is present in the URL
|
||||
component. For ease of implementation, the URL's host and
|
||||
port are set as the destination address.
|
||||
|
||||
\row
|
||||
\li SctpServer
|
||||
\li Passive server sockets that listen on a SCTP port and await
|
||||
incoming connections from the network. Normally, only the
|
||||
local port is used, but the remote address could be used in
|
||||
specific circumstances, for example to indicate which remote
|
||||
host a connection is expected from. The URL component is not used.
|
||||
\endtable
|
||||
|
||||
It should be noted that any of the criteria may be missing or
|
||||
@ -1001,10 +1027,13 @@ template<> void QSharedDataPointer<QNetworkProxyQueryPrivate>::detach()
|
||||
\value TcpSocket a normal, outgoing TCP socket
|
||||
\value UdpSocket a datagram-based UDP socket, which could send
|
||||
to multiple destinations
|
||||
\value SctpSocket a message-oriented, outgoing SCTP socket
|
||||
\value TcpServer a TCP server that listens for incoming
|
||||
connections from the network
|
||||
\value UrlRequest a more complex request which involves loading
|
||||
of a URL
|
||||
\value SctpServer a SCTP server that listens for incoming
|
||||
connections from the network
|
||||
|
||||
\sa queryType(), setQueryType()
|
||||
*/
|
||||
@ -1614,6 +1643,10 @@ QDebug operator<<(QDebug debug, const QNetworkProxy &proxy)
|
||||
scaps << QStringLiteral("Caching");
|
||||
if (caps & QNetworkProxy::HostNameLookupCapability)
|
||||
scaps << QStringLiteral("NameLookup");
|
||||
if (caps & QNetworkProxy::SctpTunnelingCapability)
|
||||
scaps << QStringLiteral("SctpTunnel");
|
||||
if (caps & QNetworkProxy::SctpListeningCapability)
|
||||
scaps << QStringLiteral("SctpListen");
|
||||
debug << '[' << scaps.join(QLatin1Char(' ')) << ']';
|
||||
return debug;
|
||||
}
|
||||
|
@ -60,8 +60,10 @@ public:
|
||||
enum QueryType {
|
||||
TcpSocket,
|
||||
UdpSocket,
|
||||
SctpSocket,
|
||||
TcpServer = 100,
|
||||
UrlRequest
|
||||
UrlRequest,
|
||||
SctpServer
|
||||
};
|
||||
|
||||
QNetworkProxyQuery();
|
||||
@ -141,7 +143,9 @@ public:
|
||||
ListeningCapability = 0x0002,
|
||||
UdpTunnelingCapability = 0x0004,
|
||||
CachingCapability = 0x0008,
|
||||
HostNameLookupCapability = 0x0010
|
||||
HostNameLookupCapability = 0x0010,
|
||||
SctpTunnelingCapability = 0x00020,
|
||||
SctpListeningCapability = 0x00040
|
||||
};
|
||||
Q_DECLARE_FLAGS(Capabilities, Capability)
|
||||
|
||||
|
@ -232,9 +232,15 @@ static QList<QNetworkProxy> filterProxyListByCapabilities(const QList<QNetworkPr
|
||||
case QNetworkProxyQuery::UdpSocket:
|
||||
requiredCaps = QNetworkProxy::UdpTunnelingCapability;
|
||||
break;
|
||||
case QNetworkProxyQuery::SctpSocket:
|
||||
requiredCaps = QNetworkProxy::SctpTunnelingCapability;
|
||||
break;
|
||||
case QNetworkProxyQuery::TcpServer:
|
||||
requiredCaps = QNetworkProxy::ListeningCapability;
|
||||
break;
|
||||
case QNetworkProxyQuery::SctpServer:
|
||||
requiredCaps = QNetworkProxy::SctpListeningCapability;
|
||||
break;
|
||||
default:
|
||||
return proxyList;
|
||||
break;
|
||||
@ -281,7 +287,9 @@ static QList<QNetworkProxy> parseServerList(const QNetworkProxyQuery &query, con
|
||||
QList<QNetworkProxy> result;
|
||||
QHash<QString, QNetworkProxy> taggedProxies;
|
||||
const QString requiredTag = query.protocolTag();
|
||||
bool checkTags = !requiredTag.isEmpty() && query.queryType() != QNetworkProxyQuery::TcpServer; //windows tags are only for clients
|
||||
// windows tags are only for clients
|
||||
bool checkTags = !requiredTag.isEmpty() && query.queryType() != QNetworkProxyQuery::TcpServer
|
||||
&& query.queryType() != QNetworkProxyQuery::SctpServer;
|
||||
for (const QString &entry : proxyList) {
|
||||
int server = 0;
|
||||
|
||||
|
@ -9,6 +9,7 @@ DEFINES += QT_NO_USING_NAMESPACE QT_NO_FOREACH
|
||||
#DEFINES += QABSTRACTSOCKET_DEBUG QNATIVESOCKETENGINE_DEBUG
|
||||
#DEFINES += QTCPSOCKETENGINE_DEBUG QTCPSOCKET_DEBUG QTCPSERVER_DEBUG QSSLSOCKET_DEBUG
|
||||
#DEFINES += QUDPSOCKET_DEBUG QUDPSERVER_DEBUG
|
||||
#DEFINES += QSCTPSOCKET_DEBUG QSCTPSERVER_DEBUG
|
||||
win32-msvc*|win32-icc:QMAKE_LFLAGS += /BASE:0x64000000
|
||||
|
||||
QMAKE_DOCS = $$PWD/doc/qtnetwork.qdocconf
|
||||
|
@ -267,7 +267,8 @@
|
||||
|
||||
\value TcpSocket TCP
|
||||
\value UdpSocket UDP
|
||||
\value UnknownSocketType Other than TCP and UDP
|
||||
\value SctpSocket SCTP
|
||||
\value UnknownSocketType Other than TCP, UDP and SCTP
|
||||
|
||||
\sa QAbstractSocket::socketType()
|
||||
*/
|
||||
@ -626,6 +627,7 @@ bool QAbstractSocketPrivate::initSocketLayer(QAbstractSocket::NetworkLayerProtoc
|
||||
QString typeStr;
|
||||
if (q->socketType() == QAbstractSocket::TcpSocket) typeStr = QLatin1String("TcpSocket");
|
||||
else if (q->socketType() == QAbstractSocket::UdpSocket) typeStr = QLatin1String("UdpSocket");
|
||||
else if (q->socketType() == QAbstractSocket::SctpSocket) typeStr = QLatin1String("SctpSocket");
|
||||
else typeStr = QLatin1String("UnknownSocketType");
|
||||
QString protocolStr;
|
||||
if (protocol == QAbstractSocket::IPv4Protocol) protocolStr = QLatin1String("IPv4Protocol");
|
||||
@ -670,6 +672,12 @@ bool QAbstractSocketPrivate::initSocketLayer(QAbstractSocket::NetworkLayerProtoc
|
||||
*/
|
||||
void QAbstractSocketPrivate::configureCreatedSocket()
|
||||
{
|
||||
#ifndef QT_NO_SCTP
|
||||
Q_Q(QAbstractSocket);
|
||||
// Set single stream mode for unbuffered SCTP socket
|
||||
if (socketEngine && q->socketType() == QAbstractSocket::SctpSocket)
|
||||
socketEngine->setOption(QAbstractSocketEngine::MaxStreamsSocketOption, 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*! \internal
|
||||
@ -771,7 +779,8 @@ void QAbstractSocketPrivate::canCloseNotification()
|
||||
|
||||
QMetaObject::invokeMethod(socketEngine, "closeNotification", Qt::QueuedConnection);
|
||||
}
|
||||
} else if (socketType == QAbstractSocket::TcpSocket && socketEngine) {
|
||||
} else if ((socketType == QAbstractSocket::TcpSocket ||
|
||||
socketType == QAbstractSocket::SctpSocket) && socketEngine) {
|
||||
emitReadyRead();
|
||||
}
|
||||
}
|
||||
@ -862,13 +871,9 @@ bool QAbstractSocketPrivate::writeToSocket()
|
||||
if (written > 0) {
|
||||
// Remove what we wrote so far.
|
||||
writeBuffer.free(written);
|
||||
// Don't emit bytesWritten() recursively.
|
||||
if (!emittedBytesWritten) {
|
||||
QScopedValueRollback<bool> r(emittedBytesWritten);
|
||||
emittedBytesWritten = true;
|
||||
emit q->bytesWritten(written);
|
||||
}
|
||||
emit q->channelBytesWritten(0, written);
|
||||
|
||||
// Emit notifications.
|
||||
emitBytesWritten(written);
|
||||
}
|
||||
|
||||
if (writeBuffer.isEmpty() && socketEngine && !socketEngine->bytesToWrite())
|
||||
@ -889,7 +894,7 @@ bool QAbstractSocketPrivate::flush()
|
||||
{
|
||||
bool dataWasWritten = false;
|
||||
|
||||
while (!writeBuffer.isEmpty() && writeToSocket())
|
||||
while (!allWriteBuffersEmpty() && writeToSocket())
|
||||
dataWasWritten = true;
|
||||
|
||||
return dataWasWritten;
|
||||
@ -912,6 +917,8 @@ void QAbstractSocketPrivate::resolveProxy(const QString &hostname, quint16 port)
|
||||
QNetworkProxyQuery query(hostname, port, QString(),
|
||||
socketType == QAbstractSocket::TcpSocket ?
|
||||
QNetworkProxyQuery::TcpSocket :
|
||||
socketType == QAbstractSocket::SctpSocket ?
|
||||
QNetworkProxyQuery::SctpSocket :
|
||||
QNetworkProxyQuery::UdpSocket);
|
||||
proxies = QNetworkProxyFactory::proxyForQuery(query);
|
||||
}
|
||||
@ -926,6 +933,10 @@ void QAbstractSocketPrivate::resolveProxy(const QString &hostname, quint16 port)
|
||||
(p.capabilities() & QNetworkProxy::TunnelingCapability) == 0)
|
||||
continue;
|
||||
|
||||
if (socketType == QAbstractSocket::SctpSocket &&
|
||||
(p.capabilities() & QNetworkProxy::SctpTunnelingCapability) == 0)
|
||||
continue;
|
||||
|
||||
proxyInUse = p;
|
||||
return;
|
||||
}
|
||||
@ -1280,16 +1291,34 @@ bool QAbstractSocketPrivate::readFromSocket()
|
||||
|
||||
Prevents from the recursive readyRead() emission.
|
||||
*/
|
||||
void QAbstractSocketPrivate::emitReadyRead()
|
||||
void QAbstractSocketPrivate::emitReadyRead(int channel)
|
||||
{
|
||||
Q_Q(QAbstractSocket);
|
||||
// Only emit readyRead() when not recursing.
|
||||
if (!emittedReadyRead) {
|
||||
if (!emittedReadyRead && channel == currentReadChannel) {
|
||||
QScopedValueRollback<bool> r(emittedReadyRead);
|
||||
emittedReadyRead = true;
|
||||
emit q->readyRead();
|
||||
}
|
||||
emit q->channelReadyRead(0);
|
||||
// channelReadyRead() can be emitted recursively - even for the same channel.
|
||||
emit q->channelReadyRead(channel);
|
||||
}
|
||||
|
||||
/*! \internal
|
||||
|
||||
Prevents from the recursive bytesWritten() emission.
|
||||
*/
|
||||
void QAbstractSocketPrivate::emitBytesWritten(qint64 bytes, int channel)
|
||||
{
|
||||
Q_Q(QAbstractSocket);
|
||||
// Only emit bytesWritten() when not recursing.
|
||||
if (!emittedBytesWritten && channel == currentWriteChannel) {
|
||||
QScopedValueRollback<bool> r(emittedBytesWritten);
|
||||
emittedBytesWritten = true;
|
||||
emit q->bytesWritten(bytes);
|
||||
}
|
||||
// channelBytesWritten() can be emitted recursively - even for the same channel.
|
||||
emit q->channelBytesWritten(channel, bytes);
|
||||
}
|
||||
|
||||
/*! \internal
|
||||
@ -1400,8 +1429,8 @@ QAbstractSocket::QAbstractSocket(SocketType socketType,
|
||||
Q_D(QAbstractSocket);
|
||||
#if defined(QABSTRACTSOCKET_DEBUG)
|
||||
qDebug("QAbstractSocket::QAbstractSocket(%sSocket, QAbstractSocketPrivate == %p, parent == %p)",
|
||||
socketType == TcpSocket ? "Tcp" : socketType == UdpSocket
|
||||
? "Udp" : "Unknown", &dd, parent);
|
||||
socketType == TcpSocket ? "Tcp" : socketType == UdpSocket ? "Udp"
|
||||
: socketType == SctpSocket ? "Sctp" : "Unknown", &dd, parent);
|
||||
#endif
|
||||
d->socketType = socketType;
|
||||
}
|
||||
@ -1665,9 +1694,9 @@ void QAbstractSocket::connectToHost(const QString &hostName, quint16 port,
|
||||
#endif
|
||||
|
||||
if (openMode & QIODevice::Unbuffered)
|
||||
d->isBuffered = false; // Unbuffered QTcpSocket
|
||||
d->isBuffered = false;
|
||||
else if (!d_func()->isBuffered)
|
||||
openMode |= QAbstractSocket::Unbuffered; // QUdpSocket
|
||||
openMode |= QAbstractSocket::Unbuffered;
|
||||
|
||||
QIODevice::open(openMode);
|
||||
d->readChannelCount = d->writeChannelCount = 0;
|
||||
@ -2503,10 +2532,8 @@ qint64 QAbstractSocket::writeData(const char *data, qint64 size)
|
||||
qt_prettyDebug(data, qMin((int)size, 32), size).data(),
|
||||
size, written);
|
||||
#endif
|
||||
if (written >= 0) {
|
||||
emit bytesWritten(written);
|
||||
emit channelBytesWritten(0, written);
|
||||
}
|
||||
if (written >= 0)
|
||||
d->emitBytesWritten(written);
|
||||
return written;
|
||||
}
|
||||
|
||||
@ -2714,14 +2741,14 @@ void QAbstractSocket::disconnectFromHost()
|
||||
}
|
||||
|
||||
// Wait for pending data to be written.
|
||||
if (d->socketEngine && d->socketEngine->isValid() && (d->writeBuffer.size() > 0
|
||||
if (d->socketEngine && d->socketEngine->isValid() && (!d->allWriteBuffersEmpty()
|
||||
|| d->socketEngine->bytesToWrite() > 0)) {
|
||||
// hack: when we are waiting for the socket engine to write bytes (only
|
||||
// possible when using Socks5 or HTTP socket engine), then close
|
||||
// anyway after 2 seconds. This is to prevent a timeout on Mac, where we
|
||||
// sometimes just did not get the write notifier from the underlying
|
||||
// CFSocket and no progress was made.
|
||||
if (d->writeBuffer.size() == 0 && d->socketEngine->bytesToWrite() > 0) {
|
||||
if (d->allWriteBuffersEmpty() && d->socketEngine->bytesToWrite() > 0) {
|
||||
if (!d->disconnectTimer) {
|
||||
d->disconnectTimer = new QTimer(this);
|
||||
connect(d->disconnectTimer, SIGNAL(timeout()), this,
|
||||
|
@ -64,6 +64,7 @@ public:
|
||||
enum SocketType {
|
||||
TcpSocket,
|
||||
UdpSocket,
|
||||
SctpSocket,
|
||||
UnknownSocketType = -1
|
||||
};
|
||||
Q_ENUM(SocketType)
|
||||
|
@ -86,7 +86,7 @@ public:
|
||||
|
||||
virtual bool bind(const QHostAddress &address, quint16 port, QAbstractSocket::BindMode mode);
|
||||
|
||||
bool canReadNotification();
|
||||
virtual bool canReadNotification();
|
||||
bool canWriteNotification();
|
||||
void canCloseNotification();
|
||||
|
||||
@ -136,8 +136,9 @@ public:
|
||||
void startConnectingByName(const QString &host);
|
||||
void fetchConnectionParameters();
|
||||
bool readFromSocket();
|
||||
bool writeToSocket();
|
||||
void emitReadyRead();
|
||||
virtual bool writeToSocket();
|
||||
void emitReadyRead(int channel = 0);
|
||||
void emitBytesWritten(qint64 bytes, int channel = 0);
|
||||
|
||||
void setError(QAbstractSocket::SocketError errorCode, const QString &errorString);
|
||||
void setErrorAndEmit(QAbstractSocket::SocketError errorCode, const QString &errorString);
|
||||
|
@ -104,7 +104,8 @@ public:
|
||||
MulticastLoopbackOption,
|
||||
TypeOfServiceOption,
|
||||
ReceivePacketInformation,
|
||||
ReceiveHopLimit
|
||||
ReceiveHopLimit,
|
||||
MaxStreamsSocketOption
|
||||
};
|
||||
|
||||
enum PacketHeaderOption {
|
||||
@ -112,6 +113,8 @@ public:
|
||||
WantDatagramSender = 0x01,
|
||||
WantDatagramDestination = 0x02,
|
||||
WantDatagramHopLimit = 0x04,
|
||||
WantStreamNumber = 0x08,
|
||||
WantEndOfRecord = 0x10,
|
||||
|
||||
WantAll = 0xff
|
||||
};
|
||||
@ -147,13 +150,13 @@ public:
|
||||
virtual bool setMulticastInterface(const QNetworkInterface &iface) = 0;
|
||||
#endif // QT_NO_NETWORKINTERFACE
|
||||
|
||||
virtual qint64 readDatagram(char *data, qint64 maxlen, QIpPacketHeader *header = 0,
|
||||
PacketHeaderOptions = WantNone) = 0;
|
||||
virtual qint64 writeDatagram(const char *data, qint64 len, const QIpPacketHeader &header) = 0;
|
||||
virtual bool hasPendingDatagrams() const = 0;
|
||||
virtual qint64 pendingDatagramSize() const = 0;
|
||||
#endif // QT_NO_UDPSOCKET
|
||||
|
||||
virtual qint64 readDatagram(char *data, qint64 maxlen, QIpPacketHeader *header = 0,
|
||||
PacketHeaderOptions = WantNone) = 0;
|
||||
virtual qint64 writeDatagram(const char *data, qint64 len, const QIpPacketHeader &header) = 0;
|
||||
virtual qint64 bytesToWrite() const = 0;
|
||||
|
||||
virtual int option(SocketOption option) const = 0;
|
||||
|
@ -289,6 +289,19 @@ bool QHttpSocketEngine::setMulticastInterface(const QNetworkInterface &)
|
||||
}
|
||||
#endif // QT_NO_NETWORKINTERFACE
|
||||
|
||||
bool QHttpSocketEngine::hasPendingDatagrams() const
|
||||
{
|
||||
qWarning("Operation is not supported");
|
||||
return false;
|
||||
}
|
||||
|
||||
qint64 QHttpSocketEngine::pendingDatagramSize() const
|
||||
{
|
||||
qWarning("Operation is not supported");
|
||||
return -1;
|
||||
}
|
||||
#endif // QT_NO_UDPSOCKET
|
||||
|
||||
qint64 QHttpSocketEngine::readDatagram(char *, qint64, QIpPacketHeader *, PacketHeaderOptions)
|
||||
{
|
||||
qWarning("Operation is not supported");
|
||||
@ -305,19 +318,6 @@ qint64 QHttpSocketEngine::writeDatagram(const char *, qint64, const QIpPacketHea
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool QHttpSocketEngine::hasPendingDatagrams() const
|
||||
{
|
||||
qWarning("Operation is not supported");
|
||||
return false;
|
||||
}
|
||||
|
||||
qint64 QHttpSocketEngine::pendingDatagramSize() const
|
||||
{
|
||||
qWarning("Operation is not supported");
|
||||
return -1;
|
||||
}
|
||||
#endif // QT_NO_UDPSOCKET
|
||||
|
||||
qint64 QHttpSocketEngine::bytesToWrite() const
|
||||
{
|
||||
Q_D(const QHttpSocketEngine);
|
||||
|
@ -112,13 +112,13 @@ public:
|
||||
bool setMulticastInterface(const QNetworkInterface &iface) Q_DECL_OVERRIDE;
|
||||
#endif // QT_NO_NETWORKINTERFACE
|
||||
|
||||
qint64 readDatagram(char *data, qint64 maxlen, QIpPacketHeader *,
|
||||
PacketHeaderOptions) Q_DECL_OVERRIDE;
|
||||
qint64 writeDatagram(const char *data, qint64 len, const QIpPacketHeader &) Q_DECL_OVERRIDE;
|
||||
bool hasPendingDatagrams() const Q_DECL_OVERRIDE;
|
||||
qint64 pendingDatagramSize() const Q_DECL_OVERRIDE;
|
||||
#endif // QT_NO_UDPSOCKET
|
||||
|
||||
qint64 readDatagram(char *data, qint64 maxlen, QIpPacketHeader *,
|
||||
PacketHeaderOptions) Q_DECL_OVERRIDE;
|
||||
qint64 writeDatagram(const char *data, qint64 len, const QIpPacketHeader &) Q_DECL_OVERRIDE;
|
||||
qint64 bytesToWrite() const Q_DECL_OVERRIDE;
|
||||
|
||||
int option(SocketOption option) const Q_DECL_OVERRIDE;
|
||||
|
@ -174,6 +174,12 @@ QT_BEGIN_NAMESPACE
|
||||
" socket other than "#type""); \
|
||||
return (returnValue); \
|
||||
} } while (0)
|
||||
#define Q_CHECK_TYPES(function, type1, type2, returnValue) do { \
|
||||
if (d->socketType != (type1) && d->socketType != (type2)) { \
|
||||
qWarning(#function" was called by a" \
|
||||
" socket other than "#type1" or "#type2); \
|
||||
return (returnValue); \
|
||||
} } while (0)
|
||||
#define Q_TR(a) QT_TRANSLATE_NOOP(QNativeSocketEngine, a)
|
||||
|
||||
/*! \internal
|
||||
@ -417,6 +423,7 @@ bool QNativeSocketEngine::initialize(QAbstractSocket::SocketType socketType, QAb
|
||||
QString typeStr = QLatin1String("UnknownSocketType");
|
||||
if (socketType == QAbstractSocket::TcpSocket) typeStr = QLatin1String("TcpSocket");
|
||||
else if (socketType == QAbstractSocket::UdpSocket) typeStr = QLatin1String("UdpSocket");
|
||||
else if (socketType == QAbstractSocket::SctpSocket) typeStr = QLatin1String("SctpSocket");
|
||||
QString protocolStr = QLatin1String("UnknownProtocol");
|
||||
if (protocol == QAbstractSocket::IPv4Protocol) protocolStr = QLatin1String("IPv4Protocol");
|
||||
else if (protocol == QAbstractSocket::IPv6Protocol) protocolStr = QLatin1String("IPv6Protocol");
|
||||
@ -659,7 +666,12 @@ bool QNativeSocketEngine::listen()
|
||||
Q_D(QNativeSocketEngine);
|
||||
Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::listen(), false);
|
||||
Q_CHECK_STATE(QNativeSocketEngine::listen(), QAbstractSocket::BoundState, false);
|
||||
#ifndef QT_NO_SCTP
|
||||
Q_CHECK_TYPES(QNativeSocketEngine::listen(), QAbstractSocket::TcpSocket,
|
||||
QAbstractSocket::SctpSocket, false);
|
||||
#else
|
||||
Q_CHECK_TYPE(QNativeSocketEngine::listen(), QAbstractSocket::TcpSocket, false);
|
||||
#endif
|
||||
|
||||
// We're using a backlog of 50. Most modern kernels support TCP
|
||||
// syncookies by default, and if they do, the backlog is ignored.
|
||||
@ -680,7 +692,12 @@ int QNativeSocketEngine::accept()
|
||||
Q_D(QNativeSocketEngine);
|
||||
Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::accept(), -1);
|
||||
Q_CHECK_STATE(QNativeSocketEngine::accept(), QAbstractSocket::ListeningState, -1);
|
||||
#ifndef QT_NO_SCTP
|
||||
Q_CHECK_TYPES(QNativeSocketEngine::accept(), QAbstractSocket::TcpSocket,
|
||||
QAbstractSocket::SctpSocket, -1);
|
||||
#else
|
||||
Q_CHECK_TYPE(QNativeSocketEngine::accept(), QAbstractSocket::TcpSocket, -1);
|
||||
#endif
|
||||
|
||||
return d->nativeAccept();
|
||||
}
|
||||
@ -793,6 +810,7 @@ qint64 QNativeSocketEngine::pendingDatagramSize() const
|
||||
|
||||
return d->nativePendingDatagramSize();
|
||||
}
|
||||
#endif // QT_NO_UDPSOCKET
|
||||
|
||||
/*!
|
||||
Reads up to \a maxSize bytes of a datagram from the socket,
|
||||
@ -800,9 +818,10 @@ qint64 QNativeSocketEngine::pendingDatagramSize() const
|
||||
address, port, and other IP header fields are stored in \a header
|
||||
according to the request in \a options.
|
||||
|
||||
To avoid unnecessarily loss of data, call pendingDatagramSize() to
|
||||
determine the size of the pending message before reading it. If \a
|
||||
maxSize is too small, the rest of the datagram will be lost.
|
||||
For UDP sockets, to avoid unnecessarily loss of data, call
|
||||
pendingDatagramSize() to determine the size of the pending message
|
||||
before reading it. If \a maxSize is too small, the rest of the
|
||||
datagram will be lost.
|
||||
|
||||
Returns -1 if an error occurred.
|
||||
|
||||
@ -813,13 +832,14 @@ qint64 QNativeSocketEngine::readDatagram(char *data, qint64 maxSize, QIpPacketHe
|
||||
{
|
||||
Q_D(QNativeSocketEngine);
|
||||
Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::readDatagram(), -1);
|
||||
Q_CHECK_TYPE(QNativeSocketEngine::readDatagram(), QAbstractSocket::UdpSocket, -1);
|
||||
Q_CHECK_STATES(QNativeSocketEngine::readDatagram(), QAbstractSocket::BoundState,
|
||||
QAbstractSocket::ConnectedState, -1);
|
||||
|
||||
return d->nativeReceiveDatagram(data, maxSize, header, options);
|
||||
}
|
||||
|
||||
/*!
|
||||
Writes a UDP datagram of size \a size bytes to the socket from
|
||||
Writes a datagram of size \a size bytes to the socket from
|
||||
\a data to the destination contained in \a header, and returns the
|
||||
number of bytes written, or -1 if an error occurred. If \a header
|
||||
contains other settings like hop limit or source address, this function
|
||||
@ -844,11 +864,11 @@ qint64 QNativeSocketEngine::writeDatagram(const char *data, qint64 size, const Q
|
||||
{
|
||||
Q_D(QNativeSocketEngine);
|
||||
Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::writeDatagram(), -1);
|
||||
Q_CHECK_TYPE(QNativeSocketEngine::writeDatagram(), QAbstractSocket::UdpSocket, -1);
|
||||
Q_CHECK_STATES(QNativeSocketEngine::writeDatagram(), QAbstractSocket::BoundState,
|
||||
QAbstractSocket::ConnectedState, -1);
|
||||
|
||||
return d->nativeSendDatagram(data, size, header);
|
||||
}
|
||||
#endif // QT_NO_UDPSOCKET
|
||||
|
||||
/*!
|
||||
Writes a block of \a size bytes from \a data to the socket.
|
||||
@ -881,7 +901,11 @@ qint64 QNativeSocketEngine::read(char *data, qint64 maxSize)
|
||||
qint64 readBytes = d->nativeRead(data, maxSize);
|
||||
|
||||
// Handle remote close
|
||||
if (readBytes == 0 && d->socketType == QAbstractSocket::TcpSocket) {
|
||||
if (readBytes == 0 && (d->socketType == QAbstractSocket::TcpSocket
|
||||
#ifndef QT_NO_SCTP
|
||||
|| d->socketType == QAbstractSocket::SctpSocket
|
||||
#endif
|
||||
)) {
|
||||
d->setError(QAbstractSocket::RemoteHostClosedError,
|
||||
QNativeSocketEnginePrivate::RemoteHostClosedErrorString);
|
||||
close();
|
||||
|
@ -157,13 +157,13 @@ public:
|
||||
bool setMulticastInterface(const QNetworkInterface &iface) Q_DECL_OVERRIDE;
|
||||
#endif
|
||||
|
||||
qint64 readDatagram(char *data, qint64 maxlen, QIpPacketHeader * = 0,
|
||||
PacketHeaderOptions = WantNone) Q_DECL_OVERRIDE;
|
||||
qint64 writeDatagram(const char *data, qint64 len, const QIpPacketHeader &) Q_DECL_OVERRIDE;
|
||||
bool hasPendingDatagrams() const Q_DECL_OVERRIDE;
|
||||
qint64 pendingDatagramSize() const Q_DECL_OVERRIDE;
|
||||
#endif // QT_NO_UDPSOCKET
|
||||
|
||||
qint64 readDatagram(char *data, qint64 maxlen, QIpPacketHeader * = 0,
|
||||
PacketHeaderOptions = WantNone) Q_DECL_OVERRIDE;
|
||||
qint64 writeDatagram(const char *data, qint64 len, const QIpPacketHeader &) Q_DECL_OVERRIDE;
|
||||
qint64 bytesToWrite() const Q_DECL_OVERRIDE;
|
||||
|
||||
qint64 receiveBufferSize() const;
|
||||
|
@ -68,6 +68,11 @@
|
||||
#endif
|
||||
|
||||
#include <netinet/tcp.h>
|
||||
#ifndef QT_NO_SCTP
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/sctp.h>
|
||||
#endif
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
@ -142,6 +147,7 @@ static void convertToLevelAndOption(QNativeSocketEngine::SocketOption opt,
|
||||
switch (opt) {
|
||||
case QNativeSocketEngine::NonBlockingSocketOption: // fcntl, not setsockopt
|
||||
case QNativeSocketEngine::BindExclusively: // not handled on Unix
|
||||
case QNativeSocketEngine::MaxStreamsSocketOption:
|
||||
Q_UNREACHABLE();
|
||||
|
||||
case QNativeSocketEngine::BroadcastSocketOption:
|
||||
@ -229,13 +235,28 @@ static void convertToLevelAndOption(QNativeSocketEngine::SocketOption opt,
|
||||
bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType socketType,
|
||||
QAbstractSocket::NetworkLayerProtocol &socketProtocol)
|
||||
{
|
||||
int protocol = (socketProtocol == QAbstractSocket::IPv6Protocol || socketProtocol == QAbstractSocket::AnyIPProtocol) ? AF_INET6 : AF_INET;
|
||||
#ifndef QT_NO_SCTP
|
||||
int protocol = (socketType == QAbstractSocket::SctpSocket) ? IPPROTO_SCTP : 0;
|
||||
#else
|
||||
if (socketType == QAbstractSocket::SctpSocket) {
|
||||
setError(QAbstractSocket::UnsupportedSocketOperationError,
|
||||
ProtocolUnsupportedErrorString);
|
||||
#if defined (QNATIVESOCKETENGINE_DEBUG)
|
||||
qDebug("QNativeSocketEnginePrivate::createNewSocket(%d, %d): unsupported protocol",
|
||||
socketType, socketProtocol);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
int protocol = 0;
|
||||
#endif // QT_NO_SCTP
|
||||
int domain = (socketProtocol == QAbstractSocket::IPv6Protocol
|
||||
|| socketProtocol == QAbstractSocket::AnyIPProtocol) ? AF_INET6 : AF_INET;
|
||||
int type = (socketType == QAbstractSocket::UdpSocket) ? SOCK_DGRAM : SOCK_STREAM;
|
||||
|
||||
int socket = qt_safe_socket(protocol, type, 0, O_NONBLOCK);
|
||||
int socket = qt_safe_socket(domain, type, protocol, O_NONBLOCK);
|
||||
if (socket < 0 && socketProtocol == QAbstractSocket::AnyIPProtocol && errno == EAFNOSUPPORT) {
|
||||
protocol = AF_INET;
|
||||
socket = qt_safe_socket(protocol, type, 0, O_NONBLOCK);
|
||||
domain = AF_INET;
|
||||
socket = qt_safe_socket(domain, type, protocol, O_NONBLOCK);
|
||||
socketProtocol = QAbstractSocket::IPv4Protocol;
|
||||
}
|
||||
|
||||
@ -291,10 +312,26 @@ int QNativeSocketEnginePrivate::option(QNativeSocketEngine::SocketOption opt) co
|
||||
if (!q->isValid())
|
||||
return -1;
|
||||
|
||||
// handle non-getsockopt cases first
|
||||
if (opt == QNativeSocketEngine::BindExclusively || opt == QNativeSocketEngine::NonBlockingSocketOption
|
||||
|| opt == QNativeSocketEngine::BroadcastSocketOption)
|
||||
// handle non-getsockopt and specific cases first
|
||||
switch (opt) {
|
||||
case QNativeSocketEngine::BindExclusively:
|
||||
case QNativeSocketEngine::NonBlockingSocketOption:
|
||||
case QNativeSocketEngine::BroadcastSocketOption:
|
||||
return true;
|
||||
case QNativeSocketEngine::MaxStreamsSocketOption: {
|
||||
#ifndef QT_NO_SCTP
|
||||
sctp_initmsg sctpInitMsg;
|
||||
QT_SOCKOPTLEN_T sctpInitMsgSize = sizeof(sctpInitMsg);
|
||||
if (::getsockopt(socketDescriptor, SOL_SCTP, SCTP_INITMSG, &sctpInitMsg,
|
||||
&sctpInitMsgSize) == 0)
|
||||
return int(qMin(sctpInitMsg.sinit_num_ostreams, sctpInitMsg.sinit_max_instreams));
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
int n, level;
|
||||
int v = -1;
|
||||
@ -317,7 +354,7 @@ bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt
|
||||
if (!q->isValid())
|
||||
return false;
|
||||
|
||||
// handle non-setsockopt cases first
|
||||
// handle non-setsockopt and specific cases first
|
||||
switch (opt) {
|
||||
case QNativeSocketEngine::NonBlockingSocketOption: {
|
||||
// Make the socket nonblocking.
|
||||
@ -351,6 +388,20 @@ bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt
|
||||
case QNativeSocketEngine::BindExclusively:
|
||||
return true;
|
||||
|
||||
case QNativeSocketEngine::MaxStreamsSocketOption: {
|
||||
#ifndef QT_NO_SCTP
|
||||
sctp_initmsg sctpInitMsg;
|
||||
QT_SOCKOPTLEN_T sctpInitMsgSize = sizeof(sctpInitMsg);
|
||||
if (::getsockopt(socketDescriptor, SOL_SCTP, SCTP_INITMSG, &sctpInitMsg,
|
||||
&sctpInitMsgSize) == 0) {
|
||||
sctpInitMsg.sinit_num_ostreams = sctpInitMsg.sinit_max_instreams = uint16_t(v);
|
||||
return ::setsockopt(socketDescriptor, SOL_SCTP, SCTP_INITMSG, &sctpInitMsg,
|
||||
sctpInitMsgSize) == 0;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -829,6 +880,9 @@ qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxS
|
||||
quintptr cbuf[(CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(sizeof(int))
|
||||
#if !defined(IP_PKTINFO) && defined(IP_RECVIF) && defined(Q_OS_BSD4)
|
||||
+ CMSG_SPACE(sizeof(sockaddr_dl))
|
||||
#endif
|
||||
#ifndef QT_NO_SCTP
|
||||
+ CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))
|
||||
#endif
|
||||
+ sizeof(quintptr) - 1) / sizeof(quintptr)];
|
||||
|
||||
@ -848,7 +902,8 @@ qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxS
|
||||
msg.msg_name = &aa;
|
||||
msg.msg_namelen = sizeof(aa);
|
||||
}
|
||||
if (options & (QAbstractSocketEngine::WantDatagramHopLimit | QAbstractSocketEngine::WantDatagramDestination)) {
|
||||
if (options & (QAbstractSocketEngine::WantDatagramHopLimit | QAbstractSocketEngine::WantDatagramDestination
|
||||
| QAbstractSocketEngine::WantStreamNumber)) {
|
||||
msg.msg_control = cbuf;
|
||||
msg.msg_controllen = sizeof(cbuf);
|
||||
}
|
||||
@ -859,13 +914,27 @@ qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxS
|
||||
} while (recvResult == -1 && errno == EINTR);
|
||||
|
||||
if (recvResult == -1) {
|
||||
setError(QAbstractSocket::NetworkError, ReceiveDatagramErrorString);
|
||||
switch (errno) {
|
||||
#if EWOULDBLOCK-0 && EWOULDBLOCK != EAGAIN
|
||||
case EWOULDBLOCK:
|
||||
#endif
|
||||
case EAGAIN:
|
||||
// No datagram was available for reading
|
||||
recvResult = -2;
|
||||
break;
|
||||
case ECONNREFUSED:
|
||||
setError(QAbstractSocket::ConnectionRefusedError, ConnectionRefusedErrorString);
|
||||
break;
|
||||
default:
|
||||
setError(QAbstractSocket::NetworkError, ReceiveDatagramErrorString);
|
||||
}
|
||||
if (header)
|
||||
header->clear();
|
||||
} else if (options != QAbstractSocketEngine::WantNone) {
|
||||
Q_ASSERT(header);
|
||||
qt_socket_getPortAndAddress(&aa, &header->senderPort, &header->senderAddress);
|
||||
header->destinationPort = localPort;
|
||||
header->endOfRecord = (msg.msg_flags & MSG_EOR) != 0;
|
||||
|
||||
// parse the ancillary data
|
||||
struct cmsghdr *cmsgptr;
|
||||
@ -912,6 +981,15 @@ qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxS
|
||||
|| (cmsgptr->cmsg_level == IPPROTO_IP && cmsgptr->cmsg_type == IP_TTL))) {
|
||||
header->hopLimit = *reinterpret_cast<int *>(CMSG_DATA(cmsgptr));
|
||||
}
|
||||
|
||||
#ifndef QT_NO_SCTP
|
||||
if (cmsgptr->cmsg_level == IPPROTO_SCTP && cmsgptr->cmsg_type == SCTP_SNDRCV
|
||||
&& cmsgptr->cmsg_len >= CMSG_LEN(sizeof(sctp_sndrcvinfo))) {
|
||||
sctp_sndrcvinfo *rcvInfo = reinterpret_cast<sctp_sndrcvinfo *>(CMSG_DATA(cmsgptr));
|
||||
|
||||
header->streamNumber = int(rcvInfo->sinfo_stream);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@ -924,13 +1002,17 @@ qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxS
|
||||
? header->senderPort : 0, (qint64) recvResult);
|
||||
#endif
|
||||
|
||||
return qint64(maxSize ? recvResult : recvResult == -1 ? -1 : 0);
|
||||
return qint64((maxSize || recvResult < 0) ? recvResult : Q_INT64_C(0));
|
||||
}
|
||||
|
||||
qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 len, const QIpPacketHeader &header)
|
||||
{
|
||||
// we use quintptr to force the alignment
|
||||
quintptr cbuf[(CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(sizeof(int)) + sizeof(quintptr) - 1) / sizeof(quintptr)];
|
||||
quintptr cbuf[(CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(sizeof(int))
|
||||
#ifndef QT_NO_SCTP
|
||||
+ CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))
|
||||
#endif
|
||||
+ sizeof(quintptr) - 1) / sizeof(quintptr)];
|
||||
|
||||
struct cmsghdr *cmsgptr = reinterpret_cast<struct cmsghdr *>(cbuf);
|
||||
struct msghdr msg;
|
||||
@ -943,10 +1025,13 @@ qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 l
|
||||
vec.iov_len = len;
|
||||
msg.msg_iov = &vec;
|
||||
msg.msg_iovlen = 1;
|
||||
msg.msg_name = &aa.a;
|
||||
msg.msg_control = &cbuf;
|
||||
|
||||
setPortAndAddress(header.destinationPort, header.destinationAddress, &aa, &msg.msg_namelen);
|
||||
if (header.destinationPort != 0) {
|
||||
msg.msg_name = &aa.a;
|
||||
setPortAndAddress(header.destinationPort, header.destinationAddress,
|
||||
&aa, &msg.msg_namelen);
|
||||
}
|
||||
|
||||
if (msg.msg_namelen == sizeof(aa.a6)) {
|
||||
if (header.hopLimit != -1) {
|
||||
@ -1001,15 +1086,37 @@ qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 l
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef QT_NO_SCTP
|
||||
if (header.streamNumber != -1) {
|
||||
struct sctp_sndrcvinfo *data = reinterpret_cast<sctp_sndrcvinfo *>(CMSG_DATA(cmsgptr));
|
||||
memset(data, 0, sizeof(*data));
|
||||
msg.msg_controllen += CMSG_SPACE(sizeof(sctp_sndrcvinfo));
|
||||
cmsgptr->cmsg_len = CMSG_LEN(sizeof(sctp_sndrcvinfo));
|
||||
cmsgptr->cmsg_level = IPPROTO_SCTP;
|
||||
cmsgptr->cmsg_type = SCTP_SNDRCV;
|
||||
data->sinfo_stream = uint16_t(header.streamNumber);
|
||||
cmsgptr = reinterpret_cast<cmsghdr *>(reinterpret_cast<char *>(cmsgptr) + CMSG_SPACE(sizeof(*data)));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (msg.msg_controllen == 0)
|
||||
msg.msg_control = 0;
|
||||
ssize_t sentBytes = qt_safe_sendmsg(socketDescriptor, &msg, 0);
|
||||
|
||||
if (sentBytes < 0) {
|
||||
switch (errno) {
|
||||
#if EWOULDBLOCK-0 && EWOULDBLOCK != EAGAIN
|
||||
case EWOULDBLOCK:
|
||||
#endif
|
||||
case EAGAIN:
|
||||
sentBytes = -2;
|
||||
break;
|
||||
case EMSGSIZE:
|
||||
setError(QAbstractSocket::DatagramTooLargeError, DatagramTooLargeErrorString);
|
||||
break;
|
||||
case ECONNRESET:
|
||||
setError(QAbstractSocket::RemoteHostClosedError, RemoteHostClosedErrorString);
|
||||
break;
|
||||
default:
|
||||
setError(QAbstractSocket::NetworkError, SendDatagramErrorString);
|
||||
}
|
||||
@ -1082,21 +1189,51 @@ bool QNativeSocketEnginePrivate::fetchConnectionParameters()
|
||||
#endif
|
||||
|
||||
// Determine the remote address
|
||||
if (!::getpeername(socketDescriptor, &sa.a, &sockAddrSize)) {
|
||||
bool connected = ::getpeername(socketDescriptor, &sa.a, &sockAddrSize) == 0;
|
||||
if (connected) {
|
||||
qt_socket_getPortAndAddress(&sa, &peerPort, &peerAddress);
|
||||
inboundStreamCount = outboundStreamCount = 1;
|
||||
}
|
||||
|
||||
// Determine the socket type (UDP/TCP)
|
||||
// Determine the socket type (UDP/TCP/SCTP)
|
||||
int value = 0;
|
||||
QT_SOCKOPTLEN_T valueSize = sizeof(int);
|
||||
if (::getsockopt(socketDescriptor, SOL_SOCKET, SO_TYPE, &value, &valueSize) == 0) {
|
||||
if (value == SOCK_STREAM)
|
||||
socketType = QAbstractSocket::TcpSocket;
|
||||
else if (value == SOCK_DGRAM)
|
||||
socketType = QAbstractSocket::UdpSocket;
|
||||
else
|
||||
socketType = QAbstractSocket::UnknownSocketType;
|
||||
if (value == SOCK_STREAM) {
|
||||
#ifndef QT_NO_SCTP
|
||||
if (option(QNativeSocketEngine::MaxStreamsSocketOption) != -1) {
|
||||
socketType = QAbstractSocket::SctpSocket;
|
||||
if (connected) {
|
||||
sctp_status sctpStatus;
|
||||
QT_SOCKOPTLEN_T sctpStatusSize = sizeof(sctpStatus);
|
||||
sctp_event_subscribe sctpEvents;
|
||||
|
||||
memset(&sctpEvents, 0, sizeof(sctpEvents));
|
||||
sctpEvents.sctp_data_io_event = 1;
|
||||
if (::getsockopt(socketDescriptor, SOL_SCTP, SCTP_STATUS, &sctpStatus,
|
||||
&sctpStatusSize) == 0 &&
|
||||
::setsockopt(socketDescriptor, SOL_SCTP, SCTP_EVENTS, &sctpEvents,
|
||||
sizeof(sctpEvents)) == 0) {
|
||||
inboundStreamCount = int(sctpStatus.sstat_instrms);
|
||||
outboundStreamCount = int(sctpStatus.sstat_outstrms);
|
||||
} else {
|
||||
setError(QAbstractSocket::UnsupportedSocketOperationError,
|
||||
InvalidSocketErrorString);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
socketType = QAbstractSocket::TcpSocket;
|
||||
}
|
||||
#else
|
||||
socketType = QAbstractSocket::TcpSocket;
|
||||
#endif
|
||||
} else {
|
||||
if (value == SOCK_DGRAM)
|
||||
socketType = QAbstractSocket::UdpSocket;
|
||||
else
|
||||
socketType = QAbstractSocket::UnknownSocketType;
|
||||
}
|
||||
}
|
||||
#if defined (QNATIVESOCKETENGINE_DEBUG)
|
||||
QString socketProtocolStr = QStringLiteral("UnknownProtocol");
|
||||
@ -1106,6 +1243,7 @@ bool QNativeSocketEnginePrivate::fetchConnectionParameters()
|
||||
QString socketTypeStr = QStringLiteral("UnknownSocketType");
|
||||
if (socketType == QAbstractSocket::TcpSocket) socketTypeStr = QStringLiteral("TcpSocket");
|
||||
else if (socketType == QAbstractSocket::UdpSocket) socketTypeStr = QStringLiteral("UdpSocket");
|
||||
else if (socketType == QAbstractSocket::SctpSocket) socketTypeStr = QStringLiteral("SctpSocket");
|
||||
|
||||
qDebug("QNativeSocketEnginePrivate::fetchConnectionParameters() local == %s:%i,"
|
||||
" peer == %s:%i, socket == %s - %s, inboundStreamCount == %i, outboundStreamCount == %i",
|
||||
|
@ -214,6 +214,7 @@ static void convertToLevelAndOption(QNativeSocketEngine::SocketOption opt,
|
||||
switch (opt) {
|
||||
case QNativeSocketEngine::NonBlockingSocketOption: // WSAIoctl
|
||||
case QNativeSocketEngine::TypeOfServiceOption: // not supported
|
||||
case QNativeSocketEngine::MaxStreamsSocketOption:
|
||||
Q_UNREACHABLE();
|
||||
|
||||
case QNativeSocketEngine::ReceiveBufferSocketOption:
|
||||
@ -325,6 +326,14 @@ bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType soc
|
||||
return -1;
|
||||
}
|
||||
*/
|
||||
|
||||
//### SCTP not implemented
|
||||
if (socketType == QAbstractSocket::SctpSocket) {
|
||||
setError(QAbstractSocket::UnsupportedSocketOperationError,
|
||||
ProtocolUnsupportedErrorString);
|
||||
return false;
|
||||
}
|
||||
|
||||
QSysInfo::WinVersion osver = QSysInfo::windowsVersion();
|
||||
|
||||
//Windows XP and 2003 support IPv6 but not dual stack sockets
|
||||
@ -451,6 +460,7 @@ int QNativeSocketEnginePrivate::option(QNativeSocketEngine::SocketOption opt) co
|
||||
break;
|
||||
}
|
||||
case QNativeSocketEngine::TypeOfServiceOption:
|
||||
case QNativeSocketEngine::MaxStreamsSocketOption:
|
||||
return -1;
|
||||
|
||||
default:
|
||||
@ -501,6 +511,7 @@ bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt
|
||||
break;
|
||||
}
|
||||
case QNativeSocketEngine::TypeOfServiceOption:
|
||||
case QNativeSocketEngine::MaxStreamsSocketOption:
|
||||
return false;
|
||||
|
||||
default:
|
||||
|
@ -632,6 +632,7 @@ qint64 QNativeSocketEngine::write(const char *data, qint64 len)
|
||||
qint64 QNativeSocketEngine::readDatagram(char *data, qint64 maxlen, QIpPacketHeader *header,
|
||||
PacketHeaderOptions)
|
||||
{
|
||||
#ifndef QT_NO_UDPSOCKET
|
||||
Q_D(QNativeSocketEngine);
|
||||
if (d->socketType != QAbstractSocket::UdpSocket || d->pendingDatagrams.isEmpty()) {
|
||||
if (header)
|
||||
@ -654,10 +655,17 @@ qint64 QNativeSocketEngine::readDatagram(char *data, qint64 maxlen, QIpPacketHea
|
||||
}
|
||||
memcpy(data, readOrigin, qMin(maxlen, qint64(datagram.data.length())));
|
||||
return readOrigin.length();
|
||||
#else
|
||||
Q_UNUSED(data)
|
||||
Q_UNUSED(maxlen)
|
||||
Q_UNUSED(header)
|
||||
return -1;
|
||||
#endif // QT_NO_UDPSOCKET
|
||||
}
|
||||
|
||||
qint64 QNativeSocketEngine::writeDatagram(const char *data, qint64 len, const QIpPacketHeader &header)
|
||||
{
|
||||
#ifndef QT_NO_UDPSOCKET
|
||||
Q_D(QNativeSocketEngine);
|
||||
if (d->socketType != QAbstractSocket::UdpSocket)
|
||||
return -1;
|
||||
@ -684,6 +692,12 @@ qint64 QNativeSocketEngine::writeDatagram(const char *data, qint64 len, const QI
|
||||
Q_ASSERT_SUCCEEDED(hr);
|
||||
|
||||
return writeIOStream(stream, data, len);
|
||||
#else
|
||||
Q_UNUSED(data)
|
||||
Q_UNUSED(len)
|
||||
Q_UNUSED(header)
|
||||
return -1;
|
||||
#endif // QT_NO_UDPSOCKET
|
||||
}
|
||||
|
||||
bool QNativeSocketEngine::hasPendingDatagrams() const
|
||||
@ -1088,6 +1102,7 @@ int QNativeSocketEnginePrivate::option(QAbstractSocketEngine::SocketOption opt)
|
||||
case QAbstractSocketEngine::MulticastTtlOption:
|
||||
case QAbstractSocketEngine::MulticastLoopbackOption:
|
||||
case QAbstractSocketEngine::TypeOfServiceOption:
|
||||
case QAbstractSocketEngine::MaxStreamsSocketOption:
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
@ -1146,6 +1161,7 @@ bool QNativeSocketEnginePrivate::setOption(QAbstractSocketEngine::SocketOption o
|
||||
case QAbstractSocketEngine::MulticastTtlOption:
|
||||
case QAbstractSocketEngine::MulticastLoopbackOption:
|
||||
case QAbstractSocketEngine::TypeOfServiceOption:
|
||||
case QAbstractSocketEngine::MaxStreamsSocketOption:
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
250
src/network/socket/qsctpserver.cpp
Normal file
250
src/network/socket/qsctpserver.cpp
Normal file
@ -0,0 +1,250 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 Alex Trotsenko <alex1973tr@gmail.com>
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the QtNetwork module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or any later version approved by the KDE Free
|
||||
** Qt Foundation. The licenses are as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
//#define QSCTPSERVER_DEBUG
|
||||
|
||||
/*!
|
||||
\class QSctpServer
|
||||
\since 5.8
|
||||
|
||||
\brief The QSctpServer class provides an SCTP-based server.
|
||||
|
||||
\ingroup network
|
||||
\inmodule QtNetwork
|
||||
|
||||
SCTP (Stream Control Transmission Protocol) is a transport layer
|
||||
protocol serving in a similar role as the popular protocols TCP
|
||||
and UDP. Like UDP, SCTP is message-oriented, but it ensures reliable,
|
||||
in-sequence transport of messages with congestion control like
|
||||
TCP. See the QSctpSocket documentation for more protocol details.
|
||||
|
||||
QSctpServer is a convenience subclass of QTcpServer that allows
|
||||
you to accept incoming STCP socket connections either in TCP
|
||||
emulation or in datagram mode.
|
||||
|
||||
The most common way to use QSctpServer is to construct an object
|
||||
and set the maximum number of channels that the server is
|
||||
prepared to support, by calling setMaxChannelCount(). You can set
|
||||
the TCP emulation mode by passing a negative argument in this
|
||||
call. Also, a special value of 0 (the default) indicates to use
|
||||
the peer's value as the actual number of channels. The new incoming
|
||||
connection inherits this number from the server socket descriptor
|
||||
and adjusts it according to the remote endpoint settings.
|
||||
|
||||
In TCP emulation mode, accepted clients use a single continuous
|
||||
byte stream for data transmission, and QSctpServer acts like a
|
||||
plain QTcpServer. Call nextPendingConnection() to accept the
|
||||
pending connection as a connected QTcpSocket. The function returns
|
||||
a pointer to a QTcpSocket in QAbstractSocket::ConnectedState that
|
||||
you can use for communicating with the client. This mode gives
|
||||
access only to basic SCTP protocol features. The socket transmits SCTP
|
||||
packets over IP at system level and interacts through the
|
||||
QTcpSocket interface with the application.
|
||||
|
||||
In contrast, datagram mode is message-oriented and provides a
|
||||
complete simultaneous transmission of multiple data streams
|
||||
between endpoints. Call nextPendingDatagramConnection() to accept
|
||||
the pending datagram-mode connection as a connected QSctpSocket.
|
||||
|
||||
\note This feature is not supported on the Windows platform.
|
||||
|
||||
\sa QTcpServer, QSctpSocket, QAbstractSocket
|
||||
*/
|
||||
|
||||
#include "qsctpserver.h"
|
||||
#include "qsctpserver_p.h"
|
||||
|
||||
#include "qsctpsocket.h"
|
||||
#include "qabstractsocketengine_p.h"
|
||||
|
||||
#ifdef QSCTPSERVER_DEBUG
|
||||
#include <qdebug.h>
|
||||
#endif
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
/*! \internal
|
||||
*/
|
||||
QSctpServerPrivate::QSctpServerPrivate()
|
||||
: maxChannelCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
/*! \internal
|
||||
*/
|
||||
QSctpServerPrivate::~QSctpServerPrivate()
|
||||
{
|
||||
}
|
||||
|
||||
/*! \internal
|
||||
*/
|
||||
void QSctpServerPrivate::configureCreatedSocket()
|
||||
{
|
||||
QTcpServerPrivate::configureCreatedSocket();
|
||||
if (socketEngine)
|
||||
socketEngine->setOption(QAbstractSocketEngine::MaxStreamsSocketOption,
|
||||
maxChannelCount == -1 ? 1 : maxChannelCount);
|
||||
}
|
||||
|
||||
/*!
|
||||
Constructs a QSctpServer object.
|
||||
|
||||
Sets the datagram operation mode. The \a parent argument is passed
|
||||
to QObject's constructor.
|
||||
|
||||
\sa setMaxChannelCount(), listen(), setSocketDescriptor()
|
||||
*/
|
||||
QSctpServer::QSctpServer(QObject *parent)
|
||||
: QTcpServer(QAbstractSocket::SctpSocket, *new QSctpServerPrivate, parent)
|
||||
{
|
||||
#if defined(QSCTPSERVER_DEBUG)
|
||||
qDebug("QSctpServer::QSctpServer()");
|
||||
#endif
|
||||
}
|
||||
|
||||
/*!
|
||||
Destroys the QSctpServer object. If the server is listening for
|
||||
connections, the socket is automatically closed.
|
||||
|
||||
\sa close()
|
||||
*/
|
||||
QSctpServer::~QSctpServer()
|
||||
{
|
||||
#if defined(QSCTPSERVER_DEBUG)
|
||||
qDebug("QSctpServer::~QSctpServer()");
|
||||
#endif
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the maximum number of channels that the server is prepared to
|
||||
support in datagram mode, to \a count. If \a count is 0, endpoint
|
||||
maximum number of channels value would be used. Negative \a count
|
||||
sets a TCP emulation mode.
|
||||
|
||||
Call this member only when QSctpServer is in UnconnectedState.
|
||||
|
||||
\sa maxChannelCount(), QSctpSocket
|
||||
*/
|
||||
void QSctpServer::setMaxChannelCount(int count)
|
||||
{
|
||||
Q_D(QSctpServer);
|
||||
if (d->state != QAbstractSocket::UnconnectedState) {
|
||||
qWarning("QSctpServer::setMaxChannelCount() is only allowed in UnconnectedState");
|
||||
return;
|
||||
}
|
||||
#if defined(QSCTPSERVER_DEBUG)
|
||||
qDebug("QSctpServer::setMaxChannelCount(%i)", count);
|
||||
#endif
|
||||
d->maxChannelCount = count;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the maximum number of channels that the accepted sockets are
|
||||
able to support.
|
||||
|
||||
A value of 0 (the default) means that the number of connection
|
||||
channels would be set by the remote endpoint.
|
||||
|
||||
Returns -1, if QSctpServer running in TCP emulation mode.
|
||||
|
||||
\sa setMaxChannelCount()
|
||||
*/
|
||||
int QSctpServer::maxChannelCount() const
|
||||
{
|
||||
return d_func()->maxChannelCount;
|
||||
}
|
||||
|
||||
/*! \reimp
|
||||
*/
|
||||
void QSctpServer::incomingConnection(qintptr socketDescriptor)
|
||||
{
|
||||
#if defined (QSCTPSERVER_DEBUG)
|
||||
qDebug("QSctpServer::incomingConnection(%i)", socketDescriptor);
|
||||
#endif
|
||||
|
||||
QSctpSocket *socket = new QSctpSocket(this);
|
||||
socket->setMaxChannelCount(d_func()->maxChannelCount);
|
||||
socket->setSocketDescriptor(socketDescriptor);
|
||||
addPendingConnection(socket);
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the next pending datagram-mode connection as a connected
|
||||
QSctpSocket object.
|
||||
|
||||
Datagram-mode connection provides a message-oriented, multi-stream
|
||||
communication.
|
||||
|
||||
The socket is created as a child of the server, which means that
|
||||
it is automatically deleted when the QSctpServer object is
|
||||
destroyed. It is still a good idea to delete the object
|
||||
explicitly when you are done with it, to avoid wasting memory.
|
||||
|
||||
This function returns null if there are no pending datagram-mode
|
||||
connections.
|
||||
|
||||
\note The returned QSctpSocket object cannot be used from another
|
||||
thread. If you want to use an incoming connection from another
|
||||
thread, you need to override incomingConnection().
|
||||
|
||||
\sa hasPendingConnections(), nextPendingConnection(), QSctpSocket
|
||||
*/
|
||||
QSctpSocket *QSctpServer::nextPendingDatagramConnection()
|
||||
{
|
||||
Q_D(QSctpServer);
|
||||
|
||||
QMutableListIterator<QTcpSocket *> i(d->pendingConnections);
|
||||
while (i.hasNext()) {
|
||||
QSctpSocket *socket = qobject_cast<QSctpSocket *>(i.next());
|
||||
Q_ASSERT(socket);
|
||||
|
||||
if (socket->inDatagramMode()) {
|
||||
i.remove();
|
||||
Q_ASSERT(d->socketEngine);
|
||||
d->socketEngine->setReadNotificationEnabled(true);
|
||||
return socket;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#include "moc_qsctpserver.cpp"
|
77
src/network/socket/qsctpserver.h
Normal file
77
src/network/socket/qsctpserver.h
Normal file
@ -0,0 +1,77 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 Alex Trotsenko <alex1973tr@gmail.com>
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the QtNetwork module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or any later version approved by the KDE Free
|
||||
** Qt Foundation. The licenses are as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QSCTPSERVER_H
|
||||
#define QSCTPSERVER_H
|
||||
|
||||
#include <QtNetwork/qtcpserver.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
|
||||
#ifndef QT_NO_SCTP
|
||||
|
||||
class QSctpServerPrivate;
|
||||
class QSctpSocket;
|
||||
|
||||
class Q_NETWORK_EXPORT QSctpServer : public QTcpServer
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit QSctpServer(QObject *parent = nullptr);
|
||||
virtual ~QSctpServer();
|
||||
|
||||
void setMaxChannelCount(int count);
|
||||
int maxChannelCount() const;
|
||||
|
||||
QSctpSocket *nextPendingDatagramConnection();
|
||||
|
||||
protected:
|
||||
void incomingConnection(qintptr handle) Q_DECL_OVERRIDE;
|
||||
|
||||
private:
|
||||
Q_DISABLE_COPY(QSctpServer)
|
||||
Q_DECLARE_PRIVATE(QSctpServer)
|
||||
};
|
||||
|
||||
#endif // QT_NO_SCTP
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QSCTPSERVER_H
|
76
src/network/socket/qsctpserver_p.h
Normal file
76
src/network/socket/qsctpserver_p.h
Normal file
@ -0,0 +1,76 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 Alex Trotsenko <alex1973tr@gmail.com>
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the QtNetwork module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or any later version approved by the KDE Free
|
||||
** Qt Foundation. The licenses are as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QSCTPSERVER_P_H
|
||||
#define QSCTPSERVER_P_H
|
||||
|
||||
//
|
||||
// W A R N I N G
|
||||
// -------------
|
||||
//
|
||||
// This file is not part of the Qt API. It exists for the convenience
|
||||
// of the QLibrary class. This header file may change from
|
||||
// version to version without notice, or even be removed.
|
||||
//
|
||||
// We mean it.
|
||||
//
|
||||
|
||||
#include "private/qtcpserver_p.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
#ifndef QT_NO_SCTP
|
||||
|
||||
class QSctpServerPrivate : public QTcpServerPrivate
|
||||
{
|
||||
Q_DECLARE_PUBLIC(QSctpServer)
|
||||
public:
|
||||
QSctpServerPrivate();
|
||||
virtual ~QSctpServerPrivate();
|
||||
|
||||
int maxChannelCount;
|
||||
|
||||
void configureCreatedSocket() Q_DECL_OVERRIDE;
|
||||
};
|
||||
|
||||
#endif // QT_NO_SCTP
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QSCTPSERVER_P_H
|
543
src/network/socket/qsctpsocket.cpp
Normal file
543
src/network/socket/qsctpsocket.cpp
Normal file
@ -0,0 +1,543 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 Alex Trotsenko <alex1973tr@gmail.com>
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the QtNetwork module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or any later version approved by the KDE Free
|
||||
** Qt Foundation. The licenses are as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
//#define QSCTPSOCKET_DEBUG
|
||||
|
||||
/*!
|
||||
\class QSctpSocket
|
||||
\since 5.8
|
||||
|
||||
\brief The QSctpSocket class provides an SCTP socket.
|
||||
|
||||
\ingroup network
|
||||
\inmodule QtNetwork
|
||||
|
||||
SCTP (Stream Control Transmission Protocol) is a transport layer
|
||||
protocol serving in a similar role as the popular protocols TCP
|
||||
and UDP. Like UDP, SCTP is message-oriented, but it ensures reliable,
|
||||
in-sequence transport of messages with congestion control like
|
||||
TCP.
|
||||
|
||||
SCTP is connection-oriented protocol, which provides the complete
|
||||
simultaneous transmission of multiple data streams between
|
||||
endpoints. This multi-streaming allows data to be delivered by
|
||||
independent channels, so that if there is data loss in one stream,
|
||||
delivery will not be affected for the other streams.
|
||||
|
||||
As message-oriented, SCTP transports a sequence of messages,
|
||||
rather than transporting an unbroken stream of bytes as does TCP.
|
||||
Like in UDP, in SCTP a sender sends a message in one operation,
|
||||
and that exact message is passed to the receiving application
|
||||
process in one operation. But unlike UDP, the delivery is
|
||||
guaranteed.
|
||||
|
||||
It also supports multi-homing, meaning that a connected endpoint
|
||||
can have alternate IP addresses associated with it in order to
|
||||
route around network failure or changing conditions.
|
||||
|
||||
QSctpSocket is a convenience subclass of QTcpSocket that allows
|
||||
you to emulate TCP data stream over SCTP or establish an SCTP
|
||||
connection for reliable datagram service.
|
||||
|
||||
QSctpSocket can operate in one of two possible modes:
|
||||
|
||||
\list
|
||||
\li Continuous byte stream (TCP emulation).
|
||||
\li Multi-streamed datagram mode.
|
||||
\endlist
|
||||
|
||||
To set a continuous byte stream mode, instantiate QSctpSocket and
|
||||
call setMaxChannelCount() with the negative number of channels. This
|
||||
gives the ability to use QSctpSocket as a regular buffered
|
||||
QTcpSocket. You can call connectToHost() to initiate connection
|
||||
with endpoint, write() to transmit and read() to receive data from
|
||||
the peer, but you cannot distinguish message boundaries.
|
||||
|
||||
By default, QSctpSocket operates in datagram mode. Before
|
||||
connecting, call setMaxChannelCount() to set the maximum number of
|
||||
channels that the application is prepared to support. This number
|
||||
is a negotiated parameter with remote endpoint and its value can
|
||||
be bounded by the operating system. The default value of 0
|
||||
indicates to use the peer's value. If both endpoints have default
|
||||
values, then number of connection channels is system-dependent.
|
||||
After establishing a connection, you can fetch the actual number
|
||||
of channels by calling readChannelCount() and writeChannelCount().
|
||||
|
||||
\snippet code/src_network_socket_qsctpsocket.cpp 0
|
||||
|
||||
In datagram mode, QSctpSocket performs the buffering of datagrams
|
||||
independently for each channel. You can queue a datagram to the
|
||||
buffer of the current channel by calling writeDatagram() and read
|
||||
a pending datagram by calling readDatagram() respectively.
|
||||
|
||||
Using the standard QIODevice functions read(), readLine(), write(),
|
||||
etc. is allowed in datagram mode with the same limitations as in
|
||||
continuous byte stream mode.
|
||||
|
||||
\note This feature is not supported on the Windows platform.
|
||||
|
||||
\sa QSctpServer, QTcpSocket, QAbstractSocket
|
||||
*/
|
||||
|
||||
#include "qsctpsocket.h"
|
||||
#include "qsctpsocket_p.h"
|
||||
|
||||
#include "qabstractsocketengine_p.h"
|
||||
#include "private/qbytearray_p.h"
|
||||
|
||||
#ifdef QSCTPSOCKET_DEBUG
|
||||
#include <qdebug.h>
|
||||
#endif
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
/*! \internal
|
||||
*/
|
||||
QSctpSocketPrivate::QSctpSocketPrivate()
|
||||
: maxChannelCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
/*! \internal
|
||||
*/
|
||||
QSctpSocketPrivate::~QSctpSocketPrivate()
|
||||
{
|
||||
}
|
||||
|
||||
/*! \internal
|
||||
*/
|
||||
bool QSctpSocketPrivate::canReadNotification()
|
||||
{
|
||||
Q_Q(QSctpSocket);
|
||||
#if defined (QSCTPSOCKET_DEBUG)
|
||||
qDebug("QSctpSocketPrivate::canReadNotification()");
|
||||
#endif
|
||||
|
||||
// Handle TCP emulation mode in the base implementation.
|
||||
if (!q->inDatagramMode())
|
||||
return QTcpSocketPrivate::canReadNotification();
|
||||
|
||||
const int savedCurrentChannel = currentReadChannel;
|
||||
bool currentChannelRead = false;
|
||||
do {
|
||||
int datagramSize = incomingDatagram.size();
|
||||
QIpPacketHeader header;
|
||||
|
||||
do {
|
||||
// Determine the size of the pending datagram.
|
||||
qint64 bytesToRead = socketEngine->bytesAvailable();
|
||||
if (bytesToRead == 0)
|
||||
bytesToRead = 4096;
|
||||
|
||||
Q_ASSERT((datagramSize + int(bytesToRead)) < MaxByteArraySize);
|
||||
incomingDatagram.resize(datagramSize + int(bytesToRead));
|
||||
|
||||
#if defined (QSCTPSOCKET_DEBUG)
|
||||
qDebug("QSctpSocketPrivate::canReadNotification() about to read %lli bytes",
|
||||
bytesToRead);
|
||||
#endif
|
||||
qint64 readBytes = socketEngine->readDatagram(
|
||||
incomingDatagram.data() + datagramSize, bytesToRead, &header,
|
||||
QAbstractSocketEngine::WantAll);
|
||||
if (readBytes <= 0) {
|
||||
if (readBytes == -2) { // no data available for reading
|
||||
incomingDatagram.resize(datagramSize);
|
||||
return currentChannelRead;
|
||||
}
|
||||
|
||||
socketEngine->close();
|
||||
if (readBytes == 0) {
|
||||
setErrorAndEmit(QAbstractSocket::RemoteHostClosedError,
|
||||
QSctpSocket::tr("The remote host closed the connection"));
|
||||
} else {
|
||||
#if defined (QSCTPSOCKET_DEBUG)
|
||||
qDebug("QSctpSocketPrivate::canReadNotification() read failed: %s",
|
||||
socketEngine->errorString().toLatin1().constData());
|
||||
#endif
|
||||
setErrorAndEmit(socketEngine->error(), socketEngine->errorString());
|
||||
}
|
||||
|
||||
#if defined (QSCTPSOCKET_DEBUG)
|
||||
qDebug("QSctpSocketPrivate::canReadNotification() disconnecting socket");
|
||||
#endif
|
||||
q->disconnectFromHost();
|
||||
return currentChannelRead;
|
||||
}
|
||||
datagramSize += int(readBytes); // update datagram size
|
||||
} while (!header.endOfRecord);
|
||||
|
||||
#if defined (QSCTPSOCKET_DEBUG)
|
||||
qDebug("QSctpSocketPrivate::canReadNotification() got datagram from channel %i, size = %i",
|
||||
header.streamNumber, datagramSize);
|
||||
#endif
|
||||
|
||||
// Drop the datagram, if opened only for writing
|
||||
if (!q->isReadable()) {
|
||||
incomingDatagram.clear();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Store datagram in the channel buffer
|
||||
Q_ASSERT(header.streamNumber < readBuffers.size());
|
||||
incomingDatagram.resize(datagramSize);
|
||||
readBuffers[header.streamNumber].setChunkSize(0); // set packet mode on channel buffer
|
||||
readBuffers[header.streamNumber].append(incomingDatagram);
|
||||
incomingDatagram = QByteArray();
|
||||
|
||||
if (readHeaders.size() != readBuffers.size())
|
||||
readHeaders.resize(readBuffers.size());
|
||||
readHeaders[header.streamNumber].push_back(header);
|
||||
|
||||
// Emit notifications.
|
||||
if (header.streamNumber == savedCurrentChannel)
|
||||
currentChannelRead = true;
|
||||
emitReadyRead(header.streamNumber);
|
||||
|
||||
} while (state == QAbstractSocket::ConnectedState);
|
||||
|
||||
return currentChannelRead;
|
||||
}
|
||||
|
||||
/*! \internal
|
||||
*/
|
||||
bool QSctpSocketPrivate::writeToSocket()
|
||||
{
|
||||
Q_Q(QSctpSocket);
|
||||
#if defined (QSCTPSOCKET_DEBUG)
|
||||
qDebug("QSctpSocketPrivate::writeToSocket()");
|
||||
#endif
|
||||
|
||||
// Handle TCP emulation mode in the base implementation.
|
||||
if (!q->inDatagramMode())
|
||||
return QTcpSocketPrivate::writeToSocket();
|
||||
|
||||
if (!socketEngine)
|
||||
return false;
|
||||
|
||||
QIpPacketHeader defaultHeader;
|
||||
const int savedCurrentChannel = currentWriteChannel;
|
||||
bool currentChannelWritten = false;
|
||||
bool transmitting;
|
||||
do {
|
||||
transmitting = false;
|
||||
|
||||
for (int channel = 0; channel < writeBuffers.size(); ++channel) {
|
||||
QRingBuffer &channelBuffer = writeBuffers[channel];
|
||||
|
||||
if (channelBuffer.isEmpty())
|
||||
continue;
|
||||
|
||||
const bool hasHeader = (channel < writeHeaders.size())
|
||||
&& !writeHeaders[channel].empty();
|
||||
QIpPacketHeader &header = hasHeader ? writeHeaders[channel].front() : defaultHeader;
|
||||
header.streamNumber = channel;
|
||||
qint64 sent = socketEngine->writeDatagram(channelBuffer.readPointer(),
|
||||
channelBuffer.nextDataBlockSize(),
|
||||
header);
|
||||
if (sent < 0) {
|
||||
if (sent == -2) // temporary error in writeDatagram
|
||||
return currentChannelWritten;
|
||||
|
||||
socketEngine->close();
|
||||
#if defined (QSCTPSOCKET_DEBUG)
|
||||
qDebug("QSctpSocketPrivate::writeToSocket() write error, aborting. %s",
|
||||
socketEngine->errorString().toLatin1().constData());
|
||||
#endif
|
||||
setErrorAndEmit(socketEngine->error(), socketEngine->errorString());
|
||||
// An unexpected error so close the socket.
|
||||
q->disconnectFromHost();
|
||||
return currentChannelWritten;
|
||||
}
|
||||
Q_ASSERT(sent == channelBuffer.nextDataBlockSize());
|
||||
#if defined (QSCTPSOCKET_DEBUG)
|
||||
qDebug("QSctpSocketPrivate::writeToSocket() sent datagram of size %lli to channel %i",
|
||||
sent, channel);
|
||||
#endif
|
||||
transmitting = true;
|
||||
|
||||
// Remove datagram from the buffer
|
||||
channelBuffer.read();
|
||||
if (hasHeader)
|
||||
writeHeaders[channel].pop_front();
|
||||
|
||||
// Emit notifications.
|
||||
if (channel == savedCurrentChannel)
|
||||
currentChannelWritten = true;
|
||||
emitBytesWritten(sent, channel);
|
||||
|
||||
// If we were closed as a result of the bytesWritten() signal, return.
|
||||
if (state == QAbstractSocket::UnconnectedState) {
|
||||
#if defined (QSCTPSOCKET_DEBUG)
|
||||
qDebug("QSctpSocketPrivate::writeToSocket() socket is closing - returning");
|
||||
#endif
|
||||
return currentChannelWritten;
|
||||
}
|
||||
}
|
||||
} while (transmitting);
|
||||
|
||||
// At this point socket is either in Connected or Closing state,
|
||||
// write buffers are empty.
|
||||
if (state == QAbstractSocket::ClosingState)
|
||||
q->disconnectFromHost();
|
||||
else
|
||||
socketEngine->setWriteNotificationEnabled(false);
|
||||
|
||||
return currentChannelWritten;
|
||||
}
|
||||
|
||||
/*! \internal
|
||||
*/
|
||||
void QSctpSocketPrivate::configureCreatedSocket()
|
||||
{
|
||||
if (socketEngine)
|
||||
socketEngine->setOption(QAbstractSocketEngine::MaxStreamsSocketOption,
|
||||
maxChannelCount < 0 ? 1 : maxChannelCount);
|
||||
}
|
||||
|
||||
/*!
|
||||
Creates a QSctpSocket object in state \c UnconnectedState.
|
||||
|
||||
Sets the datagram operation mode. The \a parent argument is passed
|
||||
to QObject's constructor.
|
||||
|
||||
\sa socketType(), setMaxChannelCount()
|
||||
*/
|
||||
QSctpSocket::QSctpSocket(QObject *parent)
|
||||
: QTcpSocket(SctpSocket, *new QSctpSocketPrivate, parent)
|
||||
{
|
||||
#if defined(QSCTPSOCKET_DEBUG)
|
||||
qDebug("QSctpSocket::QSctpSocket()");
|
||||
#endif
|
||||
d_func()->isBuffered = true;
|
||||
}
|
||||
|
||||
/*!
|
||||
Destroys the socket, closing the connection if necessary.
|
||||
|
||||
\sa close()
|
||||
*/
|
||||
QSctpSocket::~QSctpSocket()
|
||||
{
|
||||
#if defined(QSCTPSOCKET_DEBUG)
|
||||
qDebug("QSctpSocket::~QSctpSocket()");
|
||||
#endif
|
||||
}
|
||||
|
||||
/*! \reimp
|
||||
*/
|
||||
qint64 QSctpSocket::readData(char *data, qint64 maxSize)
|
||||
{
|
||||
Q_D(QSctpSocket);
|
||||
|
||||
// Cleanup headers, if the user calls the standard QIODevice functions
|
||||
if (d->currentReadChannel < d->readHeaders.size())
|
||||
d->readHeaders[d->currentReadChannel].clear();
|
||||
|
||||
return QTcpSocket::readData(data, maxSize);
|
||||
}
|
||||
|
||||
/*! \reimp
|
||||
*/
|
||||
qint64 QSctpSocket::readLineData(char *data, qint64 maxlen)
|
||||
{
|
||||
Q_D(QSctpSocket);
|
||||
|
||||
// Cleanup headers, if the user calls the standard QIODevice functions
|
||||
if (d->currentReadChannel < d->readHeaders.size())
|
||||
d->readHeaders[d->currentReadChannel].clear();
|
||||
|
||||
return QTcpSocket::readLineData(data, maxlen);
|
||||
}
|
||||
|
||||
/*! \reimp
|
||||
*/
|
||||
void QSctpSocket::close()
|
||||
{
|
||||
QTcpSocket::close();
|
||||
d_func()->readHeaders.clear();
|
||||
}
|
||||
|
||||
/*! \reimp
|
||||
*/
|
||||
void QSctpSocket::disconnectFromHost()
|
||||
{
|
||||
Q_D(QSctpSocket);
|
||||
|
||||
QTcpSocket::disconnectFromHost();
|
||||
if (d->state == QAbstractSocket::UnconnectedState) {
|
||||
d->incomingDatagram.clear();
|
||||
d->writeHeaders.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the maximum number of channels that the application is
|
||||
prepared to support in datagram mode, to \a count. If \a count
|
||||
is 0, endpoint's value for maximum number of channels is used.
|
||||
Negative \a count sets a continuous byte stream mode.
|
||||
|
||||
Call this member only when QSctpSocket is in UnconnectedState.
|
||||
|
||||
\sa maxChannelCount(), readChannelCount(), writeChannelCount()
|
||||
*/
|
||||
void QSctpSocket::setMaxChannelCount(int count)
|
||||
{
|
||||
Q_D(QSctpSocket);
|
||||
if (d->state != QAbstractSocket::UnconnectedState) {
|
||||
qWarning("QSctpSocket::setMaxChannelCount() is only allowed in UnconnectedState");
|
||||
return;
|
||||
}
|
||||
#if defined(QSCTPSOCKET_DEBUG)
|
||||
qDebug("QSctpSocket::setMaxChannelCount(%i)", count);
|
||||
#endif
|
||||
d->maxChannelCount = qMax(count, -1);
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the maximum number of channels that QSctpSocket is able to
|
||||
support.
|
||||
|
||||
A value of 0 (the default) means that the number of connection
|
||||
channels would be set by the remote endpoint.
|
||||
|
||||
Returns -1 if QSctpSocket is running in continuous byte stream
|
||||
mode.
|
||||
|
||||
\sa setMaxChannelCount(), readChannelCount(), writeChannelCount()
|
||||
*/
|
||||
int QSctpSocket::maxChannelCount() const
|
||||
{
|
||||
return d_func()->maxChannelCount;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns \c true if the socket is running in datagram mode.
|
||||
|
||||
\sa setMaxChannelCount()
|
||||
*/
|
||||
bool QSctpSocket::inDatagramMode() const
|
||||
{
|
||||
Q_D(const QSctpSocket);
|
||||
return d->maxChannelCount != -1 && d->isBuffered;
|
||||
}
|
||||
|
||||
/*!
|
||||
Reads a datagram from the buffer of the current read channel, and
|
||||
returns it as a QNetworkDatagram object, along with the sender's
|
||||
host address and port. If possible, this function will also try to
|
||||
determine the datagram's destination address, port, and the number
|
||||
of hop counts at reception time.
|
||||
|
||||
On failure, returns a QNetworkDatagram that reports \l
|
||||
{QNetworkDatagram::isValid()}{not valid}.
|
||||
|
||||
\sa writeDatagram(), inDatagramMode(), currentReadChannel()
|
||||
*/
|
||||
QNetworkDatagram QSctpSocket::readDatagram()
|
||||
{
|
||||
Q_D(QSctpSocket);
|
||||
|
||||
if (!isReadable() || !inDatagramMode()) {
|
||||
qWarning("QSctpSocket::readDatagram(): operation is not permitted");
|
||||
return QNetworkDatagram();
|
||||
}
|
||||
|
||||
if (d->currentReadChannel >= d->readHeaders.size()
|
||||
|| (d->readHeaders[d->currentReadChannel].size() == 0)) {
|
||||
Q_ASSERT(d->buffer.isEmpty());
|
||||
return QNetworkDatagram();
|
||||
}
|
||||
|
||||
QNetworkDatagram result(*new QNetworkDatagramPrivate(d->buffer.read(),
|
||||
d->readHeaders[d->currentReadChannel].front()));
|
||||
d->readHeaders[d->currentReadChannel].pop_front();
|
||||
|
||||
#if defined (QSCTPSOCKET_DEBUG)
|
||||
qDebug("QSctpSocket::readDatagram() returning datagram (%p, %i, \"%s\", %i)",
|
||||
result.d->data.constData(),
|
||||
result.d->data.size(),
|
||||
result.senderAddress().toString().toLatin1().constData(),
|
||||
result.senderPort());
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*!
|
||||
Writes a datagram to the buffer of the current write channel.
|
||||
Returns true on success; otherwise returns false.
|
||||
|
||||
\sa readDatagram(), inDatagramMode(), currentWriteChannel()
|
||||
*/
|
||||
bool QSctpSocket::writeDatagram(const QNetworkDatagram &datagram)
|
||||
{
|
||||
Q_D(QSctpSocket);
|
||||
|
||||
if (!isWritable() || d->state != QAbstractSocket::ConnectedState || !d->socketEngine
|
||||
|| !d->socketEngine->isValid() || !inDatagramMode()) {
|
||||
qWarning("QSctpSocket::writeDatagram(): operation is not permitted");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (datagram.d->data.isEmpty()) {
|
||||
qWarning("QSctpSocket::writeDatagram() is called with empty datagram");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
#if defined QSCTPSOCKET_DEBUG
|
||||
qDebug("QSctpSocket::writeDatagram(%p, %i, \"%s\", %i)",
|
||||
datagram.d->data.constData(),
|
||||
datagram.d->data.size(),
|
||||
datagram.destinationAddress().toString().toLatin1().constData(),
|
||||
datagram.destinationPort());
|
||||
#endif
|
||||
|
||||
if (d->writeHeaders.size() != d->writeBuffers.size())
|
||||
d->writeHeaders.resize(d->writeBuffers.size());
|
||||
Q_ASSERT(d->currentWriteChannel < d->writeHeaders.size());
|
||||
d->writeHeaders[d->currentWriteChannel].push_back(datagram.d->header);
|
||||
d->writeBuffer.setChunkSize(0); // set packet mode on channel buffer
|
||||
d->writeBuffer.append(datagram.d->data);
|
||||
|
||||
d->socketEngine->setWriteNotificationEnabled(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
82
src/network/socket/qsctpsocket.h
Normal file
82
src/network/socket/qsctpsocket.h
Normal file
@ -0,0 +1,82 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 Alex Trotsenko <alex1973tr@gmail.com>
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the QtNetwork module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or any later version approved by the KDE Free
|
||||
** Qt Foundation. The licenses are as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QSCTPSOCKET_H
|
||||
#define QSCTPSOCKET_H
|
||||
|
||||
#include <QtNetwork/qtcpsocket.h>
|
||||
#include <QtNetwork/qnetworkdatagram.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
#ifndef QT_NO_SCTP
|
||||
|
||||
class QSctpSocketPrivate;
|
||||
|
||||
class Q_NETWORK_EXPORT QSctpSocket : public QTcpSocket
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit QSctpSocket(QObject *parent = nullptr);
|
||||
virtual ~QSctpSocket();
|
||||
|
||||
void close() Q_DECL_OVERRIDE;
|
||||
void disconnectFromHost() Q_DECL_OVERRIDE;
|
||||
|
||||
void setMaxChannelCount(int count);
|
||||
int maxChannelCount() const;
|
||||
bool inDatagramMode() const;
|
||||
|
||||
QNetworkDatagram readDatagram();
|
||||
bool writeDatagram(const QNetworkDatagram &datagram);
|
||||
|
||||
protected:
|
||||
qint64 readData(char *data, qint64 maxlen) Q_DECL_OVERRIDE;
|
||||
qint64 readLineData(char *data, qint64 maxlen) Q_DECL_OVERRIDE;
|
||||
|
||||
private:
|
||||
Q_DISABLE_COPY(QSctpSocket)
|
||||
Q_DECLARE_PRIVATE(QSctpSocket)
|
||||
};
|
||||
|
||||
#endif // QT_NO_SCTP
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QSCTPSOCKET_H
|
90
src/network/socket/qsctpsocket_p.h
Normal file
90
src/network/socket/qsctpsocket_p.h
Normal file
@ -0,0 +1,90 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 Alex Trotsenko <alex1973tr@gmail.com>
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the QtNetwork module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or any later version approved by the KDE Free
|
||||
** Qt Foundation. The licenses are as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QSCTPSOCKET_P_H
|
||||
#define QSCTPSOCKET_P_H
|
||||
|
||||
//
|
||||
// W A R N I N G
|
||||
// -------------
|
||||
//
|
||||
// This file is not part of the Qt API. It exists for the convenience
|
||||
// of the QLibrary class. This header file may change from
|
||||
// version to version without notice, or even be removed.
|
||||
//
|
||||
// We mean it.
|
||||
//
|
||||
|
||||
#include <QtNetwork/qsctpsocket.h>
|
||||
#include <private/qtcpsocket_p.h>
|
||||
#include <QtCore/qbytearray.h>
|
||||
#include <QtCore/qvector.h>
|
||||
#include <private/qnetworkdatagram_p.h>
|
||||
|
||||
#include <deque>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
#ifndef QT_NO_SCTP
|
||||
|
||||
class QSctpSocketPrivate : public QTcpSocketPrivate
|
||||
{
|
||||
Q_DECLARE_PUBLIC(QSctpSocket)
|
||||
public:
|
||||
QSctpSocketPrivate();
|
||||
virtual ~QSctpSocketPrivate();
|
||||
|
||||
bool canReadNotification() Q_DECL_OVERRIDE;
|
||||
bool writeToSocket() Q_DECL_OVERRIDE;
|
||||
|
||||
QByteArray incomingDatagram;
|
||||
int maxChannelCount;
|
||||
|
||||
typedef std::deque<QIpPacketHeader> IpHeaderList;
|
||||
QVector<IpHeaderList> readHeaders;
|
||||
QVector<IpHeaderList> writeHeaders;
|
||||
|
||||
void configureCreatedSocket() Q_DECL_OVERRIDE;
|
||||
};
|
||||
|
||||
#endif // QT_NO_SCTP
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QSCTPSOCKET_P_H
|
@ -1605,8 +1605,31 @@ bool QSocks5SocketEngine::setMulticastInterface(const QNetworkInterface &)
|
||||
}
|
||||
#endif // QT_NO_NETWORKINTERFACE
|
||||
|
||||
bool QSocks5SocketEngine::hasPendingDatagrams() const
|
||||
{
|
||||
Q_D(const QSocks5SocketEngine);
|
||||
Q_INIT_CHECK(false);
|
||||
|
||||
d->checkForDatagrams();
|
||||
|
||||
return !d->udpData->pendingDatagrams.isEmpty();
|
||||
}
|
||||
|
||||
qint64 QSocks5SocketEngine::pendingDatagramSize() const
|
||||
{
|
||||
Q_D(const QSocks5SocketEngine);
|
||||
|
||||
d->checkForDatagrams();
|
||||
|
||||
if (!d->udpData->pendingDatagrams.isEmpty())
|
||||
return d->udpData->pendingDatagrams.head().data.size();
|
||||
return 0;
|
||||
}
|
||||
#endif // QT_NO_UDPSOCKET
|
||||
|
||||
qint64 QSocks5SocketEngine::readDatagram(char *data, qint64 maxlen, QIpPacketHeader *header, PacketHeaderOptions)
|
||||
{
|
||||
#ifndef QT_NO_UDPSOCKET
|
||||
Q_D(QSocks5SocketEngine);
|
||||
|
||||
d->checkForDatagrams();
|
||||
@ -1620,10 +1643,17 @@ qint64 QSocks5SocketEngine::readDatagram(char *data, qint64 maxlen, QIpPacketHea
|
||||
header->senderAddress = datagram.address;
|
||||
header->senderPort = datagram.port;
|
||||
return copyLen;
|
||||
#else
|
||||
Q_UNUSED(data)
|
||||
Q_UNUSED(maxlen)
|
||||
Q_UNUSED(header)
|
||||
return -1;
|
||||
#endif // QT_NO_UDPSOCKET
|
||||
}
|
||||
|
||||
qint64 QSocks5SocketEngine::writeDatagram(const char *data, qint64 len, const QIpPacketHeader &header)
|
||||
{
|
||||
#ifndef QT_NO_UDPSOCKET
|
||||
Q_D(QSocks5SocketEngine);
|
||||
|
||||
// it is possible to send with out first binding with udp, but socks5 requires a bind.
|
||||
@ -1660,29 +1690,13 @@ qint64 QSocks5SocketEngine::writeDatagram(const char *data, qint64 len, const QI
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
bool QSocks5SocketEngine::hasPendingDatagrams() const
|
||||
{
|
||||
Q_D(const QSocks5SocketEngine);
|
||||
Q_INIT_CHECK(false);
|
||||
|
||||
d->checkForDatagrams();
|
||||
|
||||
return !d->udpData->pendingDatagrams.isEmpty();
|
||||
}
|
||||
|
||||
qint64 QSocks5SocketEngine::pendingDatagramSize() const
|
||||
{
|
||||
Q_D(const QSocks5SocketEngine);
|
||||
|
||||
d->checkForDatagrams();
|
||||
|
||||
if (!d->udpData->pendingDatagrams.isEmpty())
|
||||
return d->udpData->pendingDatagrams.head().data.size();
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
Q_UNUSED(data)
|
||||
Q_UNUSED(len)
|
||||
Q_UNUSED(header)
|
||||
return -1;
|
||||
#endif // QT_NO_UDPSOCKET
|
||||
}
|
||||
|
||||
qint64 QSocks5SocketEngine::bytesToWrite() const
|
||||
{
|
||||
|
@ -100,13 +100,13 @@ public:
|
||||
bool setMulticastInterface(const QNetworkInterface &iface) Q_DECL_OVERRIDE;
|
||||
#endif // QT_NO_NETWORKINTERFACE
|
||||
|
||||
qint64 readDatagram(char *data, qint64 maxlen, QIpPacketHeader * = 0,
|
||||
PacketHeaderOptions = WantNone) Q_DECL_OVERRIDE;
|
||||
qint64 writeDatagram(const char *data, qint64 len, const QIpPacketHeader &) Q_DECL_OVERRIDE;
|
||||
bool hasPendingDatagrams() const Q_DECL_OVERRIDE;
|
||||
qint64 pendingDatagramSize() const Q_DECL_OVERRIDE;
|
||||
#endif // QT_NO_UDPSOCKET
|
||||
|
||||
qint64 readDatagram(char *data, qint64 maxlen, QIpPacketHeader * = 0,
|
||||
PacketHeaderOptions = WantNone) Q_DECL_OVERRIDE;
|
||||
qint64 writeDatagram(const char *data, qint64 len, const QIpPacketHeader &) Q_DECL_OVERRIDE;
|
||||
qint64 bytesToWrite() const Q_DECL_OVERRIDE;
|
||||
|
||||
int option(SocketOption option) const Q_DECL_OVERRIDE;
|
||||
|
@ -119,6 +119,7 @@ QT_BEGIN_NAMESPACE
|
||||
*/
|
||||
QTcpServerPrivate::QTcpServerPrivate()
|
||||
: port(0)
|
||||
, socketType(QAbstractSocket::UnknownSocketType)
|
||||
, state(QAbstractSocket::UnconnectedState)
|
||||
, socketEngine(0)
|
||||
, serverSocketError(QAbstractSocket::UnknownSocketError)
|
||||
@ -148,13 +149,21 @@ QNetworkProxy QTcpServerPrivate::resolveProxy(const QHostAddress &address, quint
|
||||
proxies << proxy;
|
||||
} else {
|
||||
// try the application settings instead
|
||||
QNetworkProxyQuery query(port, QString(), QNetworkProxyQuery::TcpServer);
|
||||
QNetworkProxyQuery query(port, QString(),
|
||||
socketType == QAbstractSocket::SctpSocket ?
|
||||
QNetworkProxyQuery::SctpServer :
|
||||
QNetworkProxyQuery::TcpServer);
|
||||
proxies = QNetworkProxyFactory::proxyForQuery(query);
|
||||
}
|
||||
|
||||
// return the first that we can use
|
||||
for (const QNetworkProxy &p : qAsConst(proxies)) {
|
||||
if (p.capabilities() & QNetworkProxy::ListeningCapability)
|
||||
if (socketType == QAbstractSocket::TcpSocket &&
|
||||
(p.capabilities() & QNetworkProxy::ListeningCapability) != 0)
|
||||
return p;
|
||||
|
||||
if (socketType == QAbstractSocket::SctpSocket &&
|
||||
(p.capabilities() & QNetworkProxy::SctpListeningCapability) != 0)
|
||||
return p;
|
||||
}
|
||||
|
||||
@ -228,9 +237,11 @@ void QTcpServerPrivate::readNotification()
|
||||
QTcpServer::QTcpServer(QObject *parent)
|
||||
: QObject(*new QTcpServerPrivate, parent)
|
||||
{
|
||||
Q_D(QTcpServer);
|
||||
#if defined(QTCPSERVER_DEBUG)
|
||||
qDebug("QTcpServer::QTcpServer(%p)", parent);
|
||||
#endif
|
||||
d->socketType = QAbstractSocket::TcpSocket;
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -251,13 +262,22 @@ QTcpServer::~QTcpServer()
|
||||
}
|
||||
|
||||
/*! \internal
|
||||
|
||||
Constructs a new server object with socket of type \a socketType. The \a
|
||||
parent argument is passed to QObject's constructor.
|
||||
*/
|
||||
QTcpServer::QTcpServer(QTcpServerPrivate &dd, QObject *parent)
|
||||
: QObject(dd, parent)
|
||||
QTcpServer::QTcpServer(QAbstractSocket::SocketType socketType, QTcpServerPrivate &dd,
|
||||
QObject *parent) : QObject(dd, parent)
|
||||
{
|
||||
Q_D(QTcpServer);
|
||||
#if defined(QTCPSERVER_DEBUG)
|
||||
qDebug("QTcpServer::QTcpServer(QTcpServerPrivate == %p, parent == %p)", &dd, parent);
|
||||
qDebug("QTcpServer::QTcpServer(%sSocket, QTcpServerPrivate == %p, parent == %p)",
|
||||
socketType == QAbstractSocket::TcpSocket ? "Tcp"
|
||||
: socketType == QAbstractSocket::UdpSocket ? "Udp"
|
||||
: socketType == QAbstractSocket::SctpSocket ? "Sctp"
|
||||
: "Unknown", &dd, parent);
|
||||
#endif
|
||||
d->socketType = socketType;
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -288,7 +308,7 @@ bool QTcpServer::listen(const QHostAddress &address, quint16 port)
|
||||
#endif
|
||||
|
||||
delete d->socketEngine;
|
||||
d->socketEngine = QAbstractSocketEngine::createSocketEngine(QAbstractSocket::TcpSocket, proxy, this);
|
||||
d->socketEngine = QAbstractSocketEngine::createSocketEngine(d->socketType, proxy, this);
|
||||
if (!d->socketEngine) {
|
||||
d->serverSocketError = QAbstractSocket::UnsupportedSocketOperationError;
|
||||
d->serverSocketErrorString = tr("Operation on socket is not supported");
|
||||
@ -298,7 +318,7 @@ bool QTcpServer::listen(const QHostAddress &address, quint16 port)
|
||||
//copy network session down to the socket engine (if it has been set)
|
||||
d->socketEngine->setProperty("_q_networksession", property("_q_networksession"));
|
||||
#endif
|
||||
if (!d->socketEngine->initialize(QAbstractSocket::TcpSocket, proto)) {
|
||||
if (!d->socketEngine->initialize(d->socketType, proto)) {
|
||||
d->serverSocketError = d->socketEngine->error();
|
||||
d->serverSocketErrorString = d->socketEngine->errorString();
|
||||
return false;
|
||||
|
@ -94,7 +94,8 @@ protected:
|
||||
virtual void incomingConnection(qintptr handle);
|
||||
void addPendingConnection(QTcpSocket* socket);
|
||||
|
||||
QTcpServer(QTcpServerPrivate &dd, QObject *parent = Q_NULLPTR);
|
||||
QTcpServer(QAbstractSocket::SocketType socketType, QTcpServerPrivate &dd,
|
||||
QObject *parent = Q_NULLPTR);
|
||||
|
||||
Q_SIGNALS:
|
||||
void newConnection();
|
||||
|
@ -1,6 +1,7 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Copyright (C) 2016 Alex Trotsenko <alex1973tr@gmail.com>
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the QtNetwork module of the Qt Toolkit.
|
||||
@ -74,6 +75,7 @@ public:
|
||||
quint16 port;
|
||||
QHostAddress address;
|
||||
|
||||
QAbstractSocket::SocketType socketType;
|
||||
QAbstractSocket::SocketState state;
|
||||
QAbstractSocketEngine *socketEngine;
|
||||
|
||||
|
@ -347,6 +347,12 @@ qint64 QUdpSocket::writeDatagram(const char *data, qint64 size, const QHostAddre
|
||||
if (sent >= 0) {
|
||||
emit bytesWritten(sent);
|
||||
} else {
|
||||
if (sent == -2) {
|
||||
// Socket engine reports EAGAIN. Treat as a temporary error.
|
||||
d->setErrorAndEmit(QAbstractSocket::TemporaryError,
|
||||
tr("Unable to send a datagram"));
|
||||
return -1;
|
||||
}
|
||||
d->setErrorAndEmit(d->socketEngine->error(), d->socketEngine->errorString());
|
||||
}
|
||||
return sent;
|
||||
@ -495,8 +501,15 @@ qint64 QUdpSocket::readDatagram(char *data, qint64 maxSize, QHostAddress *addres
|
||||
|
||||
d->hasPendingData = false;
|
||||
d->socketEngine->setReadNotificationEnabled(true);
|
||||
if (readBytes < 0)
|
||||
if (readBytes < 0) {
|
||||
if (readBytes == -2) {
|
||||
// No pending datagram. Treat as a temporary error.
|
||||
d->setErrorAndEmit(QAbstractSocket::TemporaryError,
|
||||
tr("No datagram available for reading"));
|
||||
return -1;
|
||||
}
|
||||
d->setErrorAndEmit(d->socketEngine->error(), d->socketEngine->errorString());
|
||||
}
|
||||
return readBytes;
|
||||
}
|
||||
|
||||
|
@ -25,6 +25,18 @@ SOURCES += socket/qabstractsocketengine.cpp \
|
||||
socket/qlocalsocket.cpp \
|
||||
socket/qlocalserver.cpp
|
||||
|
||||
# SCTP support.
|
||||
|
||||
contains(QT_CONFIG, sctp) {
|
||||
HEADERS += socket/qsctpserver.h \
|
||||
socket/qsctpserver_p.h \
|
||||
socket/qsctpsocket.h \
|
||||
socket/qsctpsocket_p.h
|
||||
|
||||
SOURCES += socket/qsctpserver.cpp \
|
||||
socket/qsctpsocket.cpp
|
||||
}
|
||||
|
||||
!winrt {
|
||||
SOURCES += socket/qnativesocketengine.cpp
|
||||
HEADERS += socket/qnativesocketengine_p.h
|
||||
|
@ -603,8 +603,8 @@ void tst_PlatformSocketEngine::invalidSend()
|
||||
PLATFORMSOCKETENGINE socket;
|
||||
QVERIFY(socket.initialize(QAbstractSocket::TcpSocket));
|
||||
|
||||
QTest::ignoreMessage(QtWarningMsg, PLATFORMSOCKETENGINESTRING "::writeDatagram() was"
|
||||
" called by a socket other than QAbstractSocket::UdpSocket");
|
||||
QTest::ignoreMessage(QtWarningMsg, PLATFORMSOCKETENGINESTRING "::writeDatagram() was called"
|
||||
" not in QAbstractSocket::BoundState or QAbstractSocket::ConnectedState");
|
||||
QCOMPARE(socket.writeDatagram("hei", 3, QIpPacketHeader(QHostAddress::LocalHost, 143)),
|
||||
(qlonglong) -1);
|
||||
}
|
||||
|
6
tests/auto/network/socket/qsctpsocket/qsctpsocket.pro
Normal file
6
tests/auto/network/socket/qsctpsocket/qsctpsocket.pro
Normal file
@ -0,0 +1,6 @@
|
||||
CONFIG += testcase
|
||||
TARGET = tst_qsctpsocket
|
||||
QT = core network testlib
|
||||
|
||||
SOURCES += tst_qsctpsocket.cpp
|
||||
|
489
tests/auto/network/socket/qsctpsocket/tst_qsctpsocket.cpp
Normal file
489
tests/auto/network/socket/qsctpsocket/tst_qsctpsocket.cpp
Normal file
@ -0,0 +1,489 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 Alex Trotsenko <alex1973tr@gmail.com>
|
||||
** Contact: http://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the test suite of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL21$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see http://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at http://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 or version 3 as published by the Free
|
||||
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
|
||||
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
|
||||
** following information to ensure the GNU Lesser General Public License
|
||||
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** As a special exception, The Qt Company gives you certain additional
|
||||
** rights. These rights are described in The Qt Company LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include <QtTest/QtTest>
|
||||
#include <QDebug>
|
||||
#include <QEventLoop>
|
||||
#include <QByteArray>
|
||||
#include <QString>
|
||||
#include <QHostAddress>
|
||||
#include <QHostInfo>
|
||||
#include <QNetworkInterface>
|
||||
#include <QTime>
|
||||
|
||||
#include <QSctpSocket>
|
||||
#include <QSctpServer>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/sctp.h>
|
||||
|
||||
#define SOCKET int
|
||||
#define INVALID_SOCKET -1
|
||||
|
||||
class tst_QSctpSocket : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static void enterLoop(int secs)
|
||||
{
|
||||
++loopLevel;
|
||||
QTestEventLoop::instance().enterLoop(secs);
|
||||
--loopLevel;
|
||||
}
|
||||
static void exitLoop()
|
||||
{
|
||||
// Safe exit - if we aren't in an event loop, don't
|
||||
// exit one.
|
||||
if (loopLevel > 0)
|
||||
QTestEventLoop::instance().exitLoop();
|
||||
}
|
||||
static bool timeout()
|
||||
{
|
||||
return QTestEventLoop::instance().timeout();
|
||||
}
|
||||
|
||||
private slots:
|
||||
void constructing();
|
||||
void bind_data();
|
||||
void bind();
|
||||
void setInvalidSocketDescriptor();
|
||||
void setSocketDescriptor();
|
||||
void socketDescriptor();
|
||||
void hostNotFound();
|
||||
void connecting();
|
||||
void readAndWrite();
|
||||
void loop_data();
|
||||
void loop();
|
||||
void loopInTCPMode_data();
|
||||
void loopInTCPMode();
|
||||
void readDatagramAfterClose();
|
||||
void clientSendDataOnDelayedDisconnect();
|
||||
|
||||
protected slots:
|
||||
void exitLoopSlot();
|
||||
|
||||
private:
|
||||
static int loopLevel;
|
||||
};
|
||||
|
||||
int tst_QSctpSocket::loopLevel = 0;
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
void tst_QSctpSocket::constructing()
|
||||
{
|
||||
QSctpSocket socket;
|
||||
|
||||
// Check the initial state of the QSctpSocket.
|
||||
QCOMPARE(socket.state(), QAbstractSocket::UnconnectedState);
|
||||
QVERIFY(socket.isSequential());
|
||||
QVERIFY(!socket.isOpen());
|
||||
QVERIFY(!socket.isValid());
|
||||
QCOMPARE(socket.socketType(), QAbstractSocket::SctpSocket);
|
||||
QCOMPARE(socket.maxChannelCount(), 0);
|
||||
QCOMPARE(socket.readChannelCount(), 0);
|
||||
QCOMPARE(socket.writeChannelCount(), 0);
|
||||
|
||||
char c;
|
||||
QCOMPARE(socket.getChar(&c), false);
|
||||
QCOMPARE((int) socket.bytesAvailable(), 0);
|
||||
QCOMPARE(socket.canReadLine(), false);
|
||||
QCOMPARE(socket.readLine(), QByteArray());
|
||||
QCOMPARE(socket.socketDescriptor(), (qintptr)-1);
|
||||
QCOMPARE((int) socket.localPort(), 0);
|
||||
QVERIFY(socket.localAddress() == QHostAddress());
|
||||
QCOMPARE((int) socket.peerPort(), 0);
|
||||
QVERIFY(socket.peerAddress() == QHostAddress());
|
||||
QCOMPARE(socket.error(), QAbstractSocket::UnknownSocketError);
|
||||
QCOMPARE(socket.errorString(), QString("Unknown error"));
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
void tst_QSctpSocket::bind_data()
|
||||
{
|
||||
QTest::addColumn<QString>("stringAddr");
|
||||
QTest::addColumn<bool>("successExpected");
|
||||
QTest::addColumn<QString>("stringExpectedLocalAddress");
|
||||
|
||||
// iterate all interfaces, add all addresses on them as test data
|
||||
QList<QNetworkInterface> interfaces = QNetworkInterface::allInterfaces();
|
||||
foreach (const QNetworkInterface &interface, interfaces) {
|
||||
if (!interface.isValid())
|
||||
continue;
|
||||
|
||||
foreach (const QNetworkAddressEntry &entry, interface.addressEntries()) {
|
||||
if (entry.ip().isInSubnet(QHostAddress::parseSubnet("fe80::/10"))
|
||||
|| entry.ip().isInSubnet(QHostAddress::parseSubnet("169.254/16")))
|
||||
continue; // link-local bind will fail, at least on Linux, so skip it.
|
||||
|
||||
QString ip(entry.ip().toString());
|
||||
QTest::newRow(ip.toLatin1().constData()) << ip << true << ip;
|
||||
}
|
||||
}
|
||||
|
||||
// additionally, try bind to known-bad addresses, and make sure this doesn't work
|
||||
// these ranges are guaranteed to be reserved for 'documentation purposes',
|
||||
// and thus, should be unused in the real world. Not that I'm assuming the
|
||||
// world is full of competent administrators, or anything.
|
||||
QStringList knownBad;
|
||||
knownBad << "198.51.100.1";
|
||||
knownBad << "2001:0DB8::1";
|
||||
foreach (const QString &badAddress, knownBad) {
|
||||
QTest::newRow(badAddress.toLatin1().constData()) << badAddress << false << QString();
|
||||
}
|
||||
}
|
||||
|
||||
// Testing bind function
|
||||
void tst_QSctpSocket::bind()
|
||||
{
|
||||
QFETCH(QString, stringAddr);
|
||||
QFETCH(bool, successExpected);
|
||||
QFETCH(QString, stringExpectedLocalAddress);
|
||||
|
||||
QHostAddress addr(stringAddr);
|
||||
QHostAddress expectedLocalAddress(stringExpectedLocalAddress);
|
||||
|
||||
QSctpSocket socket;
|
||||
qDebug() << "Binding " << addr;
|
||||
|
||||
if (successExpected) {
|
||||
QVERIFY2(socket.bind(addr), qPrintable(socket.errorString()));
|
||||
} else {
|
||||
QVERIFY(!socket.bind(addr));
|
||||
}
|
||||
|
||||
QCOMPARE(socket.localAddress(), expectedLocalAddress);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
void tst_QSctpSocket::setInvalidSocketDescriptor()
|
||||
{
|
||||
QSctpSocket socket;
|
||||
QCOMPARE(socket.socketDescriptor(), (qintptr)INVALID_SOCKET);
|
||||
QVERIFY(!socket.setSocketDescriptor(-5, QAbstractSocket::UnconnectedState));
|
||||
QCOMPARE(socket.socketDescriptor(), (qintptr)INVALID_SOCKET);
|
||||
|
||||
QCOMPARE(socket.error(), QAbstractSocket::UnsupportedSocketOperationError);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
void tst_QSctpSocket::setSocketDescriptor()
|
||||
{
|
||||
QSctpServer server;
|
||||
|
||||
server.setMaxChannelCount(16);
|
||||
QVERIFY(server.listen());
|
||||
|
||||
SOCKET sock = ::socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP);
|
||||
|
||||
QVERIFY(sock != INVALID_SOCKET);
|
||||
QSctpSocket socket;
|
||||
QVERIFY(socket.setSocketDescriptor(sock, QAbstractSocket::UnconnectedState));
|
||||
QCOMPARE(socket.socketDescriptor(), (qintptr)sock);
|
||||
QCOMPARE(socket.readChannelCount(), 0);
|
||||
QCOMPARE(socket.writeChannelCount(), 0);
|
||||
|
||||
socket.connectToHost(QHostAddress::LocalHost, server.serverPort());
|
||||
QVERIFY(socket.waitForConnected(3000));
|
||||
QVERIFY(server.waitForNewConnection(3000));
|
||||
|
||||
QCOMPARE(socket.readChannelCount(), server.maxChannelCount());
|
||||
QVERIFY(socket.writeChannelCount() <= server.maxChannelCount());
|
||||
|
||||
QSctpSocket *acceptedSocket = server.nextPendingDatagramConnection();
|
||||
QVERIFY(acceptedSocket);
|
||||
QCOMPARE(acceptedSocket->readChannelCount(), socket.writeChannelCount());
|
||||
QCOMPARE(acceptedSocket->writeChannelCount(), socket.readChannelCount());
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
void tst_QSctpSocket::socketDescriptor()
|
||||
{
|
||||
QSctpSocket socket;
|
||||
|
||||
QSctpServer server;
|
||||
|
||||
QVERIFY(server.listen());
|
||||
|
||||
QCOMPARE(socket.socketDescriptor(), (qintptr)INVALID_SOCKET);
|
||||
socket.connectToHost(QHostAddress::LocalHost, server.serverPort());
|
||||
QVERIFY(server.waitForNewConnection(3000));
|
||||
if (socket.state() != QAbstractSocket::ConnectedState) {
|
||||
QVERIFY((socket.state() == QAbstractSocket::HostLookupState
|
||||
&& socket.socketDescriptor() == INVALID_SOCKET)
|
||||
|| socket.state() == QAbstractSocket::ConnectingState);
|
||||
QVERIFY(socket.waitForConnected(3000));
|
||||
QCOMPARE(socket.state(), QAbstractSocket::ConnectedState);
|
||||
}
|
||||
QVERIFY(socket.socketDescriptor() != INVALID_SOCKET);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
void tst_QSctpSocket::hostNotFound()
|
||||
{
|
||||
QSctpSocket socket;
|
||||
|
||||
socket.connectToHost("nosuchserver.qt-project.org", 80);
|
||||
QVERIFY(!socket.waitForConnected(3000));
|
||||
QCOMPARE(socket.state(), QTcpSocket::UnconnectedState);
|
||||
QCOMPARE(socket.error(), QAbstractSocket::HostNotFoundError);
|
||||
}
|
||||
|
||||
// Testing connect function
|
||||
void tst_QSctpSocket::connecting()
|
||||
{
|
||||
QSctpServer server;
|
||||
|
||||
QVERIFY(server.listen());
|
||||
|
||||
QSctpSocket socket;
|
||||
socket.connectToHost(QHostAddress::LocalHost, server.serverPort());
|
||||
QVERIFY(socket.waitForConnected(3000));
|
||||
|
||||
QVERIFY(server.waitForNewConnection(3000));
|
||||
QSctpSocket *acceptedSocket = server.nextPendingDatagramConnection();
|
||||
QVERIFY(acceptedSocket);
|
||||
|
||||
QCOMPARE(socket.state(), QAbstractSocket::ConnectedState);
|
||||
QCOMPARE(acceptedSocket->state(), QAbstractSocket::ConnectedState);
|
||||
QCOMPARE(socket.readChannelCount(), acceptedSocket->readChannelCount());
|
||||
QCOMPARE(socket.writeChannelCount(),acceptedSocket->writeChannelCount());
|
||||
}
|
||||
|
||||
// Testing read/write functions
|
||||
void tst_QSctpSocket::readAndWrite()
|
||||
{
|
||||
QSctpServer server;
|
||||
|
||||
QVERIFY(server.listen());
|
||||
|
||||
QSctpSocket socket;
|
||||
socket.connectToHost(QHostAddress::LocalHost, server.serverPort());
|
||||
QVERIFY(socket.waitForConnected(3000));
|
||||
|
||||
QVERIFY(server.waitForNewConnection(3000));
|
||||
QSctpSocket *acceptedSocket = server.nextPendingDatagramConnection();
|
||||
QVERIFY(acceptedSocket);
|
||||
|
||||
QByteArray ba(1000, 1);
|
||||
QVERIFY(acceptedSocket->writeDatagram(ba));
|
||||
QVERIFY(acceptedSocket->waitForBytesWritten(3000));
|
||||
|
||||
QVERIFY(socket.waitForReadyRead(3000));
|
||||
QNetworkDatagram datagram = socket.readDatagram();
|
||||
QVERIFY(datagram.isValid());
|
||||
QCOMPARE(datagram.data(), ba);
|
||||
|
||||
QCOMPARE(socket.state(), QAbstractSocket::ConnectedState);
|
||||
QCOMPARE(socket.error(), QAbstractSocket::UnknownSocketError);
|
||||
QCOMPARE(socket.errorString(), QString("Unknown error"));
|
||||
QCOMPARE(acceptedSocket->state(), QAbstractSocket::ConnectedState);
|
||||
QCOMPARE(acceptedSocket->error(), QAbstractSocket::UnknownSocketError);
|
||||
QCOMPARE(acceptedSocket->errorString(), QString("Unknown error"));
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
void tst_QSctpSocket::loop_data()
|
||||
{
|
||||
QTest::addColumn<QByteArray>("peterDatagram");
|
||||
QTest::addColumn<QByteArray>("paulDatagram");
|
||||
QTest::addColumn<int>("peterChannel");
|
||||
QTest::addColumn<int>("paulChannel");
|
||||
|
||||
QTest::newRow("\"Almond!\" | \"Joy!\"") << QByteArray("Almond!") << QByteArray("Joy!") << 0 << 0;
|
||||
QTest::newRow("\"A\" | \"B\"") << QByteArray("A") << QByteArray("B") << 1 << 1;
|
||||
QTest::newRow("\"AB\" | \"B\"") << QByteArray("AB") << QByteArray("B") << 0 << 1;
|
||||
QTest::newRow("\"AB\" | \"BB\"") << QByteArray("AB") << QByteArray("BB") << 1 << 0;
|
||||
QTest::newRow("\"A\\0B\" | \"B\\0B\"") << QByteArray::fromRawData("A\0B", 3) << QByteArray::fromRawData("B\0B", 3) << 0 << 1;
|
||||
QTest::newRow("BigDatagram") << QByteArray(600, '@') << QByteArray(600, '@') << 1 << 0;
|
||||
}
|
||||
|
||||
void tst_QSctpSocket::loop()
|
||||
{
|
||||
QFETCH(QByteArray, peterDatagram);
|
||||
QFETCH(QByteArray, paulDatagram);
|
||||
QFETCH(int, peterChannel);
|
||||
QFETCH(int, paulChannel);
|
||||
|
||||
QSctpServer server;
|
||||
|
||||
server.setMaxChannelCount(10);
|
||||
QVERIFY(server.listen());
|
||||
|
||||
QSctpSocket peter;
|
||||
peter.setMaxChannelCount(10);
|
||||
peter.connectToHost(QHostAddress::LocalHost, server.serverPort());
|
||||
QVERIFY(peter.waitForConnected(3000));
|
||||
|
||||
QVERIFY(server.waitForNewConnection(3000));
|
||||
QSctpSocket *paul = server.nextPendingDatagramConnection();
|
||||
QVERIFY(paul);
|
||||
|
||||
peter.setCurrentWriteChannel(peterChannel);
|
||||
QVERIFY(peter.writeDatagram(peterDatagram));
|
||||
paul->setCurrentWriteChannel(paulChannel);
|
||||
QVERIFY(paul->writeDatagram(paulDatagram));
|
||||
QVERIFY(peter.flush());
|
||||
QVERIFY(paul->flush());
|
||||
|
||||
peter.setCurrentReadChannel(paulChannel);
|
||||
QVERIFY(peter.waitForReadyRead(3000));
|
||||
QCOMPARE(peter.bytesAvailable(), paulDatagram.size());
|
||||
QCOMPARE(peter.readDatagram().data(), paulDatagram);
|
||||
|
||||
paul->setCurrentReadChannel(peterChannel);
|
||||
QVERIFY(paul->waitForReadyRead(3000));
|
||||
QCOMPARE(paul->bytesAvailable(), peterDatagram.size());
|
||||
QCOMPARE(paul->readDatagram().data(), peterDatagram);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
void tst_QSctpSocket::loopInTCPMode_data()
|
||||
{
|
||||
QTest::addColumn<QByteArray>("peterDatagram");
|
||||
QTest::addColumn<QByteArray>("paulDatagram");
|
||||
|
||||
QTest::newRow("\"Almond!\" | \"Joy!\"") << QByteArray("Almond!") << QByteArray("Joy!");
|
||||
QTest::newRow("\"A\" | \"B\"") << QByteArray("A") << QByteArray("B");
|
||||
QTest::newRow("\"AB\" | \"B\"") << QByteArray("AB") << QByteArray("B");
|
||||
QTest::newRow("\"AB\" | \"BB\"") << QByteArray("AB") << QByteArray("BB");
|
||||
QTest::newRow("\"A\\0B\" | \"B\\0B\"") << QByteArray::fromRawData("A\0B", 3) << QByteArray::fromRawData("B\0B", 3);
|
||||
QTest::newRow("BigDatagram") << QByteArray(600, '@') << QByteArray(600, '@');
|
||||
}
|
||||
|
||||
void tst_QSctpSocket::loopInTCPMode()
|
||||
{
|
||||
QFETCH(QByteArray, peterDatagram);
|
||||
QFETCH(QByteArray, paulDatagram);
|
||||
|
||||
QSctpServer server;
|
||||
|
||||
server.setMaxChannelCount(-1);
|
||||
QVERIFY(server.listen());
|
||||
|
||||
QSctpSocket peter;
|
||||
peter.setMaxChannelCount(-1);
|
||||
peter.connectToHost(QHostAddress::LocalHost, server.serverPort());
|
||||
QVERIFY(peter.waitForConnected(3000));
|
||||
QVERIFY(server.waitForNewConnection(3000));
|
||||
|
||||
QTcpSocket *paul = server.nextPendingConnection();
|
||||
QVERIFY(paul);
|
||||
|
||||
QCOMPARE(peter.write(peterDatagram), qint64(peterDatagram.size()));
|
||||
QCOMPARE(paul->write(paulDatagram), qint64(paulDatagram.size()));
|
||||
QVERIFY(peter.flush());
|
||||
QVERIFY(paul->flush());
|
||||
|
||||
QVERIFY(peter.waitForReadyRead(3000));
|
||||
QVERIFY(paul->waitForReadyRead(3000));
|
||||
|
||||
QCOMPARE(peter.bytesAvailable(), paulDatagram.size());
|
||||
QByteArray peterBuffer = peter.readAll();
|
||||
|
||||
QCOMPARE(paul->bytesAvailable(), peterDatagram.size());
|
||||
QByteArray paulBuffer = paul->readAll();
|
||||
|
||||
QCOMPARE(peterBuffer, paulDatagram);
|
||||
QCOMPARE(paulBuffer, peterDatagram);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
void tst_QSctpSocket::exitLoopSlot()
|
||||
{
|
||||
exitLoop();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
void tst_QSctpSocket::readDatagramAfterClose()
|
||||
{
|
||||
QSctpServer server;
|
||||
|
||||
QVERIFY(server.listen());
|
||||
|
||||
QSctpSocket socket;
|
||||
socket.connectToHost(QHostAddress::LocalHost, server.serverPort());
|
||||
QVERIFY(socket.waitForConnected(3000));
|
||||
QVERIFY(server.waitForNewConnection(3000));
|
||||
|
||||
QSctpSocket *acceptedSocket = server.nextPendingDatagramConnection();
|
||||
QVERIFY(acceptedSocket);
|
||||
|
||||
connect(&socket, &QIODevice::readyRead, this, &tst_QSctpSocket::exitLoopSlot);
|
||||
|
||||
QByteArray ba(1000, 1);
|
||||
QVERIFY(acceptedSocket->writeDatagram(ba));
|
||||
|
||||
enterLoop(10);
|
||||
if (timeout())
|
||||
QFAIL("Network operation timed out");
|
||||
|
||||
QCOMPARE(socket.bytesAvailable(), ba.size());
|
||||
socket.close();
|
||||
QVERIFY(!socket.readDatagram().isValid());
|
||||
}
|
||||
|
||||
// Test buffered socket properly send data on delayed disconnect
|
||||
void tst_QSctpSocket::clientSendDataOnDelayedDisconnect()
|
||||
{
|
||||
QSctpServer server;
|
||||
|
||||
QVERIFY(server.listen());
|
||||
|
||||
// Connect to server, write data and close socket
|
||||
QSctpSocket socket;
|
||||
socket.connectToHost(QHostAddress::LocalHost, server.serverPort());
|
||||
QVERIFY(socket.waitForConnected(3000));
|
||||
|
||||
QByteArray sendData("GET /\r\n");
|
||||
sendData = sendData.repeated(1000);
|
||||
QVERIFY(socket.writeDatagram(sendData));
|
||||
socket.close();
|
||||
QCOMPARE(socket.state(), QAbstractSocket::ClosingState);
|
||||
QVERIFY(socket.waitForDisconnected(3000));
|
||||
|
||||
QVERIFY(server.waitForNewConnection(3000));
|
||||
QSctpSocket *acceptedSocket = server.nextPendingDatagramConnection();
|
||||
QVERIFY(acceptedSocket);
|
||||
|
||||
QVERIFY(acceptedSocket->waitForReadyRead(3000));
|
||||
QNetworkDatagram datagram = acceptedSocket->readDatagram();
|
||||
QVERIFY(datagram.isValid());
|
||||
QCOMPARE(datagram.data(), sendData);
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QSctpSocket)
|
||||
|
||||
#include "tst_qsctpsocket.moc"
|
@ -8,6 +8,7 @@ SUBDIRS=\
|
||||
qsocks5socketengine \
|
||||
qabstractsocket \
|
||||
platformsocketengine \
|
||||
qsctpsocket \
|
||||
|
||||
!contains(QT_CONFIG, private_tests): SUBDIRS -= \
|
||||
platformsocketengine \
|
||||
@ -15,6 +16,9 @@ SUBDIRS=\
|
||||
qhttpsocketengine \
|
||||
qsocks5socketengine \
|
||||
|
||||
!contains(QT_CONFIG, sctp): SUBDIRS -= \
|
||||
qsctpsocket \
|
||||
|
||||
winrt: SUBDIRS -= \
|
||||
qhttpsocketengine \
|
||||
qsocks5socketengine \
|
||||
|
@ -180,6 +180,7 @@ Configure::Configure(int& argc, char** argv) : verbose(0)
|
||||
dictionary[ "PPS" ] = "no";
|
||||
dictionary[ "LGMON" ] = "no";
|
||||
dictionary[ "SYSTEM_PROXIES" ] = "yes";
|
||||
dictionary[ "SCTP" ] = "no";
|
||||
dictionary[ "WERROR" ] = "auto";
|
||||
dictionary[ "QREAL" ] = "double";
|
||||
dictionary[ "ATOMIC64" ] = "auto";
|
||||
@ -829,6 +830,10 @@ void Configure::parseCmdLine()
|
||||
dictionary[ "SYSTEM_PROXIES" ] = "no";
|
||||
} else if (configCmdLine.at(i) == "-system-proxies") {
|
||||
dictionary[ "SYSTEM_PROXIES" ] = "yes";
|
||||
} else if (configCmdLine.at(i) == "-no-sctp") {
|
||||
dictionary[ "SCTP" ] = "no";
|
||||
} else if (configCmdLine.at(i) == "-sctp") {
|
||||
dictionary[ "SCTP" ] = "yes";
|
||||
} else if (configCmdLine.at(i) == "-warnings-are-errors" ||
|
||||
configCmdLine.at(i) == "-Werror") {
|
||||
dictionary[ "WERROR" ] = "yes";
|
||||
@ -1698,6 +1703,9 @@ bool Configure::displayHelp()
|
||||
desc("SYSTEM_PROXIES", "yes", "-system-proxies", "Use system network proxies by default.");
|
||||
desc("SYSTEM_PROXIES", "no", "-no-system-proxies", "Do not use system network proxies by default.\n");
|
||||
|
||||
desc("SCTP", "yes", "-sctp", "Compile SCTP support.");
|
||||
desc("SCTP", "no", "-no-sctp", "Do not compile SCTP network protocol support.\n");
|
||||
|
||||
desc("WERROR", "yes", "-warnings-are-errors", "Make warnings be treated as errors.");
|
||||
desc("WERROR", "no", "-no-warnings-are-errors","Make warnings be treated normally.");
|
||||
|
||||
@ -2103,6 +2111,8 @@ bool Configure::checkAvailability(const QString &part)
|
||||
available = (platform() == QNX) && tryCompileProject("unix/pps");
|
||||
} else if (part == "LGMON") {
|
||||
available = (platform() == QNX) && tryCompileProject("unix/lgmon");
|
||||
} else if (part == "SCTP") {
|
||||
available = tryCompileProject("unix/sctp");
|
||||
} else if (part == "NEON") {
|
||||
available = dictionary["QT_CPU_FEATURES"].contains("neon");
|
||||
} else if (part == "FONT_CONFIG") {
|
||||
@ -2301,6 +2311,10 @@ void Configure::autoDetection()
|
||||
dictionary["LGMON"] = checkAvailability("LGMON") ? "yes" : "no";
|
||||
}
|
||||
|
||||
if (dictionary["SCTP"] == "auto") {
|
||||
dictionary["SCTP"] = checkAvailability("SCTP") ? "yes" : "no";
|
||||
}
|
||||
|
||||
if (dictionary["QT_EVENTFD"] == "auto")
|
||||
dictionary["QT_EVENTFD"] = checkAvailability("QT_EVENTFD") ? "yes" : "no";
|
||||
|
||||
@ -2744,6 +2758,9 @@ void Configure::generateOutputVars()
|
||||
if (dictionary[ "SYSTEM_PROXIES" ] == "yes")
|
||||
qtConfig += "system-proxies";
|
||||
|
||||
if (dictionary[ "SCTP" ] == "yes")
|
||||
qtConfig += "sctp";
|
||||
|
||||
if (dictionary.contains("XQMAKESPEC") && (dictionary["QMAKESPEC"] != dictionary["XQMAKESPEC"])) {
|
||||
qmakeConfig += "cross_compile";
|
||||
dictionary["CROSS_COMPILE"] = "yes";
|
||||
@ -3387,6 +3404,8 @@ void Configure::generateConfigfiles()
|
||||
else
|
||||
qconfigList += "QT_NO_NIS";
|
||||
|
||||
if (dictionary["SCTP"] == "no") qconfigList += "QT_NO_SCTP";
|
||||
|
||||
if (dictionary["LARGE_FILE"] == "yes") qconfigList += "QT_LARGEFILE_SUPPORT=64";
|
||||
if (dictionary["QT_CUPS"] == "no") qconfigList += "QT_NO_CUPS";
|
||||
if (dictionary["QT_ICONV"] == "no") qconfigList += "QT_NO_ICONV";
|
||||
@ -3520,6 +3539,7 @@ void Configure::displayConfig()
|
||||
sout << "DirectWrite support........." << dictionary[ "DIRECTWRITE" ] << endl;
|
||||
sout << "DirectWrite 2 support......." << dictionary[ "DIRECTWRITE2" ] << endl;
|
||||
sout << "Use system proxies.........." << dictionary[ "SYSTEM_PROXIES" ] << endl;
|
||||
sout << "SCTP support................" << dictionary[ "SCTP" ] << endl;
|
||||
sout << endl;
|
||||
|
||||
sout << "QPA Backends:" << endl;
|
||||
|
Loading…
x
Reference in New Issue
Block a user