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

mendersoftware / mender-mcu / 2096440417

13 Oct 2025 12:38PM UTC coverage: 60.837% (-0.4%) from 61.268%
2096440417

push

gitlab-ci

danielskinstad
feat: send tier in authentication request

Ticket: MEN-8559
Changelog: Add device tier support to authentication requests. The client now
sends a 'tier' parameter in authentication requests, supporting "standard"
(default) and "micro" tiers. The tier is configurable via Kconfig or
through the client config struct before initialization, which will take
precedence over the Kconfig option.

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

18 of 19 new or added lines in 2 files covered. (94.74%)

292 existing lines in 5 files now uncovered.

2456 of 4037 relevant lines covered (60.84%)

68.87 hits per line

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

60.36
/src/platform/net/zephyr/net.c
1
/**
2
 * @file      net.c
3
 * @brief     Mender network common file for Zephyr platform
4
 *
5
 * Copyright joelguittet and mender-mcu-client contributors
6
 *
7
 * Licensed under the Apache License, Version 2.0 (the "License");
8
 * you may not use this file except in compliance with the License.
9
 * You may obtain a copy of the License at
10
 *
11
 *     http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 * Unless required by applicable law or agreed to in writing, software
14
 * distributed under the License is distributed on an "AS IS" BASIS,
15
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 * See the License for the specific language governing permissions and
17
 * limitations under the License.
18
 */
19
#include <errno.h>
20
#include <zephyr/net/socket.h>
21
#include <zephyr/kernel.h>
22
#ifdef CONFIG_NET_SOCKETS_SOCKOPT_TLS
23
#include <zephyr/net/tls_credentials.h>
24
#endif /* CONFIG_NET_SOCKETS_SOCKOPT_TLS */
25
#include "log.h"
26
#include "utils.h"
27

28
#include "net.h"
29

30
/**
31
 * @brief Default TLS_PEER_VERIFY option
32
 */
33
#ifndef CONFIG_MENDER_NET_TLS_PEER_VERIFY
34
#define CONFIG_MENDER_NET_TLS_PEER_VERIFY (2)
35
#endif /* CONFIG_MENDER_NET_TLS_PEER_VERIFY */
36

37
#define RESOLVE_ATTEMPTS (10)
38

39
mender_err_t
40
mender_net_get_host_port_url(const char *path, const char *config_host, char **host, char **port, char **url) {
312✔
41

42
    assert(NULL != path);
312✔
43
    assert(NULL != host);
312✔
44
    assert(NULL != port);
312✔
45

46
    const char *path_no_prefix = NULL;
312✔
47
    bool        is_https       = false;
312✔
48

49
    /* Check if the path start with protocol (meaning we have the full path); alternatively we have only URL (path/to/resource) */
50
    if ((false == mender_utils_strbeginswith(path, "http://")) && (false == mender_utils_strbeginswith(path, "https://"))) {
312✔
51

52
        /* Path contains the URL only, retrieve host and port from configuration (config_host) */
53
        assert(NULL != url);
150✔
54
        if (NULL == (*url = mender_utils_strdup(path))) {
150✔
55
            mender_log_error("Unable to allocate memory");
×
56
            return MENDER_FAIL;
×
57
        }
58
        return mender_net_get_host_port_url(config_host, NULL, host, port, NULL);
150✔
59
    }
60

61
    /* Determine protocol and default port */
62
    if (mender_utils_strbeginswith(path, "http://")) {
162✔
63
        path_no_prefix = path + strlen("http://");
×
64
    } else if (mender_utils_strbeginswith(path, "https://")) {
162✔
65
        path_no_prefix = path + strlen("https://");
162✔
66
        is_https       = true;
162✔
67
    }
68

69
    /* Extract url path: next '/' character in the path after finding protocol must be the beginning of url */
70
    char *path_url = strchr(path_no_prefix, '/');
162✔
71
    if ((NULL != path_url) && (NULL != url)) {
162✔
72
        if (NULL == (*url = mender_utils_strdup(path_url))) {
12✔
73
            mender_log_error("Unable to allocate memory for URL");
×
74
            return MENDER_FAIL;
×
75
        }
76
    }
77

78
    /* Extract host and port */
79
    char *path_port = strchr(path_no_prefix, ':');
162✔
80
    if ((NULL == path_port) && (NULL == path_url)) {
162✔
81
        *port = mender_utils_strdup(is_https ? "443" : "80");
150✔
82
        *host = mender_utils_strdup(path_no_prefix);
150✔
83
    } else if ((NULL == path_port) && (NULL != path_url)) {
12✔
84
        *port = mender_utils_strdup(is_https ? "443" : "80");
12✔
85
        *host = mender_utils_strndup(path_no_prefix, path_url - path_no_prefix);
12✔
86
    } else if ((NULL != path_port) && (NULL == path_url)) {
×
87
        *port = mender_utils_strdup(path_port + 1);
×
88
        *host = mender_utils_strndup(path_no_prefix, path_port - path_no_prefix);
×
89
    } else {
90
        *host = mender_utils_strndup(path_no_prefix, path_port - path_no_prefix);
×
91
        *port = mender_utils_strndup(path_port + 1, path_url - path_port - 1);
×
92
    }
93

94
    if (NULL == *host || NULL == *port) {
162✔
95
        /* Clean up */
96
        mender_free(*host);
×
97
        mender_free(*port);
×
98
        mender_free(*url);
×
99

100
        mender_log_error("Unable to allocate memory for host or port");
×
101
        return MENDER_FAIL;
×
102
    }
103

104
    return MENDER_OK;
162✔
105
}
106

