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

mendersoftware / mender-mcu / 1565513544

29 Nov 2024 09:19AM UTC coverage: 9.235%. Remained the same
1565513544

push

gitlab-ci

danielskinstad
fix: fail deployment when it's aborted

Changelog: Title
Ticket: MEN-7693

Signed-off-by: Daniel Skinstad Drabitzius <daniel.drabitzius@northern.tech>

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

219 existing lines in 3 files now uncovered.

251 of 2718 relevant lines covered (9.23%)

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-scheduler.h"
27
#include "mender-storage.h"
28
#include "mender-http.h"
29
#include "mender-log.h"
30
#include "mender-tls.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
        goto END;
×
234
    }
235

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

259
END:
×
260

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

270
    return ret;
×
271
}
272

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

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

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

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

320
    return ret;
×
321
}
322

323
static mender_err_t
324
api_check_for_deployment_v2(int *status, char **response) {
×
325
    assert(NULL != status);
×
326
    assert(NULL != response);
×
327

328
    mender_err_t ret           = MENDER_FAIL;
×
329
    cJSON       *json_payload  = NULL;
×
330
    char        *payload       = NULL;
×
331
    const char  *artifact_name = NULL;
×
332
#ifdef CONFIG_MENDER_PROVIDES_DEPENDS
333
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT
334
    mender_key_value_list_t *provides = NULL;
×
335
#endif /* CONFIG_MENDER_FULL_PARSE_ARTIFACT */
336
#endif /* CONFIG_MENDER_PROVIDES_DEPENDS */
337

338
    /* Create payload */
339
    if (NULL == (json_payload = cJSON_CreateObject())) {
×
340
        mender_log_error("Unable to allocate memory");
×
341
        goto END;
×
342
    }
343

344
    /* Add "device_provides" entity to payload */
345
    cJSON *json_provides = NULL;
×
346
    if (NULL == (json_provides = cJSON_AddObjectToObject(json_payload, "device_provides"))) {
×
347
        mender_log_error("Unable to allocate memory");
×
348
        goto END;
×
349
    }
350

351
    if (NULL == cJSON_AddStringToObject(json_provides, "device_type", api_config.device_type)) {
×
352
        mender_log_error("Unable to allocate memory");
×
353
        goto END;
×
354
    }
355

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

372
    if ((MENDER_OK != mender_storage_get_artifact_name(&artifact_name)) && (NULL != artifact_name)) {
×
373
        mender_log_error("Unable to get artifact name");
×
374
        return MENDER_FAIL;
×
375
    }
376

377
    if (NULL == cJSON_AddStringToObject(json_provides, "artifact_name", artifact_name)) {
×
378
        mender_log_error("Unable to allocate memory");
×
379
        goto END;
×
380
    }
381

382
    if (NULL == (payload = cJSON_PrintUnformatted(json_payload))) {
×
383
        mender_log_error("Unable to allocate memory");
×
384
        goto END;
×
385
    }
386

387
    /* Perform HTTP request */
388
    if (MENDER_OK != (ret = authenticated_http_perform(MENDER_API_PATH_POST_NEXT_DEPLOYMENT_V2, MENDER_HTTP_POST, payload, NULL, response, status))) {
×
389
        mender_log_error("Unable to perform HTTP request");
×
390
        goto END;
×
391
    }
392

393
    ret = MENDER_OK;
×
394

395
END:
×
396

397
#ifdef CONFIG_MENDER_PROVIDES_DEPENDS
398
#ifdef CONFIG_MENDER_FULL_PARSE_ARTIFACT
399
    mender_utils_key_value_list_free(provides);
×
400
#endif /* CONFIG_MENDER_FULL_PARSE_ARTIFACT */
401
#endif /* CONFIG_MENDER_PROVIDES_DEPENDS */
402
    cJSON_Delete(json_payload);
×
403
    free(payload);
×
404
    return ret;
×
405
}
406

407
static mender_err_t
408
api_check_for_deployment_v1(int *status, char **response) {
×
409

410
    assert(NULL != status);
×
411
    assert(NULL != response);
×
412

413
    mender_err_t ret           = MENDER_FAIL;
×
414
    char        *path          = NULL;
×
415
    const char  *artifact_name = NULL;
×
416

417
    if ((MENDER_OK != mender_storage_get_artifact_name(&artifact_name)) && (NULL != artifact_name)) {
×
418
        mender_log_error("Unable to get artifact name");
×
419
        return MENDER_FAIL;
×
420
    }
421

422
    /* Compute path */
423
    if (-1 == asprintf(&path, MENDER_API_PATH_GET_NEXT_DEPLOYMENT "?artifact_name=%s&device_type=%s", artifact_name, api_config.device_type)) {
×
424
        mender_log_error("Unable to allocate memory");
×
425
        goto END;
×
426
    }
427

428
    /* Perform HTTP request */
429
    if (MENDER_OK != (ret = authenticated_http_perform(path, MENDER_HTTP_GET, NULL, NULL, response, status))) {
×
430
        mender_log_error("Unable to perform HTTP request");
×
431
        goto END;
×
432
    }
433

434
    ret = MENDER_OK;
×
435

436
END:
×
437

438
    /* Release memory */
439
    free(path);
×
440

441
    return ret;
×
442
}
443

