5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2008 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
20 #include "silcruntime.h"
22 /************************** Types and definitions ***************************/
25 #define SIZEOF_SOCKADDR(so) ((so).sa.sa_family == AF_INET6 ? \
26 sizeof(so.sin6) : sizeof(so.sin))
28 #define SIZEOF_SOCKADDR(so) (sizeof(so.sin))
33 struct sockaddr_in sin;
35 struct sockaddr_in6 sin6;
40 /************************ Static utility functions **************************/
42 static SilcBool silc_net_set_sockaddr(SilcSockaddr *addr, const char *ip_addr,
47 memset(addr, 0, sizeof(*addr));
49 /* Check for IPv4 and IPv6 addresses */
51 if (!silc_net_is_ip(ip_addr)) {
52 SILC_LOG_ERROR(("%s is not IP address", ip_addr));
53 silc_set_errno_reason(SILC_ERR_BAD_IP, "%s is not an IP address",
58 if (silc_net_is_ip4(ip_addr)) {
60 len = sizeof(addr->sin.sin_addr);
61 if (!silc_net_addr2bin(ip_addr,
62 (unsigned char *)&addr->sin.sin_addr.s_addr,
65 addr->sin.sin_family = AF_INET;
66 addr->sin.sin_port = port ? htons(port) : 0;
70 len = sizeof(addr->sin6.sin6_addr);
71 if (!silc_net_addr2bin(ip_addr,
72 (unsigned char *)&addr->sin6.sin6_addr, len))
74 addr->sin6.sin6_family = AF_INET6;
75 addr->sin6.sin6_port = port ? htons(port) : 0;
77 SILC_LOG_ERROR(("Operating System does not support IPv6"));
83 addr->sin.sin_family = AF_INET;
84 addr->sin.sin_addr.s_addr = INADDR_ANY;
86 addr->sin.sin_port = htons(port);
93 /****************************** TCP Listener ********************************/
95 /* Deliver new stream to upper layer */
97 static void silc_net_accept_stream(SilcResult status,
98 SilcStream stream, void *context)
100 SilcNetListener listener = context;
102 if (status != SILC_OK)
105 listener->callback(SILC_OK, stream, listener->context);
108 /* Accept incoming connection and notify upper layer */
110 SILC_TASK_CALLBACK(silc_net_accept)
112 SilcNetListener listener = context;
115 SILC_LOG_DEBUG(("Accepting new connection"));
117 sock = silc_net_accept_connection(fd);
118 if (sock == INVALID_SOCKET)
121 /* Set socket options */
122 silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
124 /* Create socket stream */
125 silc_socket_tcp_stream_create(sock, listener->lookup,
126 listener->require_fqdn, schedule,
127 silc_net_accept_stream, listener);
130 /* Create TCP network listener */
133 silc_net_tcp_create_listener(const char **local_ip_addr,
134 SilcUInt32 local_ip_count, int port,
135 SilcBool lookup, SilcBool require_fqdn,
136 SilcSchedule schedule,
137 SilcNetCallback callback, void *context)
139 SilcNetListener listener = NULL;
143 const char *ipany = "0.0.0.0";
145 SILC_LOG_DEBUG(("Creating TCP listener"));
148 schedule = silc_schedule_get_global();
150 silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
155 if (port < 0 || !callback) {
156 silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
160 listener = silc_calloc(1, sizeof(*listener));
163 listener->schedule = schedule;
164 listener->callback = callback;
165 listener->context = context;
166 listener->require_fqdn = require_fqdn;
167 listener->lookup = lookup;
169 if (local_ip_count > 0) {
170 listener->socks = silc_calloc(local_ip_count, sizeof(*listener->socks));
171 if (!listener->socks)
174 listener->socks = silc_calloc(1, sizeof(*listener->socks));
175 if (!listener->socks)
181 /* Bind to local addresses */
182 for (i = 0; i < local_ip_count; i++) {
183 SILC_LOG_DEBUG(("Binding to local address %s",
184 local_ip_addr ? local_ip_addr[i] : ipany));
186 /* Set sockaddr for server */
187 if (!silc_net_set_sockaddr(&server,
188 local_ip_addr ? local_ip_addr[i] : ipany,
192 /* Create the socket */
193 sock = socket(server.sin.sin_family, SOCK_STREAM, 0);
194 if (sock == INVALID_SOCKET) {
195 silc_set_errno_posix(WSAGetLastError());
196 SILC_LOG_ERROR(("Cannot create socket, error %s",
197 silc_errno_string(silc_errno)));
201 /* Set the socket options */
202 rval = silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
203 if (rval == SOCKET_ERROR) {
204 SILC_LOG_ERROR(("Cannot set socket options, error %s",
205 silc_errno_string(silc_errno)));
210 /* Bind the listener socket */
211 rval = bind(sock, &server.sa, SIZEOF_SOCKADDR(server));
212 if (rval == SOCKET_ERROR) {
213 silc_set_errno_posix(WSAGetLastError());
214 SILC_LOG_ERROR(("Cannot bind socket, error %s",
215 silc_errno_string(silc_errno)));
220 /* Specify that we are listenning */
221 rval = listen(sock, SOMAXCONN);
222 if (rval == SOCKET_ERROR) {
223 silc_set_errno_posix(WSAGetLastError());
224 SILC_LOG_ERROR(("Cannot set socket listenning, error %s",
225 silc_errno_string(silc_errno)));
230 /* Schedule for incoming connections */
231 silc_schedule_task_add_fd(schedule, sock, silc_net_accept, listener);
233 SILC_LOG_DEBUG(("TCP listener created, fd=%d", sock));
234 listener->socks[i] = sock;
235 listener->socks_count++;
242 silc_net_close_listener(listener);
246 /* Create TCP network, multiple ports */
249 silc_net_tcp_create_listener2(const char *local_ip_addr, int *ports,
250 SilcUInt32 port_count,
251 SilcBool ignore_port_error,
252 SilcBool lookup, SilcBool require_fqdn,
253 SilcSchedule schedule,
254 SilcNetCallback callback, void *context)
256 SilcNetListener listener = NULL;
260 const char *ipany = "0.0.0.0";
262 SILC_LOG_DEBUG(("Creating TCP listener"));
265 schedule = silc_schedule_get_global();
267 silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
273 silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
277 listener = silc_calloc(1, sizeof(*listener));
280 listener->schedule = schedule;
281 listener->callback = callback;
282 listener->context = context;
283 listener->require_fqdn = require_fqdn;
284 listener->lookup = lookup;
286 if (port_count > 0) {
287 listener->socks = silc_calloc(port_count, sizeof(*listener->socks));
288 if (!listener->socks)
291 listener->socks = silc_calloc(1, sizeof(*listener->socks));
292 if (!listener->socks)
298 /* Bind to local addresses */
299 for (i = 0; i < local_ip_count; i++) {
300 SILC_LOG_DEBUG(("Binding to local address %s:%d",
301 local_ip_addr ? local_ip_addr : ipany,
302 ports ? ports[i] : 0));
304 /* Set sockaddr for server */
305 if (!silc_net_set_sockaddr(&server,
306 local_ip_addr ? local_ip_addr : ipany,
307 ports ? ports[i] : 0)) {
308 if (ignore_port_error)
313 /* Create the socket */
314 sock = socket(server.sin.sin_family, SOCK_STREAM, 0);
315 if (sock == INVALID_SOCKET) {
316 if (ignore_port_error)
318 silc_set_errno_posix(WSAGetLastError());
319 SILC_LOG_ERROR(("Cannot create socket, error %s",
320 silc_errno_string(silc_errno)));
324 /* Set the socket options */
325 rval = silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
326 if (rval == SOCKET_ERROR) {
328 if (ignore_port_error)
330 SILC_LOG_ERROR(("Cannot set socket options, error %s",
331 silc_errno_string(silc_errno)));
335 /* Bind the listener socket */
336 rval = bind(sock, &server.sa, SIZEOF_SOCKADDR(server));
337 if (rval == SOCKET_ERROR) {
339 if (ignore_port_error)
341 silc_set_errno_posix(WSAGetLastError());
342 SILC_LOG_ERROR(("Cannot bind socket, error %s",
343 silc_errno_string(silc_errno)));
347 /* Specify that we are listenning */
348 rval = listen(sock, SOMAXCONN);
349 if (rval == SOCKET_ERROR) {
351 if (ignore_port_error)
353 silc_set_errno_posix(WSAGetLastError());
354 SILC_LOG_ERROR(("Cannot set socket listenning, error %s",
355 silc_errno_string(silc_errno)));
359 /* Schedule for incoming connections */
360 silc_schedule_task_add_fd(schedule, sock, silc_net_accept, listener);
362 SILC_LOG_DEBUG(("TCP listener created, fd=%d", sock));
363 listener->socks[i] = sock;
364 listener->socks_count++;
367 if (ignore_port_error && !listener->socks_count)
374 silc_net_close_listener(listener);
378 /* Close network listener */
380 void silc_net_close_listener(SilcNetListener listener)
384 SILC_LOG_DEBUG(("Closing network listener"));
389 for (i = 0; i < listener->socks_count; i++) {
390 silc_schedule_task_del_by_fd(listener->schedule, listener->socks[i]);
391 shutdown(listener->socks[i], 2);
392 closesocket(listener->socks[i]);
395 silc_free(listener->socks);
399 /******************************* UDP Stream *********************************/
401 /* Create UDP stream */
404 silc_net_udp_connect(const char *local_ip_addr, int local_port,
405 const char *remote_ip_addr, int remote_port,
406 SilcSchedule schedule)
412 const char *ipany = "0.0.0.0";
414 SILC_LOG_DEBUG(("Creating UDP stream"));
417 schedule = silc_schedule_get_global();
419 silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
424 /* Bind to local addresses */
425 SILC_LOG_DEBUG(("Binding to local address %s",
426 local_ip_addr ? local_ip_addr : ipany));
428 /* Set sockaddr for server */
429 if (!silc_net_set_sockaddr(&server, local_ip_addr ? local_ip_addr : ipany,
433 /* Create the socket */
434 sock = socket(server.sin.sin_family, SOCK_DGRAM, 0);
435 if (sock == INVALID_SOCKET) {
436 SILC_LOG_ERROR(("Cannot create socket"));
437 silc_set_errno_posix(WSAGetLastError());
441 /* Set the socket options */
442 rval = silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
443 if (rval == SOCKET_ERROR) {
444 SILC_LOG_ERROR(("Cannot set socket options"));
448 rval = silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEPORT, 1);
449 if (rval == SOCKET_ERROR) {
450 SILC_LOG_ERROR(("Cannot set socket options"));
453 #endif /* SO_REUSEPORT */
455 /* Bind the listener socket */
456 rval = bind(sock, &server.sa, SIZEOF_SOCKADDR(server));
457 if (rval == SOCKET_ERROR) {
458 SILC_LOG_DEBUG(("Cannot bind socket"));
459 silc_set_errno_posix(WSAGetLastError());
463 /* Set to connected state if remote address is provided. */
464 if (remote_ip_addr && remote_port) {
465 if (!silc_net_set_sockaddr(&server, remote_ip_addr, remote_port))
468 rval = connect(sock, &server.sa, SIZEOF_SOCKADDR(server));
469 if (rval == SOCKET_ERROR) {
470 SILC_LOG_DEBUG(("Cannot connect UDP stream"));
471 silc_set_errno_posix(WSAGetLastError());
476 /* Encapsulate into socket stream */
478 silc_socket_udp_stream_create(sock, local_ip_addr ?
479 silc_net_is_ip6(local_ip_addr) : FALSE,
480 remote_ip_addr ? TRUE : FALSE, schedule);
484 SILC_LOG_DEBUG(("UDP stream created, fd=%d", sock));
493 /* Receive UDP packet */
495 int silc_net_udp_receive(SilcStream stream, char *remote_ip_addr,
496 SilcUInt32 remote_ip_addr_size, int *remote_port,
497 unsigned char *ret_data, SilcUInt32 data_size)
499 SilcSocketStream sock = stream;
501 struct sockaddr *from;
504 SILC_LOG_DEBUG(("Reading data from UDP socket %d", sock->sock));
506 if (remote_ip_addr && remote_port) {
509 from = (struct sockaddr *)&s.sin6;
510 flen = sizeof(s.sin6);
511 #endif /* HAVE_IPV6 */
513 from = (struct sockaddr *)&s.sin;
514 flen = sizeof(s.sin);
516 len = recvfrom(sock->sock, ret_data, data_size, 0, from, &flen);
518 len = recv(sock->sock, ret_data, data_size, 0);
520 if (len == SOCKET_ERROR) {
521 err = WSAGetLastError();
522 silc_set_errno_posix(err);
523 if (err == WSAEWOULDBLOCK) {
524 SILC_LOG_DEBUG(("Could not read immediately, will do it later"));
525 silc_schedule_set_listen_fd(sock->schedule, sock->sock,
526 SILC_TASK_READ, FALSE);
529 SILC_LOG_DEBUG(("Cannot read from UDP socket: %d: %s", sock->sock,
530 silc_errno_string(silc_errno)));
531 silc_schedule_unset_listen_fd(sock->schedule, sock->sock);
535 SILC_LOG_DEBUG(("Read %d bytes", len));
538 silc_schedule_unset_listen_fd(sock->schedule, sock->sock);
540 /* Return remote address */
541 if (remote_ip_addr && remote_port) {
544 *remote_port = ntohs(s.sin6.sin6_port);
545 inet_ntop(AF_INET6, &s.sin6.sin6_addr, remote_ip_addr,
546 remote_ip_addr_size);
547 #endif /* HAVE_IPV6 */
549 const char *ip = inet_ntoa(s.sin.sin_addr);
551 silc_snprintf(remote_ip_addr, remote_ip_addr_size, ip);
552 *remote_port = ntohs(s.sin.sin_port);
555 SILC_LOG_DEBUG(("UDP packet from %s:%d", remote_ip_addr, *remote_port));
561 /* Send UDP packet */
563 int silc_net_udp_send(SilcStream stream,
564 const char *remote_ip_addr, int remote_port,
565 const unsigned char *data, SilcUInt32 data_len)
567 SilcSocketStream sock = stream;
571 SILC_LOG_DEBUG(("Sending data to UDP socket %d", sock->sock));
574 if (!silc_net_set_sockaddr(&remote, remote_ip_addr, remote_port))
578 ret = sendto(sock->sock, data, data_len, 0, &remote.sa,
579 SIZEOF_SOCKADDR(remote));
580 if (ret == SOCKET_ERROR) {
581 err = WSAGetLastError();
582 silc_set_errno_posix(err);
583 if (err == WSAEWOULDBLOCK) {
584 SILC_LOG_DEBUG(("Could not send immediately, will do it later"));
585 silc_schedule_set_listen_fd(sock->schedule, sock->sock,
586 SILC_TASK_READ | SILC_TASK_WRITE, FALSE);
589 SILC_LOG_DEBUG(("Cannot send to UDP socket: %s",
590 silc_errno_string(silc_errno)));
591 silc_schedule_unset_listen_fd(sock->schedule, sock->sock);
595 SILC_LOG_DEBUG(("Sent data %d bytes", ret));
596 if (silc_schedule_get_fd_events(sock->schedule, sock->sock) &
598 silc_schedule_set_listen_fd(sock->schedule, sock->sock,
599 SILC_TASK_READ, FALSE);
605 /******************************* TCP Stream *********************************/
611 SilcFSMThreadStruct thread;
612 SilcAsyncOperation op;
613 SilcAsyncOperation sop;
618 SilcNetCallback callback;
620 unsigned int port : 24;
621 unsigned int retry : 7;
622 unsigned int aborted : 1;
625 SILC_FSM_STATE(silc_net_connect_st_start);
626 SILC_FSM_STATE(silc_net_connect_st_stream);
627 SILC_FSM_STATE(silc_net_connect_st_finish);
629 static void silc_net_connect_wait_stream(SilcResult status,
630 SilcStream stream, void *context)
632 SilcNetConnect conn = context;
634 conn->status = status;
635 conn->stream = stream;
636 SILC_FSM_CALL_CONTINUE(&conn->thread);
639 /* Start connecting. Create a real thread where we connect. */
641 SILC_FSM_STATE(silc_net_connect_st_thread)
643 SilcNetConnect conn = fsm_context;
645 /* Connect in real thread so as to not block the application. */
646 silc_fsm_thread_init(&conn->thread, fsm, conn, NULL, NULL, TRUE);
647 silc_fsm_start(&conn->thread, silc_net_connect_st_start);
649 /* Wait for the thread to finish */
650 silc_fsm_next(fsm, silc_net_connect_st_finish);
651 SILC_FSM_THREAD_WAIT(&conn->thread);
654 /* Connecting thread */
656 SILC_FSM_STATE(silc_net_connect_st_start)
658 SilcNetConnect conn = fsm_context;
661 SilcSockaddr desthost;
662 SilcBool prefer_ipv6 = TRUE;
665 return SILC_FSM_FINISH;
669 if (!silc_net_gethostbyname(conn->remote, prefer_ipv6,
670 conn->ip_addr, sizeof(conn->ip_addr))) {
671 SILC_LOG_ERROR(("Network (%s) unreachable: could not resolve the "
672 "host, error %d", conn->remote, WSAGetLastError()));
674 /** Network unreachable */
675 conn->status = SILC_ERR_UNREACHABLE;
676 return SILC_FSM_FINISH;
679 /* Set sockaddr for this connection */
680 if (!silc_net_set_sockaddr(&desthost, conn->ip_addr, conn->port))
681 return SILC_FSM_FINISH;
683 /* Create the connection socket */
684 sock = socket(desthost.sin.sin_family, SOCK_STREAM, 0);
685 if (sock == INVALID_SOCKET) {
686 /* If address is IPv6, then fallback to IPv4 and see whether we can do
687 better with that on socket creation. */
688 if (prefer_ipv6 && silc_net_is_ip6(conn->ip_addr)) {
693 /** Cannot create socket */
694 silc_set_errno_posix(err);
695 SILC_LOG_ERROR(("Cannot create socket, error %d",
696 silc_errno_string(silc_errno)));
697 return SILC_FSM_FINISH;
700 /* Bind to the local address if provided */
701 if (conn->local_ip) {
704 /* Set sockaddr for local listener, and try to bind it. */
705 if (silc_net_set_sockaddr(&local, conn->local_ip, 0))
706 bind(sock, &local.sa, SIZEOF_SOCKADDR(local));
709 /* Connect to the host */
710 rval = connect(sock, &desthost.sa, SIZEOF_SOCKADDR(desthost));
711 err = WSAGetLastError();
712 if (rval == SOCKET_ERROR) {
713 if (err != WSAEWOULDBLOCK) {
717 /* Retry using an IPv4 address, if IPv6 didn't work */
718 if (prefer_ipv6 && silc_net_is_ip6(conn->ip_addr)) {
724 silc_set_errno_posix(err);
725 conn->status = silc_errno;
727 SILC_LOG_ERROR(("Cannot connect to remote host: %s",
728 silc_errno_string(silc_errno)));
729 return SILC_FSM_FINISH;
733 /* Set the socket to non-blocking mode */
734 silc_net_set_socket_nonblock(sock);
736 /* Set appropriate options */
737 #if defined(TCP_NODELAY)
738 silc_net_set_socket_opt(sock, IPPROTO_TCP, TCP_NODELAY, 1);
740 silc_net_set_socket_opt(sock, SOL_SOCKET, SO_KEEPALIVE, 1);
742 SILC_LOG_DEBUG(("TCP connection established"));
746 /** Connection created */
747 silc_fsm_next(fsm, silc_net_connect_st_stream);
748 SILC_FSM_CALL((conn->sop = silc_socket_tcp_stream_create(
749 conn->sock, TRUE, FALSE,
750 silc_fsm_get_schedule(&conn->fsm),
751 silc_net_connect_wait_stream, conn)));
754 /* TCP socket stream created */
756 SILC_FSM_STATE(silc_net_connect_st_stream)
758 SilcNetConnect conn = fsm_context;
761 return SILC_FSM_FINISH;
763 if (conn->status != SILC_OK) {
764 /** Stream creation failed */
765 return SILC_FSM_FINISH;
768 /** Stream created successfully */
769 SILC_LOG_DEBUG(("Connected successfully, sock %d", conn->sock));
770 conn->status = SILC_OK;
771 return SILC_FSM_FINISH;
774 SILC_FSM_STATE(silc_net_connect_st_finish)
776 SilcNetConnect conn = fsm_context;
778 /* Deliver error or new stream */
779 if (!conn->aborted) {
780 conn->callback(conn->status, conn->stream, conn->context);
782 silc_async_free(conn->op);
785 return SILC_FSM_FINISH;
788 static void silc_net_connect_abort(SilcAsyncOperation op, void *context)
790 SilcNetConnect conn = context;
791 conn->aborted = TRUE;
793 /* Abort underlaying stream creation too */
795 silc_async_abort(conn->sop, NULL, NULL);
800 static void silc_net_connect_destructor(SilcFSM fsm, void *fsm_context,
801 void *destructor_context)
803 SilcNetConnect conn = fsm_context;
804 silc_free(conn->local_ip);
805 silc_free(conn->remote);
809 /* Create asynchronous TCP/IP connection. */
811 SilcAsyncOperation silc_net_tcp_connect(const char *local_ip_addr,
812 const char *remote_ip_addr,
814 SilcSchedule schedule,
815 SilcNetCallback callback,
821 schedule = silc_schedule_get_global();
823 silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
828 if (!remote_ip_addr || remote_port < 1 || !callback) {
829 silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
833 SILC_LOG_DEBUG(("Creating connection to host %s port %d",
834 remote_ip_addr, remote_port));
836 conn = silc_calloc(1, sizeof(*conn));
838 callback(SILC_ERR_OUT_OF_MEMORY, NULL, context);
842 /* Start async operation */
843 conn->op = silc_async_alloc(silc_net_connect_abort, NULL, conn);
846 callback(SILC_ERR_OUT_OF_MEMORY, NULL, context);
851 conn->local_ip = silc_strdup(local_ip_addr);
852 conn->remote = silc_strdup(remote_ip_addr);
854 silc_async_free(conn->op);
855 silc_free(conn->local_ip);
857 callback(SILC_ERR_OUT_OF_MEMORY, NULL, context);
860 conn->port = remote_port;
861 conn->callback = callback;
862 conn->context = context;
864 conn->status = SILC_ERR;
866 silc_fsm_init(&conn->fsm, conn, silc_net_connect_destructor, NULL, schedule);
867 silc_fsm_start(&conn->fsm, silc_net_connect_st_thread);
872 /* Closes the connection by closing the socket connection. */
874 void silc_net_close_connection(int sock)
876 SILC_LOG_DEBUG(("Closing sock %d", sock));
880 /* Converts the IP number string from numbers-and-dots notation to
883 SilcBool silc_net_addr2bin(const char *addr, void *bin, SilcUInt32 bin_len)
885 if (silc_net_is_ip4(addr)) {
887 int i = 0, c = 0, d = 0, len = strlen(addr);
888 unsigned char ret[4];
890 memset(ret, 0, sizeof(ret));
892 if (addr[i++] == '.') {
900 if (!isdigit((int)addr[i - 1]))
903 d = 10 * d + addr[i - 1] - '0';
911 if (bin_len < sizeof(ret)) {
912 silc_set_errno(SILC_ERR_OVERFLOW);
916 memcpy(bin, ret, sizeof(ret));
923 struct addrinfo hints, *ai;
928 silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
932 memset(&hints, 0, sizeof(hints));
933 hints.ai_family = AF_INET6;
934 if (getaddrinfo(addr, NULL, &hints, &ai))
938 s = (SilcSockaddr *)ai->ai_addr;
939 memcpy(bin, &s->sin6.sin6_addr, sizeof(s->sin6.sin6_addr));
946 #endif /* HAVE_IPV6 */
950 /* Set socket to non-blocking mode. */
952 int silc_net_set_socket_nonblock(SilcSocket sock)
954 unsigned long on = 1;
955 return ioctlsocket(sock, FIONBIO, &on);