107
mender_err_t
108
header_add(const char **header_list, size_t header_list_size, const char *header) {
474✔
109

110
    // Headers are added to the header list one by one so that there are no empty spaces in the list
111
    if (NULL == header_list) {
474✔
112
        return MENDER_FAIL;
×
113
    }
114

115
    // The list that we pass to the Zephyr request needs to be NULL-terminated so the last element need to stay NULL
116
    for (size_t i = 0; i < header_list_size - 1; i++) {
936✔
117
        if (NULL == header_list[i]) {
936✔
118
            header_list[i] = header;
474✔
119
            return MENDER_OK;
474✔
120
        }
121
    }
122

123
    mender_log_error("Unable to add header: list is full");
×
124
    return MENDER_FAIL;
×
125
}
126

127
char *
128
header_alloc_and_add(const char **header_list, size_t header_list_size, const char *format, ...) {
162✔
129

130
    char   *header = NULL;
162✔
131
    va_list args;
132

133
    va_start(args, format);
162✔
134
    int ret = mender_utils_vasprintf(&header, format, args);
162✔
135
    va_end(args);
162✔
136
    if (ret < 0) {
162✔
137
        mender_log_error("Unable to allocate memory, failed to create header");
×
138
        return NULL;
×
139
    }
140

141
    if (MENDER_FAIL == header_add(header_list, header_list_size, header)) {
162✔
142
        mender_log_error("Unable to add header to the list");
×
143
        mender_free(header);
×
144
        return NULL;
×
145
    }
146
    return header;
162✔
147
}
148

