xref: /aosp_15_r20/external/ot-br-posix/src/rest/rest_web_server.cpp (revision 4a64e381480ef79f0532b2421e44e6ee336b8e0d)
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