• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mendersoftware / mender-mcu / 1564392937

28 Nov 2024 01:36PM UTC coverage: 9.221% (+0.05%) from 9.171%
1564392937

push

gitlab-ci

vpodzime
chore: Try to detect too many network issues and reset network

Instead of being stuck in the non-working setup.

Ticket: MEN-7555
Changelog: none
Signed-off-by: Vratislav Podzimek <vratislav.podzimek@northern.tech>

0 of 10 new or added lines in 3 files covered. (0.0%)

403 existing lines in 3 files now uncovered.

251 of 2722 relevant lines covered (9.22%)

0.66 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/core/src/mender-api.c
1
/**
2
 * @file      mender-api.c
3
 * @brief     Implementation of the Mender API
4
 *
5
 * Copyright joelguittet and mender-mcu-client contributors
6
 * Copyright Northern.tech AS
7
 *
8
 * Licensed under the Apache License, Version 2.0 (the "License");
9
 * you may not use this file except in compliance with the License.
10
 * You may obtain a copy of the License at
11
 *
12
 *     http://www.apache.org/licenses/LICENSE-2.0
13
 *
14
 * Unless required by applicable law or agreed to in writing, software
15
 * distributed under the License is distributed on an "AS IS" BASIS,
16
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
 * See the License for the specific language governing permissions and
18
 * limitations under the License.
19
 */
20

21
#define _GNU_SOURCE // asprintf
22
#include <stdio.h>  // asprintf
23

24
#include "mender-api.h"
25
#include "mender-artifact.h"
26
#include "mender-error-counters.h"
27
#include "mender-scheduler.h"
28
#include "mender-storage.h"
29
#include "mender-http.h"
30
#include "mender-log.h"
31
#include "mender-tls.h"
32

33
/**
34
 * @brief Paths of the mender-server APIs
35
 */
36
#define MENDER_API_PATH_POST_AUTHENTICATION_REQUESTS "/api/devices/v1/authentication/auth_requests"
37
#define MENDER_API_PATH_GET_NEXT_DEPLOYMENT          "/api/devices/v1/deployments/device/deployments/next"
38
#define MENDER_API_PATH_POST_NEXT_DEPLOYMENT_V2      "/api/devices/v2/deployments/device/deployments/next"
39
#define MENDER_API_PATH_PUT_DEPLOYMENT_STATUS        "/api/devices/v1/deployments/device/deployments/%s/status"
40
#define MENDER_API_PATH_GET_DEVICE_CONFIGURATION     "/api/devices/v1/deviceconfig/configuration"
41
#define MENDER_API_PATH_PUT_DEVICE_CONFIGURATION     "/api/devices/v1/deviceconfig/configuration"
42
#define MENDER_API_PATH_GET_DEVICE_CONNECT           "/api/devices/v1/deviceconnect/connect"
43
#define MENDER_API_PATH_PUT_DEVICE_ATTRIBUTES        "/api/devices/v1/inventory/device/attributes"
44

45
/**
46
 * @brief Mender API configuration
47
 */
48
static mender_api_config_t api_config;
49

50
/**
51
 * @brief Authentication token
52
 */
53
static char *api_jwt = NULL;
54

55
/**
56
 * @brief A mutex ensuring there are no concurrent operations using or updating the authentication token
57
 */
58
static void *auth_lock = NULL;
59

60
/**
61
 * @brief HTTP callback used to handle text content
62
 * @param event HTTP client event
63
 * @param data Data received
64
 * @param data_length Data length
65
 * @param params Callback parameters
66
 * @return MENDER_OK if the function succeeds, error code otherwise
67
 */
68
static mender_err_t mender_api_http_text_callback(mender_http_client_event_t event, void *data, size_t data_length, void *params);
69

70
/**
71
 * @brief Perform authentication of the device, retrieve token from mender-server used for the next requests
72
 * @return MENDER_OK if the function succeeds, error code otherwise
73
 */
74
static mender_err_t perform_authentication(void);
75

76
/**
77
 * @brief Ensure authenticated and holding the #auth_lock
78
 * @return MENDER_OK if success, MENDER_LOCK_FAILED in case of lock failure, other errors otherwise
79
 */
80
static mender_err_t ensure_authenticated_and_locked(void);
81

