1 /*
2 * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7
8 #include <stdlib.h>
9 #include <string.h>
10 #include <esp_tls.h>
11
12 #include "sys/queue.h"
13 #include "esp_log.h"
14
15 #include "esp_transport.h"
16 #include "esp_transport_internal.h"
17 #include "esp_transport_utils.h"
18
19 static const char *TAG = "TRANSPORT";
20
21 /**
22 * Transport layer error structure including
23 * * esp-tls last error storage
24 * * sock-errno
25 */
26 struct esp_transport_error_storage {
27 struct esp_tls_last_error esp_tls_err_h_base; /*!< esp-tls last error container */
28 // additional fields
29 int sock_errno; /*!< last socket error captured for this transport */
30 };
31
32 /**
33 * This list will hold all transport available
34 */
35 STAILQ_HEAD(esp_transport_list_t, esp_transport_item_t);
36
37 struct transport_esp_tls;
38
39 /**
40 * Internal transport structure holding list of transports and other data common to all transports
41 */
42 typedef struct esp_transport_internal {
43 struct esp_transport_list_t list; /*!< List of transports */
44 struct esp_foundation_transport *base; /*!< Base transport pointer shared for each list item */
45 } esp_transport_internal_t;
46
esp_transport_init_foundation_transport(void)47 static esp_foundation_transport_t * esp_transport_init_foundation_transport(void)
48 {
49 esp_foundation_transport_t *foundation = calloc(1, sizeof(esp_foundation_transport_t));
50 ESP_TRANSPORT_MEM_CHECK(TAG, foundation, return NULL);
51 foundation->error_handle = calloc(1, sizeof(struct esp_transport_error_storage));
52 ESP_TRANSPORT_MEM_CHECK(TAG, foundation->error_handle,
53 free(foundation);
54 return NULL);
55 foundation->transport_esp_tls = esp_transport_esp_tls_create();
56 ESP_TRANSPORT_MEM_CHECK(TAG, foundation->transport_esp_tls,
57 free(foundation->error_handle);
58 free(foundation);
59 return NULL);
60 return foundation;
61 }
62
esp_transport_destroy_foundation_transport(esp_foundation_transport_t * foundation)63 static void esp_transport_destroy_foundation_transport(esp_foundation_transport_t *foundation)
64 {
65 esp_transport_esp_tls_destroy(foundation->transport_esp_tls);
66 free(foundation->error_handle);
67 free(foundation);
68 }
69
esp_transport_get_default_parent(esp_transport_handle_t t)70 static esp_transport_handle_t esp_transport_get_default_parent(esp_transport_handle_t t)
71 {
72 /*
73 * By default, the underlying transport layer handle is the handle itself
74 */
75 return t;
76 }
77
esp_transport_list_init(void)78 esp_transport_list_handle_t esp_transport_list_init(void)
79 {
80 esp_transport_list_handle_t transport = calloc(1, sizeof(esp_transport_internal_t));
81 ESP_TRANSPORT_MEM_CHECK(TAG, transport, return NULL);
82 STAILQ_INIT(&transport->list);
83 transport->base = esp_transport_init_foundation_transport();
84 ESP_TRANSPORT_MEM_CHECK(TAG, transport->base,
85 free(transport);
86 return NULL);
87 return transport;
88 }
89
esp_transport_list_add(esp_transport_list_handle_t h,esp_transport_handle_t t,const char * scheme)90 esp_err_t esp_transport_list_add(esp_transport_list_handle_t h, esp_transport_handle_t t, const char *scheme)
91 {
92 if (h == NULL || t == NULL) {
93 return ESP_ERR_INVALID_ARG;
94 }
95 t->scheme = calloc(1, strlen(scheme) + 1);
96 ESP_TRANSPORT_MEM_CHECK(TAG, t->scheme, return ESP_ERR_NO_MEM);
97 strcpy(t->scheme, scheme);
98 STAILQ_INSERT_TAIL(&h->list, t, next);
99 // Each transport in a list to share the same error tracker
100 t->base = h->base;
101 return ESP_OK;
102 }
103
esp_transport_list_get_transport(esp_transport_list_handle_t h,const char * scheme)104 esp_transport_handle_t esp_transport_list_get_transport(esp_transport_list_handle_t h, const char *scheme)
105 {
106 if (!h) {
107 return NULL;
108 }
109 if (scheme == NULL) {
110 return STAILQ_FIRST(&h->list);
111 }
112 esp_transport_handle_t item;
113 STAILQ_FOREACH(item, &h->list, next) {
114 if (strcasecmp(item->scheme, scheme) == 0) {
115 return item;
116 }
117 }
118 return NULL;
119 }
120
esp_transport_list_destroy(esp_transport_list_handle_t h)121 esp_err_t esp_transport_list_destroy(esp_transport_list_handle_t h)
122 {
123 esp_transport_list_clean(h);
124 esp_transport_destroy_foundation_transport(h->base);
125 free(h);
126 return ESP_OK;
127 }
128
esp_transport_list_clean(esp_transport_list_handle_t h)129 esp_err_t esp_transport_list_clean(esp_transport_list_handle_t h)
130 {
131 esp_transport_handle_t item = STAILQ_FIRST(&h->list);
132 esp_transport_handle_t tmp;
133 while (item != NULL) {
134 tmp = STAILQ_NEXT(item, next);
135 esp_transport_destroy(item);
136 item = tmp;
137 }
138 STAILQ_INIT(&h->list);
139 return ESP_OK;
140 }
141
esp_transport_init(void)142 esp_transport_handle_t esp_transport_init(void)
143 {
144 esp_transport_handle_t t = calloc(1, sizeof(struct esp_transport_item_t));
145 ESP_TRANSPORT_MEM_CHECK(TAG, t, return NULL);
146 return t;
147 }
148
esp_transport_get_payload_transport_handle(esp_transport_handle_t t)149 esp_transport_handle_t esp_transport_get_payload_transport_handle(esp_transport_handle_t t)
150 {
151 if (t && t->_read) {
152 return t->_parent_transfer(t);
153 }
154 return NULL;
155 }
156
esp_transport_destroy(esp_transport_handle_t t)157 esp_err_t esp_transport_destroy(esp_transport_handle_t t)
158 {
159 if (t->_destroy) {
160 t->_destroy(t);
161 }
162 if (t->scheme) {
163 free(t->scheme);
164 }
165 free(t);
166 return ESP_OK;
167 }
168
esp_transport_connect(esp_transport_handle_t t,const char * host,int port,int timeout_ms)169 int esp_transport_connect(esp_transport_handle_t t, const char *host, int port, int timeout_ms)
170 {
171 int ret = -1;
172 if (t && t->_connect) {
173 return t->_connect(t, host, port, timeout_ms);
174 }
175 return ret;
176 }
177
esp_transport_connect_async(esp_transport_handle_t t,const char * host,int port,int timeout_ms)178 int esp_transport_connect_async(esp_transport_handle_t t, const char *host, int port, int timeout_ms)
179 {
180 int ret = -1;
181 if (t && t->_connect_async) {
182 return t->_connect_async(t, host, port, timeout_ms);
183 }
184 return ret;
185 }
186
esp_transport_read(esp_transport_handle_t t,char * buffer,int len,int timeout_ms)187 int esp_transport_read(esp_transport_handle_t t, char *buffer, int len, int timeout_ms)
188 {
189 if (t && t->_read) {
190 return t->_read(t, buffer, len, timeout_ms);
191 }
192 return -1;
193 }
194
esp_transport_write(esp_transport_handle_t t,const char * buffer,int len,int timeout_ms)195 int esp_transport_write(esp_transport_handle_t t, const char *buffer, int len, int timeout_ms)
196 {
197 if (t && t->_write) {
198 return t->_write(t, buffer, len, timeout_ms);
199 }
200 return -1;
201 }
202
esp_transport_poll_read(esp_transport_handle_t t,int timeout_ms)203 int esp_transport_poll_read(esp_transport_handle_t t, int timeout_ms)
204 {
205 if (t && t->_poll_read) {
206 return t->_poll_read(t, timeout_ms);
207 }
208 return -1;
209 }
210
esp_transport_poll_write(esp_transport_handle_t t,int timeout_ms)211 int esp_transport_poll_write(esp_transport_handle_t t, int timeout_ms)
212 {
213 if (t && t->_poll_write) {
214 return t->_poll_write(t, timeout_ms);
215 }
216 return -1;
217 }
218
esp_transport_close(esp_transport_handle_t t)219 int esp_transport_close(esp_transport_handle_t t)
220 {
221 if (t && t->_close) {
222 return t->_close(t);
223 }
224 return 0;
225 }
226
esp_transport_get_context_data(esp_transport_handle_t t)227 void *esp_transport_get_context_data(esp_transport_handle_t t)
228 {
229 if (t) {
230 return t->data;
231 }
232 return NULL;
233 }
234
esp_transport_set_context_data(esp_transport_handle_t t,void * data)235 esp_err_t esp_transport_set_context_data(esp_transport_handle_t t, void *data)
236 {
237 if (t) {
238 t->data = data;
239 return ESP_OK;
240 }
241 return ESP_FAIL;
242 }
243
esp_transport_set_func(esp_transport_handle_t t,connect_func _connect,io_read_func _read,io_func _write,trans_func _close,poll_func _poll_read,poll_func _poll_write,trans_func _destroy)244 esp_err_t esp_transport_set_func(esp_transport_handle_t t,
245 connect_func _connect,
246 io_read_func _read,
247 io_func _write,
248 trans_func _close,
249 poll_func _poll_read,
250 poll_func _poll_write,
251 trans_func _destroy)
252 {
253 if (t == NULL) {
254 return ESP_FAIL;
255 }
256 t->_connect = _connect;
257 t->_read = _read;
258 t->_write = _write;
259 t->_close = _close;
260 t->_poll_read = _poll_read;
261 t->_poll_write = _poll_write;
262 t->_destroy = _destroy;
263 t->_connect_async = NULL;
264 t->_parent_transfer = esp_transport_get_default_parent;
265 return ESP_OK;
266 }
267
esp_transport_get_default_port(esp_transport_handle_t t)268 int esp_transport_get_default_port(esp_transport_handle_t t)
269 {
270 if (t == NULL) {
271 return -1;
272 }
273 return t->port;
274 }
275
esp_transport_set_default_port(esp_transport_handle_t t,int port)276 esp_err_t esp_transport_set_default_port(esp_transport_handle_t t, int port)
277 {
278 if (t == NULL) {
279 return ESP_FAIL;
280 }
281 t->port = port;
282 return ESP_OK;
283 }
284
esp_transport_set_async_connect_func(esp_transport_handle_t t,connect_async_func _connect_async_func)285 esp_err_t esp_transport_set_async_connect_func(esp_transport_handle_t t, connect_async_func _connect_async_func)
286 {
287 if (t == NULL) {
288 return ESP_FAIL;
289 }
290 t->_connect_async = _connect_async_func;
291 return ESP_OK;
292 }
293
esp_transport_set_parent_transport_func(esp_transport_handle_t t,payload_transfer_func _parent_transport)294 esp_err_t esp_transport_set_parent_transport_func(esp_transport_handle_t t, payload_transfer_func _parent_transport)
295 {
296 if (t == NULL) {
297 return ESP_FAIL;
298 }
299 t->_parent_transfer = _parent_transport;
300 return ESP_OK;
301 }
302
esp_transport_get_error_handle(esp_transport_handle_t t)303 esp_tls_error_handle_t esp_transport_get_error_handle(esp_transport_handle_t t)
304 {
305 if (t && t->base && t->base->error_handle) {
306 return &t->base->error_handle->esp_tls_err_h_base;
307 }
308 return NULL;
309 }
310
esp_transport_get_errno(esp_transport_handle_t t)311 int esp_transport_get_errno(esp_transport_handle_t t)
312 {
313 if (t && t->base && t->base->error_handle) {
314 int actual_errno = t->base->error_handle->sock_errno;
315 t->base->error_handle->sock_errno = 0;
316 return actual_errno;
317 }
318 return -1;
319 }
320
capture_tcp_transport_error(esp_transport_handle_t t,enum tcp_transport_errors error)321 void capture_tcp_transport_error(esp_transport_handle_t t, enum tcp_transport_errors error)
322 {
323 esp_tls_last_error_t *err_handle = esp_transport_get_error_handle(t);
324 switch (error) {
325 case ERR_TCP_TRANSPORT_CONNECTION_TIMEOUT:
326 err_handle->last_error = ESP_ERR_ESP_TLS_CONNECTION_TIMEOUT;
327 break;
328 case ERR_TCP_TRANSPORT_CANNOT_RESOLVE_HOSTNAME:
329 err_handle->last_error = ESP_ERR_ESP_TLS_CANNOT_RESOLVE_HOSTNAME;
330 break;
331 case ERR_TCP_TRANSPORT_CONNECTION_CLOSED_BY_FIN:
332 err_handle->last_error = ESP_ERR_ESP_TLS_TCP_CLOSED_FIN;
333 break;
334 case ERR_TCP_TRANSPORT_CONNECTION_FAILED:
335 err_handle->last_error = ESP_ERR_ESP_TLS_FAILED_CONNECT_TO_HOST;
336 break;
337 case ERR_TCP_TRANSPORT_SETOPT_FAILED:
338 err_handle->last_error = ESP_ERR_ESP_TLS_SOCKET_SETOPT_FAILED;
339 break;
340 case ERR_TCP_TRANSPORT_NO_MEM:
341 err_handle->last_error = ESP_ERR_NO_MEM;
342 break;
343 }
344 }
345
esp_transport_set_errors(esp_transport_handle_t t,const esp_tls_error_handle_t error_handle)346 void esp_transport_set_errors(esp_transport_handle_t t, const esp_tls_error_handle_t error_handle)
347 {
348 if (t && t->base && t->base->error_handle) {
349 memcpy(&t->base->error_handle->esp_tls_err_h_base, error_handle, sizeof(esp_tls_last_error_t));
350 int sock_error;
351 if (esp_tls_get_and_clear_error_type(error_handle, ESP_TLS_ERR_TYPE_SYSTEM, &sock_error) == ESP_OK) {
352 t->base->error_handle->sock_errno = sock_error;
353 }
354 }
355 }
356
esp_transport_capture_errno(esp_transport_handle_t t,int sock_errno)357 void esp_transport_capture_errno(esp_transport_handle_t t, int sock_errno)
358 {
359 if (t && t->base && t->base->error_handle) {
360 t->base->error_handle->sock_errno = sock_errno;
361 }
362 }
363
esp_transport_get_socket(esp_transport_handle_t t)364 int esp_transport_get_socket(esp_transport_handle_t t)
365 {
366 if (t && t->_get_socket) {
367 return t->_get_socket(t);
368 }
369 return -1;
370 }
371