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