82
mender_err_t
UNCOV
83
mender_api_init(mender_api_config_t *config) {
×
84
    assert(NULL != config);
×
85
    assert(NULL != config->device_type);
×
86
    assert(NULL != config->host);
×
87
    assert(NULL != config->identity_cb);
×
88

89
    mender_err_t ret;
90

91
    /* Save configuration */
UNCOV
92
    memcpy(&api_config, config, sizeof(mender_api_config_t));
×
93

94
    /* Initializations */
UNCOV
95
    mender_http_config_t mender_http_config = { .host = api_config.host };
×
96
    if (MENDER_OK != (ret = mender_http_init(&mender_http_config))) {
×
97
        mender_log_error("Unable to initialize HTTP");
×
98
        return ret;
×
99
    }
100

UNCOV
101
    if (MENDER_OK != (ret = mender_scheduler_mutex_create(&auth_lock))) {
×
102
        mender_log_error("Unable to initialize authentication lock");
×
103
        return ret;
×
104
    }
105

UNCOV
106
    return ret;
×
107
}
108

109
mender_err_t
UNCOV
110
mender_api_drop_authentication_data(void) {
×
111
    mender_err_t ret;
UNCOV
112
    if (MENDER_OK != (ret = mender_scheduler_mutex_take(auth_lock, -1))) {
×
113
        mender_log_error("Unable to obtain the authentication lock");
×
114
        return MENDER_LOCK_FAILED;
×
115
    }
UNCOV
116
    FREE_AND_NULL(api_jwt);
×
117
    if (MENDER_OK != (ret = mender_scheduler_mutex_give(auth_lock))) {
×
118
        mender_log_error("Unable to release the authentication lock");
×
119
    }
120

UNCOV
121
    return ret;
×
122
}
123

124
mender_err_t
UNCOV
125
mender_api_ensure_authenticated(void) {
×
126
    mender_err_t ret = ensure_authenticated_and_locked();
×
127
    if (MENDER_LOCK_FAILED == ret) {
×
128
        /* Error already logged. */
UNCOV
129
        return MENDER_FAIL;
×
130
    }
131

UNCOV
132
    if (MENDER_OK != (ret = mender_scheduler_mutex_give(auth_lock))) {
×
133
        mender_log_error("Unable to release the authentication lock");
×
134
    }
135

UNCOV
136
    return ret;
×
137
}
138

139
static mender_err_t
UNCOV
140
ensure_authenticated_and_locked(void) {
×
141
    mender_err_t ret;
142

UNCOV
143
    if (MENDER_OK != (ret = mender_scheduler_mutex_take(auth_lock, -1))) {
×
144
        mender_log_error("Unable to obtain the authentication lock");
×
145
        return MENDER_LOCK_FAILED;
×
146
    }
147

UNCOV
148
    if (NULL != api_jwt) {
×
149
        return MENDER_DONE;
×
150
    }
151

152
    /* Perform authentication with the mender server */
UNCOV
153
    if (MENDER_OK != (ret = perform_authentication())) {
×
154
        mender_log_error("Authentication failed");
×
155
        return MENDER_FAIL;
×
156
    } else {
157
        mender_log_debug("Authenticated successfully");
158
    }
159

UNCOV
160
    return ret;
×
161
}
162

