source: azure_iot_hub_f767zi/trunk/azure_iot_sdk/c-utility/adapters/socketio_lwip.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: 37.8 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#ifndef _BSD_SOURCE
5#define _BSD_SOURCE
6#define SOCKETIO_BERKELEY_UNDEF_BSD_SOURCE
7#endif
8
9#define _DEFAULT_SOURCE
10#include <net/if.h>
11#undef _DEFAULT_SOURCE
12
13#ifdef SOCKETIO_BERKELEY_UNDEF_BSD_SOURCE
14#undef _BSD_SOURCE
15#undef SOCKETIO_BERKELEY_UNDEF_BSD_SOURCE
16#endif
17
18#include <signal.h>
19#include <stdlib.h>
20#include <stddef.h>
21#include <stdio.h>
22#include <string.h>
23#include <ctype.h>
24#include "azure_c_shared_utility/socketio.h"
25#include <sys/types.h>
26#include <sys/socket.h>
27#include <sys/select.h>
28#ifdef TIZENRT
29#include <net/lwip/tcp.h>
30#else
31#include <lwip/tcp.h>
32#endif
33#include <netdb.h>
34#include <unistd.h>
35#include <errno.h>
36#include "azure_c_shared_utility/singlylinkedlist.h"
37#include "azure_c_shared_utility/gballoc.h"
38#include "azure_c_shared_utility/gbnetwork.h"
39#include "azure_c_shared_utility/optimize_size.h"
40#include "azure_c_shared_utility/optionhandler.h"
41#include "azure_c_shared_utility/shared_util_options.h"
42#include "azure_c_shared_utility/xlogging.h"
43#include "azure_c_shared_utility/const_defines.h"
44#include "azure_c_shared_utility/dns_resolver.h"
45//#include <sys/ioctl.h>
46//#include <netinet/in.h>
47//#include <arpa/inet.h>
48//#include <sys/un.h>
49
50#define SOCKET_SUCCESS 0
51#define INVALID_SOCKET -1
52#define SOCKET_SEND_FAILURE -1
53#define MAC_ADDRESS_STRING_LENGTH 18
54
55#ifndef IFREQ_BUFFER_SIZE
56#define IFREQ_BUFFER_SIZE 1024
57#endif
58
59// connect timeout in seconds
60#define CONNECT_TIMEOUT 10
61
62typedef enum IO_STATE_TAG
63{
64 IO_STATE_CLOSED,
65 IO_STATE_OPENING,
66 IO_STATE_OPEN,
67 IO_STATE_CLOSING,
68 IO_STATE_ERROR
69} IO_STATE;
70
71typedef struct PENDING_SOCKET_IO_TAG
72{
73 unsigned char* bytes;
74 size_t size;
75 ON_SEND_COMPLETE on_send_complete;
76 void* callback_context;
77 SINGLYLINKEDLIST_HANDLE pending_io_list;
78} PENDING_SOCKET_IO;
79
80typedef struct SOCKET_IO_INSTANCE_TAG
81{
82 int socket;
83 SOCKETIO_ADDRESS_TYPE address_type;
84 ON_BYTES_RECEIVED on_bytes_received;
85 ON_IO_ERROR on_io_error;
86 ON_IO_OPEN_COMPLETE on_io_open_complete;
87 void* on_bytes_received_context;
88 void* on_io_error_context;
89 void* on_io_open_complete_context;
90 char* hostname;
91 int port;
92 char* target_mac_address;
93 IO_STATE io_state;
94 SINGLYLINKEDLIST_HANDLE pending_io_list;
95 unsigned char recv_bytes[RECEIVE_BYTES_VALUE];
96 DNSRESOLVER_HANDLE dns_resolver;
97} SOCKET_IO_INSTANCE;
98
99typedef struct NETWORK_INTERFACE_DESCRIPTION_TAG
100{
101 char* name;
102 char* mac_address;
103 char* ip_address;
104 struct NETWORK_INTERFACE_DESCRIPTION_TAG* next;
105} NETWORK_INTERFACE_DESCRIPTION;
106
107/*this function will clone an option given by name and value*/
108static void* socketio_CloneOption(const char* name, const void* value)
109{
110 void* result;
111
112 if (name != NULL)
113 {
114 result = NULL;
115
116 if (strcmp(name, OPTION_NET_INT_MAC_ADDRESS) == 0)
117 {
118 if (value == NULL)
119 {
120 LogError("Failed cloning option %s (value is NULL)", name);
121 }
122 else
123 {
124 if ((result = malloc(sizeof(char) * (strlen((char*)value) + 1))) == NULL)
125 {
126 LogError("Failed cloning option %s (malloc failed)", name);
127 }
128 else if (strcpy((char*)result, (char*)value) == NULL)
129 {
130 LogError("Failed cloning option %s (strcpy failed)", name);
131 free(result);
132 result = NULL;
133 }
134 }
135 }
136 else
137 {
138 LogError("Cannot clone option %s (not suppported)", name);
139 }
140 }
141 else
142 {
143 result = NULL;
144 }
145 return result;
146}
147
148/*this function destroys an option previously created*/
149static void socketio_DestroyOption(const char* name, const void* value)
150{
151 if (name != NULL)
152 {
153 if (strcmp(name, OPTION_NET_INT_MAC_ADDRESS) == 0 && value != NULL)
154 {
155 free((void*)value);
156 }
157 }
158}
159
160static OPTIONHANDLER_HANDLE socketio_retrieveoptions(CONCRETE_IO_HANDLE handle)
161{
162 OPTIONHANDLER_HANDLE result;
163
164 if (handle == NULL)
165 {
166 LogError("failed retrieving options (handle is NULL)");
167 result = NULL;
168 }
169 else
170 {
171 SOCKET_IO_INSTANCE* socket_io_instance = (SOCKET_IO_INSTANCE*)handle;
172
173 result = OptionHandler_Create(socketio_CloneOption, socketio_DestroyOption, socketio_setoption);
174 if (result == NULL)
175 {
176 LogError("unable to OptionHandler_Create");
177 }
178 else if (socket_io_instance->target_mac_address != NULL &&
179 OptionHandler_AddOption(result, OPTION_NET_INT_MAC_ADDRESS, socket_io_instance->target_mac_address) != OPTIONHANDLER_OK)
180 {
181 LogError("failed retrieving options (failed adding net_interface_mac_address)");
182 OptionHandler_Destroy(result);
183 result = NULL;
184 }
185 }
186
187 return result;
188}
189
190static const IO_INTERFACE_DESCRIPTION socket_io_interface_description =
191{
192 socketio_retrieveoptions,
193 socketio_create,
194 socketio_destroy,
195 socketio_open,
196 socketio_close,
197 socketio_send,
198 socketio_dowork,
199 socketio_setoption
200};
201
202static void indicate_error(SOCKET_IO_INSTANCE* socket_io_instance)
203{
204 socket_io_instance->io_state = IO_STATE_ERROR;
205 if (socket_io_instance->on_io_error != NULL)
206 {
207 socket_io_instance->on_io_error(socket_io_instance->on_io_error_context);
208 }
209}
210
211static 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)
212{
213 int result;
214 PENDING_SOCKET_IO* pending_socket_io = (PENDING_SOCKET_IO*)malloc(sizeof(PENDING_SOCKET_IO));
215 if (pending_socket_io == NULL)
216 {
217 result = MU_FAILURE;
218 }
219 else
220 {
221 pending_socket_io->bytes = (unsigned char*)malloc(size);
222 if (pending_socket_io->bytes == NULL)
223 {
224 LogError("Allocation Failure: Unable to allocate pending list.");
225 free(pending_socket_io);
226 result = MU_FAILURE;
227 }
228 else
229 {
230 pending_socket_io->size = size;
231 pending_socket_io->on_send_complete = on_send_complete;
232 pending_socket_io->callback_context = callback_context;
233 pending_socket_io->pending_io_list = socket_io_instance->pending_io_list;
234 (void)memcpy(pending_socket_io->bytes, buffer, size);
235
236 if (singlylinkedlist_add(socket_io_instance->pending_io_list, pending_socket_io) == NULL)
237 {
238 LogError("Failure: Unable to add socket to pending list.");
239 free(pending_socket_io->bytes);
240 free(pending_socket_io);
241 result = MU_FAILURE;
242 }
243 else
244 {
245 result = 0;
246 }
247 }
248 }
249 return result;
250}
251
252static STATIC_VAR_UNUSED void signal_callback(int signum)
253{
254 AZURE_UNREFERENCED_PARAMETER(signum);
255 LogError("Socket received signal %d.", signum);
256}
257
258static int lookup_address(SOCKET_IO_INSTANCE* socket_io_instance)
259{
260 int result = 0;
261
262 if (socket_io_instance->address_type == ADDRESS_TYPE_IP)
263 {
264 if (!dns_resolver_is_lookup_complete(socket_io_instance->dns_resolver))
265 {
266 socket_io_instance->io_state = IO_STATE_OPENING;
267 }
268 else
269 {
270 socket_io_instance->io_state = IO_STATE_OPEN;
271 }
272 }
273 else //ADDRESS_TYPE_DOMAIN_SOCKET
274 {
275 socket_io_instance->io_state = IO_STATE_OPEN;
276 }
277
278 return result;
279}
280
281static int initiate_socket_connection(SOCKET_IO_INSTANCE* socket_io_instance)
282{
283 int result;
284 int flags;
285 struct addrinfo* addr = NULL;
286 struct sockaddr* connect_addr = NULL;
287 struct sockaddr_un addrInfoUn;
288 socklen_t connect_addr_len;
289
290 if (socket_io_instance->address_type == ADDRESS_TYPE_IP)
291 {
292 if(!dns_resolver_is_lookup_complete(socket_io_instance->dns_resolver))
293 {
294 LogError("DNS did not resolve IP address");
295 result = MU_FAILURE;
296 }
297 else
298 {
299 addr = dns_resolver_get_addrInfo(socket_io_instance->dns_resolver);
300
301 if (addr == NULL)
302 {
303 LogError("DNS resolution failed");
304 result = MU_FAILURE;
305 }
306 else
307 {
308 connect_addr = addr->ai_addr;
309 connect_addr_len = sizeof(*addr->ai_addr);
310 result = 0;
311 }
312 }
313 }
314 else
315 {
316 size_t hostname_len = strlen(socket_io_instance->hostname);
317 if (hostname_len + 1 > sizeof(addrInfoUn.sun_path))
318 {
319 LogError("Hostname %s is too long for a unix socket (max len = %lu)", socket_io_instance->hostname, (unsigned long)sizeof(addrInfoUn.sun_path));
320 result = MU_FAILURE;
321 }
322 else
323 {
324 memset(&addrInfoUn, 0, sizeof(addrInfoUn));
325 addrInfoUn.sun_family = AF_UNIX;
326 // No need to add NULL terminator due to the above memset
327 (void)memcpy(addrInfoUn.sun_path, socket_io_instance->hostname, hostname_len);
328
329 connect_addr = (struct sockaddr*)&addrInfoUn;
330 connect_addr_len = sizeof(addrInfoUn);
331 result = 0;
332 }
333 }
334
335 if (result == 0)
336 {
337 if ((-1 == (flags = fcntl(socket_io_instance->socket, F_GETFL, 0))) ||
338 (fcntl(socket_io_instance->socket, F_SETFL, flags | O_NONBLOCK) == -1))
339 {
340 LogError("Failure: fcntl failure.");
341 result = MU_FAILURE;
342 }
343 else
344 {
345 result = connect(socket_io_instance->socket, connect_addr, connect_addr_len);
346 if ((result != 0) && (errno != EINPROGRESS))
347 {
348 LogError("Failure: connect failure %d.", errno);
349 result = MU_FAILURE;
350 }
351 else
352 {
353 // Async connect will return -1.
354 result = 0;
355 if (socket_io_instance->on_io_open_complete != NULL)
356 {
357 socket_io_instance->on_io_open_complete(socket_io_instance->on_io_open_complete_context, IO_OPEN_OK /*: IO_OPEN_ERROR*/);
358 }
359 }
360 }
361 }
362
363 return result;
364}
365
366static int lookup_address_and_initiate_socket_connection(SOCKET_IO_INSTANCE* socket_io_instance)
367{
368 int result;
369
370 result = lookup_address(socket_io_instance);
371
372 if(socket_io_instance->io_state == IO_STATE_OPEN)
373 {
374 if (result == 0)
375 {
376 result = initiate_socket_connection(socket_io_instance);
377 }
378 }
379
380 return result;
381}
382
383static int wait_for_connection(SOCKET_IO_INSTANCE* socket_io_instance)
384{
385 int result;
386 int err;
387 int retval;
388 int select_errno = 0;
389
390 fd_set fdset;
391 struct timeval tv;
392
393 FD_ZERO(&fdset);
394 FD_SET(socket_io_instance->socket, &fdset);
395 tv.tv_sec = CONNECT_TIMEOUT;
396 tv.tv_usec = 0;
397
398 do
399 {
400 retval = select(socket_io_instance->socket + 1, NULL, &fdset, NULL, &tv);
401
402 if (retval < 0)
403 {
404 select_errno = errno;
405 }
406 } while (retval < 0 && select_errno == EINTR);
407
408 if (retval != 1)
409 {
410 LogError("Failure: select failure.");
411 result = MU_FAILURE;
412 }
413 else
414 {
415 int so_error = 0;
416 socklen_t len = sizeof(so_error);
417 err = getsockopt(socket_io_instance->socket, SOL_SOCKET, SO_ERROR, &so_error, &len);
418 if (err != 0)
419 {
420 LogError("Failure: getsockopt failure %d.", errno);
421 result = MU_FAILURE;
422 }
423 else if (so_error != 0)
424 {
425 err = so_error;
426 LogError("Failure: connect failure %d.", so_error);
427 result = MU_FAILURE;
428 }
429 else
430 {
431 result = 0;
432 }
433 }
434
435 return result;
436}
437
438
439
440#ifndef __APPLE__
441static void destroy_network_interface_descriptions(NETWORK_INTERFACE_DESCRIPTION* nid)
442{
443 if (nid != NULL)
444 {
445 if (nid->next != NULL)
446 {
447 destroy_network_interface_descriptions(nid->next);
448 }
449
450 if (nid->name != NULL)
451 {
452 free(nid->name);
453 }
454
455 if (nid->mac_address != NULL)
456 {
457 free(nid->mac_address);
458 }
459
460 if (nid->ip_address != NULL)
461 {
462 free(nid->ip_address);
463 }
464
465 free(nid);
466 }
467}
468
469static NETWORK_INTERFACE_DESCRIPTION* create_network_interface_description(struct ifreq *ifr, NETWORK_INTERFACE_DESCRIPTION* previous_nid)
470{
471 NETWORK_INTERFACE_DESCRIPTION* result;
472
473 if ((result = (NETWORK_INTERFACE_DESCRIPTION*)malloc(sizeof(NETWORK_INTERFACE_DESCRIPTION))) == NULL)
474 {
475 LogError("Failed allocating NETWORK_INTERFACE_DESCRIPTION");
476 }
477 else if ((result->name = (char*)malloc(sizeof(char) * (strlen(ifr->ifr_name) + 1))) == NULL)
478 {
479 LogError("failed setting interface description name (malloc failed)");
480 destroy_network_interface_descriptions(result);
481 result = NULL;
482 }
483 else if (strcpy(result->name, ifr->ifr_name) == NULL)
484 {
485 LogError("failed setting interface description name (strcpy failed)");
486 destroy_network_interface_descriptions(result);
487 result = NULL;
488 }
489 else
490 {
491 char* ip_address;
492 unsigned char* mac = (unsigned char*)ifr->ifr_hwaddr.sa_data;
493
494 if ((result->mac_address = (char*)malloc(sizeof(char) * MAC_ADDRESS_STRING_LENGTH)) == NULL)
495 {
496 LogError("failed formatting mac address (malloc failed)");
497 destroy_network_interface_descriptions(result);
498 result = NULL;
499 }
500 else if (sprintf(result->mac_address, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0],mac[1],mac[2],mac[3],mac[4],mac[5]) <= 0)
501 {
502 LogError("failed formatting mac address (sprintf failed)");
503 destroy_network_interface_descriptions(result);
504 result = NULL;
505 }
506 else if ((ip_address = inet_ntoa(((struct sockaddr_in*)&ifr->ifr_addr)->sin_addr)) == NULL)
507 {
508 LogError("failed setting the ip address (inet_ntoa failed)");
509 destroy_network_interface_descriptions(result);
510 result = NULL;
511 }
512 else if ((result->ip_address = (char*)malloc(sizeof(char) * (strlen(ip_address) + 1))) == NULL)
513 {
514 LogError("failed setting the ip address (malloc failed)");
515 destroy_network_interface_descriptions(result);
516 result = NULL;
517 }
518 else if (strcpy(result->ip_address, ip_address) == NULL)
519 {
520 LogError("failed setting the ip address (strcpy failed)");
521 destroy_network_interface_descriptions(result);
522 result = NULL;
523 }
524 else
525 {
526 result->next = NULL;
527
528 if (previous_nid != NULL)
529 {
530 previous_nid->next = result;
531 }
532 }
533 }
534
535 return result;
536}
537
538static int get_network_interface_descriptions(int socket, NETWORK_INTERFACE_DESCRIPTION** nid)
539{
540 int result;
541
542 struct ifreq ifr;
543 struct ifconf ifc;
544 char buf[IFREQ_BUFFER_SIZE];
545
546 ifc.ifc_len = sizeof(buf);
547 ifc.ifc_buf = buf;
548
549 if (ioctl(socket, SIOCGIFCONF, &ifc) == -1)
550 {
551 LogError("ioctl failed querying socket (SIOCGIFCONF, errno=%d)", errno);
552 result = MU_FAILURE;
553 }
554 else
555 {
556 NETWORK_INTERFACE_DESCRIPTION* root_nid = NULL;
557 NETWORK_INTERFACE_DESCRIPTION* new_nid = NULL;
558
559 struct ifreq* it = ifc.ifc_req;
560 const struct ifreq* const end = it + (ifc.ifc_len / sizeof(struct ifreq));
561
562 result = 0;
563
564 for (; it != end; ++it)
565 {
566 strcpy(ifr.ifr_name, it->ifr_name);
567
568 if (ioctl(socket, SIOCGIFFLAGS, &ifr) != 0)
569 {
570 LogError("ioctl failed querying socket (SIOCGIFFLAGS, errno=%d)", errno);
571 result = MU_FAILURE;
572 break;
573 }
574 else if (ioctl(socket, SIOCGIFHWADDR, &ifr) != 0)
575 {
576 LogError("ioctl failed querying socket (SIOCGIFHWADDR, errno=%d)", errno);
577 result = MU_FAILURE;
578 break;
579 }
580 else if (ioctl(socket, SIOCGIFADDR, &ifr) != 0)
581 {
582 LogError("ioctl failed querying socket (SIOCGIFADDR, errno=%d)", errno);
583 result = MU_FAILURE;
584 break;
585 }
586 else if ((new_nid = create_network_interface_description(&ifr, new_nid)) == NULL)
587 {
588 LogError("Failed creating network interface description");
589 result = MU_FAILURE;
590 break;
591 }
592 else if (root_nid == NULL)
593 {
594 root_nid = new_nid;
595 }
596 }
597
598 if (result == 0)
599 {
600 *nid = root_nid;
601 }
602 else
603 {
604 destroy_network_interface_descriptions(root_nid);
605 }
606 }
607
608 return result;
609}
610
611static int set_target_network_interface(int socket, char* mac_address)
612{
613 int result;
614 NETWORK_INTERFACE_DESCRIPTION* nid;
615
616 if (get_network_interface_descriptions(socket, &nid) != 0)
617 {
618 LogError("Failed getting network interface descriptions");
619 result = MU_FAILURE;
620 }
621 else
622 {
623 NETWORK_INTERFACE_DESCRIPTION* current_nid = nid;
624
625 while(current_nid != NULL)
626 {
627 if (strcmp(mac_address, current_nid->mac_address) == 0)
628 {
629 break;
630 }
631
632 current_nid = current_nid->next;
633 }
634
635 if (current_nid == NULL)
636 {
637 LogError("Did not find a network interface matching MAC ADDRESS");
638 result = MU_FAILURE;
639 }
640 else if (setsockopt(socket, SOL_SOCKET, SO_BINDTODEVICE, current_nid->name, strlen(current_nid->name)) != 0)
641 {
642 LogError("setsockopt failed (%d)", errno);
643 result = MU_FAILURE;
644 }
645 else
646 {
647 result = 0;
648 }
649
650 destroy_network_interface_descriptions(nid);
651 }
652
653 return result;
654}
655#endif //__APPLE__
656
657static void destroy_socket_io_instance(SOCKET_IO_INSTANCE* instance)
658{
659 if (instance->dns_resolver != NULL)
660 {
661 dns_resolver_destroy(instance->dns_resolver);
662 }
663
664 free(instance->hostname);
665 free(instance->target_mac_address);
666
667 if (instance->pending_io_list != NULL)
668 {
669 singlylinkedlist_destroy(instance->pending_io_list);
670 }
671
672 free(instance);
673}
674
675CONCRETE_IO_HANDLE socketio_create(void* io_create_parameters)
676{
677 SOCKETIO_CONFIG* socket_io_config = io_create_parameters;
678 SOCKET_IO_INSTANCE* result;
679
680 if (socket_io_config == NULL)
681 {
682 LogError("Invalid argument: socket_io_config is NULL");
683 result = NULL;
684 }
685 else
686 {
687 result = malloc(sizeof(SOCKET_IO_INSTANCE));
688 if (result != NULL)
689 {
690 (void)memset(result, 0, sizeof(SOCKET_IO_INSTANCE));
691
692 result->address_type = ADDRESS_TYPE_IP;
693 result->pending_io_list = singlylinkedlist_create();
694 if (result->pending_io_list == NULL)
695 {
696 LogError("Failure: singlylinkedlist_create unable to create pending list.");
697 destroy_socket_io_instance(result);
698 result = NULL;
699 }
700 else
701 {
702 if (socket_io_config->hostname != NULL)
703 {
704 result->hostname = (char*)malloc(strlen(socket_io_config->hostname) + 1);
705 if (result->hostname != NULL)
706 {
707 (void)strcpy(result->hostname, socket_io_config->hostname);
708 }
709
710 result->socket = INVALID_SOCKET;
711 }
712 else
713 {
714 result->hostname = NULL;
715 result->socket = *((int*)socket_io_config->accepted_socket);
716 }
717
718 if ((result->hostname == NULL) && (result->socket == INVALID_SOCKET))
719 {
720 LogError("Failure: hostname == NULL and socket is invalid.");
721 destroy_socket_io_instance(result);
722 result = NULL;
723 }
724 else
725 {
726 result->port = socket_io_config->port;
727 result->on_io_open_complete = NULL;
728 result->dns_resolver = dns_resolver_create(result->hostname, socket_io_config->port, NULL);
729 result->target_mac_address = NULL;
730 result->on_bytes_received = NULL;
731 result->on_io_error = NULL;
732 result->on_bytes_received_context = NULL;
733 result->on_io_error_context = NULL;
734 result->io_state = IO_STATE_CLOSED;
735 }
736 }
737 }
738 else
739 {
740 LogError("Allocation Failure: SOCKET_IO_INSTANCE");
741 }
742 }
743
744 return result;
745}
746
747void socketio_destroy(CONCRETE_IO_HANDLE socket_io)
748{
749 if (socket_io != NULL)
750 {
751 SOCKET_IO_INSTANCE* socket_io_instance = (SOCKET_IO_INSTANCE*)socket_io;
752 /* we cannot do much if the close fails, so just ignore the result */
753 if (socket_io_instance->socket != INVALID_SOCKET)
754 {
755 close(socket_io_instance->socket);
756 }
757
758 /* clear allpending IOs */
759 LIST_ITEM_HANDLE first_pending_io = singlylinkedlist_get_head_item(socket_io_instance->pending_io_list);
760 while (first_pending_io != NULL)
761 {
762 PENDING_SOCKET_IO* pending_socket_io = (PENDING_SOCKET_IO*)singlylinkedlist_item_get_value(first_pending_io);
763 if (pending_socket_io != NULL)
764 {
765 free(pending_socket_io->bytes);
766 free(pending_socket_io);
767 }
768
769 (void)singlylinkedlist_remove(socket_io_instance->pending_io_list, first_pending_io);
770 first_pending_io = singlylinkedlist_get_head_item(socket_io_instance->pending_io_list);
771 }
772
773 destroy_socket_io_instance(socket_io_instance);
774 }
775}
776
777int 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)
778{
779 int result;
780
781 SOCKET_IO_INSTANCE* socket_io_instance = (SOCKET_IO_INSTANCE*)socket_io;
782 if (socket_io == NULL)
783 {
784 LogError("Invalid argument: SOCKET_IO_INSTANCE is NULL");
785 result = MU_FAILURE;
786 }
787 else
788 {
789 if (socket_io_instance->io_state != IO_STATE_CLOSED)
790 {
791 LogError("Failure: socket state is not closed.");
792 result = MU_FAILURE;
793 }
794 else if (socket_io_instance->socket != INVALID_SOCKET)
795 {
796 // Opening an accepted socket
797 socket_io_instance->on_bytes_received_context = on_bytes_received_context;
798 socket_io_instance->on_bytes_received = on_bytes_received;
799 socket_io_instance->on_io_error = on_io_error;
800 socket_io_instance->on_io_error_context = on_io_error_context;
801
802 socket_io_instance->io_state = IO_STATE_OPEN;
803
804 result = 0;
805 }
806 else
807 {
808 socket_io_instance->socket = socket (socket_io_instance->address_type == ADDRESS_TYPE_IP ? AF_INET : AF_UNIX, SOCK_STREAM, 0);
809 if (socket_io_instance->socket < SOCKET_SUCCESS)
810 {
811 LogError("Failure: socket create failure %d.", socket_io_instance->socket);
812 result = MU_FAILURE;
813 }
814#ifndef __APPLE__
815 else if (socket_io_instance->target_mac_address != NULL &&
816 set_target_network_interface(socket_io_instance->socket, socket_io_instance->target_mac_address) != 0)
817 {
818 LogError("Failure: failed selecting target network interface (MACADDR=%s).", socket_io_instance->target_mac_address);
819 result = MU_FAILURE;
820 }
821#endif //__APPLE__
822 else if ((result = lookup_address_and_initiate_socket_connection(socket_io_instance)) != 0)
823 {
824 LogError("lookup_address_and_connect_socket failed");
825 }
826 else if ((result = wait_for_connection(socket_io_instance)) != 0)
827 {
828 LogError("wait_for_connection failed");
829 }
830
831 if (result == 0)
832 {
833 socket_io_instance->on_bytes_received = on_bytes_received;
834 socket_io_instance->on_bytes_received_context = on_bytes_received_context;
835
836 socket_io_instance->on_io_error = on_io_error;
837 socket_io_instance->on_io_error_context = on_io_error_context;
838
839 socket_io_instance->on_io_open_complete = on_io_open_complete;
840 socket_io_instance->on_io_open_complete_context = on_io_open_complete_context;
841 }
842 else
843 {
844 if (socket_io_instance->socket >= SOCKET_SUCCESS)
845 {
846 close(socket_io_instance->socket);
847 }
848 socket_io_instance->socket = INVALID_SOCKET;
849 }
850 }
851 }
852
853 if (socket_io_instance->io_state != IO_STATE_OPENING)
854 {
855 if (on_io_open_complete != NULL)
856 {
857 on_io_open_complete(on_io_open_complete_context, result == 0 ? IO_OPEN_OK : IO_OPEN_ERROR);
858 }
859 }
860
861 return result;
862}
863
864int socketio_close(CONCRETE_IO_HANDLE socket_io, ON_IO_CLOSE_COMPLETE on_io_close_complete, void* callback_context)
865{
866 int result = 0;
867
868 if (socket_io == NULL)
869 {
870 result = MU_FAILURE;
871 }
872 else
873 {
874 SOCKET_IO_INSTANCE* socket_io_instance = (SOCKET_IO_INSTANCE*)socket_io;
875 if ((socket_io_instance->io_state != IO_STATE_CLOSED) && (socket_io_instance->io_state != IO_STATE_CLOSING))
876 {
877 // Only close if the socket isn't already in the closed or closing state
878 (void)shutdown(socket_io_instance->socket, SHUT_RDWR);
879 close(socket_io_instance->socket);
880 socket_io_instance->socket = INVALID_SOCKET;
881 socket_io_instance->io_state = IO_STATE_CLOSED;
882 }
883
884 if (on_io_close_complete != NULL)
885 {
886 on_io_close_complete(callback_context);
887 }
888
889 result = 0;
890 }
891
892 return result;
893}
894
895int socketio_send(CONCRETE_IO_HANDLE socket_io, const void* buffer, size_t size, ON_SEND_COMPLETE on_send_complete, void* callback_context)
896{
897 int result;
898
899 if ((socket_io == NULL) ||
900 (buffer == NULL) ||
901 (size == 0))
902 {
903 /* Invalid arguments */
904 LogError("Invalid argument: send given invalid parameter");
905 result = MU_FAILURE;
906 }
907 else
908 {
909 SOCKET_IO_INSTANCE* socket_io_instance = (SOCKET_IO_INSTANCE*)socket_io;
910 if (socket_io_instance->io_state != IO_STATE_OPEN)
911 {
912 LogError("Failure: socket state is not opened.");
913 result = MU_FAILURE;
914 }
915 else
916 {
917 LIST_ITEM_HANDLE first_pending_io = singlylinkedlist_get_head_item(socket_io_instance->pending_io_list);
918 if (first_pending_io != NULL)
919 {
920 if (add_pending_io(socket_io_instance, buffer, size, on_send_complete, callback_context) != 0)
921 {
922 LogError("Failure: add_pending_io failed.");
923 result = MU_FAILURE;
924 }
925 else
926 {
927 result = 0;
928 }
929 }
930 else
931 {
932 signal(SIGPIPE, SIG_IGN);
933
934 ssize_t send_result = send(socket_io_instance->socket, buffer, size, 0);
935 if ((size_t)send_result != size)
936 {
937 if (send_result == SOCKET_SEND_FAILURE && errno != EAGAIN)
938 {
939 LogError("Failure: sending socket failed. errno=%d (%s).", errno, strerror(errno));
940 result = MU_FAILURE;
941 }
942 else
943 {
944 /*send says "come back later" with EAGAIN - likely the socket buffer cannot accept more data*/
945 /* queue data */
946 size_t bytes_sent = (send_result < 0 ? 0 : send_result);
947
948 if (add_pending_io(socket_io_instance, buffer + bytes_sent, size - bytes_sent, on_send_complete, callback_context) != 0)
949 {
950 LogError("Failure: add_pending_io failed.");
951 result = MU_FAILURE;
952 }
953 else
954 {
955 result = 0;
956 }
957 }
958 }
959 else
960 {
961 if (on_send_complete != NULL)
962 {
963 on_send_complete(callback_context, IO_SEND_OK);
964 }
965
966 result = 0;
967 }
968 }
969 }
970 }
971
972 return result;
973}
974
975void socketio_dowork(CONCRETE_IO_HANDLE socket_io)
976{
977 if (socket_io != NULL)
978 {
979 SOCKET_IO_INSTANCE* socket_io_instance = (SOCKET_IO_INSTANCE*)socket_io;
980 signal(SIGPIPE, SIG_IGN);
981
982 if (socket_io_instance->io_state == IO_STATE_OPEN)
983 {
984 LIST_ITEM_HANDLE first_pending_io = singlylinkedlist_get_head_item(socket_io_instance->pending_io_list);
985 while (first_pending_io != NULL)
986 {
987 PENDING_SOCKET_IO* pending_socket_io = (PENDING_SOCKET_IO*)singlylinkedlist_item_get_value(first_pending_io);
988 if (pending_socket_io == NULL)
989 {
990 indicate_error(socket_io_instance);
991 LogError("Failure: retrieving socket from list");
992 break;
993 }
994
995 ssize_t send_result = send(socket_io_instance->socket, pending_socket_io->bytes, pending_socket_io->size, 0);
996 if ((send_result < 0) || ((size_t)send_result != pending_socket_io->size))
997 {
998 if (send_result == INVALID_SOCKET)
999 {
1000 if (errno == EAGAIN) /*send says "come back later" with EAGAIN - likely the socket buffer cannot accept more data*/
1001 {
1002 /*do nothing until next dowork */
1003 break;
1004 }
1005 else
1006 {
1007 free(pending_socket_io->bytes);
1008 free(pending_socket_io);
1009 (void)singlylinkedlist_remove(socket_io_instance->pending_io_list, first_pending_io);
1010
1011 LogError("Failure: sending Socket information. errno=%d (%s).", errno, strerror(errno));
1012 indicate_error(socket_io_instance);
1013 }
1014 }
1015 else
1016 {
1017 /* simply wait until next dowork */
1018 (void)memmove(pending_socket_io->bytes, pending_socket_io->bytes + send_result, pending_socket_io->size - send_result);
1019 pending_socket_io->size -= send_result;
1020 break;
1021 }
1022 }
1023 else
1024 {
1025 if (pending_socket_io->on_send_complete != NULL)
1026 {
1027 pending_socket_io->on_send_complete(pending_socket_io->callback_context, IO_SEND_OK);
1028 }
1029
1030 free(pending_socket_io->bytes);
1031 free(pending_socket_io);
1032 if (singlylinkedlist_remove(socket_io_instance->pending_io_list, first_pending_io) != 0)
1033 {
1034 indicate_error(socket_io_instance);
1035 LogError("Failure: unable to remove socket from list");
1036 }
1037 }
1038
1039 first_pending_io = singlylinkedlist_get_head_item(socket_io_instance->pending_io_list);
1040 }
1041
1042 if (socket_io_instance->io_state == IO_STATE_OPEN)
1043 {
1044 ssize_t received = 0;
1045 do
1046 {
1047 received = recv(socket_io_instance->socket, socket_io_instance->recv_bytes, RECEIVE_BYTES_VALUE, 0);
1048 if (received > 0)
1049 {
1050 if (socket_io_instance->on_bytes_received != NULL)
1051 {
1052 /* Explicitly ignoring here the result of the callback */
1053 (void)socket_io_instance->on_bytes_received(socket_io_instance->on_bytes_received_context, socket_io_instance->recv_bytes, received);
1054 }
1055 }
1056 else if (received == 0)
1057 {
1058 // Do not log error here due to this is probably the socket being closed on the other end
1059 indicate_error(socket_io_instance);
1060 }
1061 else if (received < 0 && errno != EAGAIN)
1062 {
1063 LogError("Socketio_Failure: Receiving data from endpoint: errno=%d.", errno);
1064 indicate_error(socket_io_instance);
1065 }
1066
1067 } while (received > 0 && socket_io_instance->io_state == IO_STATE_OPEN);
1068 }
1069 }
1070 else
1071 {
1072 if (socket_io_instance->io_state == IO_STATE_OPENING)
1073 {
1074 if(lookup_address(socket_io_instance) != 0)
1075 {
1076 LogError("Socketio_Failure: lookup address failed");
1077 indicate_error(socket_io_instance);
1078 }
1079 else
1080 {
1081 if(socket_io_instance->io_state == IO_STATE_OPEN)
1082 {
1083 initiate_socket_connection(socket_io_instance);
1084 }
1085 }
1086
1087 }
1088 }
1089 }
1090}
1091
1092// Edison is missing this from netinet/tcp.h, but this code still works if we manually define it.
1093#ifndef SOL_TCP
1094#define SOL_TCP 6
1095#endif
1096
1097#ifndef __APPLE__
1098static void strtoup(char* str)
1099{
1100 if (str != NULL)
1101 {
1102 while (*str != '\0')
1103 {
1104 if (isalpha((int)*str) && islower((int)*str))
1105 {
1106 *str = (char)toupper((int)*str);
1107 }
1108 str++;
1109 }
1110 }
1111}
1112#endif // __APPLE__
1113
1114static int socketio_setaddresstype_option(SOCKET_IO_INSTANCE* socket_io_instance, const char* addressType)
1115{
1116 int result;
1117
1118 if (socket_io_instance->io_state != IO_STATE_CLOSED)
1119 {
1120 LogError("Socket's type can only be changed when in state 'IO_STATE_CLOSED'. Current state=%d", socket_io_instance->io_state);
1121 result = MU_FAILURE;
1122 }
1123 else if (strcmp(addressType, OPTION_ADDRESS_TYPE_DOMAIN_SOCKET) == 0)
1124 {
1125 socket_io_instance->address_type = ADDRESS_TYPE_DOMAIN_SOCKET;
1126 result = 0;
1127 }
1128 else if (strcmp(addressType, OPTION_ADDRESS_TYPE_IP_SOCKET) == 0)
1129 {
1130 socket_io_instance->address_type = ADDRESS_TYPE_IP;
1131 result = 0;
1132 }
1133 else
1134 {
1135 LogError("Address type %s is not supported", addressType);
1136 result = MU_FAILURE;
1137 }
1138
1139 return result;
1140}
1141
1142int socketio_setoption(CONCRETE_IO_HANDLE socket_io, const char* optionName, const void* value)
1143{
1144 int result;
1145
1146 if (socket_io == NULL ||
1147 optionName == NULL ||
1148 value == NULL)
1149 {
1150 result = MU_FAILURE;
1151 }
1152 else
1153 {
1154 SOCKET_IO_INSTANCE* socket_io_instance = (SOCKET_IO_INSTANCE*)socket_io;
1155
1156 if (strcmp(optionName, "tcp_keepalive") == 0)
1157 {
1158 result = setsockopt(socket_io_instance->socket, SOL_SOCKET, SO_KEEPALIVE, value, sizeof(int));
1159 if (result == -1) result = errno;
1160 }
1161 else if (strcmp(optionName, "tcp_keepalive_time") == 0)
1162 {
1163#ifdef __APPLE__
1164 result = setsockopt(socket_io_instance->socket, IPPROTO_TCP, TCP_KEEPALIVE, value, sizeof(int));
1165#else
1166 result = setsockopt(socket_io_instance->socket, SOL_TCP, TCP_KEEPIDLE, value, sizeof(int));
1167#endif
1168 if (result == -1) result = errno;
1169 }
1170 else if (strcmp(optionName, "tcp_keepalive_interval") == 0)
1171 {
1172 result = setsockopt(socket_io_instance->socket, SOL_TCP, TCP_KEEPINTVL, value, sizeof(int));
1173 if (result == -1) result = errno;
1174 }
1175 else if (strcmp(optionName, OPTION_NET_INT_MAC_ADDRESS) == 0)
1176 {
1177#ifdef __APPLE__
1178 LogError("option not supported.");
1179 result = MU_FAILURE;
1180#else
1181 if (strlen(value) == 0)
1182 {
1183 LogError("option value must be a valid mac address");
1184 result = MU_FAILURE;
1185 }
1186 else if ((socket_io_instance->target_mac_address = (char*)malloc(sizeof(char) * (strlen(value) + 1))) == NULL)
1187 {
1188 LogError("failed setting net_interface_mac_address option (malloc failed)");
1189 result = MU_FAILURE;
1190 }
1191 else if (strcpy(socket_io_instance->target_mac_address, value) == NULL)
1192 {
1193 LogError("failed setting net_interface_mac_address option (strcpy failed)");
1194 free(socket_io_instance->target_mac_address);
1195 socket_io_instance->target_mac_address = NULL;
1196 result = MU_FAILURE;
1197 }
1198 else
1199 {
1200 strtoup(socket_io_instance->target_mac_address);
1201 result = 0;
1202 }
1203#endif
1204 }
1205 else if (strcmp(optionName, OPTION_ADDRESS_TYPE) == 0)
1206 {
1207 result = socketio_setaddresstype_option(socket_io_instance, (const char*)value);
1208 }
1209 else
1210 {
1211 result = MU_FAILURE;
1212 }
1213 }
1214
1215 return result;
1216}
1217
1218const IO_INTERFACE_DESCRIPTION* socketio_get_interface_description(void)
1219{
1220 return &socket_io_interface_description;
1221}
1222
Note: See TracBrowser for help on using the repository browser.