If accept fails, stop accepting new connections and emit error signal.
Task-number: QTBUG-24778 Change-Id: I6c5b685b3f861a0fafc1475c41bb35cede17d712 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
parent
aa9728450c
commit
4920090da0
@ -321,6 +321,8 @@
|
||||
probably the result of a bad installation or misconfiguration of the library.
|
||||
\value SslInvalidUserDataError Invalid data(certificate, key, cypher, etc.) was
|
||||
provided and its use resulted in an error in the SSL library.
|
||||
\value TemporaryError A temporary error occurred(e.g., operation would block and socket
|
||||
is non-blocking).
|
||||
|
||||
\value UnknownSocketError An unidentified error occurred.
|
||||
\sa QAbstractSocket::error()
|
||||
|
@ -99,6 +99,7 @@ public:
|
||||
OperationError,
|
||||
SslInternalError, /* 20 */
|
||||
SslInvalidUserDataError,
|
||||
TemporaryError,
|
||||
|
||||
UnknownSocketError = -1
|
||||
};
|
||||
|
@ -274,6 +274,9 @@ void QNativeSocketEnginePrivate::setError(QAbstractSocket::SocketError error, Er
|
||||
case InvalidProxyTypeString:
|
||||
socketErrorString = QNativeSocketEngine::tr("The proxy type is invalid for this operation");
|
||||
break;
|
||||
case TemporaryErrorString:
|
||||
socketErrorString = QNativeSocketEngine::tr("Temporary error");
|
||||
break;
|
||||
case UnknownSocketErrorString:
|
||||
socketErrorString = QNativeSocketEngine::tr("Unknown error");
|
||||
break;
|
||||
|
@ -234,6 +234,7 @@ public:
|
||||
PortInuseErrorString,
|
||||
NotSocketErrorString,
|
||||
InvalidProxyTypeString,
|
||||
TemporaryErrorString,
|
||||
|
||||
UnknownSocketErrorString = -1
|
||||
};
|
||||
|
@ -588,6 +588,46 @@ bool QNativeSocketEnginePrivate::nativeListen(int backlog)
|
||||
int QNativeSocketEnginePrivate::nativeAccept()
|
||||
{
|
||||
int acceptedDescriptor = qt_safe_accept(socketDescriptor, 0, 0);
|
||||
if (acceptedDescriptor == -1) {
|
||||
switch (errno) {
|
||||
case EBADF:
|
||||
case EOPNOTSUPP:
|
||||
setError(QAbstractSocket::UnsupportedSocketOperationError, InvalidSocketErrorString);
|
||||
break;
|
||||
case ECONNABORTED:
|
||||
setError(QAbstractSocket::NetworkError, RemoteHostClosedErrorString);
|
||||
break;
|
||||
case EFAULT:
|
||||
case ENOTSOCK:
|
||||
setError(QAbstractSocket::SocketResourceError, NotSocketErrorString);
|
||||
break;
|
||||
case EPROTONOSUPPORT:
|
||||
case EPROTO:
|
||||
case EAFNOSUPPORT:
|
||||
case EINVAL:
|
||||
setError(QAbstractSocket::UnsupportedSocketOperationError, ProtocolUnsupportedErrorString);
|
||||
break;
|
||||
case ENFILE:
|
||||
case EMFILE:
|
||||
case ENOBUFS:
|
||||
case ENOMEM:
|
||||
setError(QAbstractSocket::SocketResourceError, ResourceErrorString);
|
||||
break;
|
||||
case EACCES:
|
||||
case EPERM:
|
||||
setError(QAbstractSocket::SocketAccessError, AccessErrorString);
|
||||
break;
|
||||
#if EAGAIN != EWOULDBLOCK
|
||||
case EWOULDBLOCK:
|
||||
#endif
|
||||
case EAGAIN:
|
||||
setError(QAbstractSocket::TemporaryError, TemporaryErrorString);
|
||||
break;
|
||||
default:
|
||||
setError(QAbstractSocket::UnknownSocketError, UnknownSocketErrorString);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return acceptedDescriptor;
|
||||
}
|
||||
|
@ -909,7 +909,40 @@ bool QNativeSocketEnginePrivate::nativeListen(int backlog)
|
||||
int QNativeSocketEnginePrivate::nativeAccept()
|
||||
{
|
||||
int acceptedDescriptor = WSAAccept(socketDescriptor, 0,0,0,0);
|
||||
if (acceptedDescriptor != -1 && QAbstractEventDispatcher::instance()) {
|
||||
if (acceptedDescriptor == -1) {
|
||||
int err = WSAGetLastError();
|
||||
switch (err) {
|
||||
case WSAEACCES:
|
||||
setError(QAbstractSocket::SocketAccessError, AccessErrorString);
|
||||
break;
|
||||
case WSAECONNREFUSED:
|
||||
setError(QAbstractSocket::ConnectionRefusedError, ConnectionRefusedErrorString);
|
||||
break;
|
||||
case WSAECONNRESET:
|
||||
setError(QAbstractSocket::NetworkError, RemoteHostClosedErrorString);
|
||||
break;
|
||||
case WSAENETDOWN:
|
||||
setError(QAbstractSocket::NetworkError, NetworkUnreachableErrorString);
|
||||
case WSAENOTSOCK:
|
||||
setError(QAbstractSocket::SocketResourceError, NotSocketErrorString);
|
||||
break;
|
||||
case WSAEINVAL:
|
||||
case WSAEOPNOTSUPP:
|
||||
setError(QAbstractSocket::UnsupportedSocketOperationError, ProtocolUnsupportedErrorString);
|
||||
break;
|
||||
case WSAEFAULT:
|
||||
case WSAEMFILE:
|
||||
case WSAENOBUFS:
|
||||
setError(QAbstractSocket::SocketResourceError, ResourceErrorString);
|
||||
break;
|
||||
case WSAEWOULDBLOCK:
|
||||
setError(QAbstractSocket::TemporaryError, TemporaryErrorString);
|
||||
break;
|
||||
default:
|
||||
setError(QAbstractSocket::UnknownSocketError, UnknownSocketErrorString);
|
||||
break;
|
||||
}
|
||||
} else if (acceptedDescriptor != -1 && QAbstractEventDispatcher::instance()) {
|
||||
// Because of WSAAsyncSelect() WSAAccept returns a non blocking socket
|
||||
// with the same attributes as the listening socket including the current
|
||||
// WSAAsyncSelect(). To be able to change the socket to blocking mode the
|
||||
|
@ -1453,13 +1453,15 @@ int QSocks5SocketEngine::accept()
|
||||
|
||||
QSOCKS5_Q_DEBUG << "accept()";
|
||||
|
||||
if (d->socks5State == QSocks5SocketEnginePrivate::BindSuccess) {
|
||||
qintptr sd = -1;
|
||||
switch (d->socks5State) {
|
||||
case QSocks5SocketEnginePrivate::BindSuccess:
|
||||
QSOCKS5_Q_DEBUG << "BindSuccess adding" << d->socketDescriptor << "to the bind store";
|
||||
d->data->controlSocket->disconnect();
|
||||
d->data->controlSocket->setParent(0);
|
||||
d->bindData->localAddress = d->localAddress;
|
||||
d->bindData->localPort = d->localPort;
|
||||
qintptr sd = d->socketDescriptor;
|
||||
sd = d->socketDescriptor;
|
||||
socks5BindStore()->add(sd, d->bindData);
|
||||
d->data = 0;
|
||||
d->bindData = 0;
|
||||
@ -1468,9 +1470,15 @@ int QSocks5SocketEngine::accept()
|
||||
// reset state and local port/address
|
||||
d->socks5State = QSocks5SocketEnginePrivate::Uninitialized; // ..??
|
||||
d->socketState = QAbstractSocket::UnconnectedState;
|
||||
return sd;
|
||||
break;
|
||||
case QSocks5SocketEnginePrivate::ControlSocketError:
|
||||
setError(QAbstractSocket::ProxyProtocolError, QLatin1String("Control socket error"));
|
||||
break;
|
||||
default:
|
||||
setError(QAbstractSocket::ProxyProtocolError, QLatin1String("SOCKS5 proxy error"));
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
return sd;
|
||||
}
|
||||
|
||||
void QSocks5SocketEngine::close()
|
||||
|
@ -90,6 +90,15 @@
|
||||
\sa hasPendingConnections(), nextPendingConnection()
|
||||
*/
|
||||
|
||||
/*! \fn void QTcpServer::acceptError(QAbstractSocket::SocketError socketError)
|
||||
\since 5.0
|
||||
|
||||
This signal is emitted when accepting a new connection results in an error.
|
||||
The \a socketError parameter describes the type of error that occurred.
|
||||
|
||||
\sa pauseAccepting(), resumeAccepting()
|
||||
*/
|
||||
|
||||
#include "qtcpserver.h"
|
||||
#include "private/qobject_p.h"
|
||||
#include "qalgorithms.h"
|
||||
@ -209,8 +218,15 @@ void QTcpServerPrivate::readNotification()
|
||||
}
|
||||
|
||||
int descriptor = socketEngine->accept();
|
||||
if (descriptor == -1)
|
||||
if (descriptor == -1) {
|
||||
if (socketEngine->error() != QAbstractSocket::TemporaryError) {
|
||||
q->pauseAccepting();
|
||||
serverSocketError = socketEngine->error();
|
||||
serverSocketErrorString = socketEngine->errorString();
|
||||
emit q->acceptError(serverSocketError);
|
||||
}
|
||||
break;
|
||||
}
|
||||
#if defined (QTCPSERVER_DEBUG)
|
||||
qDebug("QTcpServerPrivate::_q_processIncomingConnection() accepted socket %i", descriptor);
|
||||
#endif
|
||||
@ -650,6 +666,30 @@ QString QTcpServer::errorString() const
|
||||
return d_func()->serverSocketErrorString;
|
||||
}
|
||||
|
||||
/*!
|
||||
\since 5.0
|
||||
|
||||
Pauses accepting new connections. Queued connections will remain in queue.
|
||||
|
||||
\sa resumeAccepting()
|
||||
*/
|
||||
void QTcpServer::pauseAccepting()
|
||||
{
|
||||
d_func()->socketEngine->setReadNotificationEnabled(false);
|
||||
}
|
||||
|
||||
/*!
|
||||
\since 5.0
|
||||
|
||||
Resumes accepting new connections.
|
||||
|
||||
\sa pauseAccepting()
|
||||
*/
|
||||
void QTcpServer::resumeAccepting()
|
||||
{
|
||||
d_func()->socketEngine->setReadNotificationEnabled(true);
|
||||
}
|
||||
|
||||
#ifndef QT_NO_NETWORKPROXY
|
||||
/*!
|
||||
\since 4.1
|
||||
|
@ -85,6 +85,9 @@ public:
|
||||
QAbstractSocket::SocketError serverError() const;
|
||||
QString errorString() const;
|
||||
|
||||
void pauseAccepting();
|
||||
void resumeAccepting();
|
||||
|
||||
#ifndef QT_NO_NETWORKPROXY
|
||||
void setProxy(const QNetworkProxy &networkProxy);
|
||||
QNetworkProxy proxy() const;
|
||||
@ -96,6 +99,7 @@ protected:
|
||||
|
||||
Q_SIGNALS:
|
||||
void newConnection();
|
||||
void acceptError(QAbstractSocket::SocketError socketError);
|
||||
|
||||
private:
|
||||
Q_DISABLE_COPY(QTcpServer)
|
||||
|
@ -121,6 +121,8 @@ private slots:
|
||||
|
||||
void linkLocal();
|
||||
|
||||
void eagainBlockingAccept();
|
||||
|
||||
private:
|
||||
#ifndef QT_NO_BEARERMANAGEMENT
|
||||
QNetworkSession *networkSession;
|
||||
@ -953,5 +955,24 @@ void tst_QTcpServer::linkLocal()
|
||||
qDeleteAll(servers);
|
||||
}
|
||||
|
||||
void tst_QTcpServer::eagainBlockingAccept()
|
||||
{
|
||||
QTcpServer server;
|
||||
server.listen(QHostAddress::LocalHost, 7896);
|
||||
|
||||
// Receiving a new connection causes TemporaryError, but shouldn't pause accepting.
|
||||
QTcpSocket s;
|
||||
s.connectToHost(QHostAddress::LocalHost, 7896);
|
||||
QSignalSpy spy(&server, SIGNAL(newConnection()));
|
||||
QTRY_COMPARE_WITH_TIMEOUT(spy.count(), 1, 500);
|
||||
s.close();
|
||||
|
||||
// To test try again, should connect just fine.
|
||||
s.connectToHost(QHostAddress::LocalHost, 7896);
|
||||
QTRY_COMPARE_WITH_TIMEOUT(spy.count(), 2, 500);
|
||||
s.close();
|
||||
server.close();
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QTcpServer)
|
||||
#include "tst_qtcpserver.moc"
|
||||
|
Loading…
Reference in New Issue
Block a user