163
static mender_err_t
UNCOV
164
perform_authentication(void) {
×
165
    mender_err_t             ret;
UNCOV
166
    char                    *public_key_pem   = NULL;
×
167
    const mender_identity_t *identity         = NULL;
×
168
    cJSON                   *json_identity    = NULL;
×
169
    char                    *identity_info    = NULL;
×
170
    cJSON                   *json_payload     = NULL;
×
171
    char                    *payload          = NULL;
×
172
    char                    *response         = NULL;
×
173
    char                    *signature        = NULL;
×
174
    size_t                   signature_length = 0;
×
175
    int                      status           = 0;
×
176

177
    /* Get public key in PEM format */
UNCOV
178
    if (MENDER_OK != (ret = mender_tls_get_public_key_pem(&public_key_pem))) {
×
179
        mender_log_error("Unable to get public key");
×
180
        goto END;
×
181
    }
182

183
    /* Get identity (we don't own the returned data) */
UNCOV
184
    if (MENDER_OK != (ret = api_config.identity_cb(&identity))) {
×
185
        mender_log_error("Unable to get identity");
×
186
        goto END;
×
187
    }
188

189
    /* Format identity */
UNCOV
190
    if (MENDER_OK != (ret = mender_utils_identity_to_json(identity, &json_identity))) {
×
191
        mender_log_error("Unable to format identity");
×
192
        goto END;
×
193
    }
UNCOV
194
    if (NULL == (identity_info = cJSON_PrintUnformatted(json_identity))) {
×
195
        mender_log_error("Unable to allocate memory");
×
196
        ret = MENDER_FAIL;
×
197
        goto END;
×
198
    }
199

200
    /* Format payload */
UNCOV
201
    if (NULL == (json_payload = cJSON_CreateObject())) {
×
202
        mender_log_error("Unable to allocate memory");
×
203
        ret = MENDER_FAIL;
×
204
        goto END;
×
205
    }
UNCOV
206
    cJSON_AddStringToObject(json_payload, "id_data", identity_info);
×
207
    cJSON_AddStringToObject(json_payload, "pubkey", public_key_pem);
×
208
    if (NULL != api_config.tenant_token) {
×
209
        cJSON_AddStringToObject(json_payload, "tenant_token", api_config.tenant_token);
×
210
    }
UNCOV
211
    if (NULL == (payload = cJSON_PrintUnformatted(json_payload))) {
×
212
        mender_log_error("Unable to allocate memory");
×
213
        ret = MENDER_FAIL;
×
214
        goto END;
×
215
    }
216

217
    /* Sign payload */
UNCOV
218
    if (MENDER_OK != (ret = mender_tls_sign_payload(payload, &signature, &signature_length))) {
×
219
        mender_log_error("Unable to sign payload");
×
220
        goto END;
×
221
    }
222

223
    /* Perform HTTP request */
UNCOV
224
    if (MENDER_OK
×
225
        != (ret = mender_http_perform(NULL,
×
226
                                      MENDER_API_PATH_POST_AUTHENTICATION_REQUESTS,
227
                                      MENDER_HTTP_POST,
228
                                      payload,
229
                                      signature,
230
                                      &mender_api_http_text_callback,
231
                                      (void *)&response,
232
                                      &status))) {
UNCOV
233
        mender_log_error("Unable to perform HTTP request");
×
NEW
234
        mender_err_count_net_inc();
×
235
        goto END;
×
236
    }
237

238
    /* Treatment depending of the status */
UNCOV
239
    if (200 == status) {
×
UNCOV
240
        if (NULL == response) {
×
241
            mender_log_error("Response is empty");
×
242
            ret = MENDER_FAIL;
×
243
            goto END;
×
244
        }
245
        if (NULL != api_jwt) {
×
UNCOV
246
            free(api_jwt);
×
247
        }
248
        if (NULL == (api_jwt = strdup(response))) {
×
UNCOV
249
            mender_log_error("Unable to allocate memory");
×
250
            ret = MENDER_FAIL;
×
251
            goto END;
×
252
        }
253
        ret = MENDER_OK;
×
254
    } else {
255
        mender_api_print_response_error(response, status);
×
256
        /* Maybe the identity is wrong? Let's make sure we get fresh data for the next attempt. */
257
        FREE_AND_NULL(identity_info);
×
UNCOV
258
        ret = MENDER_FAIL;
×
259
    }
260

UNCOV
261
END:
×
262

263
    /* Release memory */
UNCOV
264
    free(response);
×
UNCOV
265
    free(signature);
×
266
    free(payload);
×
267
    cJSON_Delete(json_payload);
×
268
    cJSON_Delete(json_identity);
×
269
    free(identity_info);
×
270
    free(public_key_pem);
×
271

272
    return ret;
×
273
}
274

275
/**
276
 * @see mender_http_perform()
277
 */
