1 /*
2 * Copyright (c) 2020, The OpenThread Authors.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions 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 * 3. Neither the name of the copyright holder nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #define OTBR_LOG_TAG "REST"
30
31 #include "rest/rest_web_server.hpp"
32
33 #include <arpa/inet.h>
34 #include <cerrno>
35
36 #include <fcntl.h>
37
38 #include "utils/socket_utils.hpp"
39
40 using std::chrono::duration_cast;
41 using std::chrono::microseconds;
42 using std::chrono::steady_clock;
43
44 namespace otbr {
45 namespace rest {
46
47 // Maximum number of connection a server support at the same time.
48 static const uint32_t kMaxServeNum = 500;
49
RestWebServer(RcpHost & aHost,const std::string & aRestListenAddress,int aRestListenPort)50 RestWebServer::RestWebServer(RcpHost &aHost, const std::string &aRestListenAddress, int aRestListenPort)
51 : mResource(Resource(&aHost))
52 , mListenFd(-1)
53 {
54 mAddress.sin6_family = AF_INET6;
55 mAddress.sin6_addr = in6addr_any;
56 mAddress.sin6_port = htons(aRestListenPort);
57
58 if (!aRestListenAddress.empty())
59 {
60 if (!ParseListenAddress(aRestListenAddress, &mAddress.sin6_addr))
61 otbrLogWarning("Failed to parse REST listen address %s, listening on any address.",
62 aRestListenAddress.c_str());
63 }
64 }
65
~RestWebServer(void)66 RestWebServer::~RestWebServer(void)
67 {
68 if (mListenFd != -1)
69 {
70 close(mListenFd);
71 }
72 }
73
Init(void)74 void RestWebServer::Init(void)
75 {
76 mResource.Init();
77 InitializeListenFd();
78 }
79
Update(MainloopContext & aMainloop)80 void RestWebServer::Update(MainloopContext &aMainloop)
81 {
82 aMainloop.AddFdToReadSet(mListenFd);
83
84 return;
85 }
86
Process(const MainloopContext & aMainloop)87 void RestWebServer::Process(const MainloopContext &aMainloop)
88 {
89 UpdateConnections(aMainloop.mReadFdSet);
90 }
91
UpdateConnections(const fd_set & aReadFdSet)92 void RestWebServer::UpdateConnections(const fd_set &aReadFdSet)
93 {
94 otbrError error = OTBR_ERROR_NONE;
95 auto eraseIt = mConnectionSet.begin();
96
97 // Erase useless connections
98 for (eraseIt = mConnectionSet.begin(); eraseIt != mConnectionSet.end();)
99 {
100 Connection *connection = eraseIt->second.get();
101
102 if (connection->IsComplete())
103 {
104 eraseIt = mConnectionSet.erase(eraseIt);
105 }
106 else
107 {
108 eraseIt++;
109 }
110 }
111
112 // Create new connection if listenfd is set
113 if (FD_ISSET(mListenFd, &aReadFdSet) && mConnectionSet.size() < kMaxServeNum)
114 {
115 error = Accept(mListenFd);
116 }
117
118 if (error != OTBR_ERROR_NONE)
119 {
120 otbrLogWarning("Failed to accept new connection: %s", otbrErrorString(error));
121 }
122 }
123
ParseListenAddress(const std::string listenAddress,struct in6_addr * sin6_addr)124 bool RestWebServer::ParseListenAddress(const std::string listenAddress, struct in6_addr *sin6_addr)
125 {
126 const std::string ipv4_prefix = "::FFFF:";
127 const std::string ipv4ListenAddress = ipv4_prefix + listenAddress;
128
129 if (inet_pton(AF_INET6, listenAddress.c_str(), sin6_addr) == 1)
130 {
131 return true;
132 }
133
134 if (inet_pton(AF_INET6, ipv4ListenAddress.c_str(), sin6_addr) == 1)
135 {
136 return true;
137 }
138
139 return false;
140 }
141
InitializeListenFd(void)142 void RestWebServer::InitializeListenFd(void)
143 {
144 otbrError error = OTBR_ERROR_NONE;
145 std::string errorMessage;
146 int32_t ret;
147 int32_t err = errno;
148 int32_t yes = 1;
149 int32_t no = 0;
150
151 mListenFd = SocketWithCloseExec(AF_INET6, SOCK_STREAM, 0, kSocketNonBlock);
152 VerifyOrExit(mListenFd != -1, err = errno, error = OTBR_ERROR_REST, errorMessage = "socket");
153
154 ret = setsockopt(mListenFd, IPPROTO_IPV6, IPV6_V6ONLY, reinterpret_cast<char *>(&no), sizeof(no));
155 VerifyOrExit(ret == 0, err = errno, error = OTBR_ERROR_REST, errorMessage = "sock opt v6only");
156
157 ret = setsockopt(mListenFd, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char *>(&yes), sizeof(yes));
158 VerifyOrExit(ret == 0, err = errno, error = OTBR_ERROR_REST, errorMessage = "sock opt reuseaddr");
159
160 ret = bind(mListenFd, reinterpret_cast<struct sockaddr *>(&mAddress), sizeof(mAddress));
161 VerifyOrExit(ret == 0, err = errno, error = OTBR_ERROR_REST, errorMessage = "bind");
162
163 ret = listen(mListenFd, 5);
164 VerifyOrExit(ret >= 0, err = errno, error = OTBR_ERROR_REST, errorMessage = "listen");
165
166 exit:
167
168 if (error != OTBR_ERROR_NONE)
169 {
170 otbrLogErr("InitializeListenFd error %s : %s", errorMessage.c_str(), strerror(err));
171 }
172
173 VerifyOrDie(error == OTBR_ERROR_NONE, "otbr rest server init error");
174 }
175
Accept(int aListenFd)176 otbrError RestWebServer::Accept(int aListenFd)
177 {
178 std::string errorMessage;
179 otbrError error = OTBR_ERROR_NONE;
180 int32_t err;
181 int32_t fd;
182 sockaddr_in tmp;
183 socklen_t addrlen = sizeof(tmp);
184
185 fd = accept(aListenFd, reinterpret_cast<struct sockaddr *>(&mAddress), &addrlen);
186 err = errno;
187
188 VerifyOrExit(fd >= 0, err = errno, error = OTBR_ERROR_REST, errorMessage = "accept");
189
190 VerifyOrExit(SetFdNonblocking(fd), err = errno, error = OTBR_ERROR_REST; errorMessage = "set nonblock");
191
192 CreateNewConnection(fd);
193
194 exit:
195 if (error != OTBR_ERROR_NONE)
196 {
197 if (fd != -1)
198 {
199 close(fd);
200 fd = -1;
201 }
202 otbrLogErr("Rest server accept error: %s %s", errorMessage.c_str(), strerror(err));
203 }
204
205 return error;
206 }
207
CreateNewConnection(int & aFd)208 void RestWebServer::CreateNewConnection(int &aFd)
209 {
210 auto it =
211 mConnectionSet.emplace(aFd, std::unique_ptr<Connection>(new Connection(steady_clock::now(), &mResource, aFd)));
212
213 if (it.second == true)
214 {
215 Connection *connection = it.first->second.get();
216 connection->Init();
217 }
218 else
219 {
220 // failure on inserting new connection
221 close(aFd);
222 aFd = -1;
223 }
224 }
225
SetFdNonblocking(int32_t fd)226 bool RestWebServer::SetFdNonblocking(int32_t fd)
227 {
228 int32_t oldMode;
229 bool ret = true;
230
231 oldMode = fcntl(fd, F_GETFL);
232
233 VerifyOrExit(fcntl(fd, F_SETFL, oldMode | O_NONBLOCK) >= 0, ret = false);
234
235 exit:
236 return ret;
237 }
238
239 } // namespace rest
240 } // namespace otbr
241