summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThiago Macieira <thiago.macieira@nokia.com>2010-04-15 12:15:01 (GMT)
committerThiago Macieira <thiago.macieira@nokia.com>2010-04-16 11:33:24 (GMT)
commitbf81038a4e676c228757070028b06114a9fde2f4 (patch)
tree4f7fd17db005f105ac6bfdfa18ea056528d42f9d
parentcd28233911dd068a29f12a35fce010136c4d3ff0 (diff)
downloadQt-bf81038a4e676c228757070028b06114a9fde2f4.zip
Qt-bf81038a4e676c228757070028b06114a9fde2f4.tar.gz
Qt-bf81038a4e676c228757070028b06114a9fde2f4.tar.bz2
Add a non-blocking native function too
-rw-r--r--tests/auto/qtcpsocket_stresstest/tst_qtcpsocket_stresstest.cpp195
1 files changed, 162 insertions, 33 deletions
diff --git a/tests/auto/qtcpsocket_stresstest/tst_qtcpsocket_stresstest.cpp b/tests/auto/qtcpsocket_stresstest/tst_qtcpsocket_stresstest.cpp
index f3fac26..bc2681a 100644
--- a/tests/auto/qtcpsocket_stresstest/tst_qtcpsocket_stresstest.cpp
+++ b/tests/auto/qtcpsocket_stresstest/tst_qtcpsocket_stresstest.cpp
@@ -52,10 +52,13 @@
#ifdef Q_OS_UNIX
# include <sys/types.h>
# include <sys/socket.h>
+# include <sys/select.h>
# include <netinet/in.h>
+# include <errno.h>
# include <netdb.h>
# include <signal.h>
# include <unistd.h>
+# include <fcntl.h>
typedef int SOCKET;
# define INVALID_SOCKET -1
@@ -83,6 +86,7 @@ public slots:
private Q_SLOTS:
void nativeBlockingConnectDisconnect();
+ void nativeNonBlockingConnectDisconnect();
void blockingConnectDisconnect();
void blockingPipelined();
void blockingMultipleRequests();
@@ -119,8 +123,7 @@ void tst_QTcpSocket_stresstest::init()
QSKIP("Stress test disabled", SkipAll);
}
-
-void nativeConnect(SOCKET &fd, const char *hostname, int port)
+bool nativeLookup(const char *hostname, int port, QByteArray &buf)
{
#if !defined(QT_NO_GETADDRINFO) && 0
addrinfo *res = 0;
@@ -129,41 +132,54 @@ void nativeConnect(SOCKET &fd, const char *hostname, int port)
hints.ai_family = PF_UNSPEC;
int result = getaddrinfo(QUrl::toAce(hostname).constData(), QByteArray::number(port).constData(), &hints, &res);
- QCOMPARE(result, 0);
-
- // connect loop
- fd = -1;
- for (addrinfo *node = res; fd == -1 && node; node = node->ai_next) {
- fd = ::socket(node->ai_family, node->ai_socktype, node->ai_protocol);
- if (fd == -1)
- continue;
- if (::connect(fd, node->ai_addr, node->ai_addrlen) == -1) {
- ::close(fd);
- fd = -1;
- } else {
+ if (!result)
+ return false;
+ for (addrinfo *node = res; node; node = node->ai_next) {
+ if (node->ai_family == AF_INET) {
+ buf = QByteArray((char *)node->ai_addr, node->ai_addrlen);
break;
}
}
- QVERIFY(fd != -1);
+ freeaddrinfo(res);
#else
hostent *result = gethostbyname(hostname);
- QVERIFY(result);
- QCOMPARE(result->h_addrtype, AF_INET);
+ if (!result || result->h_addrtype != AF_INET)
+ return false;
+
struct sockaddr_in s;
- QT_SOCKLEN_T len = sizeof s;
s.sin_family = AF_INET;
-
- fd = ::socket(AF_INET, SOCK_STREAM, 0);
- QVERIFY(fd != INVALID_SOCKET);
-# ifdef Q_OS_WIN
- WSAHtons(fd, port, &(s.sin_port));
- s.sin_addr.s_addr = *(u_long *) result->h_addr_list[0];
-# else
s.sin_port = htons(port);
s.sin_addr = *(struct in_addr *) result->h_addr_list[0];
+
+ buf = QByteArray((char *)&s, sizeof s);
#endif
- QVERIFY(::connect(fd, (sockaddr*)&s, len) != SOCKET_ERROR);
-#endif
+
+ return !buf.isEmpty();
+}
+
+bool nativeSelect(int fd, int timeout, bool selectForWrite)
+{
+ if (timeout < 0)
+ return false;
+
+ // wait for connected
+ fd_set fds, fde;
+ FD_ZERO(&fds);
+ FD_ZERO(&fde);
+ FD_SET(fd, &fds);
+ FD_SET(fd, &fde);
+
+ int ret;
+ do {
+ struct timeval tv;
+ tv.tv_sec = timeout / 1000;
+ tv.tv_usec = timeout % 1000;
+ if (selectForWrite)
+ ret = ::select(fd + 1, 0, &fds, &fde, &tv);
+ else
+ ret = ::select(fd + 1, &fds, 0, &fde, &tv);
+ } while (ret == -1 && errno == EINTR);
+ return ret != 0;
}
void tst_QTcpSocket_stresstest::nativeBlockingConnectDisconnect()
@@ -182,10 +198,14 @@ void tst_QTcpSocket_stresstest::nativeBlockingConnectDisconnect()
#endif
// look up the host
- SOCKET fd;
- nativeConnect(fd, QUrl::toAce(hostname).constData(), port);
- if (fd == INVALID_SOCKET)
- return;
+ QByteArray addr;
+ if (!nativeLookup(QUrl::toAce(hostname).constData(), port, addr))
+ QFAIL("Lookup failed");
+
+ // connect
+ SOCKET fd = ::socket(AF_INET, SOCK_STREAM, 0);
+ QVERIFY(fd != INVALID_SOCKET);
+ QVERIFY(::connect(fd, (sockaddr *)addr.data(), addr.size()) != SOCKET_ERROR);
// send request
{
@@ -196,7 +216,7 @@ void tst_QTcpSocket_stresstest::nativeBlockingConnectDisconnect()
"\r\n";
qint64 bytesWritten = 0;
while (bytesWritten < request.size()) {
- qint64 ret = ::write(fd, request.constData() + bytesWritten, request.size() - bytesWritten);
+ qint64 ret = ::send(fd, request.constData() + bytesWritten, request.size() - bytesWritten, 0);
if (ret == -1) {
::close(fd);
QFAIL("Timeout");
@@ -208,7 +228,7 @@ void tst_QTcpSocket_stresstest::nativeBlockingConnectDisconnect()
// receive reply
char buf[16384];
while (true) {
- qint64 ret = ::read(fd, buf, sizeof buf);
+ qint64 ret = ::recv(fd, buf, sizeof buf, 0);
if (ret == -1) {
::close(fd);
QFAIL("Timeout");
@@ -231,6 +251,115 @@ void tst_QTcpSocket_stresstest::nativeBlockingConnectDisconnect()
#endif
}
+void tst_QTcpSocket_stresstest::nativeNonBlockingConnectDisconnect()
+{
+ QFETCH_GLOBAL(QString, hostname);
+ QFETCH_GLOBAL(int, port);
+
+ double avg = 0;
+ for (int i = 0; i < AttemptCount; ++i) {
+ QElapsedTimer timeout;
+ byteCounter = 0;
+ timeout.start();
+
+ // look up the host
+ QByteArray addr;
+ if (!nativeLookup(QUrl::toAce(hostname).constData(), port, addr))
+ QFAIL("Lookup failed");
+
+ SOCKET fd;
+
+ {
+#if defined(Q_OS_UNIX)
+ fd = ::socket(AF_INET, SOCK_STREAM, 0);
+ QVERIFY(fd != INVALID_SOCKET);
+
+ // set the socket to non-blocking and start connecting
+# if !defined(Q_OS_VXWORKS)
+ int flags = ::fcntl(fd, F_GETFL, 0);
+ QVERIFY(flags != -1);
+ QVERIFY(::fcntl(fd, F_SETFL, flags | O_NONBLOCK) != -1);
+# else // Q_OS_VXWORKS
+ int onoff = 1;
+ QVERIFY(::ioctl(socketDescriptor, FIONBIO, &onoff) >= 0);
+# endif // Q_OS_VXWORKS
+ while (true) {
+ if (::connect(fd, (sockaddr *)addr.data(), addr.size()) == -1) {
+ QVERIFY2(errno == EINPROGRESS, QByteArray("Error connecting: ").append(strerror(errno)).constData());
+ QVERIFY2(nativeSelect(fd, 10000 - timeout.elapsed(), true), "Timeout");
+ } else {
+ break; // connected
+ }
+ }
+#elif defined(Q_OS_WIN)
+ fd = ::WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
+ QVERIFY(fd != INVALID_SOCKET);
+
+ // set the socket to non-blocking and start connecting
+ unsigned long buf = v;
+ unsigned long outBuf;
+ DWORD sizeWritten = 0;
+ QVERIFY(::WSAIoctl(fd, FIONBIO, &buf, sizeof(unsigned long), &outBuf, sizeof(unsigned long), &sizeWritten, 0,0) != SOCKET_ERROR);
+
+ while (true) {
+ int connectResult = ::WSAConnect(fd, sockAddrPtr, sockAddrSize, 0,0,0,0);
+ if (connectResult == 0 || WSAGetLastError() == WSAEISCONN) {
+ break; // connected
+ } else {
+ QVERIFY2(WSAGetLastError() == WSAEINPROGRESS, "Unexpected error");
+ QVERIFY2(nativeSelect(fd, 10000 - timeout.elapsed(), true), "Timeout");
+ }
+ }
+#endif
+ }
+
+ // send request
+ {
+ QByteArray request = "GET /qtest/mediumfile HTTP/1.1\r\n"
+ "Connection: close\r\n"
+ "User-Agent: tst_QTcpSocket_stresstest/1.0\r\n"
+ "Host: " + hostname.toLatin1() + "\r\n"
+ "\r\n";
+ qint64 bytesWritten = 0;
+ while (bytesWritten < request.size()) {
+ qint64 ret = ::send(fd, request.constData() + bytesWritten, request.size() - bytesWritten, 0);
+ if (ret == -1 && errno != EWOULDBLOCK) {
+ ::close(fd);
+ QFAIL(QByteArray("Error writing: ").append(strerror(errno)).constData());
+ } else if (ret == -1) {
+ // wait for writing
+ QVERIFY2(nativeSelect(fd, 10000 - timeout.elapsed(), true), "Timeout");
+ continue;
+ }
+ bytesWritten += ret;
+ }
+ }
+
+ // receive reply
+ char buf[16384];
+ while (true) {
+ qint64 ret = ::recv(fd, buf, sizeof buf, 0);
+ if (ret == -1 && errno != EWOULDBLOCK) {
+ ::close(fd);
+ QFAIL("Timeout");
+ } else if (ret == -1) {
+ // wait for reading
+ QVERIFY2(nativeSelect(fd, 10000 - timeout.elapsed(), false), "Timeout");
+ } else if (ret == 0) {
+ break; // EOF
+ }
+ byteCounter += ret;
+ }
+ ::close(fd);
+
+ double rate = (byteCounter / timeout.elapsed());
+ avg = (i * avg + rate) / (i + 1);
+ qDebug() << i << byteCounter << "bytes in" << timeout.elapsed() << "ms:"
+ << (rate / 1024.0 / 1024 * 1000) << "MB/s";
+ }
+ qDebug() << "Average transfer rate was" << (avg / 1024.0 / 1024 * 1000) << "MB/s";
+}
+
void tst_QTcpSocket_stresstest::blockingConnectDisconnect()
{
QFETCH_GLOBAL(QString, hostname);