278
static mender_err_t
UNCOV
279
authenticated_http_perform(char *path, mender_http_method_t method, char *payload, char *signature, char **response, int *status) {
×
280
    mender_err_t ret;
281

UNCOV
282
    if (MENDER_IS_ERROR(ret = ensure_authenticated_and_locked())) {
×
283
        /* Errors already logged. */
284
        if (MENDER_LOCK_FAILED != ret) {
×
UNCOV
285
            if (MENDER_OK != mender_scheduler_mutex_give(auth_lock)) {
×
286
                mender_log_error("Unable to release the authentication lock");
×
287
                return MENDER_FAIL;
×
288
            }
289
        }
UNCOV
290
        return ret;
×
291
    }
292

UNCOV
293
    ret = mender_http_perform(api_jwt, path, method, payload, signature, &mender_api_http_text_callback, response, status);
×
UNCOV
294
    if (MENDER_OK != mender_scheduler_mutex_give(auth_lock)) {
×
295
        mender_log_error("Unable to release the authentication lock");
×
296
        return MENDER_FAIL;
×
297
    }
298
    if (MENDER_OK != ret) {
×
299
        /* HTTP errors already logged. */
NEW
300
        mender_err_count_net_inc();
×
UNCOV
301
        return ret;
×
302
    }
303

304
    if (401 == *status) {
×
305
        /* Unauthorized => try to re-authenticate and perform the request again */
UNCOV
306
        mender_log_info("Trying to re-authenticate");
×
307
        FREE_AND_NULL(api_jwt);
×
UNCOV
308
        if (MENDER_IS_ERROR(ret = ensure_authenticated_and_locked())) {
×
309
            free(*response);
×
310
            ret = mender_http_perform(api_jwt, path, method, payload, signature, &mender_api_http_text_callback, response, status);
×
311
            if (MENDER_OK != mender_scheduler_mutex_give(auth_lock)) {
×
312
                mender_log_error("Unable to release the authentication lock");
×
313
                return MENDER_FAIL;
×
314
            }
NEW
315
            if (MENDER_OK != ret) {
×
316
                /* HTTP errors already logged. */
NEW
317
                mender_err_count_net_inc();
×
318
            }
319
        } else if (MENDER_LOCK_FAILED != ret) {
×
320
            if (MENDER_OK != mender_scheduler_mutex_give(auth_lock)) {
×
UNCOV
321
                mender_log_error("Unable to release the authentication lock");
×
322
                return MENDER_FAIL;
×
323
            }
324
        }
325
    }
326

327
    return ret;
×
328
}
329

330
static mender_err_t
UNCOV
331
api_check_for_deployment_v2(int *status, char **response) {
×
UNCOV
332
    assert(NULL != status);
×
UNCOV
333
    assert(NULL != response);
×
334

UNCOV
335
    mender_err_t ret           = MENDER_FAIL;
×
UNCOV
336
    cJSON       *json_payload  = NULL;
×
UNCOV
337
    char        *payload       = NULL;
×
338
    const char  *artifact_name = NULL;
×
339
#ifdef CONFIG_MENDER_PROVIDES_DEPENDS
340
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT
UNCOV
341
    mender_key_value_list_t *provides = NULL;
×
342
#endif /* CONFIG_MENDER_FULL_PARSE_ARTIFACT */
343
#endif /* CONFIG_MENDER_PROVIDES_DEPENDS */
344

345
    /* Create payload */
UNCOV
346
    if (NULL == (json_payload = cJSON_CreateObject())) {
×
UNCOV
347
        mender_log_error("Unable to allocate memory");
×
348
        goto END;
×
349
    }
350

351
    /* Add "device_provides" entity to payload */
UNCOV
352
    cJSON *json_provides = NULL;
×
353
    if (NULL == (json_provides = cJSON_AddObjectToObject(json_payload, "device_provides"))) {
×
354
        mender_log_error("Unable to allocate memory");
×
355
        goto END;
×
356
    }
357

UNCOV
358
    if (NULL == cJSON_AddStringToObject(json_provides, "device_type", api_config.device_type)) {
×
359
        mender_log_error("Unable to allocate memory");
×
360
        goto END;
×
361
    }
362

363
#ifdef CONFIG_MENDER_PROVIDES_DEPENDS
364
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT
365
    /* Add provides from storage */
366
    if (MENDER_FAIL == mender_storage_get_provides(&provides)) {
×
367
        mender_log_error("Unable to get provides");
×
UNCOV
368
        goto END;
×
369
    }
UNCOV
370
    for (mender_key_value_list_t *item = provides; NULL != item; item = item->next) {
×
UNCOV
371
        if (NULL == cJSON_AddStringToObject(json_provides, item->key, item->value)) {
×
UNCOV
372
            mender_log_error("Unable to allocate memory");
×
373
            goto END;
×
374
        }
375
    }
376
#endif /* CONFIG_MENDER_FULL_PARSE_ARTIFACT */
377
#endif /* CONFIG_MENDER_PROVIDES_DEPENDS */
378

379
    if ((MENDER_OK != mender_storage_get_artifact_name(&artifact_name)) && (NULL != artifact_name)) {
×
380
        mender_log_error("Unable to get artifact name");
×
UNCOV
381
        return MENDER_FAIL;
×
382
    }
383

UNCOV
384
    if (NULL == cJSON_AddStringToObject(json_provides, "artifact_name", artifact_name)) {
×
UNCOV
385
        mender_log_error("Unable to allocate memory");
×
386
        goto END;
×
387
    }
388

UNCOV
389
    if (NULL == (payload = cJSON_PrintUnformatted(json_payload))) {
×
UNCOV
390
        mender_log_error("Unable to allocate memory");
×
391
        goto END;
×
392
    }
393

394
    /* Perform HTTP request */
UNCOV
395
    if (MENDER_OK != (ret = authenticated_http_perform(MENDER_API_PATH_POST_NEXT_DEPLOYMENT_V2, MENDER_HTTP_POST, payload, NULL, response, status))) {
×
396
        mender_log_error("Unable to perform HTTP request");
×
397
        goto END;
×
398
    }
399

UNCOV
400
    ret = MENDER_OK;
×
401

402
END:
×
403

404
#ifdef CONFIG_MENDER_PROVIDES_DEPENDS
405
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT
UNCOV
406
    mender_utils_key_value_list_free(provides);
×
407
#endif /* CONFIG_MENDER_FULL_PARSE_ARTIFACT */
408
#endif /* CONFIG_MENDER_PROVIDES_DEPENDS */
409
    cJSON_Delete(json_payload);
×
UNCOV
410
    free(payload);
×
UNCOV
411
    return ret;
×
412
}
413

