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