summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJonas M. Gastal <jgastal@gmail.com>2012-06-11 22:27:03 -0300
committerThe Qt Project <gerrit-noreply@qt-project.org>2012-09-26 04:03:51 +0200
commit4920090da0fc937d171065694d5274221d2747c9 (patch)
tree8959b519b3ebcf772fee2db640c0b2b4818a6e85
parentaa9728450cc515c66545323646c66d826a1af50a (diff)
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>
-rw-r--r--src/network/socket/qabstractsocket.cpp2
-rw-r--r--src/network/socket/qabstractsocket.h1
-rw-r--r--src/network/socket/qnativesocketengine.cpp3
-rw-r--r--src/network/socket/qnativesocketengine_p.h1
-rw-r--r--src/network/socket/qnativesocketengine_unix.cpp40
-rw-r--r--src/network/socket/qnativesocketengine_win.cpp35
-rw-r--r--src/network/socket/qsocks5socketengine.cpp16
-rw-r--r--src/network/socket/qtcpserver.cpp42
-rw-r--r--src/network/socket/qtcpserver.h4
-rw-r--r--tests/auto/network/socket/qtcpserver/tst_qtcpserver.cpp21
10 files changed, 159 insertions, 6 deletions
diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp
index 0d3492e639..5ff7da9e9d 100644
--- a/src/network/socket/qabstractsocket.cpp
+++ b/src/network/socket/qabstractsocket.cpp
@@ -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()
diff --git a/src/network/socket/qabstractsocket.h b/src/network/socket/qabstractsocket.h
index 79d6e63449..9e1e4f81b8 100644
--- a/src/network/socket/qabstractsocket.h
+++ b/src/network/socket/qabstractsocket.h
@@ -99,6 +99,7 @@ public:
OperationError,
SslInternalError, /* 20 */
SslInvalidUserDataError,
+ TemporaryError,
UnknownSocketError = -1
};
diff --git a/src/network/socket/qnativesocketengine.cpp b/src/network/socket/qnativesocketengine.cpp
index 5fba64a981..8239324b1a 100644
--- a/src/network/socket/qnativesocketengine.cpp
+++ b/src/network/socket/qnativesocketengine.cpp
@@ -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;
diff --git a/src/network/socket/qnativesocketengine_p.h b/src/network/socket/qnativesocketengine_p.h
index c363413d6b..dc95de9c86 100644
--- a/src/network/socket/qnativesocketengine_p.h
+++ b/src/network/socket/qnativesocketengine_p.h
@@ -234,6 +234,7 @@ public:
PortInuseErrorString,
NotSocketErrorString,
InvalidProxyTypeString,
+ TemporaryErrorString,
UnknownSocketErrorString = -1
};
diff --git a/src/network/socket/qnativesocketengine_unix.cpp b/src/network/socket/qnativesocketengine_unix.cpp
index 3f6b6b556c..224bee8fd6 100644
--- a/src/network/socket/qnativesocketengine_unix.cpp
+++ b/src/network/socket/qnativesocketengine_unix.cpp
@@ -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;
}
diff --git a/src/network/socket/qnativesocketengine_win.cpp b/src/network/socket/qnativesocketengine_win.cpp
index ef93455134..0c14e1380b 100644
--- a/src/network/socket/qnativesocketengine_win.cpp
+++ b/src/network/socket/qnativesocketengine_win.cpp
@@ -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
diff --git a/src/network/socket/qsocks5socketengine.cpp b/src/network/socket/qsocks5socketengine.cpp
index ba7ca1b92e..bb0e911aef 100644
--- a/src/network/socket/qsocks5socketengine.cpp
+++ b/src/network/socket/qsocks5socketengine.cpp
@@ -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()
diff --git a/src/network/socket/qtcpserver.cpp b/src/network/socket/qtcpserver.cpp
index 331db627dd..90419502ba 100644
--- a/src/network/socket/qtcpserver.cpp
+++ b/src/network/socket/qtcpserver.cpp
@@ -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
diff --git a/src/network/socket/qtcpserver.h b/src/network/socket/qtcpserver.h
index 0f319e6c7d..f83df734eb 100644
--- a/src/network/socket/qtcpserver.h
+++ b/src/network/socket/qtcpserver.h
@@ -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)
diff --git a/tests/auto/network/socket/qtcpserver/tst_qtcpserver.cpp b/tests/auto/network/socket/qtcpserver/tst_qtcpserver.cpp
index 66c6c97786..18401fb40d 100644
--- a/tests/auto/network/socket/qtcpserver/tst_qtcpserver.cpp
+++ b/tests/auto/network/socket/qtcpserver/tst_qtcpserver.cpp
@@ -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"