• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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