414
static mender_err_t
UNCOV
415
api_check_for_deployment_v1(int *status, char **response) {
×
416

417
    assert(NULL != status);
×
418
    assert(NULL != response);
×
419

UNCOV
420
    mender_err_t ret           = MENDER_FAIL;
×
UNCOV
421
    char        *path          = NULL;
×
422
    const char  *artifact_name = NULL;
×
423

424
    if ((MENDER_OK != mender_storage_get_artifact_name(&artifact_name)) && (NULL != artifact_name)) {
×
425
        mender_log_error("Unable to get artifact name");
×
UNCOV
426
        return MENDER_FAIL;
×
427
    }
428

429
    /* Compute path */
UNCOV
430
    if (-1 == asprintf(&path, MENDER_API_PATH_GET_NEXT_DEPLOYMENT "?artifact_name=%s&device_type=%s", artifact_name, api_config.device_type)) {
×
431
        mender_log_error("Unable to allocate memory");
×
432
        goto END;
×
433
    }
434

435
    /* Perform HTTP request */
UNCOV
436
    if (MENDER_OK != (ret = authenticated_http_perform(path, MENDER_HTTP_GET, NULL, NULL, response, status))) {
×
437
        mender_log_error("Unable to perform HTTP request");
×
438
        goto END;
×
439
    }
440

UNCOV
441
    ret = MENDER_OK;
×
442

443
END:
×
444

445
    /* Release memory */
UNCOV
446
    free(path);
×
447

448
    return ret;
×
449
}
450

