source: azure_iot_hub_f767zi/trunk/azure_iot_sdk/c-utility/adapters/socketio_lwip.c@ 468

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

Ethernet版でもビルドが通るよう変更。

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