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.
|
-no-system-proxies ... Do not use system network proxies by default.
|
||||||
* -system-proxies ...... 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
|
-no-warnings-are-errors Make warnings be treated normally
|
||||||
-warnings-are-errors Make warnings be treated as errors
|
-warnings-are-errors Make warnings be treated as errors
|
||||||
(enabled if -developer-build is active)
|
(enabled if -developer-build is active)
|
||||||
|
@ -130,6 +130,7 @@
|
|||||||
"release": { "type": "enum", "name": "debug", "values": { "yes": "no", "no": "yes" } },
|
"release": { "type": "enum", "name": "debug", "values": { "yes": "no", "no": "yes" } },
|
||||||
"rpath": "boolean",
|
"rpath": "boolean",
|
||||||
"sanitize": "sanitize",
|
"sanitize": "sanitize",
|
||||||
|
"sctp": "boolean",
|
||||||
"sdk": "string",
|
"sdk": "string",
|
||||||
"securetransport": "boolean",
|
"securetransport": "boolean",
|
||||||
"separate-debug-info": { "type": "boolean", "name": "separate_debug_info" },
|
"separate-debug-info": { "type": "boolean", "name": "separate_debug_info" },
|
||||||
@ -596,6 +597,11 @@
|
|||||||
"type": "openssl",
|
"type": "openssl",
|
||||||
"libs": "-lssl -lcrypto"
|
"libs": "-lssl -lcrypto"
|
||||||
},
|
},
|
||||||
|
"sctp": {
|
||||||
|
"description": "SCTP support",
|
||||||
|
"type": "compile",
|
||||||
|
"test": "unix/sctp"
|
||||||
|
},
|
||||||
"icu": {
|
"icu": {
|
||||||
"description": "ICU",
|
"description": "ICU",
|
||||||
"type": "compile",
|
"type": "compile",
|
||||||
@ -1625,6 +1631,12 @@
|
|||||||
"condition": "features.securetransport || features.openssl",
|
"condition": "features.securetransport || features.openssl",
|
||||||
"output": [ "feature" ]
|
"output": [ "feature" ]
|
||||||
},
|
},
|
||||||
|
"sctp": {
|
||||||
|
"description": "SCTP",
|
||||||
|
"autoDetect": false,
|
||||||
|
"condition": "tests.sctp",
|
||||||
|
"output": [ "feature" ]
|
||||||
|
},
|
||||||
"accessibility": {
|
"accessibility": {
|
||||||
"description": "Accessibility",
|
"description": "Accessibility",
|
||||||
"output": [ "feature" ]
|
"output": [ "feature" ]
|
||||||
@ -2462,6 +2474,7 @@ Please apply the patch corresponding to your Standard Library vendor, found in
|
|||||||
},
|
},
|
||||||
"openssl",
|
"openssl",
|
||||||
"openssl-linked",
|
"openssl-linked",
|
||||||
|
"sctp",
|
||||||
"system-proxies"
|
"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):SUBDIRS += securesocketclient
|
||||||
contains(QT_CONFIG, openssl-linked):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);
|
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;
|
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
|
otherwise returns \c false. This function should be called from any
|
||||||
|
@ -154,6 +154,8 @@ public:
|
|||||||
return buffer.isEmpty() || (transactionStarted && isSequential()
|
return buffer.isEmpty() || (transactionStarted && isSequential()
|
||||||
&& transactionPos == buffer.size());
|
&& transactionPos == buffer.size());
|
||||||
}
|
}
|
||||||
|
bool allWriteBuffersEmpty() const;
|
||||||
|
|
||||||
void seekBuffer(qint64 newPos);
|
void seekBuffer(qint64 newPos);
|
||||||
|
|
||||||
inline void setCurrentReadChannel(int channel)
|
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:
|
private:
|
||||||
QNetworkDatagramPrivate *d;
|
QNetworkDatagramPrivate *d;
|
||||||
friend class QUdpSocket;
|
friend class QUdpSocket;
|
||||||
|
friend class QSctpSocket;
|
||||||
|
|
||||||
explicit QNetworkDatagram(QNetworkDatagramPrivate &dd);
|
explicit QNetworkDatagram(QNetworkDatagramPrivate &dd);
|
||||||
QNetworkDatagram makeReply_helper(const QByteArray &data) const;
|
QNetworkDatagram makeReply_helper(const QByteArray &data) const;
|
||||||
|
@ -54,7 +54,8 @@ class QIpPacketHeader
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
QIpPacketHeader(const QHostAddress &dstAddr = QHostAddress(), quint16 port = 0)
|
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()
|
void clear()
|
||||||
@ -63,6 +64,8 @@ public:
|
|||||||
destinationAddress.clear();
|
destinationAddress.clear();
|
||||||
ifindex = 0;
|
ifindex = 0;
|
||||||
hopLimit = -1;
|
hopLimit = -1;
|
||||||
|
streamNumber = -1;
|
||||||
|
endOfRecord = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
QHostAddress senderAddress;
|
QHostAddress senderAddress;
|
||||||
@ -70,8 +73,10 @@ public:
|
|||||||
|
|
||||||
uint ifindex;
|
uint ifindex;
|
||||||
int hopLimit;
|
int hopLimit;
|
||||||
|
int streamNumber;
|
||||||
quint16 senderPort;
|
quint16 senderPort;
|
||||||
quint16 destinationPort;
|
quint16 destinationPort;
|
||||||
|
bool endOfRecord;
|
||||||
};
|
};
|
||||||
|
|
||||||
class QNetworkDatagramPrivate
|
class QNetworkDatagramPrivate
|
||||||
@ -81,6 +86,9 @@ public:
|
|||||||
const QHostAddress &dstAddr = QHostAddress(), quint16 port = 0)
|
const QHostAddress &dstAddr = QHostAddress(), quint16 port = 0)
|
||||||
: data(data), header(dstAddr, port)
|
: data(data), header(dstAddr, port)
|
||||||
{}
|
{}
|
||||||
|
QNetworkDatagramPrivate(const QByteArray &data, const QIpPacketHeader &header)
|
||||||
|
: data(data), header(header)
|
||||||
|
{}
|
||||||
|
|
||||||
QByteArray data;
|
QByteArray data;
|
||||||
QIpPacketHeader header;
|
QIpPacketHeader header;
|
||||||
|
@ -212,6 +212,12 @@
|
|||||||
lookup on a remote host name and connect to it, as opposed to
|
lookup on a remote host name and connect to it, as opposed to
|
||||||
requiring the application to perform the name lookup and request
|
requiring the application to perform the name lookup and request
|
||||||
connection to IP addresses only.
|
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"
|
#include "qnetworkproxy.h"
|
||||||
@ -369,7 +375,9 @@ static QNetworkProxy::Capabilities defaultCapabilitiesForType(QNetworkProxy::Pro
|
|||||||
/* [QNetworkProxy::DefaultProxy] = */
|
/* [QNetworkProxy::DefaultProxy] = */
|
||||||
(int(QNetworkProxy::ListeningCapability) |
|
(int(QNetworkProxy::ListeningCapability) |
|
||||||
int(QNetworkProxy::TunnelingCapability) |
|
int(QNetworkProxy::TunnelingCapability) |
|
||||||
int(QNetworkProxy::UdpTunnelingCapability)),
|
int(QNetworkProxy::UdpTunnelingCapability) |
|
||||||
|
int(QNetworkProxy::SctpTunnelingCapability) |
|
||||||
|
int(QNetworkProxy::SctpListeningCapability)),
|
||||||
/* [QNetworkProxy::Socks5Proxy] = */
|
/* [QNetworkProxy::Socks5Proxy] = */
|
||||||
(int(QNetworkProxy::TunnelingCapability) |
|
(int(QNetworkProxy::TunnelingCapability) |
|
||||||
int(QNetworkProxy::ListeningCapability) |
|
int(QNetworkProxy::ListeningCapability) |
|
||||||
@ -379,7 +387,9 @@ static QNetworkProxy::Capabilities defaultCapabilitiesForType(QNetworkProxy::Pro
|
|||||||
/* [QNetworkProxy::NoProxy] = */
|
/* [QNetworkProxy::NoProxy] = */
|
||||||
(int(QNetworkProxy::ListeningCapability) |
|
(int(QNetworkProxy::ListeningCapability) |
|
||||||
int(QNetworkProxy::TunnelingCapability) |
|
int(QNetworkProxy::TunnelingCapability) |
|
||||||
int(QNetworkProxy::UdpTunnelingCapability)),
|
int(QNetworkProxy::UdpTunnelingCapability) |
|
||||||
|
int(QNetworkProxy::SctpTunnelingCapability) |
|
||||||
|
int(QNetworkProxy::SctpListeningCapability)),
|
||||||
/* [QNetworkProxy::HttpProxy] = */
|
/* [QNetworkProxy::HttpProxy] = */
|
||||||
(int(QNetworkProxy::TunnelingCapability) |
|
(int(QNetworkProxy::TunnelingCapability) |
|
||||||
int(QNetworkProxy::CachingCapability) |
|
int(QNetworkProxy::CachingCapability) |
|
||||||
@ -965,6 +975,14 @@ template<> void QSharedDataPointer<QNetworkProxyQueryPrivate>::detach()
|
|||||||
can all be used or be left unused, depending on the
|
can all be used or be left unused, depending on the
|
||||||
characteristics of the socket. The URL component is not used.
|
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
|
\row
|
||||||
\li TcpServer
|
\li TcpServer
|
||||||
\li Passive server sockets that listen on a port and await
|
\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
|
indicate that more detailed information is present in the URL
|
||||||
component. For ease of implementation, the URL's host and
|
component. For ease of implementation, the URL's host and
|
||||||
port are set as the destination address.
|
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
|
\endtable
|
||||||
|
|
||||||
It should be noted that any of the criteria may be missing or
|
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 TcpSocket a normal, outgoing TCP socket
|
||||||
\value UdpSocket a datagram-based UDP socket, which could send
|
\value UdpSocket a datagram-based UDP socket, which could send
|
||||||
to multiple destinations
|
to multiple destinations
|
||||||
|
\value SctpSocket a message-oriented, outgoing SCTP socket
|
||||||
\value TcpServer a TCP server that listens for incoming
|
\value TcpServer a TCP server that listens for incoming
|
||||||
connections from the network
|
connections from the network
|
||||||
\value UrlRequest a more complex request which involves loading
|
\value UrlRequest a more complex request which involves loading
|
||||||
of a URL
|
of a URL
|
||||||
|
\value SctpServer a SCTP server that listens for incoming
|
||||||
|
connections from the network
|
||||||
|
|
||||||
\sa queryType(), setQueryType()
|
\sa queryType(), setQueryType()
|
||||||
*/
|
*/
|
||||||
@ -1614,6 +1643,10 @@ QDebug operator<<(QDebug debug, const QNetworkProxy &proxy)
|
|||||||
scaps << QStringLiteral("Caching");
|
scaps << QStringLiteral("Caching");
|
||||||
if (caps & QNetworkProxy::HostNameLookupCapability)
|
if (caps & QNetworkProxy::HostNameLookupCapability)
|
||||||
scaps << QStringLiteral("NameLookup");
|
scaps << QStringLiteral("NameLookup");
|
||||||
|
if (caps & QNetworkProxy::SctpTunnelingCapability)
|
||||||
|
scaps << QStringLiteral("SctpTunnel");
|
||||||
|
if (caps & QNetworkProxy::SctpListeningCapability)
|
||||||
|
scaps << QStringLiteral("SctpListen");
|
||||||
debug << '[' << scaps.join(QLatin1Char(' ')) << ']';
|
debug << '[' << scaps.join(QLatin1Char(' ')) << ']';
|
||||||
return debug;
|
return debug;
|
||||||
}
|
}
|
||||||
|
@ -60,8 +60,10 @@ public:
|
|||||||
enum QueryType {
|
enum QueryType {
|
||||||
TcpSocket,
|
TcpSocket,
|
||||||
UdpSocket,
|
UdpSocket,
|
||||||
|
SctpSocket,
|
||||||
TcpServer = 100,
|
TcpServer = 100,
|
||||||
UrlRequest
|
UrlRequest,
|
||||||
|
SctpServer
|
||||||
};
|
};
|
||||||
|
|
||||||
QNetworkProxyQuery();
|
QNetworkProxyQuery();
|
||||||
@ -141,7 +143,9 @@ public:
|
|||||||
ListeningCapability = 0x0002,
|
ListeningCapability = 0x0002,
|
||||||
UdpTunnelingCapability = 0x0004,
|
UdpTunnelingCapability = 0x0004,
|
||||||
CachingCapability = 0x0008,
|
CachingCapability = 0x0008,
|
||||||
HostNameLookupCapability = 0x0010
|
HostNameLookupCapability = 0x0010,
|
||||||
|
SctpTunnelingCapability = 0x00020,
|
||||||
|
SctpListeningCapability = 0x00040
|
||||||
};
|
};
|
||||||
Q_DECLARE_FLAGS(Capabilities, Capability)
|
Q_DECLARE_FLAGS(Capabilities, Capability)
|
||||||
|
|
||||||
|
@ -232,9 +232,15 @@ static QList<QNetworkProxy> filterProxyListByCapabilities(const QList<QNetworkPr
|
|||||||
case QNetworkProxyQuery::UdpSocket:
|
case QNetworkProxyQuery::UdpSocket:
|
||||||
requiredCaps = QNetworkProxy::UdpTunnelingCapability;
|
requiredCaps = QNetworkProxy::UdpTunnelingCapability;
|
||||||
break;
|
break;
|
||||||
|
case QNetworkProxyQuery::SctpSocket:
|
||||||
|
requiredCaps = QNetworkProxy::SctpTunnelingCapability;
|
||||||
|
break;
|
||||||
case QNetworkProxyQuery::TcpServer:
|
case QNetworkProxyQuery::TcpServer:
|
||||||
requiredCaps = QNetworkProxy::ListeningCapability;
|
requiredCaps = QNetworkProxy::ListeningCapability;
|
||||||
break;
|
break;
|
||||||
|
case QNetworkProxyQuery::SctpServer:
|
||||||
|
requiredCaps = QNetworkProxy::SctpListeningCapability;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return proxyList;
|
return proxyList;
|
||||||
break;
|
break;
|
||||||
@ -281,7 +287,9 @@ static QList<QNetworkProxy> parseServerList(const QNetworkProxyQuery &query, con
|
|||||||
QList<QNetworkProxy> result;
|
QList<QNetworkProxy> result;
|
||||||
QHash<QString, QNetworkProxy> taggedProxies;
|
QHash<QString, QNetworkProxy> taggedProxies;
|
||||||
const QString requiredTag = query.protocolTag();
|
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) {
|
for (const QString &entry : proxyList) {
|
||||||
int server = 0;
|
int server = 0;
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ DEFINES += QT_NO_USING_NAMESPACE QT_NO_FOREACH
|
|||||||
#DEFINES += QABSTRACTSOCKET_DEBUG QNATIVESOCKETENGINE_DEBUG
|
#DEFINES += QABSTRACTSOCKET_DEBUG QNATIVESOCKETENGINE_DEBUG
|
||||||
#DEFINES += QTCPSOCKETENGINE_DEBUG QTCPSOCKET_DEBUG QTCPSERVER_DEBUG QSSLSOCKET_DEBUG
|
#DEFINES += QTCPSOCKETENGINE_DEBUG QTCPSOCKET_DEBUG QTCPSERVER_DEBUG QSSLSOCKET_DEBUG
|
||||||
#DEFINES += QUDPSOCKET_DEBUG QUDPSERVER_DEBUG
|
#DEFINES += QUDPSOCKET_DEBUG QUDPSERVER_DEBUG
|
||||||
|
#DEFINES += QSCTPSOCKET_DEBUG QSCTPSERVER_DEBUG
|
||||||
win32-msvc*|win32-icc:QMAKE_LFLAGS += /BASE:0x64000000
|
win32-msvc*|win32-icc:QMAKE_LFLAGS += /BASE:0x64000000
|
||||||
|
|
||||||
QMAKE_DOCS = $$PWD/doc/qtnetwork.qdocconf
|
QMAKE_DOCS = $$PWD/doc/qtnetwork.qdocconf
|
||||||
|
@ -267,7 +267,8 @@
|
|||||||
|
|
||||||
\value TcpSocket TCP
|
\value TcpSocket TCP
|
||||||
\value UdpSocket UDP
|
\value UdpSocket UDP
|
||||||
\value UnknownSocketType Other than TCP and UDP
|
\value SctpSocket SCTP
|
||||||
|
\value UnknownSocketType Other than TCP, UDP and SCTP
|
||||||
|
|
||||||
\sa QAbstractSocket::socketType()
|
\sa QAbstractSocket::socketType()
|
||||||
*/
|
*/
|
||||||
@ -626,6 +627,7 @@ bool QAbstractSocketPrivate::initSocketLayer(QAbstractSocket::NetworkLayerProtoc
|
|||||||
QString typeStr;
|
QString typeStr;
|
||||||
if (q->socketType() == QAbstractSocket::TcpSocket) typeStr = QLatin1String("TcpSocket");
|
if (q->socketType() == QAbstractSocket::TcpSocket) typeStr = QLatin1String("TcpSocket");
|
||||||
else if (q->socketType() == QAbstractSocket::UdpSocket) typeStr = QLatin1String("UdpSocket");
|
else if (q->socketType() == QAbstractSocket::UdpSocket) typeStr = QLatin1String("UdpSocket");
|
||||||
|
else if (q->socketType() == QAbstractSocket::SctpSocket) typeStr = QLatin1String("SctpSocket");
|
||||||
else typeStr = QLatin1String("UnknownSocketType");
|
else typeStr = QLatin1String("UnknownSocketType");
|
||||||
QString protocolStr;
|
QString protocolStr;
|
||||||
if (protocol == QAbstractSocket::IPv4Protocol) protocolStr = QLatin1String("IPv4Protocol");
|
if (protocol == QAbstractSocket::IPv4Protocol) protocolStr = QLatin1String("IPv4Protocol");
|
||||||
@ -670,6 +672,12 @@ bool QAbstractSocketPrivate::initSocketLayer(QAbstractSocket::NetworkLayerProtoc
|
|||||||
*/
|
*/
|
||||||
void QAbstractSocketPrivate::configureCreatedSocket()
|
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
|
/*! \internal
|
||||||
@ -771,7 +779,8 @@ void QAbstractSocketPrivate::canCloseNotification()
|
|||||||
|
|
||||||
QMetaObject::invokeMethod(socketEngine, "closeNotification", Qt::QueuedConnection);
|
QMetaObject::invokeMethod(socketEngine, "closeNotification", Qt::QueuedConnection);
|
||||||
}
|
}
|
||||||
} else if (socketType == QAbstractSocket::TcpSocket && socketEngine) {
|
} else if ((socketType == QAbstractSocket::TcpSocket ||
|
||||||
|
socketType == QAbstractSocket::SctpSocket) && socketEngine) {
|
||||||
emitReadyRead();
|
emitReadyRead();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -862,13 +871,9 @@ bool QAbstractSocketPrivate::writeToSocket()
|
|||||||
if (written > 0) {
|
if (written > 0) {
|
||||||
// Remove what we wrote so far.
|
// Remove what we wrote so far.
|
||||||
writeBuffer.free(written);
|
writeBuffer.free(written);
|
||||||
// Don't emit bytesWritten() recursively.
|
|
||||||
if (!emittedBytesWritten) {
|
// Emit notifications.
|
||||||
QScopedValueRollback<bool> r(emittedBytesWritten);
|
emitBytesWritten(written);
|
||||||
emittedBytesWritten = true;
|
|
||||||
emit q->bytesWritten(written);
|
|
||||||
}
|
|
||||||
emit q->channelBytesWritten(0, written);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (writeBuffer.isEmpty() && socketEngine && !socketEngine->bytesToWrite())
|
if (writeBuffer.isEmpty() && socketEngine && !socketEngine->bytesToWrite())
|
||||||
@ -889,7 +894,7 @@ bool QAbstractSocketPrivate::flush()
|
|||||||
{
|
{
|
||||||
bool dataWasWritten = false;
|
bool dataWasWritten = false;
|
||||||
|
|
||||||
while (!writeBuffer.isEmpty() && writeToSocket())
|
while (!allWriteBuffersEmpty() && writeToSocket())
|
||||||
dataWasWritten = true;
|
dataWasWritten = true;
|
||||||
|
|
||||||
return dataWasWritten;
|
return dataWasWritten;
|
||||||
@ -912,6 +917,8 @@ void QAbstractSocketPrivate::resolveProxy(const QString &hostname, quint16 port)
|
|||||||
QNetworkProxyQuery query(hostname, port, QString(),
|
QNetworkProxyQuery query(hostname, port, QString(),
|
||||||
socketType == QAbstractSocket::TcpSocket ?
|
socketType == QAbstractSocket::TcpSocket ?
|
||||||
QNetworkProxyQuery::TcpSocket :
|
QNetworkProxyQuery::TcpSocket :
|
||||||
|
socketType == QAbstractSocket::SctpSocket ?
|
||||||
|
QNetworkProxyQuery::SctpSocket :
|
||||||
QNetworkProxyQuery::UdpSocket);
|
QNetworkProxyQuery::UdpSocket);
|
||||||
proxies = QNetworkProxyFactory::proxyForQuery(query);
|
proxies = QNetworkProxyFactory::proxyForQuery(query);
|
||||||
}
|
}
|
||||||
@ -926,6 +933,10 @@ void QAbstractSocketPrivate::resolveProxy(const QString &hostname, quint16 port)
|
|||||||
(p.capabilities() & QNetworkProxy::TunnelingCapability) == 0)
|
(p.capabilities() & QNetworkProxy::TunnelingCapability) == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (socketType == QAbstractSocket::SctpSocket &&
|
||||||
|
(p.capabilities() & QNetworkProxy::SctpTunnelingCapability) == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
proxyInUse = p;
|
proxyInUse = p;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1280,16 +1291,34 @@ bool QAbstractSocketPrivate::readFromSocket()
|
|||||||
|
|
||||||
Prevents from the recursive readyRead() emission.
|
Prevents from the recursive readyRead() emission.
|
||||||
*/
|
*/
|
||||||
void QAbstractSocketPrivate::emitReadyRead()
|
void QAbstractSocketPrivate::emitReadyRead(int channel)
|
||||||
{
|
{
|
||||||
Q_Q(QAbstractSocket);
|
Q_Q(QAbstractSocket);
|
||||||
// Only emit readyRead() when not recursing.
|
// Only emit readyRead() when not recursing.
|
||||||
if (!emittedReadyRead) {
|
if (!emittedReadyRead && channel == currentReadChannel) {
|
||||||
QScopedValueRollback<bool> r(emittedReadyRead);
|
QScopedValueRollback<bool> r(emittedReadyRead);
|
||||||
emittedReadyRead = true;
|
emittedReadyRead = true;
|
||||||
emit q->readyRead();
|
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
|
/*! \internal
|
||||||
@ -1400,8 +1429,8 @@ QAbstractSocket::QAbstractSocket(SocketType socketType,
|
|||||||
Q_D(QAbstractSocket);
|
Q_D(QAbstractSocket);
|
||||||
#if defined(QABSTRACTSOCKET_DEBUG)
|
#if defined(QABSTRACTSOCKET_DEBUG)
|
||||||
qDebug("QAbstractSocket::QAbstractSocket(%sSocket, QAbstractSocketPrivate == %p, parent == %p)",
|
qDebug("QAbstractSocket::QAbstractSocket(%sSocket, QAbstractSocketPrivate == %p, parent == %p)",
|
||||||
socketType == TcpSocket ? "Tcp" : socketType == UdpSocket
|
socketType == TcpSocket ? "Tcp" : socketType == UdpSocket ? "Udp"
|
||||||
? "Udp" : "Unknown", &dd, parent);
|
: socketType == SctpSocket ? "Sctp" : "Unknown", &dd, parent);
|
||||||
#endif
|
#endif
|
||||||
d->socketType = socketType;
|
d->socketType = socketType;
|
||||||
}
|
}
|
||||||
@ -1665,9 +1694,9 @@ void QAbstractSocket::connectToHost(const QString &hostName, quint16 port,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (openMode & QIODevice::Unbuffered)
|
if (openMode & QIODevice::Unbuffered)
|
||||||
d->isBuffered = false; // Unbuffered QTcpSocket
|
d->isBuffered = false;
|
||||||
else if (!d_func()->isBuffered)
|
else if (!d_func()->isBuffered)
|
||||||
openMode |= QAbstractSocket::Unbuffered; // QUdpSocket
|
openMode |= QAbstractSocket::Unbuffered;
|
||||||
|
|
||||||
QIODevice::open(openMode);
|
QIODevice::open(openMode);
|
||||||
d->readChannelCount = d->writeChannelCount = 0;
|
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(),
|
qt_prettyDebug(data, qMin((int)size, 32), size).data(),
|
||||||
size, written);
|
size, written);
|
||||||
#endif
|
#endif
|
||||||
if (written >= 0) {
|
if (written >= 0)
|
||||||
emit bytesWritten(written);
|
d->emitBytesWritten(written);
|
||||||
emit channelBytesWritten(0, written);
|
|
||||||
}
|
|
||||||
return written;
|
return written;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2714,14 +2741,14 @@ void QAbstractSocket::disconnectFromHost()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Wait for pending data to be written.
|
// 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)) {
|
|| d->socketEngine->bytesToWrite() > 0)) {
|
||||||
// hack: when we are waiting for the socket engine to write bytes (only
|
// hack: when we are waiting for the socket engine to write bytes (only
|
||||||
// possible when using Socks5 or HTTP socket engine), then close
|
// possible when using Socks5 or HTTP socket engine), then close
|
||||||
// anyway after 2 seconds. This is to prevent a timeout on Mac, where we
|
// 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
|
// sometimes just did not get the write notifier from the underlying
|
||||||
// CFSocket and no progress was made.
|
// 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) {
|
if (!d->disconnectTimer) {
|
||||||
d->disconnectTimer = new QTimer(this);
|
d->disconnectTimer = new QTimer(this);
|
||||||
connect(d->disconnectTimer, SIGNAL(timeout()), this,
|
connect(d->disconnectTimer, SIGNAL(timeout()), this,
|
||||||
|
@ -64,6 +64,7 @@ public:
|
|||||||
enum SocketType {
|
enum SocketType {
|
||||||
TcpSocket,
|
TcpSocket,
|
||||||
UdpSocket,
|
UdpSocket,
|
||||||
|
SctpSocket,
|
||||||
UnknownSocketType = -1
|
UnknownSocketType = -1
|
||||||
};
|
};
|
||||||
Q_ENUM(SocketType)
|
Q_ENUM(SocketType)
|
||||||
|
@ -86,7 +86,7 @@ public:
|
|||||||
|
|
||||||
virtual bool bind(const QHostAddress &address, quint16 port, QAbstractSocket::BindMode mode);
|
virtual bool bind(const QHostAddress &address, quint16 port, QAbstractSocket::BindMode mode);
|
||||||
|
|
||||||
bool canReadNotification();
|
virtual bool canReadNotification();
|
||||||
bool canWriteNotification();
|
bool canWriteNotification();
|
||||||
void canCloseNotification();
|
void canCloseNotification();
|
||||||
|
|
||||||
@ -136,8 +136,9 @@ public:
|
|||||||
void startConnectingByName(const QString &host);
|
void startConnectingByName(const QString &host);
|
||||||
void fetchConnectionParameters();
|
void fetchConnectionParameters();
|
||||||
bool readFromSocket();
|
bool readFromSocket();
|
||||||
bool writeToSocket();
|
virtual bool writeToSocket();
|
||||||
void emitReadyRead();
|
void emitReadyRead(int channel = 0);
|
||||||
|
void emitBytesWritten(qint64 bytes, int channel = 0);
|
||||||
|
|
||||||
void setError(QAbstractSocket::SocketError errorCode, const QString &errorString);
|
void setError(QAbstractSocket::SocketError errorCode, const QString &errorString);
|
||||||
void setErrorAndEmit(QAbstractSocket::SocketError errorCode, const QString &errorString);
|
void setErrorAndEmit(QAbstractSocket::SocketError errorCode, const QString &errorString);
|
||||||
|
@ -104,7 +104,8 @@ public:
|
|||||||
MulticastLoopbackOption,
|
MulticastLoopbackOption,
|
||||||
TypeOfServiceOption,
|
TypeOfServiceOption,
|
||||||
ReceivePacketInformation,
|
ReceivePacketInformation,
|
||||||
ReceiveHopLimit
|
ReceiveHopLimit,
|
||||||
|
MaxStreamsSocketOption
|
||||||
};
|
};
|
||||||
|
|
||||||
enum PacketHeaderOption {
|
enum PacketHeaderOption {
|
||||||
@ -112,6 +113,8 @@ public:
|
|||||||
WantDatagramSender = 0x01,
|
WantDatagramSender = 0x01,
|
||||||
WantDatagramDestination = 0x02,
|
WantDatagramDestination = 0x02,
|
||||||
WantDatagramHopLimit = 0x04,
|
WantDatagramHopLimit = 0x04,
|
||||||
|
WantStreamNumber = 0x08,
|
||||||
|
WantEndOfRecord = 0x10,
|
||||||
|
|
||||||
WantAll = 0xff
|
WantAll = 0xff
|
||||||
};
|
};
|
||||||
@ -147,13 +150,13 @@ public:
|
|||||||
virtual bool setMulticastInterface(const QNetworkInterface &iface) = 0;
|
virtual bool setMulticastInterface(const QNetworkInterface &iface) = 0;
|
||||||
#endif // QT_NO_NETWORKINTERFACE
|
#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 bool hasPendingDatagrams() const = 0;
|
||||||
virtual qint64 pendingDatagramSize() const = 0;
|
virtual qint64 pendingDatagramSize() const = 0;
|
||||||
#endif // QT_NO_UDPSOCKET
|
#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 qint64 bytesToWrite() const = 0;
|
||||||
|
|
||||||
virtual int option(SocketOption option) const = 0;
|
virtual int option(SocketOption option) const = 0;
|
||||||
|
@ -289,6 +289,19 @@ bool QHttpSocketEngine::setMulticastInterface(const QNetworkInterface &)
|
|||||||
}
|
}
|
||||||
#endif // QT_NO_NETWORKINTERFACE
|
#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)
|
qint64 QHttpSocketEngine::readDatagram(char *, qint64, QIpPacketHeader *, PacketHeaderOptions)
|
||||||
{
|
{
|
||||||
qWarning("Operation is not supported");
|
qWarning("Operation is not supported");
|
||||||
@ -305,19 +318,6 @@ qint64 QHttpSocketEngine::writeDatagram(const char *, qint64, const QIpPacketHea
|
|||||||
return -1;
|
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
|
qint64 QHttpSocketEngine::bytesToWrite() const
|
||||||
{
|
{
|
||||||
Q_D(const QHttpSocketEngine);
|
Q_D(const QHttpSocketEngine);
|
||||||
|
@ -112,13 +112,13 @@ public:
|
|||||||
bool setMulticastInterface(const QNetworkInterface &iface) Q_DECL_OVERRIDE;
|
bool setMulticastInterface(const QNetworkInterface &iface) Q_DECL_OVERRIDE;
|
||||||
#endif // QT_NO_NETWORKINTERFACE
|
#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;
|
bool hasPendingDatagrams() const Q_DECL_OVERRIDE;
|
||||||
qint64 pendingDatagramSize() const Q_DECL_OVERRIDE;
|
qint64 pendingDatagramSize() const Q_DECL_OVERRIDE;
|
||||||
#endif // QT_NO_UDPSOCKET
|
#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;
|
qint64 bytesToWrite() const Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
int option(SocketOption option) const Q_DECL_OVERRIDE;
|
int option(SocketOption option) const Q_DECL_OVERRIDE;
|
||||||
|
@ -174,6 +174,12 @@ QT_BEGIN_NAMESPACE
|
|||||||
" socket other than "#type""); \
|
" socket other than "#type""); \
|
||||||
return (returnValue); \
|
return (returnValue); \
|
||||||
} } while (0)
|
} } 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)
|
#define Q_TR(a) QT_TRANSLATE_NOOP(QNativeSocketEngine, a)
|
||||||
|
|
||||||
/*! \internal
|
/*! \internal
|
||||||
@ -417,6 +423,7 @@ bool QNativeSocketEngine::initialize(QAbstractSocket::SocketType socketType, QAb
|
|||||||
QString typeStr = QLatin1String("UnknownSocketType");
|
QString typeStr = QLatin1String("UnknownSocketType");
|
||||||
if (socketType == QAbstractSocket::TcpSocket) typeStr = QLatin1String("TcpSocket");
|
if (socketType == QAbstractSocket::TcpSocket) typeStr = QLatin1String("TcpSocket");
|
||||||
else if (socketType == QAbstractSocket::UdpSocket) typeStr = QLatin1String("UdpSocket");
|
else if (socketType == QAbstractSocket::UdpSocket) typeStr = QLatin1String("UdpSocket");
|
||||||
|
else if (socketType == QAbstractSocket::SctpSocket) typeStr = QLatin1String("SctpSocket");
|
||||||
QString protocolStr = QLatin1String("UnknownProtocol");
|
QString protocolStr = QLatin1String("UnknownProtocol");
|
||||||
if (protocol == QAbstractSocket::IPv4Protocol) protocolStr = QLatin1String("IPv4Protocol");
|
if (protocol == QAbstractSocket::IPv4Protocol) protocolStr = QLatin1String("IPv4Protocol");
|
||||||
else if (protocol == QAbstractSocket::IPv6Protocol) protocolStr = QLatin1String("IPv6Protocol");
|
else if (protocol == QAbstractSocket::IPv6Protocol) protocolStr = QLatin1String("IPv6Protocol");
|
||||||
@ -659,7 +666,12 @@ bool QNativeSocketEngine::listen()
|
|||||||
Q_D(QNativeSocketEngine);
|
Q_D(QNativeSocketEngine);
|
||||||
Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::listen(), false);
|
Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::listen(), false);
|
||||||
Q_CHECK_STATE(QNativeSocketEngine::listen(), QAbstractSocket::BoundState, 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);
|
Q_CHECK_TYPE(QNativeSocketEngine::listen(), QAbstractSocket::TcpSocket, false);
|
||||||
|
#endif
|
||||||
|
|
||||||
// We're using a backlog of 50. Most modern kernels support TCP
|
// We're using a backlog of 50. Most modern kernels support TCP
|
||||||
// syncookies by default, and if they do, the backlog is ignored.
|
// syncookies by default, and if they do, the backlog is ignored.
|
||||||
@ -680,7 +692,12 @@ int QNativeSocketEngine::accept()
|
|||||||
Q_D(QNativeSocketEngine);
|
Q_D(QNativeSocketEngine);
|
||||||
Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::accept(), -1);
|
Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::accept(), -1);
|
||||||
Q_CHECK_STATE(QNativeSocketEngine::accept(), QAbstractSocket::ListeningState, -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);
|
Q_CHECK_TYPE(QNativeSocketEngine::accept(), QAbstractSocket::TcpSocket, -1);
|
||||||
|
#endif
|
||||||
|
|
||||||
return d->nativeAccept();
|
return d->nativeAccept();
|
||||||
}
|
}
|
||||||
@ -793,6 +810,7 @@ qint64 QNativeSocketEngine::pendingDatagramSize() const
|
|||||||
|
|
||||||
return d->nativePendingDatagramSize();
|
return d->nativePendingDatagramSize();
|
||||||
}
|
}
|
||||||
|
#endif // QT_NO_UDPSOCKET
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Reads up to \a maxSize bytes of a datagram from the socket,
|
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
|
address, port, and other IP header fields are stored in \a header
|
||||||
according to the request in \a options.
|
according to the request in \a options.
|
||||||
|
|
||||||
To avoid unnecessarily loss of data, call pendingDatagramSize() to
|
For UDP sockets, to avoid unnecessarily loss of data, call
|
||||||
determine the size of the pending message before reading it. If \a
|
pendingDatagramSize() to determine the size of the pending message
|
||||||
maxSize is too small, the rest of the datagram will be lost.
|
before reading it. If \a maxSize is too small, the rest of the
|
||||||
|
datagram will be lost.
|
||||||
|
|
||||||
Returns -1 if an error occurred.
|
Returns -1 if an error occurred.
|
||||||
|
|
||||||
@ -813,13 +832,14 @@ qint64 QNativeSocketEngine::readDatagram(char *data, qint64 maxSize, QIpPacketHe
|
|||||||
{
|
{
|
||||||
Q_D(QNativeSocketEngine);
|
Q_D(QNativeSocketEngine);
|
||||||
Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::readDatagram(), -1);
|
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);
|
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
|
\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
|
number of bytes written, or -1 if an error occurred. If \a header
|
||||||
contains other settings like hop limit or source address, this function
|
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_D(QNativeSocketEngine);
|
||||||
Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::writeDatagram(), -1);
|
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);
|
return d->nativeSendDatagram(data, size, header);
|
||||||
}
|
}
|
||||||
#endif // QT_NO_UDPSOCKET
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Writes a block of \a size bytes from \a data to the socket.
|
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);
|
qint64 readBytes = d->nativeRead(data, maxSize);
|
||||||
|
|
||||||
// Handle remote close
|
// 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,
|
d->setError(QAbstractSocket::RemoteHostClosedError,
|
||||||
QNativeSocketEnginePrivate::RemoteHostClosedErrorString);
|
QNativeSocketEnginePrivate::RemoteHostClosedErrorString);
|
||||||
close();
|
close();
|
||||||
|
@ -157,13 +157,13 @@ public:
|
|||||||
bool setMulticastInterface(const QNetworkInterface &iface) Q_DECL_OVERRIDE;
|
bool setMulticastInterface(const QNetworkInterface &iface) Q_DECL_OVERRIDE;
|
||||||
#endif
|
#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;
|
bool hasPendingDatagrams() const Q_DECL_OVERRIDE;
|
||||||
qint64 pendingDatagramSize() const Q_DECL_OVERRIDE;
|
qint64 pendingDatagramSize() const Q_DECL_OVERRIDE;
|
||||||
#endif // QT_NO_UDPSOCKET
|
#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 bytesToWrite() const Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
qint64 receiveBufferSize() const;
|
qint64 receiveBufferSize() const;
|
||||||
|
@ -68,6 +68,11 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <netinet/tcp.h>
|
#include <netinet/tcp.h>
|
||||||
|
#ifndef QT_NO_SCTP
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/sctp.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
@ -142,6 +147,7 @@ static void convertToLevelAndOption(QNativeSocketEngine::SocketOption opt,
|
|||||||
switch (opt) {
|
switch (opt) {
|
||||||
case QNativeSocketEngine::NonBlockingSocketOption: // fcntl, not setsockopt
|
case QNativeSocketEngine::NonBlockingSocketOption: // fcntl, not setsockopt
|
||||||
case QNativeSocketEngine::BindExclusively: // not handled on Unix
|
case QNativeSocketEngine::BindExclusively: // not handled on Unix
|
||||||
|
case QNativeSocketEngine::MaxStreamsSocketOption:
|
||||||
Q_UNREACHABLE();
|
Q_UNREACHABLE();
|
||||||
|
|
||||||
case QNativeSocketEngine::BroadcastSocketOption:
|
case QNativeSocketEngine::BroadcastSocketOption:
|
||||||
@ -229,13 +235,28 @@ static void convertToLevelAndOption(QNativeSocketEngine::SocketOption opt,
|
|||||||
bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType socketType,
|
bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType socketType,
|
||||||
QAbstractSocket::NetworkLayerProtocol &socketProtocol)
|
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 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) {
|
if (socket < 0 && socketProtocol == QAbstractSocket::AnyIPProtocol && errno == EAFNOSUPPORT) {
|
||||||
protocol = AF_INET;
|
domain = AF_INET;
|
||||||
socket = qt_safe_socket(protocol, type, 0, O_NONBLOCK);
|
socket = qt_safe_socket(domain, type, protocol, O_NONBLOCK);
|
||||||
socketProtocol = QAbstractSocket::IPv4Protocol;
|
socketProtocol = QAbstractSocket::IPv4Protocol;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -291,10 +312,26 @@ int QNativeSocketEnginePrivate::option(QNativeSocketEngine::SocketOption opt) co
|
|||||||
if (!q->isValid())
|
if (!q->isValid())
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
// handle non-getsockopt cases first
|
// handle non-getsockopt and specific cases first
|
||||||
if (opt == QNativeSocketEngine::BindExclusively || opt == QNativeSocketEngine::NonBlockingSocketOption
|
switch (opt) {
|
||||||
|| opt == QNativeSocketEngine::BroadcastSocketOption)
|
case QNativeSocketEngine::BindExclusively:
|
||||||
|
case QNativeSocketEngine::NonBlockingSocketOption:
|
||||||
|
case QNativeSocketEngine::BroadcastSocketOption:
|
||||||
return true;
|
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 n, level;
|
||||||
int v = -1;
|
int v = -1;
|
||||||
@ -317,7 +354,7 @@ bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt
|
|||||||
if (!q->isValid())
|
if (!q->isValid())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// handle non-setsockopt cases first
|
// handle non-setsockopt and specific cases first
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case QNativeSocketEngine::NonBlockingSocketOption: {
|
case QNativeSocketEngine::NonBlockingSocketOption: {
|
||||||
// Make the socket nonblocking.
|
// Make the socket nonblocking.
|
||||||
@ -351,6 +388,20 @@ bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt
|
|||||||
case QNativeSocketEngine::BindExclusively:
|
case QNativeSocketEngine::BindExclusively:
|
||||||
return true;
|
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:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -829,6 +880,9 @@ qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxS
|
|||||||
quintptr cbuf[(CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(sizeof(int))
|
quintptr cbuf[(CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(sizeof(int))
|
||||||
#if !defined(IP_PKTINFO) && defined(IP_RECVIF) && defined(Q_OS_BSD4)
|
#if !defined(IP_PKTINFO) && defined(IP_RECVIF) && defined(Q_OS_BSD4)
|
||||||
+ CMSG_SPACE(sizeof(sockaddr_dl))
|
+ CMSG_SPACE(sizeof(sockaddr_dl))
|
||||||
|
#endif
|
||||||
|
#ifndef QT_NO_SCTP
|
||||||
|
+ CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))
|
||||||
#endif
|
#endif
|
||||||
+ sizeof(quintptr) - 1) / sizeof(quintptr)];
|
+ sizeof(quintptr) - 1) / sizeof(quintptr)];
|
||||||
|
|
||||||
@ -848,7 +902,8 @@ qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxS
|
|||||||
msg.msg_name = &aa;
|
msg.msg_name = &aa;
|
||||||
msg.msg_namelen = sizeof(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_control = cbuf;
|
||||||
msg.msg_controllen = sizeof(cbuf);
|
msg.msg_controllen = sizeof(cbuf);
|
||||||
}
|
}
|
||||||
@ -859,13 +914,27 @@ qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxS
|
|||||||
} while (recvResult == -1 && errno == EINTR);
|
} while (recvResult == -1 && errno == EINTR);
|
||||||
|
|
||||||
if (recvResult == -1) {
|
if (recvResult == -1) {
|
||||||
|
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);
|
setError(QAbstractSocket::NetworkError, ReceiveDatagramErrorString);
|
||||||
|
}
|
||||||
if (header)
|
if (header)
|
||||||
header->clear();
|
header->clear();
|
||||||
} else if (options != QAbstractSocketEngine::WantNone) {
|
} else if (options != QAbstractSocketEngine::WantNone) {
|
||||||
Q_ASSERT(header);
|
Q_ASSERT(header);
|
||||||
qt_socket_getPortAndAddress(&aa, &header->senderPort, &header->senderAddress);
|
qt_socket_getPortAndAddress(&aa, &header->senderPort, &header->senderAddress);
|
||||||
header->destinationPort = localPort;
|
header->destinationPort = localPort;
|
||||||
|
header->endOfRecord = (msg.msg_flags & MSG_EOR) != 0;
|
||||||
|
|
||||||
// parse the ancillary data
|
// parse the ancillary data
|
||||||
struct cmsghdr *cmsgptr;
|
struct cmsghdr *cmsgptr;
|
||||||
@ -912,6 +981,15 @@ qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxS
|
|||||||
|| (cmsgptr->cmsg_level == IPPROTO_IP && cmsgptr->cmsg_type == IP_TTL))) {
|
|| (cmsgptr->cmsg_level == IPPROTO_IP && cmsgptr->cmsg_type == IP_TTL))) {
|
||||||
header->hopLimit = *reinterpret_cast<int *>(CMSG_DATA(cmsgptr));
|
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);
|
? header->senderPort : 0, (qint64) recvResult);
|
||||||
#endif
|
#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)
|
qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 len, const QIpPacketHeader &header)
|
||||||
{
|
{
|
||||||
// we use quintptr to force the alignment
|
// 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 cmsghdr *cmsgptr = reinterpret_cast<struct cmsghdr *>(cbuf);
|
||||||
struct msghdr msg;
|
struct msghdr msg;
|
||||||
@ -943,10 +1025,13 @@ qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 l
|
|||||||
vec.iov_len = len;
|
vec.iov_len = len;
|
||||||
msg.msg_iov = &vec;
|
msg.msg_iov = &vec;
|
||||||
msg.msg_iovlen = 1;
|
msg.msg_iovlen = 1;
|
||||||
msg.msg_name = &aa.a;
|
|
||||||
msg.msg_control = &cbuf;
|
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 (msg.msg_namelen == sizeof(aa.a6)) {
|
||||||
if (header.hopLimit != -1) {
|
if (header.hopLimit != -1) {
|
||||||
@ -1001,15 +1086,37 @@ qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 l
|
|||||||
#endif
|
#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)
|
if (msg.msg_controllen == 0)
|
||||||
msg.msg_control = 0;
|
msg.msg_control = 0;
|
||||||
ssize_t sentBytes = qt_safe_sendmsg(socketDescriptor, &msg, 0);
|
ssize_t sentBytes = qt_safe_sendmsg(socketDescriptor, &msg, 0);
|
||||||
|
|
||||||
if (sentBytes < 0) {
|
if (sentBytes < 0) {
|
||||||
switch (errno) {
|
switch (errno) {
|
||||||
|
#if EWOULDBLOCK-0 && EWOULDBLOCK != EAGAIN
|
||||||
|
case EWOULDBLOCK:
|
||||||
|
#endif
|
||||||
|
case EAGAIN:
|
||||||
|
sentBytes = -2;
|
||||||
|
break;
|
||||||
case EMSGSIZE:
|
case EMSGSIZE:
|
||||||
setError(QAbstractSocket::DatagramTooLargeError, DatagramTooLargeErrorString);
|
setError(QAbstractSocket::DatagramTooLargeError, DatagramTooLargeErrorString);
|
||||||
break;
|
break;
|
||||||
|
case ECONNRESET:
|
||||||
|
setError(QAbstractSocket::RemoteHostClosedError, RemoteHostClosedErrorString);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
setError(QAbstractSocket::NetworkError, SendDatagramErrorString);
|
setError(QAbstractSocket::NetworkError, SendDatagramErrorString);
|
||||||
}
|
}
|
||||||
@ -1082,22 +1189,52 @@ bool QNativeSocketEnginePrivate::fetchConnectionParameters()
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Determine the remote address
|
// 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);
|
qt_socket_getPortAndAddress(&sa, &peerPort, &peerAddress);
|
||||||
inboundStreamCount = outboundStreamCount = 1;
|
inboundStreamCount = outboundStreamCount = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine the socket type (UDP/TCP)
|
// Determine the socket type (UDP/TCP/SCTP)
|
||||||
int value = 0;
|
int value = 0;
|
||||||
QT_SOCKOPTLEN_T valueSize = sizeof(int);
|
QT_SOCKOPTLEN_T valueSize = sizeof(int);
|
||||||
if (::getsockopt(socketDescriptor, SOL_SOCKET, SO_TYPE, &value, &valueSize) == 0) {
|
if (::getsockopt(socketDescriptor, SOL_SOCKET, SO_TYPE, &value, &valueSize) == 0) {
|
||||||
if (value == SOCK_STREAM)
|
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;
|
socketType = QAbstractSocket::TcpSocket;
|
||||||
else if (value == SOCK_DGRAM)
|
}
|
||||||
|
#else
|
||||||
|
socketType = QAbstractSocket::TcpSocket;
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
if (value == SOCK_DGRAM)
|
||||||
socketType = QAbstractSocket::UdpSocket;
|
socketType = QAbstractSocket::UdpSocket;
|
||||||
else
|
else
|
||||||
socketType = QAbstractSocket::UnknownSocketType;
|
socketType = QAbstractSocket::UnknownSocketType;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
#if defined (QNATIVESOCKETENGINE_DEBUG)
|
#if defined (QNATIVESOCKETENGINE_DEBUG)
|
||||||
QString socketProtocolStr = QStringLiteral("UnknownProtocol");
|
QString socketProtocolStr = QStringLiteral("UnknownProtocol");
|
||||||
if (socketProtocol == QAbstractSocket::IPv4Protocol) socketProtocolStr = QStringLiteral("IPv4Protocol");
|
if (socketProtocol == QAbstractSocket::IPv4Protocol) socketProtocolStr = QStringLiteral("IPv4Protocol");
|
||||||
@ -1106,6 +1243,7 @@ bool QNativeSocketEnginePrivate::fetchConnectionParameters()
|
|||||||
QString socketTypeStr = QStringLiteral("UnknownSocketType");
|
QString socketTypeStr = QStringLiteral("UnknownSocketType");
|
||||||
if (socketType == QAbstractSocket::TcpSocket) socketTypeStr = QStringLiteral("TcpSocket");
|
if (socketType == QAbstractSocket::TcpSocket) socketTypeStr = QStringLiteral("TcpSocket");
|
||||||
else if (socketType == QAbstractSocket::UdpSocket) socketTypeStr = QStringLiteral("UdpSocket");
|
else if (socketType == QAbstractSocket::UdpSocket) socketTypeStr = QStringLiteral("UdpSocket");
|
||||||
|
else if (socketType == QAbstractSocket::SctpSocket) socketTypeStr = QStringLiteral("SctpSocket");
|
||||||
|
|
||||||
qDebug("QNativeSocketEnginePrivate::fetchConnectionParameters() local == %s:%i,"
|
qDebug("QNativeSocketEnginePrivate::fetchConnectionParameters() local == %s:%i,"
|
||||||
" peer == %s:%i, socket == %s - %s, inboundStreamCount == %i, outboundStreamCount == %i",
|
" peer == %s:%i, socket == %s - %s, inboundStreamCount == %i, outboundStreamCount == %i",
|
||||||
|
@ -214,6 +214,7 @@ static void convertToLevelAndOption(QNativeSocketEngine::SocketOption opt,
|
|||||||
switch (opt) {
|
switch (opt) {
|
||||||
case QNativeSocketEngine::NonBlockingSocketOption: // WSAIoctl
|
case QNativeSocketEngine::NonBlockingSocketOption: // WSAIoctl
|
||||||
case QNativeSocketEngine::TypeOfServiceOption: // not supported
|
case QNativeSocketEngine::TypeOfServiceOption: // not supported
|
||||||
|
case QNativeSocketEngine::MaxStreamsSocketOption:
|
||||||
Q_UNREACHABLE();
|
Q_UNREACHABLE();
|
||||||
|
|
||||||
case QNativeSocketEngine::ReceiveBufferSocketOption:
|
case QNativeSocketEngine::ReceiveBufferSocketOption:
|
||||||
@ -325,6 +326,14 @@ bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType soc
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
//### SCTP not implemented
|
||||||
|
if (socketType == QAbstractSocket::SctpSocket) {
|
||||||
|
setError(QAbstractSocket::UnsupportedSocketOperationError,
|
||||||
|
ProtocolUnsupportedErrorString);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
QSysInfo::WinVersion osver = QSysInfo::windowsVersion();
|
QSysInfo::WinVersion osver = QSysInfo::windowsVersion();
|
||||||
|
|
||||||
//Windows XP and 2003 support IPv6 but not dual stack sockets
|
//Windows XP and 2003 support IPv6 but not dual stack sockets
|
||||||
@ -451,6 +460,7 @@ int QNativeSocketEnginePrivate::option(QNativeSocketEngine::SocketOption opt) co
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case QNativeSocketEngine::TypeOfServiceOption:
|
case QNativeSocketEngine::TypeOfServiceOption:
|
||||||
|
case QNativeSocketEngine::MaxStreamsSocketOption:
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -501,6 +511,7 @@ bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case QNativeSocketEngine::TypeOfServiceOption:
|
case QNativeSocketEngine::TypeOfServiceOption:
|
||||||
|
case QNativeSocketEngine::MaxStreamsSocketOption:
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -632,6 +632,7 @@ qint64 QNativeSocketEngine::write(const char *data, qint64 len)
|
|||||||
qint64 QNativeSocketEngine::readDatagram(char *data, qint64 maxlen, QIpPacketHeader *header,
|
qint64 QNativeSocketEngine::readDatagram(char *data, qint64 maxlen, QIpPacketHeader *header,
|
||||||
PacketHeaderOptions)
|
PacketHeaderOptions)
|
||||||
{
|
{
|
||||||
|
#ifndef QT_NO_UDPSOCKET
|
||||||
Q_D(QNativeSocketEngine);
|
Q_D(QNativeSocketEngine);
|
||||||
if (d->socketType != QAbstractSocket::UdpSocket || d->pendingDatagrams.isEmpty()) {
|
if (d->socketType != QAbstractSocket::UdpSocket || d->pendingDatagrams.isEmpty()) {
|
||||||
if (header)
|
if (header)
|
||||||
@ -654,10 +655,17 @@ qint64 QNativeSocketEngine::readDatagram(char *data, qint64 maxlen, QIpPacketHea
|
|||||||
}
|
}
|
||||||
memcpy(data, readOrigin, qMin(maxlen, qint64(datagram.data.length())));
|
memcpy(data, readOrigin, qMin(maxlen, qint64(datagram.data.length())));
|
||||||
return readOrigin.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)
|
qint64 QNativeSocketEngine::writeDatagram(const char *data, qint64 len, const QIpPacketHeader &header)
|
||||||
{
|
{
|
||||||
|
#ifndef QT_NO_UDPSOCKET
|
||||||
Q_D(QNativeSocketEngine);
|
Q_D(QNativeSocketEngine);
|
||||||
if (d->socketType != QAbstractSocket::UdpSocket)
|
if (d->socketType != QAbstractSocket::UdpSocket)
|
||||||
return -1;
|
return -1;
|
||||||
@ -684,6 +692,12 @@ qint64 QNativeSocketEngine::writeDatagram(const char *data, qint64 len, const QI
|
|||||||
Q_ASSERT_SUCCEEDED(hr);
|
Q_ASSERT_SUCCEEDED(hr);
|
||||||
|
|
||||||
return writeIOStream(stream, data, len);
|
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
|
bool QNativeSocketEngine::hasPendingDatagrams() const
|
||||||
@ -1088,6 +1102,7 @@ int QNativeSocketEnginePrivate::option(QAbstractSocketEngine::SocketOption opt)
|
|||||||
case QAbstractSocketEngine::MulticastTtlOption:
|
case QAbstractSocketEngine::MulticastTtlOption:
|
||||||
case QAbstractSocketEngine::MulticastLoopbackOption:
|
case QAbstractSocketEngine::MulticastLoopbackOption:
|
||||||
case QAbstractSocketEngine::TypeOfServiceOption:
|
case QAbstractSocketEngine::TypeOfServiceOption:
|
||||||
|
case QAbstractSocketEngine::MaxStreamsSocketOption:
|
||||||
default:
|
default:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -1146,6 +1161,7 @@ bool QNativeSocketEnginePrivate::setOption(QAbstractSocketEngine::SocketOption o
|
|||||||
case QAbstractSocketEngine::MulticastTtlOption:
|
case QAbstractSocketEngine::MulticastTtlOption:
|
||||||
case QAbstractSocketEngine::MulticastLoopbackOption:
|
case QAbstractSocketEngine::MulticastLoopbackOption:
|
||||||
case QAbstractSocketEngine::TypeOfServiceOption:
|
case QAbstractSocketEngine::TypeOfServiceOption:
|
||||||
|
case QAbstractSocketEngine::MaxStreamsSocketOption:
|
||||||
default:
|
default:
|
||||||
return false;
|
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
|
#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)
|
qint64 QSocks5SocketEngine::readDatagram(char *data, qint64 maxlen, QIpPacketHeader *header, PacketHeaderOptions)
|
||||||
{
|
{
|
||||||
|
#ifndef QT_NO_UDPSOCKET
|
||||||
Q_D(QSocks5SocketEngine);
|
Q_D(QSocks5SocketEngine);
|
||||||
|
|
||||||
d->checkForDatagrams();
|
d->checkForDatagrams();
|
||||||
@ -1620,10 +1643,17 @@ qint64 QSocks5SocketEngine::readDatagram(char *data, qint64 maxlen, QIpPacketHea
|
|||||||
header->senderAddress = datagram.address;
|
header->senderAddress = datagram.address;
|
||||||
header->senderPort = datagram.port;
|
header->senderPort = datagram.port;
|
||||||
return copyLen;
|
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)
|
qint64 QSocks5SocketEngine::writeDatagram(const char *data, qint64 len, const QIpPacketHeader &header)
|
||||||
{
|
{
|
||||||
|
#ifndef QT_NO_UDPSOCKET
|
||||||
Q_D(QSocks5SocketEngine);
|
Q_D(QSocks5SocketEngine);
|
||||||
|
|
||||||
// it is possible to send with out first binding with udp, but socks5 requires a bind.
|
// 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;
|
return len;
|
||||||
}
|
#else
|
||||||
|
Q_UNUSED(data)
|
||||||
bool QSocks5SocketEngine::hasPendingDatagrams() const
|
Q_UNUSED(len)
|
||||||
{
|
Q_UNUSED(header)
|
||||||
Q_D(const QSocks5SocketEngine);
|
return -1;
|
||||||
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
|
#endif // QT_NO_UDPSOCKET
|
||||||
|
}
|
||||||
|
|
||||||
qint64 QSocks5SocketEngine::bytesToWrite() const
|
qint64 QSocks5SocketEngine::bytesToWrite() const
|
||||||
{
|
{
|
||||||
|
@ -100,13 +100,13 @@ public:
|
|||||||
bool setMulticastInterface(const QNetworkInterface &iface) Q_DECL_OVERRIDE;
|
bool setMulticastInterface(const QNetworkInterface &iface) Q_DECL_OVERRIDE;
|
||||||
#endif // QT_NO_NETWORKINTERFACE
|
#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;
|
bool hasPendingDatagrams() const Q_DECL_OVERRIDE;
|
||||||
qint64 pendingDatagramSize() const Q_DECL_OVERRIDE;
|
qint64 pendingDatagramSize() const Q_DECL_OVERRIDE;
|
||||||
#endif // QT_NO_UDPSOCKET
|
#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 bytesToWrite() const Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
int option(SocketOption option) const Q_DECL_OVERRIDE;
|
int option(SocketOption option) const Q_DECL_OVERRIDE;
|
||||||
|
@ -119,6 +119,7 @@ QT_BEGIN_NAMESPACE
|
|||||||
*/
|
*/
|
||||||
QTcpServerPrivate::QTcpServerPrivate()
|
QTcpServerPrivate::QTcpServerPrivate()
|
||||||
: port(0)
|
: port(0)
|
||||||
|
, socketType(QAbstractSocket::UnknownSocketType)
|
||||||
, state(QAbstractSocket::UnconnectedState)
|
, state(QAbstractSocket::UnconnectedState)
|
||||||
, socketEngine(0)
|
, socketEngine(0)
|
||||||
, serverSocketError(QAbstractSocket::UnknownSocketError)
|
, serverSocketError(QAbstractSocket::UnknownSocketError)
|
||||||
@ -148,13 +149,21 @@ QNetworkProxy QTcpServerPrivate::resolveProxy(const QHostAddress &address, quint
|
|||||||
proxies << proxy;
|
proxies << proxy;
|
||||||
} else {
|
} else {
|
||||||
// try the application settings instead
|
// 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);
|
proxies = QNetworkProxyFactory::proxyForQuery(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
// return the first that we can use
|
// return the first that we can use
|
||||||
for (const QNetworkProxy &p : qAsConst(proxies)) {
|
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;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -228,9 +237,11 @@ void QTcpServerPrivate::readNotification()
|
|||||||
QTcpServer::QTcpServer(QObject *parent)
|
QTcpServer::QTcpServer(QObject *parent)
|
||||||
: QObject(*new QTcpServerPrivate, parent)
|
: QObject(*new QTcpServerPrivate, parent)
|
||||||
{
|
{
|
||||||
|
Q_D(QTcpServer);
|
||||||
#if defined(QTCPSERVER_DEBUG)
|
#if defined(QTCPSERVER_DEBUG)
|
||||||
qDebug("QTcpServer::QTcpServer(%p)", parent);
|
qDebug("QTcpServer::QTcpServer(%p)", parent);
|
||||||
#endif
|
#endif
|
||||||
|
d->socketType = QAbstractSocket::TcpSocket;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -251,13 +262,22 @@ QTcpServer::~QTcpServer()
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*! \internal
|
/*! \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)
|
QTcpServer::QTcpServer(QAbstractSocket::SocketType socketType, QTcpServerPrivate &dd,
|
||||||
: QObject(dd, parent)
|
QObject *parent) : QObject(dd, parent)
|
||||||
{
|
{
|
||||||
|
Q_D(QTcpServer);
|
||||||
#if defined(QTCPSERVER_DEBUG)
|
#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
|
#endif
|
||||||
|
d->socketType = socketType;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -288,7 +308,7 @@ bool QTcpServer::listen(const QHostAddress &address, quint16 port)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
delete d->socketEngine;
|
delete d->socketEngine;
|
||||||
d->socketEngine = QAbstractSocketEngine::createSocketEngine(QAbstractSocket::TcpSocket, proxy, this);
|
d->socketEngine = QAbstractSocketEngine::createSocketEngine(d->socketType, proxy, this);
|
||||||
if (!d->socketEngine) {
|
if (!d->socketEngine) {
|
||||||
d->serverSocketError = QAbstractSocket::UnsupportedSocketOperationError;
|
d->serverSocketError = QAbstractSocket::UnsupportedSocketOperationError;
|
||||||
d->serverSocketErrorString = tr("Operation on socket is not supported");
|
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)
|
//copy network session down to the socket engine (if it has been set)
|
||||||
d->socketEngine->setProperty("_q_networksession", property("_q_networksession"));
|
d->socketEngine->setProperty("_q_networksession", property("_q_networksession"));
|
||||||
#endif
|
#endif
|
||||||
if (!d->socketEngine->initialize(QAbstractSocket::TcpSocket, proto)) {
|
if (!d->socketEngine->initialize(d->socketType, proto)) {
|
||||||
d->serverSocketError = d->socketEngine->error();
|
d->serverSocketError = d->socketEngine->error();
|
||||||
d->serverSocketErrorString = d->socketEngine->errorString();
|
d->serverSocketErrorString = d->socketEngine->errorString();
|
||||||
return false;
|
return false;
|
||||||
|
@ -94,7 +94,8 @@ protected:
|
|||||||
virtual void incomingConnection(qintptr handle);
|
virtual void incomingConnection(qintptr handle);
|
||||||
void addPendingConnection(QTcpSocket* socket);
|
void addPendingConnection(QTcpSocket* socket);
|
||||||
|
|
||||||
QTcpServer(QTcpServerPrivate &dd, QObject *parent = Q_NULLPTR);
|
QTcpServer(QAbstractSocket::SocketType socketType, QTcpServerPrivate &dd,
|
||||||
|
QObject *parent = Q_NULLPTR);
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void newConnection();
|
void newConnection();
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
**
|
**
|
||||||
** Copyright (C) 2016 The Qt Company Ltd.
|
** Copyright (C) 2016 The Qt Company Ltd.
|
||||||
|
** Copyright (C) 2016 Alex Trotsenko <alex1973tr@gmail.com>
|
||||||
** Contact: https://www.qt.io/licensing/
|
** Contact: https://www.qt.io/licensing/
|
||||||
**
|
**
|
||||||
** This file is part of the QtNetwork module of the Qt Toolkit.
|
** This file is part of the QtNetwork module of the Qt Toolkit.
|
||||||
@ -74,6 +75,7 @@ public:
|
|||||||
quint16 port;
|
quint16 port;
|
||||||
QHostAddress address;
|
QHostAddress address;
|
||||||
|
|
||||||
|
QAbstractSocket::SocketType socketType;
|
||||||
QAbstractSocket::SocketState state;
|
QAbstractSocket::SocketState state;
|
||||||
QAbstractSocketEngine *socketEngine;
|
QAbstractSocketEngine *socketEngine;
|
||||||
|
|
||||||
|
@ -347,6 +347,12 @@ qint64 QUdpSocket::writeDatagram(const char *data, qint64 size, const QHostAddre
|
|||||||
if (sent >= 0) {
|
if (sent >= 0) {
|
||||||
emit bytesWritten(sent);
|
emit bytesWritten(sent);
|
||||||
} else {
|
} 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());
|
d->setErrorAndEmit(d->socketEngine->error(), d->socketEngine->errorString());
|
||||||
}
|
}
|
||||||
return sent;
|
return sent;
|
||||||
@ -495,8 +501,15 @@ qint64 QUdpSocket::readDatagram(char *data, qint64 maxSize, QHostAddress *addres
|
|||||||
|
|
||||||
d->hasPendingData = false;
|
d->hasPendingData = false;
|
||||||
d->socketEngine->setReadNotificationEnabled(true);
|
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());
|
d->setErrorAndEmit(d->socketEngine->error(), d->socketEngine->errorString());
|
||||||
|
}
|
||||||
return readBytes;
|
return readBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,6 +25,18 @@ SOURCES += socket/qabstractsocketengine.cpp \
|
|||||||
socket/qlocalsocket.cpp \
|
socket/qlocalsocket.cpp \
|
||||||
socket/qlocalserver.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 {
|
!winrt {
|
||||||
SOURCES += socket/qnativesocketengine.cpp
|
SOURCES += socket/qnativesocketengine.cpp
|
||||||
HEADERS += socket/qnativesocketengine_p.h
|
HEADERS += socket/qnativesocketengine_p.h
|
||||||
|
@ -603,8 +603,8 @@ void tst_PlatformSocketEngine::invalidSend()
|
|||||||
PLATFORMSOCKETENGINE socket;
|
PLATFORMSOCKETENGINE socket;
|
||||||
QVERIFY(socket.initialize(QAbstractSocket::TcpSocket));
|
QVERIFY(socket.initialize(QAbstractSocket::TcpSocket));
|
||||||
|
|
||||||
QTest::ignoreMessage(QtWarningMsg, PLATFORMSOCKETENGINESTRING "::writeDatagram() was"
|
QTest::ignoreMessage(QtWarningMsg, PLATFORMSOCKETENGINESTRING "::writeDatagram() was called"
|
||||||
" called by a socket other than QAbstractSocket::UdpSocket");
|
" not in QAbstractSocket::BoundState or QAbstractSocket::ConnectedState");
|
||||||
QCOMPARE(socket.writeDatagram("hei", 3, QIpPacketHeader(QHostAddress::LocalHost, 143)),
|
QCOMPARE(socket.writeDatagram("hei", 3, QIpPacketHeader(QHostAddress::LocalHost, 143)),
|
||||||
(qlonglong) -1);
|
(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 \
|
qsocks5socketengine \
|
||||||
qabstractsocket \
|
qabstractsocket \
|
||||||
platformsocketengine \
|
platformsocketengine \
|
||||||
|
qsctpsocket \
|
||||||
|
|
||||||
!contains(QT_CONFIG, private_tests): SUBDIRS -= \
|
!contains(QT_CONFIG, private_tests): SUBDIRS -= \
|
||||||
platformsocketengine \
|
platformsocketengine \
|
||||||
@ -15,6 +16,9 @@ SUBDIRS=\
|
|||||||
qhttpsocketengine \
|
qhttpsocketengine \
|
||||||
qsocks5socketengine \
|
qsocks5socketengine \
|
||||||
|
|
||||||
|
!contains(QT_CONFIG, sctp): SUBDIRS -= \
|
||||||
|
qsctpsocket \
|
||||||
|
|
||||||
winrt: SUBDIRS -= \
|
winrt: SUBDIRS -= \
|
||||||
qhttpsocketengine \
|
qhttpsocketengine \
|
||||||
qsocks5socketengine \
|
qsocks5socketengine \
|
||||||
|
@ -180,6 +180,7 @@ Configure::Configure(int& argc, char** argv) : verbose(0)
|
|||||||
dictionary[ "PPS" ] = "no";
|
dictionary[ "PPS" ] = "no";
|
||||||
dictionary[ "LGMON" ] = "no";
|
dictionary[ "LGMON" ] = "no";
|
||||||
dictionary[ "SYSTEM_PROXIES" ] = "yes";
|
dictionary[ "SYSTEM_PROXIES" ] = "yes";
|
||||||
|
dictionary[ "SCTP" ] = "no";
|
||||||
dictionary[ "WERROR" ] = "auto";
|
dictionary[ "WERROR" ] = "auto";
|
||||||
dictionary[ "QREAL" ] = "double";
|
dictionary[ "QREAL" ] = "double";
|
||||||
dictionary[ "ATOMIC64" ] = "auto";
|
dictionary[ "ATOMIC64" ] = "auto";
|
||||||
@ -829,6 +830,10 @@ void Configure::parseCmdLine()
|
|||||||
dictionary[ "SYSTEM_PROXIES" ] = "no";
|
dictionary[ "SYSTEM_PROXIES" ] = "no";
|
||||||
} else if (configCmdLine.at(i) == "-system-proxies") {
|
} else if (configCmdLine.at(i) == "-system-proxies") {
|
||||||
dictionary[ "SYSTEM_PROXIES" ] = "yes";
|
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" ||
|
} else if (configCmdLine.at(i) == "-warnings-are-errors" ||
|
||||||
configCmdLine.at(i) == "-Werror") {
|
configCmdLine.at(i) == "-Werror") {
|
||||||
dictionary[ "WERROR" ] = "yes";
|
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", "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("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", "yes", "-warnings-are-errors", "Make warnings be treated as errors.");
|
||||||
desc("WERROR", "no", "-no-warnings-are-errors","Make warnings be treated normally.");
|
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");
|
available = (platform() == QNX) && tryCompileProject("unix/pps");
|
||||||
} else if (part == "LGMON") {
|
} else if (part == "LGMON") {
|
||||||
available = (platform() == QNX) && tryCompileProject("unix/lgmon");
|
available = (platform() == QNX) && tryCompileProject("unix/lgmon");
|
||||||
|
} else if (part == "SCTP") {
|
||||||
|
available = tryCompileProject("unix/sctp");
|
||||||
} else if (part == "NEON") {
|
} else if (part == "NEON") {
|
||||||
available = dictionary["QT_CPU_FEATURES"].contains("neon");
|
available = dictionary["QT_CPU_FEATURES"].contains("neon");
|
||||||
} else if (part == "FONT_CONFIG") {
|
} else if (part == "FONT_CONFIG") {
|
||||||
@ -2301,6 +2311,10 @@ void Configure::autoDetection()
|
|||||||
dictionary["LGMON"] = checkAvailability("LGMON") ? "yes" : "no";
|
dictionary["LGMON"] = checkAvailability("LGMON") ? "yes" : "no";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dictionary["SCTP"] == "auto") {
|
||||||
|
dictionary["SCTP"] = checkAvailability("SCTP") ? "yes" : "no";
|
||||||
|
}
|
||||||
|
|
||||||
if (dictionary["QT_EVENTFD"] == "auto")
|
if (dictionary["QT_EVENTFD"] == "auto")
|
||||||
dictionary["QT_EVENTFD"] = checkAvailability("QT_EVENTFD") ? "yes" : "no";
|
dictionary["QT_EVENTFD"] = checkAvailability("QT_EVENTFD") ? "yes" : "no";
|
||||||
|
|
||||||
@ -2744,6 +2758,9 @@ void Configure::generateOutputVars()
|
|||||||
if (dictionary[ "SYSTEM_PROXIES" ] == "yes")
|
if (dictionary[ "SYSTEM_PROXIES" ] == "yes")
|
||||||
qtConfig += "system-proxies";
|
qtConfig += "system-proxies";
|
||||||
|
|
||||||
|
if (dictionary[ "SCTP" ] == "yes")
|
||||||
|
qtConfig += "sctp";
|
||||||
|
|
||||||
if (dictionary.contains("XQMAKESPEC") && (dictionary["QMAKESPEC"] != dictionary["XQMAKESPEC"])) {
|
if (dictionary.contains("XQMAKESPEC") && (dictionary["QMAKESPEC"] != dictionary["XQMAKESPEC"])) {
|
||||||
qmakeConfig += "cross_compile";
|
qmakeConfig += "cross_compile";
|
||||||
dictionary["CROSS_COMPILE"] = "yes";
|
dictionary["CROSS_COMPILE"] = "yes";
|
||||||
@ -3387,6 +3404,8 @@ void Configure::generateConfigfiles()
|
|||||||
else
|
else
|
||||||
qconfigList += "QT_NO_NIS";
|
qconfigList += "QT_NO_NIS";
|
||||||
|
|
||||||
|
if (dictionary["SCTP"] == "no") qconfigList += "QT_NO_SCTP";
|
||||||
|
|
||||||
if (dictionary["LARGE_FILE"] == "yes") qconfigList += "QT_LARGEFILE_SUPPORT=64";
|
if (dictionary["LARGE_FILE"] == "yes") qconfigList += "QT_LARGEFILE_SUPPORT=64";
|
||||||
if (dictionary["QT_CUPS"] == "no") qconfigList += "QT_NO_CUPS";
|
if (dictionary["QT_CUPS"] == "no") qconfigList += "QT_NO_CUPS";
|
||||||
if (dictionary["QT_ICONV"] == "no") qconfigList += "QT_NO_ICONV";
|
if (dictionary["QT_ICONV"] == "no") qconfigList += "QT_NO_ICONV";
|
||||||
@ -3520,6 +3539,7 @@ void Configure::displayConfig()
|
|||||||
sout << "DirectWrite support........." << dictionary[ "DIRECTWRITE" ] << endl;
|
sout << "DirectWrite support........." << dictionary[ "DIRECTWRITE" ] << endl;
|
||||||
sout << "DirectWrite 2 support......." << dictionary[ "DIRECTWRITE2" ] << endl;
|
sout << "DirectWrite 2 support......." << dictionary[ "DIRECTWRITE2" ] << endl;
|
||||||
sout << "Use system proxies.........." << dictionary[ "SYSTEM_PROXIES" ] << endl;
|
sout << "Use system proxies.........." << dictionary[ "SYSTEM_PROXIES" ] << endl;
|
||||||
|
sout << "SCTP support................" << dictionary[ "SCTP" ] << endl;
|
||||||
sout << endl;
|
sout << endl;
|
||||||
|
|
||||||
sout << "QPA Backends:" << endl;
|
sout << "QPA Backends:" << endl;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user