summaryrefslogtreecommitdiffstats
path: root/tests/manual/qt_poll/tst_qt_poll.cpp
blob: 068120666eee898f32f6e6d46ba0f1645b2c10b1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only

#ifndef QT_NO_NATIVE_POLL
#define QT_NO_NATIVE_POLL
#endif

#include <QTest>
#include <QtNetwork>

#include <private/qcore_unix_p.h>

QT_BEGIN_NAMESPACE
// defined in qpoll.cpp
int qt_poll(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout_ts);
QT_END_NAMESPACE

class tst_qt_poll : public QObject
{
    Q_OBJECT

private slots:
    void pollout();
    void pollin();
    void pollnval();
    void pollprihup();
};

void tst_qt_poll::pollout()
{
    int fds[2];
    QCOMPARE(pipe(fds), 0);

    struct pollfd pfd = { fds[1], POLLOUT, 0 };
    const int nready = qt_poll(&pfd, 1, NULL);

    QCOMPARE(nready, 1);
    QCOMPARE(pfd.revents, short(POLLOUT));

    qt_safe_close(fds[0]);
    qt_safe_close(fds[1]);
}

void tst_qt_poll::pollin()
{
    int fds[2];
    QCOMPARE(pipe(fds), 0);

    const char data = 'Q';
    QCOMPARE(qt_safe_write(fds[1], &data, 1), 1);

    struct pollfd pfd = { fds[0], POLLIN, 0 };
    const int nready = qt_poll(&pfd, 1, NULL);

    QCOMPARE(nready, 1);
    QCOMPARE(pfd.revents, short(POLLIN));

    qt_safe_close(fds[0]);
    qt_safe_close(fds[1]);
}

void tst_qt_poll::pollnval()
{
    struct pollfd pfd = { 42, POLLOUT, 0 };

    int nready = qt_poll(&pfd, 1, NULL);
    QCOMPARE(nready, 1);
    QCOMPARE(pfd.revents, short(POLLNVAL));

    pfd.events = 0;
    pfd.revents = 0;

    nready = qt_poll(&pfd, 1, NULL);
    QCOMPARE(nready, 1);
    QCOMPARE(pfd.revents, short(POLLNVAL));
}

void tst_qt_poll::pollprihup()
{
    QTcpServer server;
    QTcpSocket client_socket;

    QVERIFY(server.listen(QHostAddress::LocalHost));

    const quint16 server_port = server.serverPort();
    client_socket.connectToHost(server.serverAddress(), server_port);

    QVERIFY(client_socket.waitForConnected());
    QVERIFY(server.waitForNewConnection());

    QTcpSocket *server_socket = server.nextPendingConnection();
    server.close();

    // TCP supports only a single byte of urgent data
    static const char oob_out = 'Q';
    QCOMPARE(::send(server_socket->socketDescriptor(), &oob_out, 1, MSG_OOB),
             ssize_t(1));

    struct pollfd pfd = {
        int(client_socket.socketDescriptor()),
        POLLPRI | POLLIN,
        0
    };
    int res = qt_poll(&pfd, 1, NULL);

    QCOMPARE(res, 1);
    QCOMPARE(pfd.revents, short(POLLPRI | POLLIN));

    char oob_in = 0;
    // We do not specify MSG_OOB here as SO_OOBINLINE is turned on by default
    // in the native socket engine
    QCOMPARE(::recv(client_socket.socketDescriptor(), &oob_in, 1, 0),
             ssize_t(1));
    QCOMPARE(oob_in, oob_out);

    server_socket->close();
    pfd.events = POLLIN;
    res = qt_poll(&pfd, 1, NULL);

    QCOMPARE(res, 1);
    QCOMPARE(pfd.revents, short(POLLHUP));
}

QTEST_APPLESS_MAIN(tst_qt_poll)
#include "tst_qt_poll.moc"