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;
39 /************************ Static utility functions **************************/
41 static SilcBool silc_net_set_sockaddr(SilcSockaddr *addr, const char *ip_addr,
46 memset(addr, 0, sizeof(*addr));
48 /* Check for IPv4 and IPv6 addresses */
50 if (!silc_net_is_ip(ip_addr)) {
51 SILC_LOG_ERROR(("%s is not IP address", ip_addr));
52 silc_set_errno_reason(SILC_ERR_BAD_IP, "%s is not an IP address",
57 if (silc_net_is_ip4(ip_addr)) {
59 len = sizeof(addr->sin.sin_addr);
60 if (!silc_net_addr2bin(ip_addr,
61 (unsigned char *)&addr->sin.sin_addr.s_addr, len))
63 addr->sin.sin_family = AF_INET;
64 addr->sin.sin_port = port ? htons(port) : 0;
68 len = sizeof(addr->sin6.sin6_addr);
69 if (!silc_net_addr2bin(ip_addr,
70 (unsigned char *)&addr->sin6.sin6_addr, len))
72 addr->sin6.sin6_family = AF_INET6;
73 addr->sin6.sin6_port = port ? htons(port) : 0;
75 SILC_LOG_ERROR(("IPv6 support is not compiled in"));
76 silc_set_errno(SILC_ERR_NOT_SUPPORTED);
82 addr->sin.sin_family = AF_INET;
83 addr->sin.sin_addr.s_addr = INADDR_ANY;
85 addr->sin.sin_port = htons(port);
91 /****************************** TCP Listener ********************************/
93 /* Deliver new stream to upper layer */
95 static void silc_net_accept_stream(SilcResult status,
96 SilcStream stream, void *context)
98 SilcNetListener listener = context;
100 if (status != SILC_OK)
103 listener->callback(SILC_OK, stream, listener->context);
106 /* Accept incoming connection and notify upper layer */
108 SILC_TASK_CALLBACK(silc_net_accept)
110 SilcNetListener listener = context;
113 SILC_LOG_DEBUG(("Accepting new connection"));
115 sock = silc_net_accept_connection(fd);
119 /* Set socket options */
120 silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
122 /* Create socket stream */
123 silc_socket_tcp_stream_create(sock, listener->lookup,
124 listener->require_fqdn, schedule,
125 silc_net_accept_stream, listener);
128 /* Create TCP network listener */
131 silc_net_tcp_create_listener(const char **local_ip_addr,
132 SilcUInt32 local_ip_count, int port,
133 SilcBool lookup, SilcBool require_fqdn,
134 SilcSchedule schedule,
135 SilcNetCallback callback, void *context)
137 SilcNetListener listener = NULL;
140 const char *ipany = "0.0.0.0";
142 SILC_LOG_DEBUG(("Creating TCP listener"));
145 schedule = silc_schedule_get_global();
147 silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
152 if (port < 0 || !callback) {
153 silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
157 listener = silc_calloc(1, sizeof(*listener));
160 listener->schedule = schedule;
161 listener->callback = callback;
162 listener->context = context;
163 listener->require_fqdn = require_fqdn;
164 listener->lookup = lookup;
166 if (local_ip_count > 0) {
167 listener->socks = silc_calloc(local_ip_count, sizeof(*listener->socks));
168 if (!listener->socks)
171 listener->socks = silc_calloc(1, sizeof(*listener->socks));
172 if (!listener->socks)
178 /* Bind to local addresses */
179 for (i = 0; i < local_ip_count; i++) {
180 SILC_LOG_DEBUG(("Binding to local address %s:%d",
181 local_ip_addr ? local_ip_addr[i] : ipany, port));
183 /* Set sockaddr for server */
184 if (!silc_net_set_sockaddr(&server,
185 local_ip_addr ? local_ip_addr[i] : ipany,
189 /* Create the socket */
190 sock = socket(server.sin.sin_family, SOCK_STREAM, 0);
192 silc_set_errno_posix(errno);
193 SILC_LOG_ERROR(("Cannot create socket: %s",
194 silc_errno_string(silc_errno)));
198 /* Set the socket options */
199 rval = silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
201 SILC_LOG_ERROR(("Cannot set socket options: %s", strerror(errno)));
206 /* Bind the listener socket */
207 rval = bind(sock, &server.sa, SIZEOF_SOCKADDR(server));
209 silc_set_errno_posix(errno);
210 SILC_LOG_ERROR(("Cannot bind socket: %s",
211 silc_errno_string(silc_errno)));
216 /* Specify that we are listenning */
217 rval = listen(sock, 64);
219 silc_set_errno_posix(errno);
220 SILC_LOG_ERROR(("Cannot set socket listenning: %s",
221 silc_errno_string(silc_errno)));
226 /* Set the server socket to non-blocking mode */
227 silc_net_set_socket_nonblock(sock);
229 /* Schedule for incoming connections */
230 silc_schedule_task_add_fd(schedule, sock, silc_net_accept, listener);
232 SILC_LOG_DEBUG(("TCP listener created, fd=%d", sock));
233 listener->socks[i] = sock;
234 listener->socks_count++;
241 silc_net_close_listener(listener);
245 /* Create TCP listener, multiple ports */
248 silc_net_tcp_create_listener2(const char *local_ip_addr, int *ports,
249 SilcUInt32 port_count,
250 SilcBool ignore_port_error,
251 SilcBool lookup, SilcBool require_fqdn,
252 SilcSchedule schedule,
253 SilcNetCallback callback, void *context)
255 SilcNetListener listener = NULL;
258 const char *ipany = "0.0.0.0";
260 SILC_LOG_DEBUG(("Creating TCP listener"));
263 schedule = silc_schedule_get_global();
265 silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
271 silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
275 listener = silc_calloc(1, sizeof(*listener));
278 listener->schedule = schedule;
279 listener->callback = callback;
280 listener->context = context;
281 listener->require_fqdn = require_fqdn;
282 listener->lookup = lookup;
284 if (port_count > 0) {
285 listener->socks = silc_calloc(port_count, sizeof(*listener->socks));
286 if (!listener->socks)
289 listener->socks = silc_calloc(1, sizeof(*listener->socks));
290 if (!listener->socks)
297 for (i = 0; i < port_count; i++) {
298 SILC_LOG_DEBUG(("Binding to local address %s:%d",
299 local_ip_addr ? local_ip_addr : ipany,
300 ports ? ports[i] : 0));
302 /* Set sockaddr for server */
303 if (!silc_net_set_sockaddr(&server,
304 local_ip_addr ? local_ip_addr : ipany,
305 ports ? ports[i] : 0)) {
306 if (ignore_port_error)
311 /* Create the socket */
312 sock = socket(server.sin.sin_family, SOCK_STREAM, 0);
314 if (ignore_port_error)
316 silc_set_errno_posix(errno);
317 SILC_LOG_ERROR(("Cannot create socket: %s",
318 silc_errno_string(silc_errno)));
322 /* Set the socket options */
323 rval = silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
326 if (ignore_port_error)
328 SILC_LOG_ERROR(("Cannot set socket options: %s",
329 silc_errno_string(silc_errno)));
333 /* Bind the listener socket */
334 rval = bind(sock, &server.sa, SIZEOF_SOCKADDR(server));
337 if (ignore_port_error)
339 silc_set_errno_posix(errno);
340 SILC_LOG_ERROR(("Cannot bind socket: %s",
341 silc_errno_string(silc_errno)));
345 /* Specify that we are listenning */
346 rval = listen(sock, 64);
349 if (ignore_port_error)
351 silc_set_errno_posix(errno);
352 SILC_LOG_ERROR(("Cannot set socket listenning: %s",
353 silc_errno_string(silc_errno)));
357 /* Set the server socket to non-blocking mode */
358 silc_net_set_socket_nonblock(sock);
360 /* Schedule for incoming connections */
361 silc_schedule_task_add_fd(schedule, sock, silc_net_accept, listener);
363 SILC_LOG_DEBUG(("TCP listener created, fd=%d", sock));
364 listener->socks[i] = sock;
365 listener->socks_count++;
368 if (ignore_port_error && !listener->socks_count)
375 silc_net_close_listener(listener);
379 /* Close network listener */
381 void silc_net_close_listener(SilcNetListener listener)
385 SILC_LOG_DEBUG(("Closing network listener"));
387 for (i = 0; i < listener->socks_count; i++) {
388 silc_schedule_task_del_by_fd(listener->schedule, listener->socks[i]);
389 shutdown(listener->socks[i], 2);
390 close(listener->socks[i]);
393 silc_free(listener->socks);
397 /******************************* UDP Stream *********************************/
399 /* Create UDP stream */
402 silc_net_udp_connect(const char *local_ip_addr, int local_port,
403 const char *remote_ip_addr, int remote_port,
404 SilcSchedule schedule)
409 const char *ipany = "0.0.0.0";
411 SILC_LOG_DEBUG(("Creating UDP stream"));
414 schedule = silc_schedule_get_global();
416 silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
421 /* Bind to local addresses */
422 SILC_LOG_DEBUG(("Binding to local address %s",
423 local_ip_addr ? local_ip_addr : ipany));
425 /* Set sockaddr for server */
426 if (!silc_net_set_sockaddr(&server, local_ip_addr ? local_ip_addr : ipany,
430 /* Create the socket */
431 sock = socket(server.sin.sin_family, SOCK_DGRAM, 0);
433 silc_set_errno_posix(errno);
434 SILC_LOG_ERROR(("Cannot create socket: %s",
435 silc_errno_string(silc_errno)));
439 /* Set the socket options */
440 rval = silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
442 SILC_LOG_ERROR(("Cannot set socket options: %s",
443 silc_errno_string(silc_errno)));
447 rval = silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEPORT, 1);
449 SILC_LOG_ERROR(("Cannot set socket options: %s",
450 silc_errno_string(silc_errno)));
453 #endif /* SO_REUSEPORT */
455 /* Bind the listener socket */
456 rval = bind(sock, &server.sa, SIZEOF_SOCKADDR(server));
458 silc_set_errno_posix(errno);
459 SILC_LOG_DEBUG(("Cannot bind socket: %s", silc_errno_string(silc_errno)));
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));
470 silc_set_errno_posix(errno);
471 SILC_LOG_DEBUG(("Cannot connect UDP stream: %s",
472 silc_errno_string(silc_errno)));
477 /* Set send and receive buffer size */
479 rval = silc_net_set_socket_opt(sock, SOL_SOCKET, SO_SNDBUF, 765535);
481 rval = silc_net_set_socket_opt(sock, SOL_SOCKET, SO_SNDBUF, 65535);
483 SILC_LOG_ERROR(("Cannot set socket options: %s", strerror(errno)));
487 #endif /* SO_SNDBUF */
489 rval = silc_net_set_socket_opt(sock, SOL_SOCKET, SO_RCVBUF, 765535);
491 rval = silc_net_set_socket_opt(sock, SOL_SOCKET, SO_RCVBUF, 65535);
493 SILC_LOG_ERROR(("Cannot set socket options: %s", strerror(errno)));
497 #endif /* SO_RCVBUF */
499 /* Encapsulate into socket stream */
501 silc_socket_udp_stream_create(sock, local_ip_addr ?
502 silc_net_is_ip6(local_ip_addr) : FALSE,
503 remote_ip_addr ? TRUE : FALSE, schedule);
507 SILC_LOG_DEBUG(("UDP stream created, fd=%d", sock));
516 /* Receive UDP packet */
518 int silc_net_udp_receive(SilcStream stream, char *remote_ip_addr,
519 SilcUInt32 remote_ip_addr_size, int *remote_port,
520 unsigned char *ret_data, SilcUInt32 data_size)
522 SilcSocketStream sock = stream;
524 struct sockaddr *from;
528 SILC_LOG_DEBUG(("Reading data from UDP socket %d", sock->sock));
530 if (remote_ip_addr && remote_port) {
533 from = (struct sockaddr *)&s.sin6;
534 flen = sizeof(s.sin6);
535 #endif /* HAVE_IPV6 */
537 from = (struct sockaddr *)&s.sin;
538 flen = sizeof(s.sin);
540 len = recvfrom(sock->sock, ret_data, data_size, 0, from, &flen);
542 len = recv(sock->sock, ret_data, data_size, 0);
545 silc_set_errno_posix(errno);
546 if (errno == EAGAIN || errno == EINTR) {
547 SILC_LOG_DEBUG(("Could not read immediately, will do it later"));
548 silc_schedule_set_listen_fd(sock->schedule, sock->sock,
549 SILC_TASK_READ, FALSE);
552 SILC_LOG_DEBUG(("Cannot read from UDP socket: %d:%s",
553 sock->sock, strerror(errno)));
554 silc_schedule_unset_listen_fd(sock->schedule, sock->sock);
558 SILC_LOG_DEBUG(("Read %d bytes", len));
561 silc_schedule_unset_listen_fd(sock->schedule, sock->sock);
563 /* Return remote address */
564 if (remote_ip_addr && remote_port) {
567 *remote_port = ntohs(s.sin6.sin6_port);
568 inet_ntop(AF_INET6, &s.sin6.sin6_addr, remote_ip_addr,
569 remote_ip_addr_size);
572 #endif /* HAVE_IPV6 */
574 *remote_port = ntohs(s.sin.sin_port);
575 inet_ntop(AF_INET, &s.sin.sin_addr, remote_ip_addr,
576 remote_ip_addr_size);
579 SILC_LOG_DEBUG(("UDP packet from %s:%d", remote_ip_addr, *remote_port));
585 /* Send UDP packet */
587 int silc_net_udp_send(SilcStream stream,
588 const char *remote_ip_addr, int remote_port,
589 const unsigned char *data, SilcUInt32 data_len)
591 SilcSocketStream sock = stream;
595 SILC_LOG_DEBUG(("Sending data to UDP socket %d", sock->sock));
598 if (!silc_net_set_sockaddr(&remote, remote_ip_addr, remote_port))
602 ret = sendto(sock->sock, data, data_len, 0, &remote.sa,
603 SIZEOF_SOCKADDR(remote));
605 silc_set_errno_posix(errno);
606 if (errno == EAGAIN || errno == EINTR) {
607 SILC_LOG_DEBUG(("Could not send immediately, will do it later"));
608 silc_schedule_set_listen_fd(sock->schedule, sock->sock,
609 SILC_TASK_READ | SILC_TASK_WRITE, FALSE);
612 SILC_LOG_DEBUG(("Cannot send to UDP socket: %s", strerror(errno)));
613 silc_schedule_unset_listen_fd(sock->schedule, sock->sock);
617 SILC_LOG_DEBUG(("Sent data %d bytes", ret));
618 if (silc_schedule_get_fd_events(sock->schedule, sock->sock) &
620 silc_schedule_set_listen_fd(sock->schedule, sock->sock,
621 SILC_TASK_READ, FALSE);
626 /******************************* TCP Stream *********************************/
628 /* Asynchronous TCP/IP connecting */
634 SilcFSMEventStruct event;
635 SilcAsyncOperation op;
636 SilcAsyncOperation sop;
641 SilcNetCallback callback;
643 unsigned int port : 24;
644 unsigned int retry : 7;
645 unsigned int aborted : 1;
648 SILC_FSM_STATE(silc_net_connect_st_start);
649 SILC_FSM_STATE(silc_net_connect_st_connected);
650 SILC_FSM_STATE(silc_net_connect_st_stream);
651 SILC_FSM_STATE(silc_net_connect_st_finish);
653 SILC_TASK_CALLBACK(silc_net_connect_wait)
655 SilcNetConnect conn = context;
656 SILC_FSM_EVENT_SIGNAL(&conn->event);
659 SILC_FSM_STATE(silc_net_connect_st_start)
661 SilcNetConnect conn = fsm_context;
663 SilcSockaddr desthost;
664 SilcBool prefer_ipv6 = TRUE;
668 silc_fsm_next(fsm, silc_net_connect_st_finish);
669 return SILC_FSM_CONTINUE;
674 if (!silc_net_gethostbyname(conn->remote, prefer_ipv6,
675 conn->ip_addr, sizeof(conn->ip_addr))) {
676 SILC_LOG_ERROR(("Network (%s) unreachable: could not resolve the "
677 "host", conn->remote));
679 /** Network unreachable */
680 conn->status = SILC_ERR_UNREACHABLE;
681 silc_fsm_next(fsm, silc_net_connect_st_finish);
682 return SILC_FSM_CONTINUE;
685 /* Set sockaddr for this connection */
686 if (!silc_net_set_sockaddr(&desthost, conn->ip_addr, conn->port)) {
687 /** Sockaddr failed */
688 silc_fsm_next(fsm, silc_net_connect_st_finish);
689 return SILC_FSM_CONTINUE;
692 /* Create the connection socket */
693 sock = socket(desthost.sin.sin_family, SOCK_STREAM, 0);
695 /* If address is IPv6, then fallback to IPv4 and see whether we can do
696 better with that on socket creation. */
697 if (prefer_ipv6 && silc_net_is_ip6(conn->ip_addr)) {
702 /** Cannot create socket */
703 silc_set_errno_posix(errno);
704 SILC_LOG_ERROR(("Cannot create socket: %s", strerror(errno)));
705 silc_fsm_next(fsm, silc_net_connect_st_finish);
706 return SILC_FSM_CONTINUE;
709 /* Bind to the local address if provided */
710 if (conn->local_ip) {
713 /* Set sockaddr for local listener, and try to bind it. */
714 if (silc_net_set_sockaddr(&local, conn->local_ip, 0))
715 bind(sock, &local.sa, SIZEOF_SOCKADDR(local));
718 /* Set the socket to non-blocking mode */
719 silc_net_set_socket_nonblock(sock);
721 /* Connect to the host */
722 rval = connect(sock, &desthost.sa, SIZEOF_SOCKADDR(desthost));
724 if (errno != EINPROGRESS) {
725 silc_set_errno_posix(errno);
729 /* Retry using an IPv4 adress, if IPv6 didn't work */
730 if (prefer_ipv6 && silc_net_is_ip6(conn->ip_addr)) {
735 /** Cannot connect to remote host */
736 SILC_LOG_ERROR(("Cannot connect to remote host: %s",
737 silc_errno_string(silc_errno)));
738 silc_fsm_next(fsm, silc_net_connect_st_finish);
739 return SILC_FSM_CONTINUE;
743 /* Set appropriate options */
744 #if defined(TCP_NODELAY)
745 silc_net_set_socket_opt(sock, IPPROTO_TCP, TCP_NODELAY, 1);
747 silc_net_set_socket_opt(sock, SOL_SOCKET, SO_KEEPALIVE, 1);
749 SILC_LOG_DEBUG(("Connection operation in progress"));
753 /** Wait for connection */
754 silc_fsm_next(fsm, silc_net_connect_st_connected);
755 silc_fsm_event_init(&conn->event, fsm);
756 silc_schedule_task_add_fd(silc_fsm_get_schedule(fsm), sock,
757 silc_net_connect_wait, conn);
758 silc_schedule_set_listen_fd(silc_fsm_get_schedule(fsm), sock,
759 SILC_TASK_WRITE, FALSE);
760 SILC_FSM_EVENT_WAIT(&conn->event);
761 return SILC_FSM_CONTINUE;
764 static void silc_net_connect_wait_stream(SilcResult status,
765 SilcStream stream, void *context)
767 SilcNetConnect conn = context;
769 conn->status = status;
770 conn->stream = stream;
771 SILC_FSM_CALL_CONTINUE(&conn->fsm);
774 SILC_FSM_STATE(silc_net_connect_st_connected)
776 SilcNetConnect conn = fsm_context;
777 SilcSchedule schedule = silc_fsm_get_schedule(fsm);
778 int opt = EINVAL, optlen = sizeof(opt), ret;
782 silc_schedule_unset_listen_fd(schedule, conn->sock);
783 silc_schedule_task_del_by_fd(schedule, conn->sock);
784 silc_fsm_next(fsm, silc_net_connect_st_finish);
785 return SILC_FSM_CONTINUE;
788 ret = silc_net_get_socket_opt(conn->sock, SOL_SOCKET, SO_ERROR,
791 silc_schedule_unset_listen_fd(schedule, conn->sock);
792 silc_schedule_task_del_by_fd(schedule, conn->sock);
794 if (ret != 0 || opt != 0) {
796 /** Retry connecting */
797 SILC_LOG_DEBUG(("Retry connecting"));
799 silc_net_close_connection(conn->sock);
800 silc_fsm_next(fsm, silc_net_connect_st_start);
801 return SILC_FSM_CONTINUE;
805 silc_set_errno_posix(opt);
806 conn->status = silc_errno;
808 /** Connecting failed */
809 SILC_LOG_DEBUG(("Connecting failed, error %s",
810 silc_errno_string(silc_errno)));
811 silc_fsm_next(fsm, silc_net_connect_st_finish);
812 return SILC_FSM_CONTINUE;
815 SILC_LOG_DEBUG(("TCP connection established"));
817 /** Connection created */
818 silc_fsm_next(fsm, silc_net_connect_st_stream);
819 SILC_FSM_CALL((conn->sop = silc_socket_tcp_stream_create(
820 conn->sock, TRUE, FALSE, schedule,
821 silc_net_connect_wait_stream, conn)));
824 SILC_FSM_STATE(silc_net_connect_st_stream)
826 SilcNetConnect conn = fsm_context;
830 silc_fsm_next(fsm, silc_net_connect_st_finish);
831 return SILC_FSM_CONTINUE;
834 if (conn->status != SILC_OK) {
835 /** Stream creation failed */
836 silc_fsm_next(fsm, silc_net_connect_st_finish);
837 return SILC_FSM_CONTINUE;
840 /** Stream created successfully */
841 SILC_LOG_DEBUG(("Connected successfully, sock %d", conn->sock));
842 conn->status = SILC_OK;
843 silc_fsm_next(fsm, silc_net_connect_st_finish);
844 return SILC_FSM_CONTINUE;
847 SILC_FSM_STATE(silc_net_connect_st_finish)
849 SilcNetConnect conn = fsm_context;
851 /* Deliver error or new stream */
852 if (!conn->aborted) {
853 conn->callback(conn->status, conn->stream, conn->context);
855 silc_async_free(conn->op);
858 if (conn->sock && conn->status != SILC_NET_OK)
859 silc_net_close_connection(conn->sock);
861 return SILC_FSM_FINISH;
864 static void silc_net_connect_abort(SilcAsyncOperation op, void *context)
866 SilcNetConnect conn = context;
867 conn->aborted = TRUE;
869 /* Abort underlaying stream creation too */
871 silc_async_abort(conn->sop, NULL, NULL);
876 static void silc_net_connect_destructor(SilcFSM fsm, void *fsm_context,
877 void *destructor_context)
879 SilcNetConnect conn = fsm_context;
880 silc_free(conn->local_ip);
881 silc_free(conn->remote);
885 /* Create asynchronous TCP/IP connection. */
887 SilcAsyncOperation silc_net_tcp_connect(const char *local_ip_addr,
888 const char *remote_ip_addr,
890 SilcSchedule schedule,
891 SilcNetCallback callback,
897 schedule = silc_schedule_get_global();
899 silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
904 if (!remote_ip_addr || remote_port < 1 || !callback) {
905 silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
909 SILC_LOG_DEBUG(("Creating connection to host %s port %d",
910 remote_ip_addr, remote_port));
912 conn = silc_calloc(1, sizeof(*conn));
914 callback(silc_errno, NULL, context);
918 /* Start async operation */
919 conn->op = silc_async_alloc(silc_net_connect_abort, NULL, conn);
922 callback(silc_errno, NULL, context);
927 conn->local_ip = silc_strdup(local_ip_addr);
928 conn->remote = silc_strdup(remote_ip_addr);
930 silc_async_free(conn->op);
931 silc_free(conn->local_ip);
933 callback(silc_errno, NULL, context);
936 conn->port = remote_port;
937 conn->callback = callback;
938 conn->context = context;
940 conn->status = SILC_ERR;
942 silc_fsm_init(&conn->fsm, conn, silc_net_connect_destructor, NULL, schedule);
943 silc_fsm_start(&conn->fsm, silc_net_connect_st_start);
948 /* Closes the connection by closing the socket connection. */
950 void silc_net_close_connection(int sock)
952 SILC_LOG_DEBUG(("Closing sock %d", sock));
956 /* Set's the socket to non-blocking mode. */
958 int silc_net_set_socket_nonblock(SilcSocket sock)
960 int ret = fcntl((int)sock, F_SETFL, fcntl(sock, F_GETFL, 0) | O_NONBLOCK);
962 silc_set_errno_posix(errno);
966 /* Converts the IP number string from numbers-and-dots notation to
969 SilcBool silc_net_addr2bin(const char *addr, void *bin, SilcUInt32 bin_len)
973 if (silc_net_is_ip4(addr)) {
978 silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
982 ret = inet_aton(addr, &tmp);
984 silc_set_errno_posix(errno);
988 memcpy(bin, (unsigned char *)&tmp.s_addr, 4);
991 struct addrinfo hints, *ai;
996 silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
1000 memset(&hints, 0, sizeof(hints));
1001 hints.ai_family = AF_INET6;
1002 if (getaddrinfo(addr, NULL, &hints, &ai))
1006 s = (SilcSockaddr *)ai->ai_addr;
1007 memcpy(bin, &s->sin6.sin6_addr, sizeof(s->sin6.sin6_addr));
1012 #endif /* HAVE_IPV6 */