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:
Jonas M. Gastal 2012-06-11 22:27:03 -03:00 committed by The Qt Project
parent aa9728450c
commit 4920090da0
10 changed files with 159 additions and 6 deletions

View File

@ -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()

View File

@ -99,6 +99,7 @@ public:
OperationError,
SslInternalError, /* 20 */
SslInvalidUserDataError,
TemporaryError,
UnknownSocketError = -1
};

View File

@ -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;

View File

@ -234,6 +234,7 @@ public:
PortInuseErrorString,
NotSocketErrorString,
InvalidProxyTypeString,
TemporaryErrorString,
UnknownSocketErrorString = -1
};

View File

@ -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;
}

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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)

View File

@ -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"