f6dedeea11eb53b3e4fdaa7b867804365bf177f1
[WebKit-https.git] / Tools / TestWebKitAPI / TCPServer.cpp
1 /*
2  * Copyright (C) 2019 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "TCPServer.h"
28
29 #include <netinet/in.h>
30 #include <thread>
31 #include <unistd.h>
32 #include <vector>
33
34 namespace TestWebKitAPI {
35
36 TCPServer::TCPServer(Function<void(Socket)>&& socketHandler)
37     : m_socketHandler(WTFMove(socketHandler))
38 {
39     socketBindListen();
40     m_thread = std::thread(&TCPServer::waitForAndReplyToRequests, this);
41 }
42
43 TCPServer::~TCPServer()
44 {
45     m_thread.join();
46     if (m_listeningSocket != InvalidSocket) {
47         close(m_listeningSocket);
48         m_listeningSocket = InvalidSocket;
49     }
50     if (m_connectionSocket != InvalidSocket) {
51         close(m_connectionSocket);
52         m_connectionSocket = InvalidSocket;
53     }
54 }
55
56 void TCPServer::socketBindListen()
57 {
58     m_listeningSocket = socket(PF_INET, SOCK_STREAM, 0);
59     if (m_listeningSocket == InvalidSocket)
60         return;
61     
62     // Ports 49152-65535 are unallocated ports. Try until we find one that's free.
63     for (Port port = 49152; port; port++) {
64         struct sockaddr_in name;
65         memset(&name, 0, sizeof(name));
66         name.sin_family = AF_INET;
67         name.sin_port = htons(port);
68         name.sin_addr.s_addr = htonl(INADDR_ANY);
69         if (bind(m_listeningSocket, reinterpret_cast<sockaddr*>(&name), sizeof(name)) < 0) {
70             // This port is busy. Try the next port.
71             continue;
72         }
73         const unsigned maxConnections = 1;
74         if (listen(m_listeningSocket, maxConnections) == -1) {
75             // Listening failed.
76             close(m_listeningSocket);
77             m_listeningSocket = InvalidSocket;
78             return;
79         }
80         m_port = port;
81         return; // Successfully set up listening port.
82     }
83     
84     // Couldn't find an available port.
85     close(m_listeningSocket);
86     m_listeningSocket = InvalidSocket;
87 }
88
89 void TCPServer::waitForAndReplyToRequests()
90 {
91     if (m_listeningSocket == InvalidSocket)
92         return;
93     
94     m_connectionSocket = accept(m_listeningSocket, nullptr, nullptr);
95     m_socketHandler(m_connectionSocket);
96     shutdown(m_connectionSocket, SHUT_RDWR);
97 }
98
99 } // namespace TestWebKitAPI