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

mendersoftware / mender-mcu / 1642556678

27 Jan 2025 01:30PM UTC coverage: 25.749%. First build
1642556678

push

gitlab-ci

vpodzime
feat: Support platform-specific or custom allocators

And use Zephyr-specific allocation functions on Zephyr by
default, using either a separate heap (default) or the system
heap.

This means we have to use our memory management functions instead
of the standard ones everywhere, even if they can actually just
call the standard ones.

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

64 of 184 new or added lines in 12 files covered. (34.78%)

731 of 2839 relevant lines covered (25.75%)

8.54 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
#include "mender-alloc.h"
22
#include "mender-api.h"
23
#include "mender-artifact.h"
24
#include "mender-error-counters.h"
25
#include "mender-scheduler.h"
26
#include "mender-storage.h"
27
#include "mender-http.h"
28
#include "mender-log.h"
29
#include "mender-tls.h"
30
#include "mender-utils.h"
31

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

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

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

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

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

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

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

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

88
    mender_err_t ret;
89

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

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

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

105
    return ret;
×
106
}
107

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

120
    return ret;
×
121
}
122

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

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

135
    return ret;
×
136
}
137

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

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

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

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

159
    return ret;
×
160
}
161

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

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

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

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

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

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

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

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

260
END:
×
261

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

271
    return ret;
×
272
}
273

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

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

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

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

326
    return ret;
×
327
}
328

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

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

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

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

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

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

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

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

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

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

399
    ret = MENDER_OK;
×
400

401
END:
×
402

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

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

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

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

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

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

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

440
    ret = MENDER_OK;
×
441

442
END:
×
443

444
    /* Release memory */
NEW
445
    mender_free(path);
×
446

447
    return ret;
×
448
}
449

450
mender_err_t
451
mender_api_check_for_deployment(mender_api_deployment_data_t *deployment) {
×
452

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

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

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

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

550
END:
×
551

552
    /* Release memory */
NEW
553
    mender_free(response);
×
554

555
    return ret;
×
556
}
557

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

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

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

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

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

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

605
    /* Treatment depending of the status */
606
    if (204 == status) {
×
607
        /* No response expected */
608
        ret = MENDER_OK;
×
609
    } else if (409 == status) {
×
610
        /* Deployment aborted */
611
        mender_api_print_response_error(response, status);
×
612
        ret = MENDER_ABORTED;
×
613
    } else {
614
        mender_api_print_response_error(response, status);
×
615
        ret = MENDER_FAIL;
×
616
    }
617

618
END:
×
619

620
    /* Release memory */
NEW
621
    mender_free(response);
×
NEW
622
    mender_free(path);
×
NEW
623
    mender_free(payload);
×
624
    cJSON_Delete(json_payload);
×
625

626
    return ret;
×
627
}
628

629
#ifdef CONFIG_MENDER_CLIENT_INVENTORY
630

631
mender_err_t
632
mender_api_publish_inventory_data(mender_keystore_t *inventory) {
633

634
    mender_err_t ret;
635
    char        *payload       = NULL;
636
    char        *response      = NULL;
637
    int          status        = 0;
638
    const char  *artifact_name = NULL;
639

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

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

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

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

705
END:
706

707
    /* Release memory */
708
    mender_free(response);
709
    mender_free(payload);
710
    cJSON_Delete(object);
711

712
    return ret;
713
}
714

715
#endif /* CONFIG_MENDER_CLIENT_INVENTORY */
716

717
mender_err_t
718
mender_api_exit(void) {
×
719

720
    /* Release all modules */
721
    mender_http_exit();
×
722

723
    /* Destroy the authentication lock */
724
    mender_scheduler_mutex_delete(auth_lock);
×
725

726
    /* Release memory */
727
    FREE_AND_NULL(api_jwt);
×
728

729
    return MENDER_OK;
×
730
}
731

732
static mender_err_t
733
mender_api_http_text_callback(mender_http_client_event_t event, void *data, size_t data_length, void *params) {
×
734

735
    assert(NULL != params);
×
736
    char       **response = (char **)params;
×
737
    mender_err_t ret      = MENDER_OK;
×
738
    char        *tmp;
739

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

777
    return ret;
×
778
}
779

780
void
781
mender_api_print_response_error(char *response, int status) {
×
782
    const char *desc;
783

784
    /* Treatment depending of the status */
785
    if (NULL != (desc = mender_utils_http_status_to_string(status))) {
×
786
        if (NULL != response) {
×
787
            cJSON *json_response = cJSON_Parse(response);
×
788
            if (NULL != json_response) {
×
789
                cJSON *json_error = cJSON_GetObjectItemCaseSensitive(json_response, "error");
×
790
                if (NULL != json_error) {
×
791
                    mender_log_error("[%d] %s: %s", status, desc, cJSON_GetStringValue(json_error));
×
792
                } else {
793
                    mender_log_error("[%d] %s: unknown error", status, desc);
×
794
                }
795
                cJSON_Delete(json_response);
×
796
            } else {
797
                mender_log_error("[%d] %s: unknown error", status, desc);
×
798
            }
799
        } else {
800
            mender_log_error("[%d] %s: unknown error", status, desc);
×
801
        }
802
    } else {
803
        mender_log_error("Unknown error occurred, status=%d", status);
×
804
    }
805
}
×
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