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