source: azure_iot_hub_f767zi/trunk/azure_iot_sdk/c-utility/adapters/tlsio_esp_at.c@ 457

Last change on this file since 457 was 457, checked in by coas-nagasima, 4 years ago

ファイルを追加

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 15.7 KB
Line 
1// Copyright (c) Microsoft. All rights reserved.
2// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
4#include <stdlib.h>
5#include <stddef.h>
6#include <stdio.h>
7#include <string.h>
8#include "azure_c_shared_utility/tlsio.h"
9#include "azure_c_shared_utility/tlsio_esp_at.h"
10#include "azure_c_shared_utility/singlylinkedlist.h"
11#include "azure_c_shared_utility/esp_at_socket.h"
12#include "azure_c_shared_utility/optimize_size.h"
13#include "azure_c_shared_utility/xlogging.h"
14
15#define ESP_AT_XIO_RECEIVE_BUFFER_SIZE 128
16
17typedef enum IO_STATE_TAG
18{
19 IO_STATE_CLOSED,
20 IO_STATE_OPENING,
21 IO_STATE_OPEN,
22 IO_STATE_CLOSING,
23 IO_STATE_ERROR
24} IO_STATE;
25
26typedef struct PENDING_TLS_IO_TAG
27{
28 unsigned char* bytes;
29 size_t size;
30 ON_SEND_COMPLETE on_send_complete;
31 void* callback_context;
32 SINGLYLINKEDLIST_HANDLE pending_io_list;
33} PENDING_TLS_IO;
34
35typedef struct TLS_IO_INSTANCE_TAG
36{
37 ESP_AT_SOCKET_HANDLE tcp_socket_connection;
38 ON_BYTES_RECEIVED on_bytes_received;
39 ON_IO_ERROR on_io_error;
40 void* on_bytes_received_context;
41 void* on_io_error_context;
42 char* hostname;
43 int port;
44 IO_STATE io_state;
45 SINGLYLINKEDLIST_HANDLE pending_io_list;
46} TLS_IO_INSTANCE;
47
48/*this function will clone an option given by name and value*/
49static void* tlsio_esp_at_CloneOption(const char* name, const void* value)
50{
51 (void)name;
52 (void)value;
53 return NULL;
54}
55
56/*this function destroys an option previously created*/
57static void tlsio_esp_at_DestroyOption(const char* name, const void* value)
58{
59 (void)name;
60 (void)value;
61}
62
63static OPTIONHANDLER_HANDLE tlsio_esp_at_retrieveoptions(CONCRETE_IO_HANDLE tlsio_esp_at)
64{
65 OPTIONHANDLER_HANDLE result;
66 (void)tlsio_esp_at;
67 result = OptionHandler_Create(tlsio_esp_at_CloneOption, tlsio_esp_at_DestroyOption, tlsio_esp_at_setoption);
68 if (result == NULL)
69 {
70 /*return as is*/
71 }
72 else
73 {
74 /*insert here work to add the options to "result" handle*/
75 }
76 return result;
77}
78
79static const IO_INTERFACE_DESCRIPTION tlsio_esp_at_interface_description =
80{
81 tlsio_esp_at_retrieveoptions,
82 tlsio_esp_at_create,
83 tlsio_esp_at_destroy,
84 tlsio_esp_at_open,
85 tlsio_esp_at_close,
86 tlsio_esp_at_send,
87 tlsio_esp_at_dowork,
88 tlsio_esp_at_setoption
89};
90
91static void indicate_error(TLS_IO_INSTANCE* tlsio_esp_at_instance)
92{
93 if ((tlsio_esp_at_instance->io_state == IO_STATE_CLOSED)
94 || (tlsio_esp_at_instance->io_state == IO_STATE_ERROR))
95 {
96 return;
97 }
98 tlsio_esp_at_instance->io_state = IO_STATE_ERROR;
99 if (tlsio_esp_at_instance->on_io_error != NULL)
100 {
101 tlsio_esp_at_instance->on_io_error(tlsio_esp_at_instance->on_io_error_context);
102 }
103}
104
105static int add_pending_io(TLS_IO_INSTANCE* tlsio_esp_at_instance, const unsigned char* buffer, size_t size, ON_SEND_COMPLETE on_send_complete, void* callback_context)
106{
107 int result;
108 PENDING_TLS_IO* pending_tlsio_esp_at = (PENDING_TLS_IO*)malloc(sizeof(PENDING_TLS_IO));
109 if (pending_tlsio_esp_at == NULL)
110 {
111 LogError("Allocation Failure: Unable to allocate pending list.");
112 result = MU_FAILURE;
113 }
114 else
115 {
116 pending_tlsio_esp_at->bytes = (unsigned char*)malloc(size);
117 if (pending_tlsio_esp_at->bytes == NULL)
118 {
119 LogError("Allocation Failure: Unable to allocate pending list.");
120 free(pending_tlsio_esp_at);
121 result = MU_FAILURE;
122 }
123 else
124 {
125 pending_tlsio_esp_at->size = size;
126 pending_tlsio_esp_at->on_send_complete = on_send_complete;
127 pending_tlsio_esp_at->callback_context = callback_context;
128 pending_tlsio_esp_at->pending_io_list = tlsio_esp_at_instance->pending_io_list;
129 (void)memcpy(pending_tlsio_esp_at->bytes, buffer, size);
130 if (singlylinkedlist_add(tlsio_esp_at_instance->pending_io_list, pending_tlsio_esp_at) == NULL)
131 {
132 LogError("Failure: Unable to add socket to pending list.");
133 free(pending_tlsio_esp_at->bytes);
134 free(pending_tlsio_esp_at);
135 result = MU_FAILURE;
136 }
137 else
138 {
139 result = 0;
140 }
141 }
142 }
143
144 return result;
145}
146
147#define NSAPI_ERROR_WOULD_BLOCK -3001
148
149static int retrieve_data(TLS_IO_INSTANCE* tlsio_esp_at_instance)
150{
151 int received = 1;
152 int total_received = 0;
153
154 unsigned char* recv_bytes = malloc(ESP_AT_XIO_RECEIVE_BUFFER_SIZE);
155 if (recv_bytes == NULL)
156 {
157 LogError("Socketio_Failure: NULL allocating input buffer.");
158 indicate_error(tlsio_esp_at_instance);
159 return -1;
160 }
161
162 while (received > 0)
163 {
164 received = esp_at_socket_receive(tlsio_esp_at_instance->tcp_socket_connection, (char*)recv_bytes, ESP_AT_XIO_RECEIVE_BUFFER_SIZE);
165 if (received > 0)
166 {
167 total_received += received;
168 if (tlsio_esp_at_instance->on_bytes_received != NULL)
169 {
170 /* explictly ignoring here the result of the callback */
171 tlsio_esp_at_instance->on_bytes_received(tlsio_esp_at_instance->on_bytes_received_context, recv_bytes, received);
172 }
173 }
174 else if (received < 0)
175 {
176 if(received != NSAPI_ERROR_WOULD_BLOCK) // NSAPI_ERROR_WOULD_BLOCK is not a real error but pending.
177 {
178 indicate_error(tlsio_esp_at_instance);
179 LogError("Socketio_Failure: underlying IO error %d.", received);
180 free(recv_bytes);
181 return -1;
182 }
183 }
184 }
185 free(recv_bytes);
186
187 return total_received;
188}
189
190static int send_queued_data(TLS_IO_INSTANCE* tlsio_esp_at_instance)
191{
192 int errors = 0;
193 int sent = 0;
194
195 LIST_ITEM_HANDLE first_pending_io = singlylinkedlist_get_head_item(tlsio_esp_at_instance->pending_io_list);
196 while (first_pending_io != NULL)
197 {
198 PENDING_TLS_IO* pending_tlsio_esp_at = (PENDING_TLS_IO*)singlylinkedlist_item_get_value(first_pending_io);
199 if (pending_tlsio_esp_at == NULL)
200 {
201 indicate_error(tlsio_esp_at_instance);
202 return -1;
203 }
204
205 int send_result = esp_at_socket_send(tlsio_esp_at_instance->tcp_socket_connection, (const char*)pending_tlsio_esp_at->bytes, pending_tlsio_esp_at->size);
206 if (send_result != (int)pending_tlsio_esp_at->size)
207 {
208 if (send_result == 0)
209 {
210 // The underlying network layer may encounter hardware / environment issues,
211 // but the driver doesn't handle it properly. So here the send API always return 0,
212 // this causes the program running into dead loop if not check it here.
213 if (errors++ >= 10)
214 {
215 // Treat it as a network error after try 10 times.
216 LogError("Socketio_Failure: encountered unknow connection issue, the connection will be restarted.");
217 indicate_error(tlsio_esp_at_instance);
218 return -1;
219 }
220 ThreadAPI_Sleep(10);
221 }
222 else if (send_result < 0)
223 {
224 indicate_error(tlsio_esp_at_instance);
225 return -1;
226 }
227 else
228 {
229 /* send something, wait for the rest */
230 memmove(pending_tlsio_esp_at->bytes, pending_tlsio_esp_at->bytes + send_result, pending_tlsio_esp_at->size - send_result);
231 sent += send_result;
232 }
233 }
234 else
235 {
236 sent += send_result;
237 if (pending_tlsio_esp_at->on_send_complete != NULL)
238 {
239 pending_tlsio_esp_at->on_send_complete(pending_tlsio_esp_at->callback_context, IO_SEND_OK);
240 }
241
242 free(pending_tlsio_esp_at->bytes);
243 free(pending_tlsio_esp_at);
244 if (singlylinkedlist_remove(tlsio_esp_at_instance->pending_io_list, first_pending_io) != 0)
245 {
246 indicate_error(tlsio_esp_at_instance);
247 return -1;
248 }
249 errors = 0;
250 }
251
252 first_pending_io = singlylinkedlist_get_head_item(tlsio_esp_at_instance->pending_io_list);
253 }
254
255 return sent;
256}
257
258static void close_tcp_connection(TLS_IO_INSTANCE* tlsio_esp_at_instance)
259{
260 if (tlsio_esp_at_instance->io_state != IO_STATE_CLOSED)
261 {
262 if (tlsio_esp_at_instance->tcp_socket_connection != NULL)
263 {
264 esp_at_socket_close(tlsio_esp_at_instance->tcp_socket_connection);
265 esp_at_socket_destroy(tlsio_esp_at_instance->tcp_socket_connection);
266 tlsio_esp_at_instance->tcp_socket_connection = NULL;
267 }
268 tlsio_esp_at_instance->io_state = IO_STATE_CLOSED;
269 }
270}
271
272CONCRETE_IO_HANDLE tlsio_esp_at_create(void* io_create_parameters)
273{
274 TLSIO_CONFIG* tlsio_esp_at_config = io_create_parameters;
275 TLS_IO_INSTANCE* result;
276
277 if (tlsio_esp_at_config == NULL)
278 {
279 result = NULL;
280 }
281 else
282 {
283 result = (TLS_IO_INSTANCE*)malloc(sizeof(TLS_IO_INSTANCE));
284 if (result == NULL) {
285 LogError("Socketio_Failure: NULL allocating socket io instance.");
286 }
287 else
288 {
289 result->pending_io_list = singlylinkedlist_create();
290 if (result->pending_io_list == NULL)
291 {
292 free(result);
293 result = NULL;
294 }
295 else
296 {
297 result->hostname = strdup(tlsio_esp_at_config->hostname);
298 if (result->hostname == NULL)
299 {
300 singlylinkedlist_destroy(result->pending_io_list);
301 free(result);
302 result = NULL;
303 }
304 else
305 {
306 result->port = tlsio_esp_at_config->port;
307 result->on_bytes_received = NULL;
308 result->on_io_error = NULL;
309 result->on_bytes_received_context = NULL;
310 result->on_io_error_context = NULL;
311 result->io_state = IO_STATE_CLOSED;
312 result->tcp_socket_connection = NULL;
313 }
314 }
315 }
316 }
317
318 return result;
319}
320
321void tlsio_esp_at_destroy(CONCRETE_IO_HANDLE tlsio_esp_at)
322{
323 if (tlsio_esp_at != NULL)
324 {
325 TLS_IO_INSTANCE* tlsio_esp_at_instance = (TLS_IO_INSTANCE*)tlsio_esp_at;
326
327 // Close the tcp connection
328 close_tcp_connection(tlsio_esp_at_instance);
329
330 // Clear all pending IOs
331 LIST_ITEM_HANDLE first_pending_io = singlylinkedlist_get_head_item(tlsio_esp_at_instance->pending_io_list);
332 while (first_pending_io != NULL)
333 {
334 PENDING_TLS_IO* pending_tlsio_esp_at = (PENDING_TLS_IO*)singlylinkedlist_item_get_value(first_pending_io);
335 if (pending_tlsio_esp_at != NULL)
336 {
337 free(pending_tlsio_esp_at->bytes);
338 free(pending_tlsio_esp_at);
339 }
340
341 (void)singlylinkedlist_remove(tlsio_esp_at_instance->pending_io_list, first_pending_io);
342 first_pending_io = singlylinkedlist_get_head_item(tlsio_esp_at_instance->pending_io_list);
343 }
344 singlylinkedlist_destroy(tlsio_esp_at_instance->pending_io_list);
345
346 if(tlsio_esp_at_instance->hostname != NULL)
347 {
348 free(tlsio_esp_at_instance->hostname);
349 tlsio_esp_at_instance->hostname = NULL;
350 }
351 free(tlsio_esp_at);
352 }
353}
354
355int tlsio_esp_at_open(CONCRETE_IO_HANDLE tlsio_esp_at, ON_IO_OPEN_COMPLETE on_io_open_complete, void* on_io_open_complete_context, ON_BYTES_RECEIVED on_bytes_received, void* on_bytes_received_context, ON_IO_ERROR on_io_error, void* on_io_error_context)
356{
357 int result;
358 TLS_IO_INSTANCE* tlsio_esp_at_instance = (TLS_IO_INSTANCE*)tlsio_esp_at;
359
360
361 if (tlsio_esp_at_instance == NULL ||
362 tlsio_esp_at_instance->io_state != IO_STATE_CLOSED)
363 {
364 result = MU_FAILURE;
365 }
366 else
367 {
368 tlsio_esp_at_instance->tcp_socket_connection = esp_at_socket_create(true);
369 if (tlsio_esp_at_instance->tcp_socket_connection == NULL)
370 {
371 result = MU_FAILURE;
372 }
373 else
374 {
375 if (esp_at_socket_connect(tlsio_esp_at_instance->tcp_socket_connection, tlsio_esp_at_instance->hostname, tlsio_esp_at_instance->port) != 0)
376 {
377 esp_at_socket_destroy(tlsio_esp_at_instance->tcp_socket_connection);
378 tlsio_esp_at_instance->tcp_socket_connection = NULL;
379 result = MU_FAILURE;
380 }
381 else
382 {
383 esp_at_socket_set_blocking(tlsio_esp_at_instance->tcp_socket_connection, false, 0);
384
385 tlsio_esp_at_instance->on_bytes_received = on_bytes_received;
386 tlsio_esp_at_instance->on_bytes_received_context = on_bytes_received_context;
387
388 tlsio_esp_at_instance->on_io_error = on_io_error;
389 tlsio_esp_at_instance->on_io_error_context = on_io_error_context;
390
391 tlsio_esp_at_instance->io_state = IO_STATE_OPEN;
392
393 result = 0;
394 }
395 }
396 }
397
398 if (on_io_open_complete != NULL)
399 {
400 on_io_open_complete(on_io_open_complete_context, result == 0 ? IO_OPEN_OK : IO_OPEN_ERROR);
401 }
402
403 return result;
404}
405
406int tlsio_esp_at_close(CONCRETE_IO_HANDLE tlsio_esp_at, ON_IO_CLOSE_COMPLETE on_io_close_complete, void* callback_context)
407{
408 int result = 0;
409
410 if (tlsio_esp_at == NULL)
411 {
412 result = MU_FAILURE;
413 }
414 else
415 {
416 TLS_IO_INSTANCE* tlsio_esp_at_instance = (TLS_IO_INSTANCE*)tlsio_esp_at;
417 if (tlsio_esp_at_instance->io_state == IO_STATE_CLOSED ||
418 tlsio_esp_at_instance->io_state == IO_STATE_ERROR)
419 {
420 result = MU_FAILURE;
421 }
422 else
423 {
424 close_tcp_connection(tlsio_esp_at_instance);
425 if (on_io_close_complete != NULL)
426 {
427 on_io_close_complete(callback_context);
428 }
429 result = 0;
430 }
431 }
432
433 return result;
434}
435
436int tlsio_esp_at_send(CONCRETE_IO_HANDLE tlsio_esp_at, const void* buffer, size_t size, ON_SEND_COMPLETE on_send_complete, void* callback_context)
437{
438 int result;
439
440 if ((tlsio_esp_at == NULL) ||
441 (buffer == NULL) ||
442 (size == 0))
443 {
444 /* Invalid arguments */
445 result = MU_FAILURE;
446 }
447 else
448 {
449 result = 0;
450
451 TLS_IO_INSTANCE* tlsio_esp_at_instance = (TLS_IO_INSTANCE*)tlsio_esp_at;
452 if (tlsio_esp_at_instance->io_state != IO_STATE_OPEN)
453 {
454 result = MU_FAILURE;
455 }
456 else
457 {
458 // Queue the data, and the tlsio_esp_at_dowork sends the package later
459 if (add_pending_io(tlsio_esp_at_instance, buffer, size, on_send_complete, callback_context) != 0)
460 {
461 result = MU_FAILURE;
462 }
463 }
464 }
465
466 return result;
467}
468
469void tlsio_esp_at_dowork(CONCRETE_IO_HANDLE tlsio_esp_at)
470{
471 if (tlsio_esp_at != NULL)
472 {
473 TLS_IO_INSTANCE* tlsio_esp_at_instance = (TLS_IO_INSTANCE*)tlsio_esp_at;
474 if (tlsio_esp_at_instance->io_state == IO_STATE_OPEN)
475 {
476 // Retrieve all data from IoT Hub
477 if (retrieve_data(tlsio_esp_at_instance) < 0)
478 {
479 return;
480 }
481
482 // Send all packages in the queue
483 send_queued_data(tlsio_esp_at_instance);
484 }
485 }
486}
487
488int tlsio_esp_at_setoption(CONCRETE_IO_HANDLE tlsio_esp_at, const char* optionName, const void* value)
489{
490 /* Not implementing any options, do nothing */
491 return OPTIONHANDLER_OK;
492}
493
494const IO_INTERFACE_DESCRIPTION* tlsio_esp_at_get_interface_description(void)
495{
496 return &tlsio_esp_at_interface_description;
497}
Note: See TracBrowser for help on using the repository browser.