SILC Runtime Toolkit 1.2 Beta 1
[runtime.git] / lib / silcutil / win32 / silcwin32net.c
1 /*
2
3   silcwin32net.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2008 Pekka Riikonen
8
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.
12
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.
17
18 */
19
20 #include "silcruntime.h"
21
22 /************************** Types and definitions ***************************/
23
24 #ifdef HAVE_IPV6
25 #define SIZEOF_SOCKADDR(so) ((so).sa.sa_family == AF_INET6 ?    \
26   sizeof(so.sin6) : sizeof(so.sin))
27 #else
28 #define SIZEOF_SOCKADDR(so) (sizeof(so.sin))
29 #endif
30
31 typedef union {
32   struct sockaddr sa;
33   struct sockaddr_in sin;
34 #ifdef HAVE_IPV6
35   struct sockaddr_in6 sin6;
36 #endif
37 } SilcSockaddr;
38
39
40 /************************ Static utility functions **************************/
41
42 static SilcBool silc_net_set_sockaddr(SilcSockaddr *addr, const char *ip_addr,
43                                       int port)
44 {
45   int len;
46
47   memset(addr, 0, sizeof(*addr));
48
49   /* Check for IPv4 and IPv6 addresses */
50   if (ip_addr) {
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",
54                             ip_addr);
55       return FALSE;
56     }
57
58     if (silc_net_is_ip4(ip_addr)) {
59       /* IPv4 address */
60       len = sizeof(addr->sin.sin_addr);
61       if (!silc_net_addr2bin(ip_addr,
62                              (unsigned char *)&addr->sin.sin_addr.s_addr,
63                              len))
64         return FALSE;
65       addr->sin.sin_family = AF_INET;
66       addr->sin.sin_port = port ? htons(port) : 0;
67     } else {
68 #ifdef HAVE_IPV6
69       /* IPv6 address */
70       len = sizeof(addr->sin6.sin6_addr);
71       if (!silc_net_addr2bin(ip_addr,
72                              (unsigned char *)&addr->sin6.sin6_addr, len))
73         return FALSE;
74       addr->sin6.sin6_family = AF_INET6;
75       addr->sin6.sin6_port = port ? htons(port) : 0;
76 #else
77       SILC_LOG_ERROR(("Operating System does not support IPv6"));
78       return FALSE;
79 #endif
80     }
81   } else {
82     /* Any address */
83     addr->sin.sin_family = AF_INET;
84     addr->sin.sin_addr.s_addr = INADDR_ANY;
85     if (port)
86       addr->sin.sin_port = htons(port);
87   }
88
89   return TRUE;
90 }
91
92
93 /****************************** TCP Listener ********************************/
94
95 /* Deliver new stream to upper layer */
96
97 static void silc_net_accept_stream(SilcResult status,
98                                    SilcStream stream, void *context)
99 {
100   SilcNetListener listener = context;
101
102   if (status != SILC_OK)
103     return;
104
105   listener->callback(SILC_OK, stream, listener->context);
106 }
107
108 /* Accept incoming connection and notify upper layer */
109
110 SILC_TASK_CALLBACK(silc_net_accept)
111 {
112   SilcNetListener listener = context;
113   int sock;
114
115   SILC_LOG_DEBUG(("Accepting new connection"));
116
117   sock = silc_net_accept_connection(fd);
118   if (sock == INVALID_SOCKET)
119     return;
120
121   /* Set socket options */
122   silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
123
124   /* Create socket stream */
125   silc_socket_tcp_stream_create(sock, listener->lookup,
126                                 listener->require_fqdn, schedule,
127                                 silc_net_accept_stream, listener);
128 }
129
130 /* Create TCP network listener */
131
132 SilcNetListener
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)
138 {
139   SilcNetListener listener = NULL;
140   SOCKET sock;
141   SilcSockaddr server;
142   int i, rval;
143   const char *ipany = "0.0.0.0";
144
145   SILC_LOG_DEBUG(("Creating TCP listener"));
146
147   if (!schedule) {
148     schedule = silc_schedule_get_global();
149     if (!schedule) {
150       silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
151       goto err;
152     }
153   }
154
155   if (port < 0 || !callback) {
156     silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
157     goto err;
158   }
159
160   listener = silc_calloc(1, sizeof(*listener));
161   if (!listener)
162     return NULL;
163   listener->schedule = schedule;
164   listener->callback = callback;
165   listener->context = context;
166   listener->require_fqdn = require_fqdn;
167   listener->lookup = lookup;
168
169   if (local_ip_count > 0) {
170     listener->socks = silc_calloc(local_ip_count, sizeof(*listener->socks));
171     if (!listener->socks)
172       return NULL;
173   } else {
174     listener->socks = silc_calloc(1, sizeof(*listener->socks));
175     if (!listener->socks)
176       return NULL;
177
178     local_ip_count = 1;
179   }
180
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));
185
186     /* Set sockaddr for server */
187     if (!silc_net_set_sockaddr(&server,
188                                local_ip_addr ? local_ip_addr[i] : ipany,
189                                port))
190       goto err;
191
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)));
198       goto err;
199     }
200
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)));
206       closesocket(sock);
207       goto err;
208     }
209
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)));
216       closesocket(sock);
217       goto err;
218     }
219
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)));
226       closesocket(sock);
227       goto err;
228     }
229
230     /* Schedule for incoming connections */
231     silc_schedule_task_add_fd(schedule, sock, silc_net_accept, listener);
232
233     SILC_LOG_DEBUG(("TCP listener created, fd=%d", sock));
234     listener->socks[i] = sock;
235     listener->socks_count++;
236   }
237
238   return listener;
239
240  err:
241   if (listener)
242     silc_net_close_listener(listener);
243   return NULL;
244 }
245
246 /* Create TCP network, multiple ports */
247
248 SilcNetListener
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)
255 {
256   SilcNetListener listener = NULL;
257   SOCKET sock;
258   SilcSockaddr server;
259   int i, rval;
260   const char *ipany = "0.0.0.0";
261
262   SILC_LOG_DEBUG(("Creating TCP listener"));
263
264   if (!schedule) {
265     schedule = silc_schedule_get_global();
266     if (!schedule) {
267       silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
268       goto err;
269     }
270   }
271
272   if (!callback) {
273     silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
274     goto err;
275   }
276
277   listener = silc_calloc(1, sizeof(*listener));
278   if (!listener)
279     return NULL;
280   listener->schedule = schedule;
281   listener->callback = callback;
282   listener->context = context;
283   listener->require_fqdn = require_fqdn;
284   listener->lookup = lookup;
285
286   if (port_count > 0) {
287     listener->socks = silc_calloc(port_count, sizeof(*listener->socks));
288     if (!listener->socks)
289       return NULL;
290   } else {
291     listener->socks = silc_calloc(1, sizeof(*listener->socks));
292     if (!listener->socks)
293       return NULL;
294
295     port_count = 1;
296   }
297
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));
303
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)
309         continue;
310       goto err;
311     }
312
313     /* Create the socket */
314     sock = socket(server.sin.sin_family, SOCK_STREAM, 0);
315     if (sock == INVALID_SOCKET) {
316       if (ignore_port_error)
317         continue;
318       silc_set_errno_posix(WSAGetLastError());
319       SILC_LOG_ERROR(("Cannot create socket, error %s",
320                       silc_errno_string(silc_errno)));
321       goto err;
322     }
323
324     /* Set the socket options */
325     rval = silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
326     if (rval == SOCKET_ERROR) {
327       closesocket(sock);
328       if (ignore_port_error)
329         continue;
330       SILC_LOG_ERROR(("Cannot set socket options, error %s",
331                       silc_errno_string(silc_errno)));
332       goto err;
333     }
334
335     /* Bind the listener socket */
336     rval = bind(sock, &server.sa, SIZEOF_SOCKADDR(server));
337     if (rval == SOCKET_ERROR) {
338       closesocket(sock);
339       if (ignore_port_error)
340         continue;
341       silc_set_errno_posix(WSAGetLastError());
342       SILC_LOG_ERROR(("Cannot bind socket, error %s",
343                       silc_errno_string(silc_errno)));
344       goto err;
345     }
346
347     /* Specify that we are listenning */
348     rval = listen(sock, SOMAXCONN);
349     if (rval == SOCKET_ERROR) {
350       closesocket(sock);
351       if (ignore_port_error)
352         continue;
353       silc_set_errno_posix(WSAGetLastError());
354       SILC_LOG_ERROR(("Cannot set socket listenning, error %s",
355                       silc_errno_string(silc_errno)));
356       goto err;
357     }
358
359     /* Schedule for incoming connections */
360     silc_schedule_task_add_fd(schedule, sock, silc_net_accept, listener);
361
362     SILC_LOG_DEBUG(("TCP listener created, fd=%d", sock));
363     listener->socks[i] = sock;
364     listener->socks_count++;
365   }
366
367   if (ignore_port_error && !listener->socks_count)
368     goto err;
369
370   return listener;
371
372  err:
373   if (listener)
374     silc_net_close_listener(listener);
375   return NULL;
376 }
377
378 /* Close network listener */
379
380 void silc_net_close_listener(SilcNetListener listener)
381 {
382   int i;
383
384   SILC_LOG_DEBUG(("Closing network listener"));
385
386   if (!listener)
387     return;
388
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]);
393   }
394
395   silc_free(listener->socks);
396   silc_free(listener);
397 }
398
399 /******************************* UDP Stream *********************************/
400
401 /* Create UDP stream */
402
403 SilcStream
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)
407 {
408   SilcStream stream;
409   SilcSockaddr server;
410   SOCKET sock;
411   int rval;
412   const char *ipany = "0.0.0.0";
413
414   SILC_LOG_DEBUG(("Creating UDP stream"));
415
416   if (!schedule) {
417     schedule = silc_schedule_get_global();
418     if (!schedule) {
419       silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
420       goto err;
421     }
422   }
423
424   /* Bind to local addresses */
425   SILC_LOG_DEBUG(("Binding to local address %s",
426                   local_ip_addr ? local_ip_addr : ipany));
427
428   /* Set sockaddr for server */
429   if (!silc_net_set_sockaddr(&server, local_ip_addr ? local_ip_addr : ipany,
430                              local_port))
431     goto err;
432
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());
438     goto err;
439   }
440
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"));
445     goto err;
446   }
447 #ifdef SO_REUSEPORT
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"));
451     goto err;
452   }
453 #endif /* SO_REUSEPORT */
454
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());
460     goto err;
461   }
462
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))
466       goto err;
467
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());
472       goto err;
473     }
474   }
475
476   /* Encapsulate into socket stream */
477   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);
481   if (!stream)
482     goto err;
483
484   SILC_LOG_DEBUG(("UDP stream created, fd=%d", sock));
485   return stream;
486
487  err:
488   if (sock != -1)
489     close(sock);
490   return NULL;
491 }
492
493 /* Receive UDP packet */
494
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)
498 {
499   SilcSocketStream sock = stream;
500   SilcSockaddr s;
501   struct sockaddr *from;
502   int len, flen, err;
503
504   SILC_LOG_DEBUG(("Reading data from UDP socket %d", sock->sock));
505
506   if (remote_ip_addr && remote_port) {
507     if (sock->ipv6) {
508 #ifdef HAVE_IPV6
509       from = (struct sockaddr *)&s.sin6;
510       flen = sizeof(s.sin6);
511 #endif /* HAVE_IPV6 */
512     } else {
513       from = (struct sockaddr *)&s.sin;
514       flen = sizeof(s.sin);
515     }
516     len = recvfrom(sock->sock, ret_data, data_size, 0, from, &flen);
517   } else
518     len = recv(sock->sock, ret_data, data_size, 0);
519
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);
527       return -1;
528     }
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);
532     return -2;
533   }
534
535   SILC_LOG_DEBUG(("Read %d bytes", len));
536
537   if (!len)
538     silc_schedule_unset_listen_fd(sock->schedule, sock->sock);
539
540   /* Return remote address */
541   if (remote_ip_addr && remote_port) {
542     if (sock->ipv6) {
543 #ifdef HAVE_IPV6
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 */
548     } else {
549       const char *ip = inet_ntoa(s.sin.sin_addr);
550       if (ip)
551         silc_snprintf(remote_ip_addr, remote_ip_addr_size, ip);
552       *remote_port = ntohs(s.sin.sin_port);
553     }
554
555     SILC_LOG_DEBUG(("UDP packet from %s:%d", remote_ip_addr, *remote_port));
556   }
557
558   return len;
559 }
560
561 /* Send UDP packet */
562
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)
566 {
567   SilcSocketStream sock = stream;
568   SilcSockaddr remote;
569   int ret, err;
570
571   SILC_LOG_DEBUG(("Sending data to UDP socket %d", sock->sock));
572
573   /* Set sockaddr */
574   if (!silc_net_set_sockaddr(&remote, remote_ip_addr, remote_port))
575     return -2;
576
577   /* Send */
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);
587       return -1;
588     }
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);
592     return -2;
593   }
594
595   SILC_LOG_DEBUG(("Sent data %d bytes", ret));
596   if (silc_schedule_get_fd_events(sock->schedule, sock->sock) &
597       SILC_TASK_WRITE)
598     silc_schedule_set_listen_fd(sock->schedule, sock->sock,
599                                 SILC_TASK_READ, FALSE);
600
601   return ret;
602 }
603
604
605 /******************************* TCP Stream *********************************/
606
607 typedef struct {
608   SilcResult status;
609   SilcStream stream;
610   SilcFSMStruct fsm;
611   SilcFSMThreadStruct thread;
612   SilcAsyncOperation op;
613   SilcAsyncOperation sop;
614   char *local_ip;
615   char *remote;
616   char ip_addr[64];
617   int sock;
618   SilcNetCallback callback;
619   void *context;
620   unsigned int port     : 24;
621   unsigned int retry    : 7;
622   unsigned int aborted  : 1;
623 } *SilcNetConnect;
624
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);
628
629 static void silc_net_connect_wait_stream(SilcResult status,
630                                          SilcStream stream, void *context)
631 {
632   SilcNetConnect conn = context;
633   conn->sop = NULL;
634   conn->status = status;
635   conn->stream = stream;
636   SILC_FSM_CALL_CONTINUE(&conn->thread);
637 }
638
639 /* Start connecting.  Create a real thread where we connect. */
640
641 SILC_FSM_STATE(silc_net_connect_st_thread)
642 {
643   SilcNetConnect conn = fsm_context;
644
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);
648
649   /* Wait for the thread to finish */
650   silc_fsm_next(fsm, silc_net_connect_st_finish);
651   SILC_FSM_THREAD_WAIT(&conn->thread);
652 }
653
654 /* Connecting thread */
655
656 SILC_FSM_STATE(silc_net_connect_st_start)
657 {
658   SilcNetConnect conn = fsm_context;
659   SOCKET sock;
660   int rval, err;
661   SilcSockaddr desthost;
662   SilcBool prefer_ipv6 = TRUE;
663
664   if (conn->aborted)
665     return SILC_FSM_FINISH;
666
667   /* Do host lookup */
668  retry:
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()));
673
674     /** Network unreachable */
675     conn->status = SILC_ERR_UNREACHABLE;
676     return SILC_FSM_FINISH;
677   }
678
679   /* Set sockaddr for this connection */
680   if (!silc_net_set_sockaddr(&desthost, conn->ip_addr, conn->port))
681     return SILC_FSM_FINISH;
682
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)) {
689       prefer_ipv6 = FALSE;
690       goto retry;
691     }
692
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;
698   }
699
700   /* Bind to the local address if provided */
701   if (conn->local_ip) {
702     SilcSockaddr local;
703
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));
707   }
708
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) {
714       shutdown(sock, 2);
715       closesocket(sock);
716
717       /* Retry using an IPv4 address, if IPv6 didn't work */
718       if (prefer_ipv6 && silc_net_is_ip6(conn->ip_addr)) {
719         prefer_ipv6 = FALSE;
720         goto retry;
721       }
722
723       /* Set error */
724       silc_set_errno_posix(err);
725       conn->status = silc_errno;
726
727       SILC_LOG_ERROR(("Cannot connect to remote host: %s",
728                       silc_errno_string(silc_errno)));
729       return SILC_FSM_FINISH;
730     }
731   }
732
733   /* Set the socket to non-blocking mode */
734   silc_net_set_socket_nonblock(sock);
735
736   /* Set appropriate options */
737 #if defined(TCP_NODELAY)
738   silc_net_set_socket_opt(sock, IPPROTO_TCP, TCP_NODELAY, 1);
739 #endif
740   silc_net_set_socket_opt(sock, SOL_SOCKET, SO_KEEPALIVE, 1);
741
742   SILC_LOG_DEBUG(("TCP connection established"));
743
744   conn->sock = sock;
745
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)));
752 }
753
754 /* TCP socket stream created */
755
756 SILC_FSM_STATE(silc_net_connect_st_stream)
757 {
758   SilcNetConnect conn = fsm_context;
759
760   if (conn->aborted)
761     return SILC_FSM_FINISH;
762
763   if (conn->status != SILC_OK) {
764     /** Stream creation failed */
765     return SILC_FSM_FINISH;
766   }
767
768   /** Stream created successfully */
769   SILC_LOG_DEBUG(("Connected successfully, sock %d", conn->sock));
770   conn->status = SILC_OK;
771   return SILC_FSM_FINISH;
772 }
773
774 SILC_FSM_STATE(silc_net_connect_st_finish)
775 {
776   SilcNetConnect conn = fsm_context;
777
778   /* Deliver error or new stream */
779   if (!conn->aborted) {
780     conn->callback(conn->status, conn->stream, conn->context);
781     if (conn->op)
782       silc_async_free(conn->op);
783   }
784
785   return SILC_FSM_FINISH;
786 }
787
788 static void silc_net_connect_abort(SilcAsyncOperation op, void *context)
789 {
790   SilcNetConnect conn = context;
791   conn->aborted = TRUE;
792
793   /* Abort underlaying stream creation too */
794   if (conn->sop) {
795     silc_async_abort(conn->sop, NULL, NULL);
796     conn->sop = NULL;
797   }
798 }
799
800 static void silc_net_connect_destructor(SilcFSM fsm, void *fsm_context,
801                                         void *destructor_context)
802 {
803   SilcNetConnect conn = fsm_context;
804   silc_free(conn->local_ip);
805   silc_free(conn->remote);
806   silc_free(conn);
807 }
808
809 /* Create asynchronous TCP/IP connection. */
810
811 SilcAsyncOperation silc_net_tcp_connect(const char *local_ip_addr,
812                                         const char *remote_ip_addr,
813                                         int remote_port,
814                                         SilcSchedule schedule,
815                                         SilcNetCallback callback,
816                                         void *context)
817 {
818   SilcNetConnect conn;
819
820   if (!schedule) {
821     schedule = silc_schedule_get_global();
822     if (!schedule) {
823       silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
824       return NULL;
825     }
826   }
827
828   if (!remote_ip_addr || remote_port < 1 || !callback) {
829     silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
830     return NULL;
831   }
832
833   SILC_LOG_DEBUG(("Creating connection to host %s port %d",
834                   remote_ip_addr, remote_port));
835
836   conn = silc_calloc(1, sizeof(*conn));
837   if (!conn) {
838     callback(SILC_ERR_OUT_OF_MEMORY, NULL, context);
839     return NULL;
840   }
841
842   /* Start async operation */
843   conn->op = silc_async_alloc(silc_net_connect_abort, NULL, conn);
844   if (!conn->op) {
845     silc_free(conn);
846     callback(SILC_ERR_OUT_OF_MEMORY, NULL, context);
847     return NULL;
848   }
849
850   if (local_ip_addr)
851     conn->local_ip = silc_strdup(local_ip_addr);
852   conn->remote = silc_strdup(remote_ip_addr);
853   if (!conn->remote) {
854     silc_async_free(conn->op);
855     silc_free(conn->local_ip);
856     silc_free(conn);
857     callback(SILC_ERR_OUT_OF_MEMORY, NULL, context);
858     return NULL;
859   }
860   conn->port = remote_port;
861   conn->callback = callback;
862   conn->context = context;
863   conn->retry = 1;
864   conn->status = SILC_ERR;
865
866   silc_fsm_init(&conn->fsm, conn, silc_net_connect_destructor, NULL, schedule);
867   silc_fsm_start(&conn->fsm, silc_net_connect_st_thread);
868
869   return conn->op;
870 }
871
872 /* Closes the connection by closing the socket connection. */
873
874 void silc_net_close_connection(int sock)
875 {
876   SILC_LOG_DEBUG(("Closing sock %d", sock));
877   closesocket(sock);
878 }
879
880 /* Converts the IP number string from numbers-and-dots notation to
881    binary form. */
882
883 SilcBool silc_net_addr2bin(const char *addr, void *bin, SilcUInt32 bin_len)
884 {
885   if (silc_net_is_ip4(addr)) {
886     /* IPv4 address */
887     int i = 0, c = 0, d = 0, len = strlen(addr);
888     unsigned char ret[4];
889
890     memset(ret, 0, sizeof(ret));
891     while (len-- > 0) {
892       if (addr[i++] == '.') {
893         ret[c++] = d;
894         d = 0;
895         if (c > 3)
896           goto err;
897         continue;
898       }
899
900       if (!isdigit((int)addr[i - 1]))
901         goto err;
902
903       d = 10 * d + addr[i - 1] - '0';
904       if (d > 255)
905         goto err;
906     }
907     if (c != 3)
908       goto err;
909     ret[c] = d;
910
911     if (bin_len < sizeof(ret)) {
912       silc_set_errno(SILC_ERR_OVERFLOW);
913       return FALSE;
914     }
915
916     memcpy(bin, ret, sizeof(ret));
917     return TRUE;
918
919     err:
920     return FALSE;
921   } else {
922 #ifdef HAVE_IPV6
923     struct addrinfo hints, *ai;
924     SilcSockaddr *s;
925
926     /* IPv6 address */
927     if (bin_len < 16) {
928       silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
929       return FALSE;
930     }
931
932     memset(&hints, 0, sizeof(hints));
933     hints.ai_family = AF_INET6;
934     if (getaddrinfo(addr, NULL, &hints, &ai))
935       return FALSE;
936
937     if (ai) {
938       s = (SilcSockaddr *)ai->ai_addr;
939       memcpy(bin, &s->sin6.sin6_addr, sizeof(s->sin6.sin6_addr));
940       freeaddrinfo(ai);
941     }
942
943     return TRUE;
944 #else
945     return FALSE;
946 #endif /* HAVE_IPV6 */
947   }
948 }
949
950 /* Set socket to non-blocking mode. */
951
952 int silc_net_set_socket_nonblock(SilcSocket sock)
953 {
954   unsigned long on = 1;
955   return ioctlsocket(sock, FIONBIO, &on);
956 }