source: azure_iot_hub_f767zi/trunk/azure_iot_sdk/c-utility/adapters/socketio_esp_at.c

Last change on this file was 473, checked in by coas-nagasima, 3 years ago

lwipとESP ATの両方使えるよう変更

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