1 /*
2 * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include "restapi_location_strategy.h"
8
9 #include <assert.h>
10 #include <string.h>
11 #include <unistd.h>
12
13 #include "restapi_location.h"
14 #include "restapi_service_context.h"
15 #include "rpc/http/caller/http_caller.h"
16 #include "service/locator/service_name.h"
17 #include "trace.h"
18
19 /* Maximum wait for an unresponsive API server. During testing, this period
20 * may need to accommodate the boot time for a device under test.
21 */
22 #ifndef RESTAPI_LOCATOR_MAX_API_WAIT
23 #define RESTAPI_LOCATOR_MAX_API_WAIT (120)
24 #endif
25
probe_api_server(void)26 static bool probe_api_server(void)
27 {
28 unsigned int seconds_waited = 0;
29
30 do {
31 long http_code = 0;
32
33 if (http_caller_probe(RESTAPI_LOCATOR_API_URL, &http_code))
34 return true;
35
36 /* Failed to reach API or received an error response */
37 if (http_code == 0) {
38 /* It's possible that the device hosting the API server is in the
39 * process of booting up so it's worth waiting and trying again.
40 */
41 sleep(1);
42 ++seconds_waited;
43
44 } else {
45 /* The server was reached but it returned an error */
46 EMSG("API server HTTP error: %ld", http_code);
47 return false;
48 }
49
50 } while (seconds_waited < RESTAPI_LOCATOR_MAX_API_WAIT);
51
52 IMSG("API server not reachable");
53
54 return false;
55 }
56
prepare_service_url(const char * sn,char * url_buf,size_t url_buf_size)57 static void prepare_service_url(const char *sn, char *url_buf, size_t url_buf_size)
58 {
59 strncpy(url_buf, RESTAPI_LOCATOR_API_URL, url_buf_size);
60
61 size_t url_len = strnlen(url_buf, url_buf_size);
62
63 assert(url_len < url_buf_size);
64
65 size_t remaining_space = url_buf_size - url_len;
66
67 url_len += sn_read_service(sn, &url_buf[url_len], remaining_space);
68
69 assert(url_len < url_buf_size - 1);
70
71 url_buf[url_len] = '/';
72 url_buf[url_len + 1] = '\0';
73 }
74
query(const char * sn,int * status)75 static struct service_context *query(const char *sn, int *status)
76 {
77 *status = -1;
78
79 if (!probe_api_server())
80 return NULL;
81
82 /* API server reachable so check if service endpoint exists */
83 char service_url[HTTP_CALLER_MAX_URL_LEN];
84 long http_code = 0;
85
86 prepare_service_url(sn, service_url, sizeof(service_url));
87
88 if (!http_caller_probe(service_url, &http_code)) {
89 if (http_code != 404)
90 EMSG("Unexpected HTTP error: %ld", http_code);
91
92 /* Service endpoint not reachable */
93 return NULL;
94 }
95
96 return restapi_service_context_create(service_url);
97 }
98
restapi_location_strategy(void)99 const struct service_location_strategy *restapi_location_strategy(void)
100 {
101 static const struct service_location_strategy strategy = { query };
102
103 return &strategy;
104 }
105