source: azure_iot_hub/trunk/azure_iothub/c-utility/adapters/socketio_berkeley.c@ 389

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

ビルドが通るよう更新

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