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()
OperationError,
SslInternalError, /* 20 */
SslInvalidUserDataError,
+ TemporaryError,
UnknownSocketError = -1
};
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;
PortInuseErrorString,
NotSocketErrorString,
InvalidProxyTypeString,
+ TemporaryErrorString,
UnknownSocketErrorString = -1
};
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;
}
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
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;
// 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()
\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"
}
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
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
QAbstractSocket::SocketError serverError() const;
QString errorString() const;
+ void pauseAccepting();
+ void resumeAccepting();
+
#ifndef QT_NO_NETWORKPROXY
void setProxy(const QNetworkProxy &networkProxy);
QNetworkProxy proxy() const;
Q_SIGNALS:
void newConnection();
+ void acceptError(QAbstractSocket::SocketError socketError);
private:
Q_DISABLE_COPY(QTcpServer)
void linkLocal();
+ void eagainBlockingAccept();
+
private:
#ifndef QT_NO_BEARERMANAGEMENT
QNetworkSession *networkSession;
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"