451
mender_err_t
UNCOV
452
mender_api_check_for_deployment(mender_api_deployment_data_t *deployment) {
×
453

UNCOV
454
    assert(NULL != deployment);
×
455
    mender_err_t ret      = MENDER_FAIL;
×
UNCOV
456
    char        *response = NULL;
×
UNCOV
457
    int          status   = 0;
×
458

459
    if (MENDER_FAIL == (ret = api_check_for_deployment_v2(&status, &response))) {
×
UNCOV
460
        goto END;
×
461
    }
462

463
    /* Yes, 404 still means MENDER_OK above */
464
    if (404 == status) {
×
465
        mender_log_debug("POST request to v2 version of the deployments API failed, falling back to v1 version and GET");
466
        FREE_AND_NULL(response);
×
467
        if (MENDER_FAIL == (ret = api_check_for_deployment_v1(&status, &response))) {
×
UNCOV
468
            goto END;
×
469
        }
470
    }
471

472
    /* Treatment depending of the status */
473
    if (200 == status) {
×
474
        cJSON *json_response = cJSON_Parse(response);
×
475
        if (NULL != json_response) {
×
UNCOV
476
            cJSON *json_id = cJSON_GetObjectItem(json_response, "id");
×
UNCOV
477
            if (NULL != json_id) {
×
UNCOV
478
                if (NULL == (deployment->id = strdup(cJSON_GetStringValue(json_id)))) {
×
UNCOV
479
                    ret = MENDER_FAIL;
×
480
                    goto END;
×
481
                }
482
            }
483
            cJSON *json_artifact = cJSON_GetObjectItem(json_response, "artifact");
×
484
            if (NULL != json_artifact) {
×
485
                cJSON *json_artifact_name = cJSON_GetObjectItem(json_artifact, "artifact_name");
×
486
                if (NULL != json_artifact_name) {
×
487
                    if (NULL == (deployment->artifact_name = strdup(cJSON_GetStringValue(json_artifact_name)))) {
×
UNCOV
488
                        ret = MENDER_FAIL;
×
UNCOV
489
                        goto END;
×
490
                    }
491
                }
492
                cJSON *json_source = cJSON_GetObjectItem(json_artifact, "source");
×
493
                if (NULL != json_source) {
×
494
                    cJSON *json_uri = cJSON_GetObjectItem(json_source, "uri");
×
495
                    if (NULL != json_uri) {
×
496
                        if (NULL == (deployment->uri = strdup(cJSON_GetStringValue(json_uri)))) {
×
UNCOV
497
                            ret = MENDER_FAIL;
×
UNCOV
498
                            goto END;
×
499
                        }
500
                        ret = MENDER_OK;
×
501
                    } else {
502
                        mender_log_error("Invalid response");
×
503
                        ret = MENDER_FAIL;
×
504
                    }
505
                } else {
UNCOV
506
                    mender_log_error("Invalid response");
×
507
                    ret = MENDER_FAIL;
×
508
                }
509
                cJSON *json_device_types_compatible = cJSON_GetObjectItem(json_artifact, "device_types_compatible");
×
510
                if (NULL != json_device_types_compatible && cJSON_IsArray(json_device_types_compatible)) {
×
UNCOV
511
                    deployment->device_types_compatible_size = cJSON_GetArraySize(json_device_types_compatible);
×
UNCOV
512
                    deployment->device_types_compatible      = (char **)malloc(deployment->device_types_compatible_size * sizeof(char *));
×
513
                    if (NULL == deployment->device_types_compatible) {
×
514
                        mender_log_error("Unable to allocate memory");
×
UNCOV
515
                        ret = MENDER_FAIL;
×
516
                        goto END;
×
517
                    }
518
                    for (size_t i = 0; i < deployment->device_types_compatible_size; i++) {
×
519
                        cJSON *json_device_type = cJSON_GetArrayItem(json_device_types_compatible, i);
×
520
                        if (NULL != json_device_type && cJSON_IsString(json_device_type)) {
×
521
                            if (NULL == (deployment->device_types_compatible[i] = strdup(cJSON_GetStringValue(json_device_type)))) {
×
522
                                ret = MENDER_FAIL;
×
523
                                goto END;
×
524
                            }
525
                        } else {
526
                            mender_log_error("Could not get device type form device_types_compatible array");
×
527
                            ret = MENDER_FAIL;
×
528
                        }
529
                    }
530
                } else {
UNCOV
531
                    mender_log_error("Could not load device_types_compatible");
×
UNCOV
532
                    ret = MENDER_FAIL;
×
533
                }
534
            } else {
UNCOV
535
                mender_log_error("Invalid response");
×
UNCOV
536
                ret = MENDER_FAIL;
×
537
            }
538
            cJSON_Delete(json_response);
×
539
        } else {
UNCOV
540
            mender_log_error("Invalid response");
×
UNCOV
541
            ret = MENDER_FAIL;
×
542
        }
543
    } else if (204 == status) {
×
544
        /* No response expected */
545
        ret = MENDER_NOT_FOUND;
×
546
    } else {
547
        mender_api_print_response_error(response, status);
×
548
        ret = MENDER_FAIL;
×
549
    }
550

UNCOV
551
END:
×
552

553
    /* Release memory */
554
    free(response);
×
555

UNCOV
556
    return ret;
×
557
}
558

