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

mendersoftware / mender-mcu / 2099574738

14 Oct 2025 08:53AM UTC coverage: 60.837% (+3.4%) from 57.388%
2099574738

push

gitlab-ci

web-flow
Merge pull request #214 from danielskinstad/device-tiers

feat: send tier in authentication request

19 of 20 new or added lines in 3 files covered. (95.0%)

21 existing lines in 4 files now uncovered.

2456 of 4037 relevant lines covered (60.84%)

68.91 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