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(ControllerOpenThread & aNcp,const std::string & aRestListenAddress,int aRestListenPort)50 RestWebServer::RestWebServer(ControllerOpenThread &aNcp, const std::string &aRestListenAddress, int aRestListenPort)
51 : mResource(Resource(&aNcp))
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 FD_SET(mListenFd, &aMainloop.mReadFdSet);
83 aMainloop.mMaxFd = std::max(aMainloop.mMaxFd, mListenFd);
84
85 return;
86 }
87
Process(const MainloopContext & aMainloop)88 void RestWebServer::Process(const MainloopContext &aMainloop)
89 {
90 UpdateConnections(aMainloop.mReadFdSet);
91 }
92
UpdateConnections(const fd_set & aReadFdSet)93 void RestWebServer::UpdateConnections(const fd_set &aReadFdSet)
94 {
95 otbrError error = OTBR_ERROR_NONE;
96 auto eraseIt = mConnectionSet.begin();
97
98 // Erase useless connections
99 for (eraseIt = mConnectionSet.begin(); eraseIt != mConnectionSet.end();)
100 {
101 Connection *connection = eraseIt->second.get();
102
103 if (connection->IsComplete())
104 {
105 eraseIt = mConnectionSet.erase(eraseIt);
106 }
107 else
108 {
109 eraseIt++;
110 }
111 }
112
113 // Create new connection if listenfd is set
114 if (FD_ISSET(mListenFd, &aReadFdSet) && mConnectionSet.size() < kMaxServeNum)
115 {
116 error = Accept(mListenFd);
117 }
118
119 if (error != OTBR_ERROR_NONE)
120 {
121 otbrLogWarning("Failed to accept new connection: %s", otbrErrorString(error));
122 }
123 }
124
ParseListenAddress(const std::string listenAddress,struct in6_addr * sin6_addr)125 bool RestWebServer::ParseListenAddress(const std::string listenAddress, struct in6_addr *sin6_addr)
126 {
127 const std::string ipv4_prefix = "::FFFF:";
128 const std::string ipv4ListenAddress = ipv4_prefix + listenAddress;
129
130 if (inet_pton(AF_INET6, listenAddress.c_str(), sin6_addr) == 1)
131 {
132 return true;
133 }
134
135 if (inet_pton(AF_INET6, ipv4ListenAddress.c_str(), sin6_addr) == 1)
136 {
137 return true;
138 }
139
140 return false;
141 }
142
InitializeListenFd(void)143 void RestWebServer::InitializeListenFd(void)
144 {
145 otbrError error = OTBR_ERROR_NONE;
146 std::string errorMessage;
147 int32_t ret;
148 int32_t err = errno;
149 int32_t yes = 1;
150 int32_t no = 0;
151
152 mListenFd = SocketWithCloseExec(AF_INET6, SOCK_STREAM, 0, kSocketNonBlock);
153 VerifyOrExit(mListenFd != -1, err = errno, error = OTBR_ERROR_REST, errorMessage = "socket");
154
155 ret = setsockopt(mListenFd, IPPROTO_IPV6, IPV6_V6ONLY, reinterpret_cast<char *>(&no), sizeof(no));
156 VerifyOrExit(ret == 0, err = errno, error = OTBR_ERROR_REST, errorMessage = "sock opt v6only");
157
158 ret = setsockopt(mListenFd, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char *>(&yes), sizeof(yes));
159 VerifyOrExit(ret == 0, err = errno, error = OTBR_ERROR_REST, errorMessage = "sock opt reuseaddr");
160
161 ret = bind(mListenFd, reinterpret_cast<struct sockaddr *>(&mAddress), sizeof(mAddress));
162 VerifyOrExit(ret == 0, err = errno, error = OTBR_ERROR_REST, errorMessage = "bind");
163
164 ret = listen(mListenFd, 5);
165 VerifyOrExit(ret >= 0, err = errno, error = OTBR_ERROR_REST, errorMessage = "listen");
166
167 exit:
168
169 if (error != OTBR_ERROR_NONE)
170 {
171 otbrLogErr("InitializeListenFd error %s : %s", errorMessage.c_str(), strerror(err));
172 }
173
174 VerifyOrDie(error == OTBR_ERROR_NONE, "otbr rest server init error");
175 }
176
Accept(int aListenFd)177 otbrError RestWebServer::Accept(int aListenFd)
178 {
179 std::string errorMessage;
180 otbrError error = OTBR_ERROR_NONE;
181 int32_t err;
182 int32_t fd;
183 sockaddr_in tmp;
184 socklen_t addrlen = sizeof(tmp);
185
186 fd = accept(aListenFd, reinterpret_cast<struct sockaddr *>(&mAddress), &addrlen);
187 err = errno;
188
189 VerifyOrExit(fd >= 0, err = errno, error = OTBR_ERROR_REST, errorMessage = "accept");
190
191 VerifyOrExit(SetFdNonblocking(fd), err = errno, error = OTBR_ERROR_REST; errorMessage = "set nonblock");
192
193 CreateNewConnection(fd);
194
195 exit:
196 if (error != OTBR_ERROR_NONE)
197 {
198 if (fd != -1)
199 {
200 close(fd);
201 fd = -1;
202 }
203 otbrLogErr("Rest server accept error: %s %s", errorMessage.c_str(), strerror(err));
204 }
205
206 return error;
207 }
208
CreateNewConnection(int & aFd)209 void RestWebServer::CreateNewConnection(int &aFd)
210 {
211 auto it =
212 mConnectionSet.emplace(aFd, std::unique_ptr<Connection>(new Connection(steady_clock::now(), &mResource, aFd)));
213
214 if (it.second == true)
215 {
216 Connection *connection = it.first->second.get();
217 connection->Init();
218 }
219 else
220 {
221 // failure on inserting new connection
222 close(aFd);
223 aFd = -1;
224 }
225 }
226
SetFdNonblocking(int32_t fd)227 bool RestWebServer::SetFdNonblocking(int32_t fd)
228 {
229 int32_t oldMode;
230 bool ret = true;
231
232 oldMode = fcntl(fd, F_GETFL);
233
234 VerifyOrExit(fcntl(fd, F_SETFL, oldMode | O_NONBLOCK) >= 0, ret = false);
235
236 exit:
237 return ret;
238 }
239
240 } // namespace rest
241 } // namespace otbr
242