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 #include "rest/connection.hpp"
30
31 #include <cerrno>
32
33 #include <assert.h>
34
35 #include <sys/socket.h>
36 #include <sys/time.h>
37
38 using std::chrono::duration_cast;
39 using std::chrono::microseconds;
40 using std::chrono::seconds;
41 using std::chrono::steady_clock;
42
43 namespace otbr {
44 namespace rest {
45
46 // The timeout (in microseconds) since a connection is in wait callback state
47 static const uint32_t kCallbackTimeout = 10000000;
48
49 // The time interval (in microseconds) for checking again if there is a connection need callback.
50 static const uint32_t kCallbackCheckInterval = 500000;
51
52 // The timeout (in microseconds) since a connection is in wait write state
53 static const uint32_t kWriteTimeout = 10000000;
54
55 // The timeout (in microseconds) since a connection is in wait read state
56 static const uint32_t kReadTimeout = 1000000;
57
Connection(steady_clock::time_point aStartTime,Resource * aResource,int aFd)58 Connection::Connection(steady_clock::time_point aStartTime, Resource *aResource, int aFd)
59 : mTimeStamp(aStartTime)
60 , mFd(aFd)
61 , mState(ConnectionState::kInit)
62 , mParser(&mRequest)
63 , mResource(aResource)
64 {
65 }
66
~Connection(void)67 Connection::~Connection(void)
68 {
69 Disconnect();
70 }
71
Init(void)72 void Connection::Init(void)
73 {
74 mParser.Init();
75 }
76
UpdateReadFdSet(fd_set & aReadFdSet,int & aMaxFd) const77 void Connection::UpdateReadFdSet(fd_set &aReadFdSet, int &aMaxFd) const
78 {
79 if (mState == ConnectionState::kReadWait || mState == ConnectionState::kInit)
80 {
81 FD_SET(mFd, &aReadFdSet);
82 aMaxFd = aMaxFd < mFd ? mFd : aMaxFd;
83 }
84 }
85
UpdateWriteFdSet(fd_set & aWriteFdSet,int & aMaxFd) const86 void Connection::UpdateWriteFdSet(fd_set &aWriteFdSet, int &aMaxFd) const
87 {
88 if (mState == ConnectionState::kWriteWait)
89 {
90 FD_SET(mFd, &aWriteFdSet);
91 aMaxFd = aMaxFd < mFd ? mFd : aMaxFd;
92 }
93 }
94
UpdateTimeout(timeval & aTimeout) const95 void Connection::UpdateTimeout(timeval &aTimeout) const
96 {
97 struct timeval timeout;
98 uint32_t timeoutLen = kReadTimeout;
99 auto duration = duration_cast<microseconds>(steady_clock::now() - mTimeStamp).count();
100
101 switch (mState)
102 {
103 case ConnectionState::kReadWait:
104 timeoutLen = kReadTimeout;
105 break;
106 case ConnectionState::kCallbackWait:
107 timeoutLen = kCallbackCheckInterval;
108 break;
109 case ConnectionState::kWriteWait:
110 timeoutLen = kWriteTimeout;
111 break;
112 case ConnectionState::kComplete:
113 timeoutLen = 0;
114 break;
115 default:
116 break;
117 }
118
119 if (duration <= timeoutLen)
120 {
121 timeout.tv_sec = 0;
122 timeout.tv_usec = timeoutLen - duration;
123 }
124 else
125 {
126 timeout.tv_sec = 0;
127 timeout.tv_usec = 0;
128 }
129
130 if (timercmp(&timeout, &aTimeout, <))
131 {
132 aTimeout = timeout;
133 }
134 }
135
Update(MainloopContext & aMainloop)136 void Connection::Update(MainloopContext &aMainloop)
137 {
138 UpdateTimeout(aMainloop.mTimeout);
139 UpdateReadFdSet(aMainloop.mReadFdSet, aMainloop.mMaxFd);
140 UpdateWriteFdSet(aMainloop.mWriteFdSet, aMainloop.mMaxFd);
141 }
142
Disconnect(void)143 void Connection::Disconnect(void)
144 {
145 mState = ConnectionState::kComplete;
146
147 if (mFd != -1)
148 {
149 close(mFd);
150 mFd = -1;
151 }
152 }
153
Process(const MainloopContext & aMainloop)154 void Connection::Process(const MainloopContext &aMainloop)
155 {
156 otbrError error = OTBR_ERROR_NONE;
157
158 switch (mState)
159 {
160 // Initial state, directly read for the first time.
161 case ConnectionState::kInit:
162 case ConnectionState::kReadWait:
163 ProcessWaitRead(aMainloop.mReadFdSet);
164 break;
165 case ConnectionState::kCallbackWait:
166 // Wait for Callback process.
167 ProcessWaitCallback();
168 break;
169 case ConnectionState::kWriteWait:
170 ProcessWaitWrite(aMainloop.mWriteFdSet);
171 break;
172 default:
173 assert(false);
174 }
175
176 if (error != OTBR_ERROR_NONE)
177 {
178 Disconnect();
179 }
180 }
181
ProcessWaitRead(const fd_set & aReadFdSet)182 void Connection::ProcessWaitRead(const fd_set &aReadFdSet)
183 {
184 otbrError error = OTBR_ERROR_NONE;
185 int32_t received = 0, err;
186 char buf[2048];
187 auto duration = duration_cast<microseconds>(steady_clock::now() - mTimeStamp).count();
188
189 // Reach a read timeout, will send response about this timeout later.
190 VerifyOrExit(duration <= kReadTimeout, error = OTBR_ERROR_REST);
191
192 // It will succeed either fd is set or it is in kInit state.
193 VerifyOrExit(FD_ISSET(mFd, &aReadFdSet) || mState == ConnectionState::kInit);
194
195 do
196 {
197 mState = ConnectionState::kReadWait;
198 received = read(mFd, buf, sizeof(buf));
199 err = errno;
200 if (received > 0)
201 {
202 mParser.Process(buf, received);
203 }
204 } while ((received > 0 && !mRequest.IsComplete()) || err == EINTR);
205
206 if (mRequest.IsComplete())
207 {
208 Handle();
209 }
210
211 // Check first failure situation: received == 0 (indicate another side at least has closes its write side )
212 // and at the same time, the request has not been parsed completely.
213 VerifyOrExit(received != 0 || mRequest.IsComplete(), error = OTBR_ERROR_REST);
214
215 // Check second failure situation : received = -1 error(indicates that our system call read raise an error )
216 // then try to send back a response that there is an internal error.
217 VerifyOrExit(received > 0 || (received == -1 && (err == EAGAIN || err == EWOULDBLOCK)), error = OTBR_ERROR_REST);
218
219 exit:
220 if (error != OTBR_ERROR_NONE)
221 {
222 if (received < 0)
223 {
224 mResource->ErrorHandler(mResponse, HttpStatusCode::kStatusInternalServerError);
225 Write();
226 }
227 else
228 {
229 mResource->ErrorHandler(mResponse, HttpStatusCode::kStatusRequestTimeout);
230 Write();
231 }
232 }
233 }
234
Handle(void)235 void Connection::Handle(void)
236 {
237 otbrError error = OTBR_ERROR_NONE;
238
239 // Try to close server read side here, because we have started to handle the request and no longler read from
240 // socket.
241 VerifyOrExit((shutdown(mFd, SHUT_RD) == 0), error = OTBR_ERROR_REST);
242
243 mResource->Handle(mRequest, mResponse);
244
245 if (mResponse.NeedCallback())
246 {
247 mState = ConnectionState::kCallbackWait;
248 mTimeStamp = steady_clock::now();
249 }
250 else
251 {
252 // Normal Write back process.
253 Write();
254 }
255
256 exit:
257
258 if (error != OTBR_ERROR_NONE)
259 {
260 mResource->ErrorHandler(mResponse, HttpStatusCode::kStatusInternalServerError);
261 Write();
262 }
263 }
264
ProcessWaitCallback(void)265 void Connection::ProcessWaitCallback(void)
266 {
267 auto duration = duration_cast<microseconds>(steady_clock::now() - mTimeStamp).count();
268
269 mResource->HandleCallback(mRequest, mResponse);
270
271 if (mResponse.IsComplete())
272 {
273 Write();
274 }
275 else
276 {
277 if (duration >= kCallbackTimeout)
278 {
279 mResource->ErrorHandler(mResponse, HttpStatusCode::kStatusInternalServerError);
280 Write();
281 }
282 }
283 }
284
ProcessWaitWrite(const fd_set & aWriteFdSet)285 void Connection::ProcessWaitWrite(const fd_set &aWriteFdSet)
286 {
287 auto duration = duration_cast<microseconds>(steady_clock::now() - mTimeStamp).count();
288
289 if (duration <= kWriteTimeout)
290 {
291 if (FD_ISSET(mFd, &aWriteFdSet))
292 {
293 Write();
294 }
295 }
296 else
297 {
298 Disconnect();
299 }
300 }
301
Write(void)302 void Connection::Write(void)
303 {
304 otbrError error = OTBR_ERROR_NONE;
305 std::string errorCode;
306 int32_t sendLength;
307 int32_t err;
308
309 if (mState != ConnectionState::kWriteWait)
310 {
311 // Change its state when try write for the first time.
312 mState = ConnectionState::kWriteWait;
313 mTimeStamp = steady_clock::now();
314 mWriteContent = mResponse.Serialize();
315 }
316
317 // Check we do have something to write.
318 VerifyOrExit(mWriteContent.size() > 0, error = OTBR_ERROR_REST);
319
320 sendLength = write(mFd, mWriteContent.c_str(), mWriteContent.size());
321 err = errno;
322
323 // Write successfully
324 if (sendLength == static_cast<int32_t>(mWriteContent.size()))
325 {
326 // Normal Exit
327 Disconnect();
328 }
329 else if (sendLength > 0)
330 {
331 // Partly write
332 mWriteContent = mWriteContent.substr(sendLength);
333 }
334 else
335 {
336 if (errno == EINTR)
337 {
338 // Try again
339 Write();
340 }
341 else
342 {
343 // There is an error when we write, if this, we directly disconnect this connection.
344 VerifyOrExit(err == EAGAIN || err == EWOULDBLOCK, error = OTBR_ERROR_REST);
345 }
346 }
347
348 exit:
349 if (error != OTBR_ERROR_NONE)
350 {
351 Disconnect();
352 }
353 }
354
IsComplete() const355 bool Connection::IsComplete() const
356 {
357 return mState == ConnectionState::kComplete;
358 }
359
360 } // namespace rest
361 } // namespace otbr
362