559
mender_err_t
UNCOV
560
mender_api_publish_deployment_status(const char *id, mender_deployment_status_t deployment_status) {
×
561
    assert(NULL != id);
×
562

563
    mender_err_t ret;
UNCOV
564
    char        *value        = NULL;
×
UNCOV
565
    cJSON       *json_payload = NULL;
×
UNCOV
566
    char        *payload      = NULL;
×
567
    char        *path         = NULL;
×
568
    char        *response     = NULL;
×
UNCOV
569
    int          status       = 0;
×
570

571
    /* Deployment status to string */
572
    if (NULL == (value = mender_utils_deployment_status_to_string(deployment_status))) {
×
573
        mender_log_error("Invalid status");
×
574
        ret = MENDER_FAIL;
×
575
        goto END;
×
576
    }
577

578
    /* Format payload */
579
    if (NULL == (json_payload = cJSON_CreateObject())) {
×
580
        mender_log_error("Unable to allocate memory");
×
581
        ret = MENDER_FAIL;
×
582
        goto END;
×
583
    }
UNCOV
584
    cJSON_AddStringToObject(json_payload, "status", value);
×
UNCOV
585
    if (NULL == (payload = cJSON_PrintUnformatted(json_payload))) {
×
586
        mender_log_error("Unable to allocate memory");
×
587
        ret = MENDER_FAIL;
×
588
        goto END;
×
589
    }
590

591
    /* Compute path */
592
    size_t str_length = strlen(MENDER_API_PATH_PUT_DEPLOYMENT_STATUS) - strlen("%s") + strlen(id) + 1;
×
593
    if (NULL == (path = (char *)malloc(str_length))) {
×
594
        mender_log_error("Unable to allocate memory");
×
595
        ret = MENDER_FAIL;
×
UNCOV
596
        goto END;
×
597
    }
UNCOV
598
    snprintf(path, str_length, MENDER_API_PATH_PUT_DEPLOYMENT_STATUS, id);
×
599

600
    /* Perform HTTP request */
601
    if (MENDER_OK != (ret = authenticated_http_perform(path, MENDER_HTTP_PUT, payload, NULL, &response, &status))) {
×
602
        mender_log_error("Unable to perform HTTP request");
×
603
        goto END;
×
604
    }
605

606
    /* Treatment depending of the status */
UNCOV
607
    if (204 == status) {
×
608
        /* No response expected */
609
        ret = MENDER_OK;
×
610
    } else {
UNCOV
611
        mender_api_print_response_error(response, status);
×
UNCOV
612
        ret = MENDER_FAIL;
×
613
    }
614

UNCOV
615
END:
×
616

617
    /* Release memory */
618
    free(response);
×
619
    free(path);
×
UNCOV
620
    free(payload);
×
UNCOV
621
    cJSON_Delete(json_payload);
×
622

UNCOV
623
    return ret;
×
624
}
625

626
#ifdef CONFIG_MENDER_CLIENT_INVENTORY
627

628
mender_err_t
629
mender_api_publish_inventory_data(mender_keystore_t *inventory) {
630

631
    mender_err_t ret;
632
    char        *payload       = NULL;
633
    char        *response      = NULL;
634
    int          status        = 0;
635
    const char  *artifact_name = NULL;
636

637
    if ((MENDER_OK != mender_storage_get_artifact_name(&artifact_name)) && (NULL != artifact_name)) {
638
        mender_log_error("Unable to get artifact name");
639
        return MENDER_FAIL;
640
    }
641

642
    /* Format payload */
643
    cJSON *object = cJSON_CreateArray();
644
    if (NULL == object) {
645
        mender_log_error("Unable to allocate memory");
646
        ret = MENDER_FAIL;
647
        goto END;
648
    }
649
    cJSON *item = cJSON_CreateObject();
650
    if (NULL == item) {
651
        mender_log_error("Unable to allocate memory");
652
        ret = MENDER_FAIL;
653
        goto END;
654
    }
655
    cJSON_AddStringToObject(item, "name", "artifact_name");
656
    cJSON_AddStringToObject(item, "value", artifact_name);
657
    cJSON_AddItemToArray(object, item);
658
    item = cJSON_CreateObject();
659
    if (NULL == item) {
660
        mender_log_error("Unable to allocate memory");
661
        ret = MENDER_FAIL;
662
        goto END;
663
    }
664
    cJSON_AddStringToObject(item, "name", "device_type");
665
    cJSON_AddStringToObject(item, "value", api_config.device_type);
666
    cJSON_AddItemToArray(object, item);
667
    if (NULL != inventory) {
668
        size_t index = 0;
669
        while ((NULL != inventory[index].name) && (NULL != inventory[index].value)) {
670
            if (NULL == (item = cJSON_CreateObject())) {
671
                mender_log_error("Unable to allocate memory");
672
                ret = MENDER_FAIL;
673
                goto END;
674
            }
675
            cJSON_AddStringToObject(item, "name", inventory[index].name);
676
            cJSON_AddStringToObject(item, "value", inventory[index].value);
677
            cJSON_AddItemToArray(object, item);
678
            index++;
679
        }
680
    }
681
    if (NULL == (payload = cJSON_PrintUnformatted(object))) {
682
        mender_log_error("Unable to allocate memory");
683
        ret = MENDER_FAIL;
684
        goto END;
685
    }
686

687
    /* Perform HTTP request */
688
    if (MENDER_OK != (ret = authenticated_http_perform(MENDER_API_PATH_PUT_DEVICE_ATTRIBUTES, MENDER_HTTP_PUT, payload, NULL, &response, &status))) {
689
        mender_log_error("Unable to perform HTTP request");
690
        goto END;
691
    }
692

693
    /* Treatment depending of the status */
694
    if (200 == status) {
695
        /* No response expected */
696
        ret = MENDER_OK;
697
    } else {
698
        mender_api_print_response_error(response, status);
699
        ret = MENDER_FAIL;
700
    }
701

702
END:
703

704
    /* Release memory */
705
    free(response);
706
    free(payload);
707
    cJSON_Delete(object);
708

709
    return ret;
710
}
711