149
int
150
mender_net_connect(const char *host, const char *port) {
162✔
151

152
    assert(NULL != host);
162✔
153
    assert(NULL != port);
162✔
154

155
    int                    result;
156
    int                    sock             = -1;
162✔
157
    struct zsock_addrinfo  hints            = { 0 };
162✔
158
    struct zsock_addrinfo *addr             = NULL;
162✔
159
    unsigned int           resolve_attempts = RESOLVE_ATTEMPTS;
162✔
160

161
    /* Set hints */
162
    if (IS_ENABLED(CONFIG_NET_IPV6)) {
163
        hints.ai_family = AF_INET6;
164
    } else if (IS_ENABLED(CONFIG_NET_IPV4)) {
165
        hints.ai_family = AF_INET;
162✔
166
    }
167
    hints.ai_socktype = SOCK_STREAM;
162✔
168
    hints.ai_protocol = IPPROTO_TCP;
162✔
169

170
    /* Perform DNS resolution of the host; try RESOLVE_ATTEMPTS times */
171
    do {
172
        result = zsock_getaddrinfo(host, port, &hints, &addr);
162✔
173
        if (0 == result) {
159✔
174
            break;
159✔
175
        }
176
        mender_log_debug("Unable to resolve host name '%s:%s': %s", host, port, zsock_gai_strerror(result));
×
177
        /* Introduce a backoff mechanism to try every 10ms, 20ms, ..., 100ms */
178
        k_sleep(K_MSEC(10 * (RESOLVE_ATTEMPTS - resolve_attempts + 1)));
×
179
    } while (0 != --resolve_attempts);
×
180

181
    if (0 != result) {
159✔
182
        mender_log_error("Unable to resolve host name '%s:%s': %s", host, port, zsock_gai_strerror(result));
×
183
        goto END;
×
184
    }
185

186
    /* Create socket */
187
#ifdef CONFIG_NET_SOCKETS_SOCKOPT_TLS
188
    if ((sock = zsock_socket(addr->ai_family, SOCK_STREAM, IPPROTO_TLS_1_2)) < 0) {
159✔
189
#else
190
    if ((sock = zsock_socket(addr->ai_family, SOCK_STREAM, IPPROTO_TCP)) < 0) {
191
#endif /* CONFIG_NET_SOCKETS_SOCKOPT_TLS */
192
        mender_log_error("Unable to create socket, result = %d, error: %s", sock, strerror(errno));
×
193
        goto END;
×
194
    }
195

196
#ifdef CONFIG_NET_SOCKETS_SOCKOPT_TLS
197

198
    /* Set TLS_SEC_TAG_LIST option */
199
#ifdef CONFIG_MENDER_NET_CA_CERTIFICATE_TAG_SECONDARY_ENABLED
200
    sec_tag_t sec_tag[2] = {
159✔
201
        CONFIG_MENDER_NET_CA_CERTIFICATE_TAG_PRIMARY,
202
        CONFIG_MENDER_NET_CA_CERTIFICATE_TAG_SECONDARY,
203
    };
204
#else
205
    sec_tag_t sec_tag[1] = {
206
        CONFIG_MENDER_NET_CA_CERTIFICATE_TAG_PRIMARY,
207
    };
208
#endif
209

210
    if ((result = zsock_setsockopt(sock, SOL_TLS, TLS_SEC_TAG_LIST, sec_tag, sizeof(sec_tag))) < 0) {
159✔
211
        mender_log_error("Unable to set TLS_SEC_TAG_LIST option, result = %d, error: %s", result, strerror(errno));
×
212
        goto END;
×
213
    }
214

215
    /* Set TLS_HOSTNAME option */
216
    if ((result = zsock_setsockopt(sock, SOL_TLS, TLS_HOSTNAME, host, strlen(host))) < 0) {
159✔
217
        mender_log_error("Unable to set TLS_HOSTNAME option, result = %d, error: %s", result, strerror(errno));
×
218
        goto END;
×
219
    }
220

221
    /* Set TLS_PEER_VERIFY option */
222
    int verify = CONFIG_MENDER_NET_TLS_PEER_VERIFY;
159✔
223
    if ((result = zsock_setsockopt(sock, SOL_TLS, TLS_PEER_VERIFY, &verify, sizeof(int))) < 0) {
159✔
224
        mender_log_error("Unable to set TLS_PEER_VERIFY option, result = %d, error: %s", result, strerror(errno));
×
225
        goto END;
×
226
    }
227

228
#endif /* CONFIG_NET_SOCKETS_SOCKOPT_TLS */
229

230
    /* Connect to the host */
231
    if (0 != (result = zsock_connect(sock, addr->ai_addr, addr->ai_addrlen))) {
159✔
UNCOV
232
        mender_log_error("Unable to connect to the host '%s:%s', result = %d, error: %s", host, port, result, strerror(errno));
×
UNCOV
233
        goto END;
×
234
    }
235

236
    /* Free the address info */
237
    if (NULL != addr) {
147✔
238
        zsock_freeaddrinfo(addr);
147✔
239
    }
240
    return sock;
147✔
241

UNCOV
242
END:
×
243
    /* Close socket */
UNCOV
244
    if (sock >= 0) {
×
UNCOV
245
        zsock_close(sock);
×
246
    }
247

UNCOV
248
    if (NULL != addr) {
×
UNCOV
249
        zsock_freeaddrinfo(addr);
×
250
    }
251

UNCOV
252
    return -1; /* Error */
×
253
}
254

255
mender_err_t
256
mender_net_disconnect(int sock) {
147✔
257

258
    /* Close socket */
259
    zsock_close(sock);
147✔
260

261
    return MENDER_OK;
147✔
262
}
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