WIN32 compilation error fixes.
[silc.git] / lib / silcutil / win32 / silcwin32net.c
1 /*
2
3   silcwin32net.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2007 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 /* $Id$ */
20
21 #include "silc.h"
22
23 /************************** Types and definitions ***************************/
24
25 #ifdef HAVE_IPV6
26 #define SIZEOF_SOCKADDR(so) ((so).sa.sa_family == AF_INET6 ?    \
27   sizeof(so.sin6) : sizeof(so.sin))
28 #else
29 #define SIZEOF_SOCKADDR(so) (sizeof(so.sin))
30 #endif
31
32 typedef union {
33   struct sockaddr sa;
34   struct sockaddr_in sin;
35 #ifdef HAVE_IPV6
36   struct sockaddr_in6 sin6;
37 #endif
38 } SilcSockaddr;
39
40
41 /************************ Static utility functions **************************/
42
43 static SilcBool silc_net_set_sockaddr(SilcSockaddr *addr, const char *ip_addr,
44                                       int port)
45 {
46   int len;
47
48   memset(addr, 0, sizeof(*addr));
49
50   /* Check for IPv4 and IPv6 addresses */
51   if (ip_addr) {
52     if (!silc_net_is_ip(ip_addr)) {
53       SILC_LOG_ERROR(("%s is not IP address", ip_addr));
54       return FALSE;
55     }
56
57     if (silc_net_is_ip4(ip_addr)) {
58       /* IPv4 address */
59       len = sizeof(addr->sin.sin_addr);
60       silc_net_addr2bin(ip_addr,
61                         (unsigned char *)&addr->sin.sin_addr.s_addr, len);
62       addr->sin.sin_family = AF_INET;
63       addr->sin.sin_port = port ? htons(port) : 0;
64     } else {
65 #ifdef HAVE_IPV6
66       /* IPv6 address */
67       len = sizeof(addr->sin6.sin6_addr);
68       silc_net_addr2bin(ip_addr,
69                         (unsigned char *)&addr->sin6.sin6_addr, len);
70       addr->sin6.sin6_family = AF_INET6;
71       addr->sin6.sin6_port = port ? htons(port) : 0;
72 #else
73       SILC_LOG_ERROR(("Operating System does not support IPv6"));
74       return FALSE;
75 #endif
76     }
77   } else {
78     /* Any address */
79     addr->sin.sin_family = AF_INET;
80     addr->sin.sin_addr.s_addr = INADDR_ANY;
81     if (port)
82       addr->sin.sin_port = htons(port);
83   }
84
85   return TRUE;
86 }
87
88
89 /****************************** TCP Listener ********************************/
90
91 /* Deliver new stream to upper layer */
92
93 static void silc_net_accept_stream(SilcSocketStreamStatus status,
94                                    SilcStream stream, void *context)
95 {
96   SilcNetListener listener = context;
97
98   if (status != SILC_SOCKET_OK)
99     return;
100
101   listener->callback(SILC_NET_OK, stream, listener->context);
102 }
103
104 /* Accept incoming connection and notify upper layer */
105
106 SILC_TASK_CALLBACK(silc_net_accept)
107 {
108   SilcNetListener listener = context;
109   int sock;
110
111   SILC_LOG_DEBUG(("Accepting new connection"));
112
113   sock = silc_net_accept_connection(fd);
114   if (sock == INVALID_SOCKET)
115     return;
116
117   /* Set socket options */
118   silc_net_set_socket_nonblock(sock);
119   silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
120
121   /* Create socket stream */
122   silc_socket_tcp_stream_create(sock, listener->lookup,
123                                 listener->require_fqdn, schedule,
124                                 silc_net_accept_stream, listener);
125 }
126
127 /* Create TCP network listener */
128
129 SilcNetListener
130 silc_net_tcp_create_listener(const char **local_ip_addr,
131                              SilcUInt32 local_ip_count, int port,
132                              SilcBool lookup, SilcBool require_fqdn,
133                              SilcSchedule schedule,
134                              SilcNetCallback callback, void *context)
135 {
136   SilcNetListener listener = NULL;
137   SOCKET sock;
138   SilcSockaddr server;
139   int i, rval;
140   const char *ipany = "0.0.0.0";
141
142   SILC_LOG_DEBUG(("Creating TCP listener"));
143
144   if (port < 0 || !schedule || !callback)
145     goto err;
146
147   listener = silc_calloc(1, sizeof(*listener));
148   if (!listener)
149     return NULL;
150   listener->schedule = schedule;
151   listener->callback = callback;
152   listener->context = context;
153   listener->require_fqdn = require_fqdn;
154   listener->lookup = lookup;
155
156   if (local_ip_count > 0) {
157     listener->socks = silc_calloc(local_ip_count, sizeof(*listener->socks));
158     if (!listener->socks)
159       return NULL;
160   } else {
161     listener->socks = silc_calloc(1, sizeof(*listener->socks));
162     if (!listener->socks)
163       return NULL;
164
165     local_ip_count = 1;
166   }
167
168   /* Bind to local addresses */
169   for (i = 0; i < local_ip_count; i++) {
170     SILC_LOG_DEBUG(("Binding to local address %s",
171                     local_ip_addr ? local_ip_addr[i] : ipany));
172
173     /* Set sockaddr for server */
174     if (!silc_net_set_sockaddr(&server,
175                                local_ip_addr ? local_ip_addr[i] : ipany,
176                                port))
177       goto err;
178
179     /* Create the socket */
180     sock = socket(server.sin.sin_family, SOCK_STREAM, 0);
181     if (sock == INVALID_SOCKET) {
182       SILC_LOG_ERROR(("Cannot create socket"));
183       goto err;
184     }
185
186     /* Set the socket options */
187     rval = silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
188     if (rval == SOCKET_ERROR) {
189       SILC_LOG_ERROR(("Cannot set socket options"));
190       closesocket(sock);
191       goto err;
192     }
193
194     /* Bind the listener socket */
195     rval = bind(sock, &server.sa, SIZEOF_SOCKADDR(server));
196     if (rval == SOCKET_ERROR) {
197       SILC_LOG_ERROR(("Cannot bind socket"));
198       closesocket(sock);
199       goto err;
200     }
201
202     /* Specify that we are listenning */
203     rval = listen(sock, SOMAXCONN);
204     if (rval == SOCKET_ERROR) {
205       SILC_LOG_ERROR(("Cannot set socket listenning"));
206       closesocket(sock);
207       goto err;
208     }
209
210     /* Set the server socket to non-blocking mode.  Dunno if this works. */
211     silc_net_set_socket_nonblock(sock);
212
213     /* Schedule for incoming connections */
214     silc_schedule_task_add_fd(schedule, sock, silc_net_accept, listener);
215
216     SILC_LOG_DEBUG(("TCP listener created, fd=%d", sock));
217     listener->socks[i] = sock;
218     listener->socks_count++;
219   }
220
221   return listener;
222
223  err:
224   if (listener)
225     silc_net_close_listener(listener);
226   return NULL;
227 }
228
229 /* Close network listener */
230
231 void silc_net_close_listener(SilcNetListener listener)
232 {
233   int i;
234
235   SILC_LOG_DEBUG(("Closing network listener"));
236
237   for (i = 0; i < listener->socks_count; i++) {
238     silc_schedule_task_del_by_fd(listener->schedule, listener->socks[i]);
239     shutdown(listener->socks[i], 2);
240     closesocket(listener->socks[i]);
241   }
242
243   silc_free(listener->socks);
244   silc_free(listener);
245 }
246
247 /******************************* UDP Stream *********************************/
248
249 /* Create UDP stream */
250
251 SilcStream
252 silc_net_udp_connect(const char *local_ip_addr, int local_port,
253                      const char *remote_ip_addr, int remote_port,
254                      SilcSchedule schedule)
255 {
256   SilcStream stream;
257   SilcSockaddr server;
258   SOCKET sock;
259   int rval;
260   const char *ipany = "0.0.0.0";
261
262   SILC_LOG_DEBUG(("Creating UDP stream"));
263
264   if (!schedule)
265     goto err;
266
267   /* Bind to local addresses */
268   SILC_LOG_DEBUG(("Binding to local address %s",
269                   local_ip_addr ? local_ip_addr : ipany));
270
271   /* Set sockaddr for server */
272   if (!silc_net_set_sockaddr(&server, local_ip_addr ? local_ip_addr : ipany,
273                              local_port))
274     goto err;
275
276   /* Create the socket */
277   sock = socket(server.sin.sin_family, SOCK_DGRAM, 0);
278   if (sock == INVALID_SOCKET) {
279     SILC_LOG_ERROR(("Cannot create socket"));
280     goto err;
281   }
282
283   /* Set the socket options */
284   rval = silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
285   if (rval == SOCKET_ERROR) {
286     SILC_LOG_ERROR(("Cannot set socket options"));
287     goto err;
288   }
289 #ifdef SO_REUSEPORT
290   rval = silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEPORT, 1);
291   if (rval == SOCKET_ERROR) {
292     SILC_LOG_ERROR(("Cannot set socket options"));
293     goto err;
294   }
295 #endif /* SO_REUSEPORT */
296
297   /* Bind the listener socket */
298   rval = bind(sock, &server.sa, SIZEOF_SOCKADDR(server));
299   if (rval == SOCKET_ERROR) {
300     SILC_LOG_DEBUG(("Cannot bind socket"));
301     goto err;
302   }
303
304   /* Set socket to non-blocking mode */
305   silc_net_set_socket_nonblock(sock);
306
307   /* Set to connected state if remote address is provided. */
308   if (remote_ip_addr && remote_port) {
309     if (!silc_net_set_sockaddr(&server, remote_ip_addr, remote_port))
310       goto err;
311
312     rval = connect(sock, &server.sa, SIZEOF_SOCKADDR(server));
313     if (rval == SOCKET_ERROR) {
314       SILC_LOG_DEBUG(("Cannot connect UDP stream"));
315       goto err;
316     }
317   }
318
319   /* Encapsulate into socket stream */
320   stream =
321     silc_socket_udp_stream_create(sock, local_ip_addr ?
322                                   silc_net_is_ip6(local_ip_addr) : FALSE,
323                                   remote_ip_addr ? TRUE : FALSE, schedule);
324   if (!stream)
325     goto err;
326
327   SILC_LOG_DEBUG(("UDP stream created, fd=%d", sock));
328   return stream;
329
330  err:
331   if (sock != -1)
332     close(sock);
333   return NULL;
334 }
335
336 /* Receive UDP packet */
337
338 int silc_net_udp_receive(SilcStream stream, char *remote_ip_addr,
339                          SilcUInt32 remote_ip_addr_size, int *remote_port,
340                          unsigned char *ret_data, SilcUInt32 data_size)
341 {
342   SilcSocketStream sock = stream;
343   SilcSockaddr s;
344   struct sockaddr *from;
345   int len, flen, err;
346
347   SILC_LOG_DEBUG(("Reading data from UDP socket %d", sock->sock));
348
349   if (remote_ip_addr && remote_port) {
350     if (sock->ipv6) {
351 #ifdef HAVE_IPV6
352       from = (struct sockaddr *)&s.sin6;
353       flen = sizeof(s.sin6);
354 #endif /* HAVE_IPV6 */
355     } else {
356       from = (struct sockaddr *)&s.sin;
357       flen = sizeof(s.sin);
358     }
359     len = recvfrom(sock->sock, ret_data, data_size, 0, from, &flen);
360   } else
361     len = recv(sock->sock, ret_data, data_size, 0);
362
363   if (len == SOCKET_ERROR) {
364     err = WSAGetLastError();
365     if (err == WSAEWOULDBLOCK) {
366       SILC_LOG_DEBUG(("Could not read immediately, will do it later"));
367       silc_schedule_set_listen_fd(sock->schedule, sock->sock,
368                                   SILC_TASK_READ, FALSE);
369       return -1;
370     }
371     SILC_LOG_DEBUG(("Cannot read from UDP socket: %d", sock->sock));
372     silc_schedule_unset_listen_fd(sock->schedule, sock->sock);
373     sock->sock_error = err;
374     return -2;
375   }
376
377   SILC_LOG_DEBUG(("Read %d bytes", len));
378
379   if (!len)
380     silc_schedule_unset_listen_fd(sock->schedule, sock->sock);
381
382   /* Return remote address */
383   if (remote_ip_addr && remote_port) {
384     if (sock->ipv6) {
385 #ifdef HAVE_IPV6
386       *remote_port = ntohs(s.sin6.sin6_port);
387       inet_ntop(AF_INET6, &s.sin6.sin6_addr, remote_ip_addr,
388                 remote_ip_addr_size);
389 #endif /* HAVE_IPV6 */
390     } else {
391       const char *ip = inet_ntoa(s.sin.sin_addr);
392       if (ip)
393         silc_snprintf(remote_ip_addr, remote_ip_addr_size, ip);
394       *remote_port = ntohs(s.sin.sin_port);
395     }
396
397     SILC_LOG_DEBUG(("UDP packet from %s:%d", remote_ip_addr, *remote_port));
398   }
399
400   return len;
401 }
402
403 /* Send UDP packet */
404
405 int silc_net_udp_send(SilcStream stream,
406                       const char *remote_ip_addr, int remote_port,
407                       const unsigned char *data, SilcUInt32 data_len)
408 {
409   SilcSocketStream sock = stream;
410   SilcSockaddr remote;
411   int ret, err;
412
413   SILC_LOG_DEBUG(("Sending data to UDP socket %d", sock->sock));
414
415   /* Set sockaddr */
416   if (!silc_net_set_sockaddr(&remote, remote_ip_addr, remote_port))
417     return -2;
418
419   /* Send */
420   ret = sendto(sock->sock, data, data_len, 0, &remote.sa,
421                SIZEOF_SOCKADDR(remote));
422   if (ret == SOCKET_ERROR) {
423     err = WSAGetLastError();
424     if (err == WSAEWOULDBLOCK) {
425       SILC_LOG_DEBUG(("Could not send immediately, will do it later"));
426       silc_schedule_set_listen_fd(sock->schedule, sock->sock,
427                                   SILC_TASK_READ | SILC_TASK_WRITE, FALSE);
428       return -1;
429     }
430     SILC_LOG_DEBUG(("Cannot send to UDP socket: %s", strerror(errno)));
431     silc_schedule_unset_listen_fd(sock->schedule, sock->sock);
432     sock->sock_error = err;
433     return -2;
434   }
435
436   SILC_LOG_DEBUG(("Sent data %d bytes", ret));
437   if (silc_schedule_get_fd_events(sock->schedule, sock->sock) &
438       SILC_TASK_WRITE)
439     silc_schedule_set_listen_fd(sock->schedule, sock->sock,
440                                 SILC_TASK_READ, FALSE);
441
442   return ret;
443 }
444
445
446 /******************************* TCP Stream *********************************/
447
448 typedef struct {
449   SilcNetStatus status;
450   SilcSocketStreamStatus stream_status;
451   SilcStream stream;
452   SilcFSMStruct fsm;
453   SilcFSMThreadStruct thread;
454   SilcAsyncOperation op;
455   SilcAsyncOperation sop;
456   char *local_ip;
457   char *remote;
458   char ip_addr[64];
459   int sock;
460   SilcNetCallback callback;
461   void *context;
462   unsigned int port     : 24;
463   unsigned int retry    : 7;
464   unsigned int aborted  : 1;
465 } *SilcNetConnect;
466
467 SILC_FSM_STATE(silc_net_connect_st_start);
468 SILC_FSM_STATE(silc_net_connect_st_stream);
469 SILC_FSM_STATE(silc_net_connect_st_finish);
470
471 static void silc_net_connect_wait_stream(SilcSocketStreamStatus status,
472                                          SilcStream stream, void *context)
473 {
474   SilcNetConnect conn = context;
475   conn->stream_status = status;
476   conn->stream = stream;
477   SILC_FSM_CALL_CONTINUE(&conn->fsm);
478 }
479
480 /* Start connecting.  Create a real thread where we connect. */
481
482 SILC_FSM_STATE(silc_net_connect_st_thread)
483 {
484   SilcNetConnect conn = fsm_context;
485
486   /* Connect in real thread as as to not block the application. */
487   silc_fsm_thread_init(&conn->thread, fsm, conn, NULL, NULL, TRUE);
488   silc_fsm_start(&conn->thread, silc_net_connect_st_start);
489
490   /* Wait for the thread to finish */
491   silc_fsm_next(fsm, silc_net_connect_st_finish);
492   SILC_FSM_THREAD_WAIT(&conn->thread);
493 }
494
495 /* Connecting thread */
496
497 SILC_FSM_STATE(silc_net_connect_st_start)
498 {
499   SilcNetConnect conn = fsm_context;
500   SOCKET sock;
501   int rval, err;
502   SilcSockaddr desthost;
503   SilcBool prefer_ipv6 = TRUE;
504
505   if (conn->aborted)
506     return SILC_FSM_FINISH;
507
508   /* Do host lookup */
509  retry:
510   if (!silc_net_gethostbyname(conn->remote, prefer_ipv6,
511                               conn->ip_addr, sizeof(conn->ip_addr))) {
512     SILC_LOG_ERROR(("Network (%s) unreachable: could not resolve the "
513                     "host", conn->remote));
514
515     /** Network unreachable */
516     conn->status = SILC_NET_HOST_UNREACHABLE;
517     return SILC_FSM_FINISH;
518   }
519
520   /* Set sockaddr for this connection */
521   if (!silc_net_set_sockaddr(&desthost, conn->ip_addr, conn->port))
522     return SILC_FSM_FINISH;
523
524   /* Create the connection socket */
525   sock = socket(desthost.sin.sin_family, SOCK_STREAM, 0);
526   if (sock == INVALID_SOCKET) {
527     /* If address is IPv6, then fallback to IPv4 and see whether we can do
528        better with that on socket creation. */
529     if (prefer_ipv6 && silc_net_is_ip6(conn->ip_addr)) {
530       prefer_ipv6 = FALSE;
531       goto retry;
532     }
533
534     /** Cannot create socket */
535     SILC_LOG_ERROR(("Cannot create socket"));
536     return SILC_FSM_FINISH;
537   }
538
539   /* Bind to the local address if provided */
540   if (conn->local_ip) {
541     SilcSockaddr local;
542
543     /* Set sockaddr for local listener, and try to bind it. */
544     if (silc_net_set_sockaddr(&local, conn->local_ip, 0))
545       bind(sock, &local.sa, SIZEOF_SOCKADDR(local));
546   }
547
548   /* Connect to the host */
549   rval = connect(sock, &desthost.sa, SIZEOF_SOCKADDR(desthost));
550   err = WSAGetLastError();
551   if (rval == SOCKET_ERROR) {
552     if (err != WSAEWOULDBLOCK) {
553       shutdown(sock, 2);
554       closesocket(sock);
555
556       /* Retry using an IPv4 adress, if IPv6 didn't work */
557       if (prefer_ipv6 && silc_net_is_ip6(conn->ip_addr)) {
558         prefer_ipv6 = FALSE;
559         goto retry;
560       }
561
562       switch (err) {
563       case WSAETIMEDOUT:
564         conn->status = SILC_NET_CONNECTION_TIMEOUT;
565         break;
566       case WSAECONNREFUSED:
567         conn->status = SILC_NET_CONNECTION_REFUSED;
568         break;
569       case WSAEHOSTUNREACH:
570         conn->status = SILC_NET_HOST_UNREACHABLE;
571         break;
572       default:
573         break;
574       }
575
576       SILC_LOG_ERROR(("Cannot connect to remote host"));
577       return SILC_FSM_FINISH;
578     }
579   }
580
581   /* Set the socket to non-blocking mode */
582   silc_net_set_socket_nonblock(sock);
583
584   /* Set appropriate options */
585 #if defined(TCP_NODELAY)
586   silc_net_set_socket_opt(sock, IPPROTO_TCP, TCP_NODELAY, 1);
587 #endif
588   silc_net_set_socket_opt(sock, SOL_SOCKET, SO_KEEPALIVE, 1);
589
590   SILC_LOG_DEBUG(("TCP connection established"));
591
592   conn->sock = sock;
593
594   /** Connection created */
595   silc_fsm_next(fsm, silc_net_connect_st_stream);
596   SILC_FSM_CALL((conn->sop = silc_socket_tcp_stream_create(
597                                      conn->sock, FALSE, FALSE,
598                                      silc_fsm_get_schedule(fsm),
599                                      silc_net_connect_wait_stream, conn)));
600 }
601
602 /* TCP socket stream created */
603
604 SILC_FSM_STATE(silc_net_connect_st_stream)
605 {
606   SilcNetConnect conn = fsm_context;
607
608   if (conn->aborted)
609     return SILC_FSM_FINISH;
610
611   if (conn->stream_status != SILC_SOCKET_OK) {
612     /** Stream creation failed */
613     if (conn->stream_status == SILC_SOCKET_UNKNOWN_IP)
614       conn->status = SILC_NET_UNKNOWN_IP;
615     else if (conn->stream_status == SILC_SOCKET_UNKNOWN_HOST)
616       conn->status = SILC_NET_UNKNOWN_HOST;
617     else
618       conn->status = SILC_NET_ERROR;
619
620     return SILC_FSM_FINISH;
621   }
622
623   /* Set stream information */
624   silc_socket_stream_set_info(conn->stream,
625                               !silc_net_is_ip(conn->remote) ? conn->remote :
626                               conn->ip_addr, conn->ip_addr, conn->port);
627
628   /** Stream created successfully */
629   SILC_LOG_DEBUG(("Connected successfully, sock %d", conn->sock));
630   conn->status = SILC_NET_OK;
631   return SILC_FSM_FINISH;
632 }
633
634 SILC_FSM_STATE(silc_net_connect_st_finish)
635 {
636   SilcNetConnect conn = fsm_context;
637
638   /* Deliver error or new stream */
639   if (!conn->aborted) {
640     conn->callback(conn->status, conn->stream, conn->context);
641     if (conn->op)
642       silc_async_free(conn->op);
643     if (conn->sop)
644       silc_async_free(conn->sop);
645   }
646
647   return SILC_FSM_FINISH;
648 }
649
650 static void silc_net_connect_abort(SilcAsyncOperation op, void *context)
651 {
652   SilcNetConnect conn = context;
653   conn->aborted = TRUE;
654
655   /* Abort underlaying stream creation too */
656   if (conn->sop)
657     silc_async_abort(conn->sop, NULL, NULL);
658 }
659
660 static void silc_net_connect_destructor(SilcFSM fsm, void *fsm_context,
661                                         void *destructor_context)
662 {
663   SilcNetConnect conn = fsm_context;
664   silc_free(conn->local_ip);
665   silc_free(conn->remote);
666   silc_free(conn);
667 }
668
669 /* Create asynchronous TCP/IP connection. */
670
671 SilcAsyncOperation silc_net_tcp_connect(const char *local_ip_addr,
672                                         const char *remote_ip_addr,
673                                         int remote_port,
674                                         SilcSchedule schedule,
675                                         SilcNetCallback callback,
676                                         void *context)
677 {
678   SilcNetConnect conn;
679
680   if (!remote_ip_addr || remote_port < 1 || !schedule || !callback)
681     return NULL;
682
683   SILC_LOG_DEBUG(("Creating connection to host %s port %d",
684                   remote_ip_addr, remote_port));
685
686   conn = silc_calloc(1, sizeof(*conn));
687   if (!conn) {
688     callback(SILC_NET_NO_MEMORY, NULL, context);
689     return NULL;
690   }
691
692   /* Start async operation */
693   conn->op = silc_async_alloc(silc_net_connect_abort, NULL, conn);
694   if (!conn->op) {
695     silc_free(conn);
696     callback(SILC_NET_NO_MEMORY, NULL, context);
697     return NULL;
698   }
699
700   if (local_ip_addr)
701     conn->local_ip = strdup(local_ip_addr);
702   conn->remote = strdup(remote_ip_addr);
703   if (!conn->remote) {
704     silc_async_free(conn->op);
705     silc_free(conn->local_ip);
706     silc_free(conn);
707     callback(SILC_NET_NO_MEMORY, NULL, context);
708     return NULL;
709   }
710   conn->port = remote_port;
711   conn->callback = callback;
712   conn->context = context;
713   conn->retry = 1;
714   conn->status = SILC_NET_ERROR;
715
716   silc_fsm_init(&conn->fsm, conn, silc_net_connect_destructor, NULL, schedule);
717   silc_fsm_start(&conn->fsm, silc_net_connect_st_thread);
718
719   return conn->op;
720 }
721
722 /* Closes the connection by closing the socket connection. */
723
724 void silc_net_close_connection(int sock)
725 {
726   SILC_LOG_DEBUG(("Closing sock %d", sock));
727   closesocket(sock);
728 }
729
730 /* Converts the IP number string from numbers-and-dots notation to
731    binary form. */
732
733 SilcBool silc_net_addr2bin(const char *addr, void *bin, SilcUInt32 bin_len)
734 {
735   unsigned long ret;
736
737   if (silc_net_is_ip4(addr)) {
738     /* IPv4 address */
739     ret = inet_addr(addr);
740
741     if (bin_len < 4)
742       return FALSE;
743
744     memcpy(bin, (unsigned char *)&ret, 4);
745     return ret != INADDR_NONE;
746   } else {
747 #ifdef HAVE_IPV6
748     struct addrinfo hints, *ai;
749     SilcSockaddr *s;
750
751     /* IPv6 address */
752     if (bin_len < 16)
753       return FALSE;
754
755     memset(&hints, 0, sizeof(hints));
756     hints.ai_family = AF_INET6;
757     if (getaddrinfo(addr, NULL, &hints, &ai))
758       return FALSE;
759
760     if (ai) {
761       s = (SilcSockaddr *)ai->ai_addr;
762       memcpy(bin, &s->sin6.sin6_addr, sizeof(s->sin6.sin6_addr));
763       freeaddrinfo(ai);
764     }
765
766     return TRUE;
767 #else
768     return FALSE;
769 #endif /* HAVE_IPV6 */
770   }
771 }
772
773 /* Set socket to non-blocking mode. */
774
775 int silc_net_set_socket_nonblock(SilcSocket sock)
776 {
777   unsigned long on = 1;
778   return ioctlsocket(sock, FIONBIO, &on);
779 }
780
781 /* Init Winsock2. */
782
783 SilcBool silc_net_win32_init(void)
784 {
785   int ret, sopt = SO_SYNCHRONOUS_NONALERT;
786   WSADATA wdata;
787   WORD ver = MAKEWORD(1, 1);
788
789   ret = WSAStartup(ver, &wdata);
790   if (ret)
791     return FALSE;
792
793   /* Allow using the SOCKET's as file descriptors so that we can poll
794      them with SILC Scheduler. */
795   ret = setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *)&sopt,
796                    sizeof(sopt));
797   if (ret)
798     return FALSE;
799
800   return TRUE;
801 }
802
803 /* Uninit Winsock2 */
804
805 void silc_net_win32_uninit(void)
806 {
807   WSACleanup();
808 }