• 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 <cerrno>
34 
35 #include <fcntl.h>
36 
37 #include "utils/socket_utils.hpp"
38 
39 using std::chrono::duration_cast;
40 using std::chrono::microseconds;
41 using std::chrono::steady_clock;
42 
43 namespace otbr {
44 namespace rest {
45 
46 // Maximum number of connection a server support at the same time.
47 static const uint32_t kMaxServeNum = 500;
48 // Port number used by Rest server.
49 static const uint32_t kPortNumber = 8081;
50 
RestWebServer(ControllerOpenThread & aNcp)51 RestWebServer::RestWebServer(ControllerOpenThread &aNcp)
52     : mResource(Resource(&aNcp))
53     , mListenFd(-1)
54 {
55 }
56 
~RestWebServer(void)57 RestWebServer::~RestWebServer(void)
58 {
59     if (mListenFd != -1)
60     {
61         close(mListenFd);
62     }
63 }
64 
Init(void)65 void RestWebServer::Init(void)
66 {
67     mResource.Init();
68     InitializeListenFd();
69 }
70 
Update(MainloopContext & aMainloop)71 void RestWebServer::Update(MainloopContext &aMainloop)
72 {
73     FD_SET(mListenFd, &aMainloop.mReadFdSet);
74     aMainloop.mMaxFd = std::max(aMainloop.mMaxFd, mListenFd);
75 
76     return;
77 }
78 
Process(const MainloopContext & aMainloop)79 void RestWebServer::Process(const MainloopContext &aMainloop)
80 {
81     UpdateConnections(aMainloop.mReadFdSet);
82 }
83 
UpdateConnections(const fd_set & aReadFdSet)84 void RestWebServer::UpdateConnections(const fd_set &aReadFdSet)
85 {
86     otbrError error   = OTBR_ERROR_NONE;
87     auto      eraseIt = mConnectionSet.begin();
88 
89     // Erase useless connections
90     for (eraseIt = mConnectionSet.begin(); eraseIt != mConnectionSet.end();)
91     {
92         Connection *connection = eraseIt->second.get();
93 
94         if (connection->IsComplete())
95         {
96             eraseIt = mConnectionSet.erase(eraseIt);
97         }
98         else
99         {
100             eraseIt++;
101         }
102     }
103 
104     // Create new connection if listenfd is set
105     if (FD_ISSET(mListenFd, &aReadFdSet) && mConnectionSet.size() < kMaxServeNum)
106     {
107         error = Accept(mListenFd);
108     }
109 
110     if (error != OTBR_ERROR_NONE)
111     {
112         otbrLogWarning("Failed to accept new connection: %s", otbrErrorString(error));
113     }
114 }
115 
InitializeListenFd(void)116 void RestWebServer::InitializeListenFd(void)
117 {
118     otbrError   error = OTBR_ERROR_NONE;
119     std::string errorMessage;
120     int32_t     ret;
121     int32_t     err    = errno;
122     int32_t     optval = 1;
123 
124     mAddress.sin_family      = AF_INET;
125     mAddress.sin_addr.s_addr = INADDR_ANY;
126     mAddress.sin_port        = htons(kPortNumber);
127 
128     mListenFd = SocketWithCloseExec(AF_INET, SOCK_STREAM, 0, kSocketNonBlock);
129     VerifyOrExit(mListenFd != -1, err = errno, error = OTBR_ERROR_REST, errorMessage = "socket");
130 
131     ret = setsockopt(mListenFd, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char *>(&optval), sizeof(optval));
132     VerifyOrExit(ret == 0, err = errno, error = OTBR_ERROR_REST, errorMessage = "sock opt");
133 
134     ret = bind(mListenFd, reinterpret_cast<struct sockaddr *>(&mAddress), sizeof(sockaddr));
135     VerifyOrExit(ret == 0, err = errno, error = OTBR_ERROR_REST, errorMessage = "bind");
136 
137     ret = listen(mListenFd, 5);
138     VerifyOrExit(ret >= 0, err = errno, error = OTBR_ERROR_REST, errorMessage = "listen");
139 
140 exit:
141 
142     if (error != OTBR_ERROR_NONE)
143     {
144         otbrLogErr("InitializeListenFd error %s : %s", errorMessage.c_str(), strerror(err));
145     }
146 
147     VerifyOrDie(error == OTBR_ERROR_NONE, "otbr rest server init error");
148 }
149 
Accept(int aListenFd)150 otbrError RestWebServer::Accept(int aListenFd)
151 {
152     std::string errorMessage;
153     otbrError   error = OTBR_ERROR_NONE;
154     int32_t     err;
155     int32_t     fd;
156     sockaddr_in tmp;
157     socklen_t   addrlen = sizeof(tmp);
158 
159     fd  = accept(aListenFd, reinterpret_cast<struct sockaddr *>(&mAddress), &addrlen);
160     err = errno;
161 
162     VerifyOrExit(fd >= 0, err = errno, error = OTBR_ERROR_REST, errorMessage = "accept");
163 
164     VerifyOrExit(SetFdNonblocking(fd), err = errno, error = OTBR_ERROR_REST; errorMessage = "set nonblock");
165 
166     CreateNewConnection(fd);
167 
168 exit:
169     if (error != OTBR_ERROR_NONE)
170     {
171         if (fd != -1)
172         {
173             close(fd);
174             fd = -1;
175         }
176         otbrLogErr("Rest server accept error: %s %s", errorMessage.c_str(), strerror(err));
177     }
178 
179     return error;
180 }
181 
CreateNewConnection(int & aFd)182 void RestWebServer::CreateNewConnection(int &aFd)
183 {
184     auto it =
185         mConnectionSet.emplace(aFd, std::unique_ptr<Connection>(new Connection(steady_clock::now(), &mResource, aFd)));
186 
187     if (it.second == true)
188     {
189         Connection *connection = it.first->second.get();
190         connection->Init();
191     }
192     else
193     {
194         // failure on inserting new connection
195         close(aFd);
196         aFd = -1;
197     }
198 }
199 
SetFdNonblocking(int32_t fd)200 bool RestWebServer::SetFdNonblocking(int32_t fd)
201 {
202     int32_t oldMode;
203     bool    ret = true;
204 
205     oldMode = fcntl(fd, F_GETFL);
206 
207     VerifyOrExit(fcntl(fd, F_SETFL, oldMode | O_NONBLOCK) >= 0, ret = false);
208 
209 exit:
210     return ret;
211 }
212 
213 } // namespace rest
214 } // namespace otbr
215