• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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 "chpp/clients.h"
18 
19 #include <inttypes.h>
20 #include <stdbool.h>
21 #include <stddef.h>
22 #include <stdint.h>
23 
24 #include "chpp/app.h"
25 #ifdef CHPP_CLIENT_ENABLED_DISCOVERY
26 #include "chpp/clients/discovery.h"
27 #endif
28 #ifdef CHPP_CLIENT_ENABLED_GNSS
29 #include "chpp/clients/gnss.h"
30 #endif
31 #ifdef CHPP_CLIENT_ENABLED_LOOPBACK
32 #include "chpp/clients/loopback.h"
33 #endif
34 #ifdef CHPP_CLIENT_ENABLED_TIMESYNC
35 #include "chpp/clients/timesync.h"
36 #endif
37 #ifdef CHPP_CLIENT_ENABLED_WIFI
38 #include "chpp/clients/wifi.h"
39 #endif
40 #ifdef CHPP_CLIENT_ENABLED_WWAN
41 #include "chpp/clients/wwan.h"
42 #endif
43 #include "chpp/log.h"
44 #include "chpp/macros.h"
45 #include "chpp/memory.h"
46 #include "chpp/time.h"
47 #include "chpp/transport.h"
48 
49 /************************************************
50  *  Prototypes
51  ***********************************************/
52 
53 static bool chppIsClientApiReady(struct ChppEndpointState *clientState);
54 static ChppClientDeinitFunction *chppGetClientDeinitFunction(
55     struct ChppAppState *context, uint8_t index);
56 
57 /************************************************
58  *  Private Functions
59  ***********************************************/
60 
61 /**
62  * Determines whether a client is ready to accept commands via its API (i.e. is
63  * initialized and opened). If the client is in the process of reopening, it
64  * will wait for the client to reopen.
65  *
66  * @param clientState State of the client sending the client request.
67  *
68  * @return Indicates whether the client is ready.
69  */
chppIsClientApiReady(struct ChppEndpointState * clientState)70 static bool chppIsClientApiReady(struct ChppEndpointState *clientState) {
71   CHPP_DEBUG_NOT_NULL(clientState);
72 
73   bool result = false;
74 
75   if (clientState->initialized) {
76     switch (clientState->openState) {
77       case (CHPP_OPEN_STATE_CLOSED):
78       case (CHPP_OPEN_STATE_WAITING_TO_OPEN): {
79         // result remains false
80         break;
81       }
82 
83       case (CHPP_OPEN_STATE_OPENED): {
84         result = true;
85         break;
86       }
87 
88       case (CHPP_OPEN_STATE_OPENING): {
89         // Allow the open request to go through
90         clientState->openState = CHPP_OPEN_STATE_WAITING_TO_OPEN;
91         result = true;
92         break;
93       }
94     }
95   }
96 
97   if (!result) {
98     CHPP_LOGE("Client not ready (everInit=%d, init=%d, open=%" PRIu8 ")",
99               clientState->everInitialized, clientState->initialized,
100               clientState->openState);
101   }
102   return result;
103 }
104 
105 /**
106  * Returns the deinitialization function pointer of a particular negotiated
107  * client.
108  *
109  * @param context Maintains status for each app layer instance.
110  * @param index Index of the registered client.
111  *
112  * @return Pointer to the match notification function.
113  */
chppGetClientDeinitFunction(struct ChppAppState * context,uint8_t index)114 static ChppClientDeinitFunction *chppGetClientDeinitFunction(
115     struct ChppAppState *context, uint8_t index) {
116   CHPP_DEBUG_NOT_NULL(context);
117 
118   return context->registeredClients[index]->deinitFunctionPtr;
119 }
120 
121 /************************************************
122  *  Public Functions
123  ***********************************************/
124 
chppRegisterCommonClients(struct ChppAppState * context)125 void chppRegisterCommonClients(struct ChppAppState *context) {
126   UNUSED_VAR(context);
127   CHPP_DEBUG_NOT_NULL(context);
128 
129   CHPP_LOGD("Registering Clients");
130 
131 #ifdef CHPP_CLIENT_ENABLED_WWAN
132   if (context->clientServiceSet.wwanClient) {
133     chppRegisterWwanClient(context);
134   }
135 #endif
136 
137 #ifdef CHPP_CLIENT_ENABLED_WIFI
138   if (context->clientServiceSet.wifiClient) {
139     chppRegisterWifiClient(context);
140   }
141 #endif
142 
143 #ifdef CHPP_CLIENT_ENABLED_GNSS
144   if (context->clientServiceSet.gnssClient) {
145     chppRegisterGnssClient(context);
146   }
147 #endif
148 }
149 
chppDeregisterCommonClients(struct ChppAppState * context)150 void chppDeregisterCommonClients(struct ChppAppState *context) {
151   UNUSED_VAR(context);
152   CHPP_DEBUG_NOT_NULL(context);
153 
154   CHPP_LOGD("Deregistering Clients");
155 
156 #ifdef CHPP_CLIENT_ENABLED_WWAN
157   if (context->clientServiceSet.wwanClient) {
158     chppDeregisterWwanClient(context);
159   }
160 #endif
161 
162 #ifdef CHPP_CLIENT_ENABLED_WIFI
163   if (context->clientServiceSet.wifiClient) {
164     chppDeregisterWifiClient(context);
165   }
166 #endif
167 
168 #ifdef CHPP_CLIENT_ENABLED_GNSS
169   if (context->clientServiceSet.gnssClient) {
170     chppDeregisterGnssClient(context);
171   }
172 #endif
173 }
174 
chppRegisterClient(struct ChppAppState * appContext,void * clientContext,struct ChppEndpointState * clientState,struct ChppOutgoingRequestState * outReqStates,const struct ChppClient * newClient)175 void chppRegisterClient(struct ChppAppState *appContext, void *clientContext,
176                         struct ChppEndpointState *clientState,
177                         struct ChppOutgoingRequestState *outReqStates,
178                         const struct ChppClient *newClient) {
179   CHPP_NOT_NULL(newClient);
180   CHPP_DEBUG_NOT_NULL(appContext);
181   CHPP_DEBUG_NOT_NULL(clientContext);
182   CHPP_DEBUG_NOT_NULL(clientState);
183   CHPP_DEBUG_NOT_NULL(newClient);
184 
185   if (appContext->registeredClientCount >= CHPP_MAX_REGISTERED_CLIENTS) {
186     CHPP_LOGE("Max clients registered: %" PRIu8,
187               appContext->registeredClientCount);
188     return;
189   }
190   clientState->appContext = appContext;
191   clientState->outReqStates = outReqStates;
192   clientState->index = appContext->registeredClientCount;
193   clientState->context = clientContext;
194   clientState->nextTimerTimeoutNs = CHPP_TIME_MAX;
195   appContext->registeredClientStates[appContext->registeredClientCount] =
196       clientState;
197 
198   appContext->registeredClients[appContext->registeredClientCount] = newClient;
199 
200   char uuidText[CHPP_SERVICE_UUID_STRING_LEN];
201   chppUuidToStr(newClient->descriptor.uuid, uuidText);
202   CHPP_LOGD("Client # %" PRIu8 " UUID=%s, version=%" PRIu8 ".%" PRIu8
203             ".%" PRIu16 ", min_len=%" PRIuSIZE,
204             appContext->registeredClientCount, uuidText,
205             newClient->descriptor.version.major,
206             newClient->descriptor.version.minor,
207             newClient->descriptor.version.patch, newClient->minLength);
208 
209   appContext->registeredClientCount++;
210 }
211 
chppInitBasicClients(struct ChppAppState * context)212 void chppInitBasicClients(struct ChppAppState *context) {
213   UNUSED_VAR(context);
214   CHPP_DEBUG_NOT_NULL(context);
215 
216   CHPP_LOGD("Initializing basic clients");
217 
218 #ifdef CHPP_CLIENT_ENABLED_LOOPBACK
219   if (context->clientServiceSet.loopbackClient) {
220     chppLoopbackClientInit(context);
221   }
222 #endif
223 
224 #ifdef CHPP_CLIENT_ENABLED_TIMESYNC
225   chppTimesyncClientInit(context);
226 #endif
227 
228 #ifdef CHPP_CLIENT_ENABLED_DISCOVERY
229   chppDiscoveryInit(context);
230 #endif
231 }
232 
chppClientInit(struct ChppEndpointState * clientState,uint8_t handle)233 void chppClientInit(struct ChppEndpointState *clientState, uint8_t handle) {
234   CHPP_DEBUG_NOT_NULL(clientState);
235   CHPP_ASSERT_LOG(!clientState->initialized,
236                   "Client H#%" PRIu8 " already initialized", handle);
237 
238   if (!clientState->everInitialized) {
239     clientState->handle = handle;
240     chppMutexInit(&clientState->syncResponse.mutex);
241     chppConditionVariableInit(&clientState->syncResponse.condVar);
242     clientState->everInitialized = true;
243   }
244 
245   clientState->initialized = true;
246 }
247 
chppClientDeinit(struct ChppEndpointState * clientState)248 void chppClientDeinit(struct ChppEndpointState *clientState) {
249   CHPP_DEBUG_NOT_NULL(clientState);
250   CHPP_ASSERT_LOG(clientState->initialized,
251                   "Client H#%" PRIu8 " already deinitialized",
252                   clientState->handle);
253 
254   clientState->initialized = false;
255 }
256 
chppDeinitBasicClients(struct ChppAppState * context)257 void chppDeinitBasicClients(struct ChppAppState *context) {
258   UNUSED_VAR(context);
259   CHPP_DEBUG_NOT_NULL(context);
260 
261   CHPP_LOGD("Deinitializing basic clients");
262 
263 #ifdef CHPP_CLIENT_ENABLED_LOOPBACK
264   if (context->clientServiceSet.loopbackClient) {
265     chppLoopbackClientDeinit(context);
266   }
267 #endif
268 
269 #ifdef CHPP_CLIENT_ENABLED_TIMESYNC
270   chppTimesyncClientDeinit(context);
271 #endif
272 
273 #ifdef CHPP_CLIENT_ENABLED_DISCOVERY
274   chppDiscoveryDeinit(context);
275 #endif
276 }
277 
chppDeinitMatchedClients(struct ChppAppState * context)278 void chppDeinitMatchedClients(struct ChppAppState *context) {
279   CHPP_DEBUG_NOT_NULL(context);
280   CHPP_LOGD("Deinitializing matched clients");
281 
282   for (uint8_t i = 0; i < context->discoveredServiceCount; i++) {
283     uint8_t clientIndex = context->clientIndexOfServiceIndex[i];
284     if (clientIndex != CHPP_CLIENT_INDEX_NONE) {
285       // Discovered service has a matched client
286       ChppClientDeinitFunction *clientDeinitFunction =
287           chppGetClientDeinitFunction(context, clientIndex);
288 
289       CHPP_LOGD("Client #%" PRIu8 " (H#%d) deinit fp found=%d", clientIndex,
290                 CHPP_SERVICE_HANDLE_OF_INDEX(i),
291                 (clientDeinitFunction != NULL));
292 
293       if (clientDeinitFunction != NULL) {
294         clientDeinitFunction(
295             context->registeredClientStates[clientIndex]->context);
296       }
297     }
298   }
299 }
300 
chppAllocClientRequest(struct ChppEndpointState * clientState,size_t len)301 struct ChppAppHeader *chppAllocClientRequest(
302     struct ChppEndpointState *clientState, size_t len) {
303   CHPP_DEBUG_NOT_NULL(clientState);
304   return chppAllocRequest(CHPP_MESSAGE_TYPE_CLIENT_REQUEST, clientState, len);
305 }
306 
chppAllocClientRequestCommand(struct ChppEndpointState * clientState,uint16_t command)307 struct ChppAppHeader *chppAllocClientRequestCommand(
308     struct ChppEndpointState *clientState, uint16_t command) {
309   struct ChppAppHeader *request =
310       chppAllocClientRequest(clientState, sizeof(struct ChppAppHeader));
311 
312   if (request != NULL) {
313     request->command = command;
314   }
315   return request;
316 }
317 
chppClientSendTimestampedRequestOrFail(struct ChppEndpointState * clientState,struct ChppOutgoingRequestState * outReqState,void * buf,size_t len,uint64_t timeoutNs)318 bool chppClientSendTimestampedRequestOrFail(
319     struct ChppEndpointState *clientState,
320     struct ChppOutgoingRequestState *outReqState, void *buf, size_t len,
321     uint64_t timeoutNs) {
322   CHPP_DEBUG_NOT_NULL(clientState);
323   CHPP_DEBUG_NOT_NULL(outReqState);
324   CHPP_DEBUG_NOT_NULL(buf);
325 
326   if (!chppIsClientApiReady(clientState)) {
327     if (clientState->initialized &&
328         clientState->openState == CHPP_OPEN_STATE_CLOSED) {
329       CHPP_LOGW("Trying to send request when closed - link broken?");
330       chppTransportForceReset(clientState->appContext->transportContext);
331     }
332     CHPP_FREE_AND_NULLIFY(buf);
333     return false;
334   }
335 
336   return chppSendTimestampedRequestOrFail(clientState, outReqState, buf, len,
337                                           timeoutNs);
338 }
339 
chppClientSendTimestampedRequestAndWait(struct ChppEndpointState * clientState,struct ChppOutgoingRequestState * outReqState,void * buf,size_t len)340 bool chppClientSendTimestampedRequestAndWait(
341     struct ChppEndpointState *clientState,
342     struct ChppOutgoingRequestState *outReqState, void *buf, size_t len) {
343   return chppClientSendTimestampedRequestAndWaitTimeout(
344       clientState, outReqState, buf, len, CHPP_REQUEST_TIMEOUT_DEFAULT);
345 }
346 
chppClientSendTimestampedRequestAndWaitTimeout(struct ChppEndpointState * clientState,struct ChppOutgoingRequestState * outReqState,void * buf,size_t len,uint64_t timeoutNs)347 bool chppClientSendTimestampedRequestAndWaitTimeout(
348     struct ChppEndpointState *clientState,
349     struct ChppOutgoingRequestState *outReqState, void *buf, size_t len,
350     uint64_t timeoutNs) {
351   bool result = chppClientSendTimestampedRequestOrFail(
352       clientState, outReqState, buf, len, CHPP_REQUEST_TIMEOUT_INFINITE);
353 
354   if (!result) {
355     return false;
356   }
357 
358   return chppWaitForResponseWithTimeout(&clientState->syncResponse, outReqState,
359                                         timeoutNs);
360 }
361 
chppClientPseudoOpen(struct ChppEndpointState * clientState)362 void chppClientPseudoOpen(struct ChppEndpointState *clientState) {
363   clientState->pseudoOpen = true;
364 }
365 
chppClientSendOpenRequest(struct ChppEndpointState * clientState,struct ChppOutgoingRequestState * openReqState,uint16_t openCommand,bool blocking)366 bool chppClientSendOpenRequest(struct ChppEndpointState *clientState,
367                                struct ChppOutgoingRequestState *openReqState,
368                                uint16_t openCommand, bool blocking) {
369   CHPP_NOT_NULL(clientState);
370   CHPP_NOT_NULL(openReqState);
371 
372   bool result = false;
373   uint8_t priorState = clientState->openState;
374 
375 #ifdef CHPP_CLIENT_ENABLED_TIMESYNC
376   chppTimesyncMeasureOffset(clientState->appContext);
377 #endif
378 
379   struct ChppAppHeader *request =
380       chppAllocClientRequestCommand(clientState, openCommand);
381 
382   if (request == NULL) {
383     return false;
384   }
385 
386   clientState->openState = CHPP_OPEN_STATE_OPENING;
387 
388   if (blocking) {
389     CHPP_LOGD("Opening service - blocking");
390     result = chppClientSendTimestampedRequestAndWait(clientState, openReqState,
391                                                      request, sizeof(*request));
392   } else {
393     CHPP_LOGD("Opening service - non-blocking");
394     result = chppClientSendTimestampedRequestOrFail(
395         clientState, openReqState, request, sizeof(*request),
396         CHPP_REQUEST_TIMEOUT_DEFAULT);
397   }
398 
399   if (!result) {
400     CHPP_LOGE("Service open fail from state=%" PRIu8 " psudo=%d blocking=%d",
401               priorState, clientState->pseudoOpen, blocking);
402     clientState->openState = CHPP_OPEN_STATE_CLOSED;
403 
404   } else if (blocking) {
405     result = (clientState->openState == CHPP_OPEN_STATE_OPENED);
406   }
407 
408   return result;
409 }
410 
chppClientProcessOpenResponse(struct ChppEndpointState * clientState,uint8_t * buf,size_t len)411 void chppClientProcessOpenResponse(struct ChppEndpointState *clientState,
412                                    uint8_t *buf, size_t len) {
413   CHPP_DEBUG_NOT_NULL(clientState);
414   CHPP_DEBUG_NOT_NULL(buf);
415 
416   UNUSED_VAR(len);  // Necessary depending on assert macro below
417   // Assert condition already guaranteed by chppAppProcessRxDatagram() but
418   // checking again since this is a public function
419   CHPP_ASSERT(len >= sizeof(struct ChppAppHeader));
420 
421   struct ChppAppHeader *rxHeader = (struct ChppAppHeader *)buf;
422   if (rxHeader->error != CHPP_APP_ERROR_NONE) {
423     CHPP_LOGE("Service open failed at service");
424     clientState->openState = CHPP_OPEN_STATE_CLOSED;
425   } else {
426     CHPP_LOGD("Service open succeeded at service");
427     clientState->openState = CHPP_OPEN_STATE_OPENED;
428   }
429 }
430 
chppClientCloseOpenRequests(struct ChppEndpointState * clientState,const struct ChppClient * client,bool clearOnly)431 void chppClientCloseOpenRequests(struct ChppEndpointState *clientState,
432                                  const struct ChppClient *client,
433                                  bool clearOnly) {
434   UNUSED_VAR(client);
435   chppCloseOpenRequests(clientState, CHPP_ENDPOINT_CLIENT, clearOnly);
436 }
437 
chppAllocClientNotification(size_t len)438 struct ChppAppHeader *chppAllocClientNotification(size_t len) {
439   return chppAllocNotification(CHPP_MESSAGE_TYPE_CLIENT_NOTIFICATION, len);
440 }