1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "clients_test.h"
18 
19 #include <gtest/gtest.h>
20 
21 #include <string.h>
22 #include <thread>
23 
24 #include "chpp/app.h"
25 #include "chpp/clients.h"
26 #include "chpp/macros.h"
27 #include "chpp/memory.h"
28 #include "chpp/platform/utils.h"
29 #include "chpp/services.h"
30 #include "chpp/time.h"
31 #include "chpp/transport.h"
32 #include "chre/pal/wwan.h"
33 
34 class ClientsTest : public testing::Test {
35  protected:
36   void SetUp() override {
37     chppClearTotalAllocBytes();
38     memset(&mTransportContext.linkParams, 0,
39            sizeof(mTransportContext.linkParams));
40     mTransportContext.linkParams.linkEstablished = true;
41     chppTransportInit(&mTransportContext, &mAppContext);
42     chppAppInit(&mAppContext, &mTransportContext);
43     mClientState =
44         (struct ChppClientState *)mAppContext.registeredClientContexts[0];
45     chppClientInit(mClientState, CHPP_HANDLE_NEGOTIATED_RANGE_START);
46 
47     mTransportContext.resetState = CHPP_RESET_STATE_NONE;
48   }
49 
50   void TearDown() override {
51     chppAppDeinit(&mAppContext);
52     chppTransportDeinit(&mTransportContext);
53 
54     EXPECT_EQ(chppGetTotalAllocBytes(), 0);
55   }
56 
57   struct ChppTransportState mTransportContext;
58   struct ChppAppState mAppContext;
59   struct ChppClient mClient;
60   struct ChppClientState *mClientState;
61   struct ChppRequestResponseState mRRState;
62 };
63 
64 void getClientRRStateInputCheck(struct ChppClientState *clientState,
65                                 struct ChppAppHeader *header) {
66   ASSERT_TRUE(clientState != NULL);
67   uint8_t clientIdx = clientState->index;
68 
69   ASSERT_TRUE(clientState->appContext != NULL);
70   ASSERT_TRUE(clientState->appContext->registeredClients != NULL);
71   ASSERT_TRUE(clientState->appContext->registeredClients[clientIdx] != NULL);
72   ASSERT_TRUE(
73       clientState->appContext->registeredClientStates[clientIdx]->rRStates !=
74       NULL);
75   ASSERT_LT(
76       header->command,
77       clientState->appContext->registeredClients[clientIdx]->rRStateCount);
78 }
79 
80 struct ChppRequestResponseState *getClientRRState(
81     struct ChppClientState *clientState, struct ChppAppHeader *header) {
82   getClientRRStateInputCheck(clientState, header);
83 
84   uint8_t clientIdx = clientState->index;
85   return &(clientState->appContext->registeredClientStates[clientIdx]
86                ->rRStates[header->command]);
87 }
88 
89 void isTimeoutAsExpected(uint64_t timeoutTimeNs, uint64_t expectedTimeNs) {
90   uint64_t kJitterNs = 10 * CHPP_NSEC_PER_MSEC;
91 
92   if (expectedTimeNs == CHPP_TIME_MAX) {
93     EXPECT_EQ(timeoutTimeNs, expectedTimeNs);
94   } else {
95     EXPECT_GE(timeoutTimeNs, expectedTimeNs);
96     EXPECT_LE(timeoutTimeNs, expectedTimeNs + kJitterNs);
97   }
98 }
99 
100 void registerAndValidateRequestForTimeout(struct ChppClientState *clientState,
101                                           struct ChppAppHeader *header,
102                                           uint64_t timeoutNs,
103                                           uint64_t expectedTimeNs) {
104   struct ChppRequestResponseState *rRState =
105       getClientRRState(clientState, header);
106   chppClientTimestampRequest(clientState, rRState, header, timeoutNs);
107 
108   isTimeoutAsExpected(clientState->appContext->nextRequestTimeoutNs,
109                       expectedTimeNs);
110 }
111 
112 void registerAndValidateResponseForTimeout(struct ChppClientState *clientState,
113                                            const struct ChppAppHeader *header,
114                                            uint64_t expectedTimeNs) {
115   ASSERT_FALSE(clientState == NULL);
116   uint8_t clientIdx = clientState->index;
117 
118   ASSERT_FALSE(clientState->appContext == NULL);
119   ASSERT_FALSE(clientState->appContext->registeredClients == NULL);
120   ASSERT_FALSE(clientState->appContext->registeredClients[clientIdx] == NULL);
121   ASSERT_FALSE(
122       clientState->appContext->registeredClientStates[clientIdx]->rRStates ==
123       NULL);
124   ASSERT_LT(
125       header->command,
126       clientState->appContext->registeredClients[clientIdx]->rRStateCount);
127 
128   struct ChppRequestResponseState *rRState =
129       &(clientState->appContext->registeredClientStates[clientIdx]
130             ->rRStates[header->command]);
131   chppClientTimestampResponse(clientState, rRState, header);
132 
133   isTimeoutAsExpected(clientState->appContext->nextRequestTimeoutNs,
134                       expectedTimeNs);
135 }
136 
137 void validateTimeoutResponse(const struct ChppAppHeader *request,
138                              const struct ChppAppHeader *response) {
139   ASSERT_TRUE(request != NULL);
140   ASSERT_TRUE(response != NULL);
141 
142   EXPECT_EQ(response->handle, request->handle);
143   EXPECT_EQ(response->type, CHPP_MESSAGE_TYPE_SERVICE_RESPONSE);
144   EXPECT_EQ(response->transaction, request->transaction);
145   EXPECT_EQ(response->error, CHPP_APP_ERROR_TIMEOUT);
146   EXPECT_EQ(response->command, request->command);
147 }
148 
149 TEST_F(ClientsTest, RequestResponseTimestampValid) {
150   struct ChppAppHeader *reqHeader =
151       chppAllocClientRequestCommand(mClientState, 0 /* command */);
152   chppClientTimestampRequest(mClientState, &mRRState, reqHeader,
153                              CHPP_CLIENT_REQUEST_TIMEOUT_INFINITE);
154 
155   struct ChppAppHeader *respHeader =
156       chppAllocServiceResponse(reqHeader, sizeof(*reqHeader));
157   ASSERT_TRUE(chppClientTimestampResponse(mClientState, &mRRState, respHeader));
158 
159   chppFree(reqHeader);
160   chppFree(respHeader);
161 }
162 
163 TEST_F(ClientsTest, RequestResponseTimestampDuplicate) {
164   struct ChppAppHeader *reqHeader =
165       chppAllocClientRequestCommand(mClientState, 0 /* command */);
166   chppClientTimestampRequest(mClientState, &mRRState, reqHeader,
167                              CHPP_CLIENT_REQUEST_TIMEOUT_INFINITE);
168 
169   struct ChppAppHeader *respHeader =
170       chppAllocServiceResponse(reqHeader, sizeof(*reqHeader));
171   ASSERT_TRUE(chppClientTimestampResponse(mClientState, &mRRState, respHeader));
172   ASSERT_FALSE(
173       chppClientTimestampResponse(mClientState, &mRRState, respHeader));
174 
175   chppFree(reqHeader);
176   chppFree(respHeader);
177 }
178 
179 TEST_F(ClientsTest, RequestResponseTimestampInvalidId) {
180   struct ChppAppHeader *reqHeader =
181       chppAllocClientRequestCommand(mClientState, 0 /* command */);
182   chppClientTimestampRequest(mClientState, &mRRState, reqHeader,
183                              CHPP_CLIENT_REQUEST_TIMEOUT_INFINITE);
184 
185   struct ChppAppHeader *newReqHeader =
186       chppAllocClientRequestCommand(mClientState, 0 /* command */);
187   struct ChppAppHeader *respHeader =
188       chppAllocServiceResponse(newReqHeader, sizeof(*reqHeader));
189   ASSERT_FALSE(
190       chppClientTimestampResponse(mClientState, &mRRState, respHeader));
191 
192   chppFree(reqHeader);
193   chppFree(newReqHeader);
194   chppFree(respHeader);
195 }
196 
197 TEST_F(ClientsTest, RequestTimeoutAddRemoveSingle) {
198   EXPECT_EQ(mAppContext.nextRequestTimeoutNs, CHPP_TIME_MAX);
199 
200   struct ChppAppHeader *reqHeader =
201       chppAllocClientRequestCommand(mClientState, 1 /* command */);
202 
203   uint64_t time = chppGetCurrentTimeNs();
204   uint64_t timeout = 1000 * CHPP_NSEC_PER_MSEC;
205   registerAndValidateRequestForTimeout(mClientState, reqHeader, timeout,
206                                        time + timeout);
207 
208   EXPECT_TRUE(
209       chppTransportGetClientRequestTimeoutResponse(&mTransportContext) == NULL);
210 
211   registerAndValidateResponseForTimeout(mClientState, reqHeader, CHPP_TIME_MAX);
212 
213   chppFree(reqHeader);
214 }
215 
216 TEST_F(ClientsTest, RequestTimeoutAddRemoveMultiple) {
217   struct ChppAppHeader *reqHeader1 =
218       chppAllocClientRequestCommand(mClientState, 0 /* command */);
219   struct ChppAppHeader *reqHeader2 =
220       chppAllocClientRequestCommand(mClientState, 1 /* command */);
221   struct ChppAppHeader *reqHeader3 =
222       chppAllocClientRequestCommand(mClientState, 2 /* command */);
223 
224   EXPECT_EQ(mAppContext.nextRequestTimeoutNs, CHPP_TIME_MAX);
225 
226   uint64_t time1 = chppGetCurrentTimeNs();
227   uint64_t timeout1 = 2000 * CHPP_NSEC_PER_MSEC;
228   registerAndValidateRequestForTimeout(mClientState, reqHeader1, timeout1,
229                                        time1 + timeout1);
230 
231   uint64_t time2 = chppGetCurrentTimeNs();
232   uint64_t timeout2 = 4000 * CHPP_NSEC_PER_MSEC;
233   registerAndValidateRequestForTimeout(mClientState, reqHeader2, timeout2,
234                                        time1 + timeout1);
235 
236   uint64_t time3 = chppGetCurrentTimeNs();
237   uint64_t timeout3 = 3000 * CHPP_NSEC_PER_MSEC;
238   registerAndValidateRequestForTimeout(mClientState, reqHeader3, timeout3,
239                                        time1 + timeout1);
240 
241   registerAndValidateResponseForTimeout(mClientState, reqHeader1,
242                                         time3 + timeout3);
243 
244   EXPECT_TRUE(
245       chppTransportGetClientRequestTimeoutResponse(&mTransportContext) == NULL);
246 
247   uint64_t time4 = chppGetCurrentTimeNs();
248   uint64_t timeout4 = 1000 * CHPP_NSEC_PER_MSEC;
249   registerAndValidateRequestForTimeout(mClientState, reqHeader1, timeout4,
250                                        time4 + timeout4);
251 
252   registerAndValidateResponseForTimeout(mClientState, reqHeader1,
253                                         time3 + timeout3);
254 
255   registerAndValidateResponseForTimeout(mClientState, reqHeader3,
256                                         time2 + timeout2);
257 
258   registerAndValidateResponseForTimeout(mClientState, reqHeader2,
259                                         CHPP_TIME_MAX);
260 
261   EXPECT_TRUE(
262       chppTransportGetClientRequestTimeoutResponse(&mTransportContext) == NULL);
263 
264   chppFree(reqHeader1);
265   chppFree(reqHeader2);
266   chppFree(reqHeader3);
267 }
268 
269 TEST_F(ClientsTest, DuplicateRequestTimeoutResponse) {
270   EXPECT_EQ(mAppContext.nextRequestTimeoutNs, CHPP_TIME_MAX);
271 
272   struct ChppAppHeader *reqHeader =
273       chppAllocClientRequestCommand(mClientState, 1 /* command */);
274 
275   uint64_t time1 = chppGetCurrentTimeNs();
276   uint64_t timeout1 = 200 * CHPP_NSEC_PER_MSEC;
277   registerAndValidateRequestForTimeout(mClientState, reqHeader, timeout1,
278                                        time1 + timeout1);
279 
280   std::this_thread::sleep_for(std::chrono::nanoseconds(timeout1 / 2));
281 
282   uint64_t time2 = chppGetCurrentTimeNs();
283   uint64_t timeout2 = 200 * CHPP_NSEC_PER_MSEC;
284   registerAndValidateRequestForTimeout(mClientState, reqHeader, timeout2,
285                                        time2 + timeout2);
286 
287   std::this_thread::sleep_for(
288       std::chrono::nanoseconds(timeout1 + time1 - chppGetCurrentTimeNs()));
289   // First request would have timed out but superseded by second request
290   ASSERT_GT(mAppContext.nextRequestTimeoutNs, chppGetCurrentTimeNs());
291 
292   std::this_thread::sleep_for(
293       std::chrono::nanoseconds(timeout2 + time2 - chppGetCurrentTimeNs()));
294   // Second request should have timed out
295   ASSERT_LT(mAppContext.nextRequestTimeoutNs, chppGetCurrentTimeNs());
296 
297   struct ChppAppHeader *response =
298       chppTransportGetClientRequestTimeoutResponse(&mTransportContext);
299   validateTimeoutResponse(reqHeader, response);
300   if (response != NULL) {
301     chppFree(response);
302   }
303 
304   registerAndValidateResponseForTimeout(mClientState, reqHeader, CHPP_TIME_MAX);
305   EXPECT_TRUE(
306       chppTransportGetClientRequestTimeoutResponse(&mTransportContext) == NULL);
307 
308   chppFree(reqHeader);
309 }
310 
311 TEST_F(ClientsTest, RequestTimeoutResponse) {
312   EXPECT_EQ(mAppContext.nextRequestTimeoutNs, CHPP_TIME_MAX);
313 
314   struct ChppAppHeader *reqHeader1 =
315       chppAllocClientRequestCommand(mClientState, 1 /* command */);
316   struct ChppAppHeader *reqHeader2 =
317       chppAllocClientRequestCommand(mClientState, 2 /* command */);
318 
319   uint64_t time1 = chppGetCurrentTimeNs();
320   uint64_t timeout1 = 200 * CHPP_NSEC_PER_MSEC;
321   registerAndValidateRequestForTimeout(mClientState, reqHeader1, timeout1,
322                                        time1 + timeout1);
323 
324   std::this_thread::sleep_for(std::chrono::nanoseconds(timeout1));
325   ASSERT_LT(mAppContext.nextRequestTimeoutNs, chppGetCurrentTimeNs());
326 
327   struct ChppAppHeader *response =
328       chppTransportGetClientRequestTimeoutResponse(&mTransportContext);
329   validateTimeoutResponse(reqHeader1, response);
330   if (response != NULL) {
331     chppFree(response);
332   }
333 
334   registerAndValidateResponseForTimeout(mClientState, reqHeader1,
335                                         CHPP_TIME_MAX);
336   EXPECT_TRUE(
337       chppTransportGetClientRequestTimeoutResponse(&mTransportContext) == NULL);
338 
339   uint64_t time2 = chppGetCurrentTimeNs();
340   uint64_t timeout2 = 200 * CHPP_NSEC_PER_MSEC;
341   registerAndValidateRequestForTimeout(mClientState, reqHeader2, timeout2,
342                                        time2 + timeout2);
343 
344   std::this_thread::sleep_for(std::chrono::nanoseconds(timeout2));
345   ASSERT_LT(mAppContext.nextRequestTimeoutNs, chppGetCurrentTimeNs());
346 
347   response = chppTransportGetClientRequestTimeoutResponse(&mTransportContext);
348   validateTimeoutResponse(reqHeader2, response);
349   if (response != NULL) {
350     chppFree(response);
351   }
352 
353   chppFree(reqHeader1);
354   chppFree(reqHeader2);
355 }
356