444
mender_err_t
445
mender_api_check_for_deployment(mender_api_deployment_data_t *deployment) {
×
446

447
    assert(NULL != deployment);
×
448
    mender_err_t ret      = MENDER_FAIL;
×
449
    char        *response = NULL;
×
450
    int          status   = 0;
×
451

452
    if (MENDER_FAIL == (ret = api_check_for_deployment_v2(&status, &response))) {
×
453
        goto END;
×
454
    }
455

456
    /* Yes, 404 still means MENDER_OK above */
457
    if (404 == status) {
×
458
        mender_log_debug("POST request to v2 version of the deployments API failed, falling back to v1 version and GET");
459
        FREE_AND_NULL(response);
×
460
        if (MENDER_FAIL == (ret = api_check_for_deployment_v1(&status, &response))) {
×
461
            goto END;
×
462
        }
463
    }
464

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

544
END:
×
545

546
    /* Release memory */
547
    free(response);
×
548

549
    return ret;
×
550
}
551

552
mender_err_t
553
mender_api_publish_deployment_status(const char *id, mender_deployment_status_t deployment_status) {
×
554
    assert(NULL != id);
×
555

556
    mender_err_t ret;
557
    char        *value        = NULL;
×
558
    cJSON       *json_payload = NULL;
×
559
    char        *payload      = NULL;
×
560
    char        *path         = NULL;
×
561
    char        *response     = NULL;
×
562
    int          status       = 0;
×
563

564
    /* Deployment status to string */
565
    if (NULL == (value = mender_utils_deployment_status_to_string(deployment_status))) {
×
566
        mender_log_error("Invalid status");
×
567
        ret = MENDER_FAIL;
×
568
        goto END;
×
569
    }
570

571
    /* Format payload */
572
    if (NULL == (json_payload = cJSON_CreateObject())) {
×
573
        mender_log_error("Unable to allocate memory");
×
574
        ret = MENDER_FAIL;
×
575
        goto END;
×
576
    }
577
    cJSON_AddStringToObject(json_payload, "status", value);
×
578
    if (NULL == (payload = cJSON_PrintUnformatted(json_payload))) {
×
579
        mender_log_error("Unable to allocate memory");
×
580
        ret = MENDER_FAIL;
×
581
        goto END;
×
582
    }
583

584
    /* Compute path */
585
    size_t str_length = strlen(MENDER_API_PATH_PUT_DEPLOYMENT_STATUS) - strlen("%s") + strlen(id) + 1;
×
586
    if (NULL == (path = (char *)malloc(str_length))) {
×
587
        mender_log_error("Unable to allocate memory");
×
588
        ret = MENDER_FAIL;
×
589
        goto END;
×
590
    }
591
    snprintf(path, str_length, MENDER_API_PATH_PUT_DEPLOYMENT_STATUS, id);
×
592

593
    /* Perform HTTP request */
594
    if (MENDER_OK != (ret = authenticated_http_perform(path, MENDER_HTTP_PUT, payload, NULL, &response, &status))) {
×
595
        mender_log_error("Unable to perform HTTP request");
×
596
        goto END;
×
597
    }
598

599
    /* Treatment depending of the status */
600
    if (204 == status) {
×
601
        /* No response expected */
602
        ret = MENDER_OK;
×
NEW
603
    } else if (409 == status) {
×
604
        /* Deployment aborted */
NEW
605
        mender_api_print_response_error(response, status);
×
NEW
606
        ret = MENDER_ABORTED;
×
607
    } else {
UNCOV
608
        mender_api_print_response_error(response, status);
×
609
        ret = MENDER_FAIL;
×
610
    }
611

612
END:
×
613

614
    /* Release memory */
UNCOV
615
    free(response);
×
616
    free(path);
×
UNCOV
617
    free(payload);
×
UNCOV
618
    cJSON_Delete(json_payload);
×
619

620
    return ret;
×
621
}
622

623
#ifdef CONFIG_MENDER_CLIENT_INVENTORY
624

625
mender_err_t
626
mender_api_publish_inventory_data(mender_keystore_t *inventory) {
627

628
    mender_err_t ret;
629
    char        *payload       = NULL;
630
    char        *response      = NULL;
631
    int          status        = 0;
632
    const char  *artifact_name = NULL;
633

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

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

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

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

699
END:
700

701
    /* Release memory */
702
    free(response);
703
    free(payload);
704
    cJSON_Delete(object);
705

706
    return ret;
707
}
708

709
#endif /* CONFIG_MENDER_CLIENT_INVENTORY */
710

711
mender_err_t
UNCOV
712
mender_api_exit(void) {
×
713

714
    /* Release all modules */
UNCOV
715
    mender_http_exit();
×
716

717
    /* Destroy the authentication lock */
UNCOV
718
    mender_scheduler_mutex_delete(auth_lock);
×
719

720
    /* Release memory */
UNCOV
721
    FREE_AND_NULL(api_jwt);
×
722

UNCOV
723
    return MENDER_OK;
×
724
}
725

726
static mender_err_t
727
mender_api_http_text_callback(mender_http_client_event_t event, void *data, size_t data_length, void *params) {
×
728

UNCOV
729
    assert(NULL != params);
×
UNCOV
730
    char       **response = (char **)params;
×
731
    mender_err_t ret      = MENDER_OK;
×
732
    char        *tmp;
733

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

771
    return ret;
×
772
}
773

774
void
775
mender_api_print_response_error(char *response, int status) {
×
776
    const char *desc;
777

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