1 /*
2 * Copyright (c) Facebook, Inc. and its affiliates.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <folly/io/async/AsyncSocket.h>
18
19 #include <iostream>
20
21 #include <folly/io/async/AsyncServerSocket.h>
22 #include <folly/io/async/EventBase.h>
23 #include <folly/portability/GTest.h>
24
25 namespace folly {
26
27 #ifndef TCP_SAVE_SYN
28 #define TCP_SAVE_SYN 27
29 #endif
30
TEST(AsyncSocketTest,getSockOpt)31 TEST(AsyncSocketTest, getSockOpt) {
32 EventBase evb;
33 std::shared_ptr<AsyncSocket> socket =
34 AsyncSocket::newSocket(&evb, NetworkSocket(0));
35
36 int val;
37 socklen_t len;
38
39 int expectedRc = netops::getsockopt(
40 socket->getNetworkSocket(), SOL_SOCKET, SO_REUSEADDR, &val, &len);
41 int actualRc = socket->getSockOpt(SOL_SOCKET, SO_REUSEADDR, &val, &len);
42
43 EXPECT_EQ(expectedRc, actualRc);
44 }
45
TEST(AsyncSocketTest,REUSEPORT)46 TEST(AsyncSocketTest, REUSEPORT) {
47 EventBase base;
48 auto serverSocket = AsyncServerSocket::newSocket(&base);
49 serverSocket->bind(0);
50 serverSocket->listen(0);
51 serverSocket->startAccepting();
52
53 try {
54 serverSocket->setReusePortEnabled(true);
55 } catch (...) {
56 LOG(INFO) << "Reuse port probably not supported";
57 return;
58 }
59
60 SocketAddress address;
61 serverSocket->getAddress(&address);
62 int port = address.getPort();
63
64 auto serverSocket2 = AsyncServerSocket::newSocket(&base);
65 serverSocket2->setReusePortEnabled(true);
66 serverSocket2->bind(port);
67 serverSocket2->listen(0);
68 serverSocket2->startAccepting();
69 }
70
TEST(AsyncSocketTest,v4v6samePort)71 TEST(AsyncSocketTest, v4v6samePort) {
72 EventBase base;
73 auto serverSocket = AsyncServerSocket::newSocket(&base);
74 serverSocket->bind(0);
75 auto addrs = serverSocket->getAddresses();
76 ASSERT_GT(addrs.size(), 0);
77 uint16_t port = addrs[0].getPort();
78 for (const auto& addr : addrs) {
79 EXPECT_EQ(port, addr.getPort());
80 }
81 }
82
TEST(AsyncSocketTest,duplicateBind)83 TEST(AsyncSocketTest, duplicateBind) {
84 EventBase base;
85 auto server1 = AsyncServerSocket::newSocket(&base);
86 server1->bind(0);
87 server1->listen(10);
88
89 SocketAddress address;
90 server1->getAddress(std::addressof(address));
91
92 auto server2 = AsyncServerSocket::newSocket(&base);
93 EXPECT_THROW(server2->bind(address.getPort()), std::exception);
94 }
95
TEST(AsyncSocketTest,tosReflect)96 TEST(AsyncSocketTest, tosReflect) {
97 EventBase base;
98 auto server1 = AsyncServerSocket::newSocket(&base);
99 server1->bind(0);
100 server1->listen(10);
101 auto fd = server1->getNetworkSocket();
102
103 // Verify if tos reflect is disabled by default
104 // and the TCP_SAVE_SYN setting is not enabled
105 EXPECT_FALSE(server1->getTosReflect());
106 int value;
107 socklen_t valueLength = sizeof(value);
108 int rc =
109 netops::getsockopt(fd, IPPROTO_TCP, TCP_SAVE_SYN, &value, &valueLength);
110 ASSERT_EQ(rc, 0);
111 ASSERT_EQ(value, 0);
112
113 // Enable TOS reflect on the server socket
114 server1->setTosReflect(true);
115
116 // Verify if tos reflect is enabled now
117 // and the TCP_SAVE_SYN setting is also enabled
118 EXPECT_TRUE(server1->getTosReflect());
119 rc = netops::getsockopt(fd, IPPROTO_TCP, TCP_SAVE_SYN, &value, &valueLength);
120 ASSERT_EQ(rc, 0);
121 ASSERT_EQ(value, 1);
122 }
123
TEST(AsyncSocketTest,listenerTosV6)124 TEST(AsyncSocketTest, listenerTosV6) {
125 EventBase base;
126 auto server1 = AsyncServerSocket::newSocket(&base);
127 server1->bind(0);
128 server1->listen(10);
129 auto fd = server1->getNetworkSocket();
130
131 // Verify if Listener TOS is disabled by default
132 EXPECT_FALSE(server1->getListenerTos());
133 int value;
134 socklen_t valueLength = sizeof(value);
135 int rc =
136 netops::getsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &value, &valueLength);
137 ASSERT_EQ(rc, 0);
138 ASSERT_EQ(value, 0);
139
140 // Set listener Tos to 116 (0x74, represents dscp 29)
141 server1->setListenerTos(116);
142
143 // Verify if listener DSCP is set now
144 EXPECT_TRUE(server1->getListenerTos());
145 rc = netops::getsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &value, &valueLength);
146 ASSERT_EQ(rc, 0);
147 ASSERT_EQ(value, 116);
148 }
149
TEST(AsyncSocketTest,listenerTosV4)150 TEST(AsyncSocketTest, listenerTosV4) {
151 EventBase base;
152 auto server1 = AsyncServerSocket::newSocket(&base);
153 folly::IPAddress ip("127.0.0.1");
154 std::vector<folly::IPAddress> serverIp;
155 serverIp.push_back(ip);
156 server1->bind(serverIp, 0);
157 server1->listen(10);
158 auto fd = server1->getNetworkSocket();
159
160 // Verify if Listener TOS is disabled by default
161 EXPECT_FALSE(server1->getListenerTos());
162 int value;
163 socklen_t valueLength = sizeof(value);
164 int rc = netops::getsockopt(fd, IPPROTO_IP, IP_TOS, &value, &valueLength);
165 ASSERT_EQ(rc, 0);
166 ASSERT_EQ(value, 0);
167
168 // Set listener Tos to 140 (0x8c, represents dscp 35)
169 server1->setListenerTos(140);
170
171 // Verify if listener DSCP is set now
172 EXPECT_TRUE(server1->getListenerTos());
173 rc = netops::getsockopt(fd, IPPROTO_IP, IP_TOS, &value, &valueLength);
174 ASSERT_EQ(rc, 0);
175 ASSERT_EQ(value, 140);
176 }
177
178 } // namespace folly
179