712
#endif /* CONFIG_MENDER_CLIENT_INVENTORY */
713

714
mender_err_t
UNCOV
715
mender_api_exit(void) {
×
716

717
    /* Release all modules */
UNCOV
718
    mender_http_exit();
×
719

720
    /* Destroy the authentication lock */
UNCOV
721
    mender_scheduler_mutex_delete(auth_lock);
×
722

723
    /* Release memory */
UNCOV
724
    FREE_AND_NULL(api_jwt);
×
725

UNCOV
726
    return MENDER_OK;
×
727
}
728

729
static mender_err_t
UNCOV
730
mender_api_http_text_callback(mender_http_client_event_t event, void *data, size_t data_length, void *params) {
×
731

UNCOV
732
    assert(NULL != params);
×
733
    char       **response = (char **)params;
×
UNCOV
734
    mender_err_t ret      = MENDER_OK;
×
735
    char        *tmp;
736

737
    /* Treatment depending of the event */
UNCOV
738
    switch (event) {
×
739
        case MENDER_HTTP_EVENT_CONNECTED:
×
740
            /* Nothing to do */
741
            break;
×
UNCOV
742
        case MENDER_HTTP_EVENT_DATA_RECEIVED:
×
743
            /* Check input data */
UNCOV
744
            if ((NULL == data) || (0 == data_length)) {
×
745
                mender_log_error("Invalid data received");
×
746
                ret = MENDER_FAIL;
×
UNCOV
747
                break;
×
748
            }
749
            /* Concatenate data to the response */
UNCOV
750
            size_t response_length = (NULL != *response) ? strlen(*response) : 0;
×
751
            if (NULL == (tmp = realloc(*response, response_length + data_length + 1))) {
×
752
                mender_log_error("Unable to allocate memory");
×
753
                ret = MENDER_FAIL;
×
754
                break;
×
755
            }
UNCOV
756
            *response = tmp;
×
757
            memcpy((*response) + response_length, data, data_length);
×
758
            *((*response) + response_length + data_length) = '\0';
×
759
            break;
×
760
        case MENDER_HTTP_EVENT_DISCONNECTED:
×
761
            /* Nothing to do */
UNCOV
762
            break;
×
763
        case MENDER_HTTP_EVENT_ERROR:
×
764
            /* Downloading the response fails */
765
            mender_log_error("An error occurred");
×
766
            ret = MENDER_FAIL;
×
767
            break;
×
UNCOV
768
        default:
×
769
            /* Should no occur */
770
            ret = MENDER_FAIL;
×
UNCOV
771
            break;
×
772
    }
773

774
    return ret;
×
775
}
776

777
void
778
mender_api_print_response_error(char *response, int status) {
×
779
    const char *desc;
780

781
    /* Treatment depending of the status */
UNCOV
782
    if (NULL != (desc = mender_utils_http_status_to_string(status))) {
×
UNCOV
783
        if (NULL != response) {
×
UNCOV
784
            cJSON *json_response = cJSON_Parse(response);
×
785
            if (NULL != json_response) {
×
UNCOV
786
                cJSON *json_error = cJSON_GetObjectItemCaseSensitive(json_response, "error");
×
UNCOV
787
                if (NULL != json_error) {
×
UNCOV
788
                    mender_log_error("[%d] %s: %s", status, desc, cJSON_GetStringValue(json_error));
×
789
                } else {
790
                    mender_log_error("[%d] %s: unknown error", status, desc);
×
791
                }
792
                cJSON_Delete(json_response);
×
793
            } else {
794
                mender_log_error("[%d] %s: unknown error", status, desc);
×
795
            }
796
        } else {
797
            mender_log_error("[%d] %s: unknown error", status, desc);
×
798
        }
799
    } else {
UNCOV
800
        mender_log_error("Unknown error occurred, status=%d", status);
×
801
    }
UNCOV
802
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc