Merge branch 'topic/mm-fixes' of git://208.110.73.182/silc into silc.1.1.branch
[silc.git] / lib / silcutil / win32 / silcwin32net.c
index 8cf1dd0e5bf1023cd6d875abf894d5e57e801c54..7d4e7339d3f9f5942624f56043378677bdb6e1cc 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2005, 2007 Pekka Riikonen
+  Copyright (C) 1997 - 2007 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -57,16 +57,19 @@ static SilcBool silc_net_set_sockaddr(SilcSockaddr *addr, const char *ip_addr,
     if (silc_net_is_ip4(ip_addr)) {
       /* IPv4 address */
       len = sizeof(addr->sin.sin_addr);
-      silc_net_addr2bin(ip_addr,
-                       (unsigned char *)&addr->sin.sin_addr.s_addr, len);
+      if (!silc_net_addr2bin(ip_addr,
+                            (unsigned char *)&addr->sin.sin_addr.s_addr,
+                            len))
+       return FALSE;
       addr->sin.sin_family = AF_INET;
       addr->sin.sin_port = port ? htons(port) : 0;
     } else {
 #ifdef HAVE_IPV6
       /* IPv6 address */
       len = sizeof(addr->sin6.sin6_addr);
-      silc_net_addr2bin(ip_addr,
-                       (unsigned char *)&addr->sin6.sin6_addr, len);
+      if (!silc_net_addr2bin(ip_addr,
+                            (unsigned char *)&addr->sin6.sin6_addr, len))
+       return FALSE;
       addr->sin6.sin6_family = AF_INET6;
       addr->sin6.sin6_port = port ? htons(port) : 0;
 #else
@@ -115,7 +118,6 @@ SILC_TASK_CALLBACK(silc_net_accept)
     return;
 
   /* Set socket options */
-  silc_net_set_socket_nonblock(sock);
   silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
 
   /* Create socket stream */
@@ -136,7 +138,7 @@ silc_net_tcp_create_listener(const char **local_ip_addr,
   SilcNetListener listener = NULL;
   SOCKET sock;
   SilcSockaddr server;
-  int i, sock, rval;
+  int i, rval;
   const char *ipany = "0.0.0.0";
 
   SILC_LOG_DEBUG(("Creating TCP listener"));
@@ -179,14 +181,15 @@ silc_net_tcp_create_listener(const char **local_ip_addr,
     /* Create the socket */
     sock = socket(server.sin.sin_family, SOCK_STREAM, 0);
     if (sock == INVALID_SOCKET) {
-      SILC_LOG_ERROR(("Cannot create socket"));
+      SILC_LOG_ERROR(("Cannot create socket, error %d", WSAGetLastError()));
       goto err;
     }
 
     /* Set the socket options */
     rval = silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
     if (rval == SOCKET_ERROR) {
-      SILC_LOG_ERROR(("Cannot set socket options"));
+      SILC_LOG_ERROR(("Cannot set socket options, error %d",
+                    WSAGetLastError()));
       closesocket(sock);
       goto err;
     }
@@ -194,7 +197,7 @@ silc_net_tcp_create_listener(const char **local_ip_addr,
     /* Bind the listener socket */
     rval = bind(sock, &server.sa, SIZEOF_SOCKADDR(server));
     if (rval == SOCKET_ERROR) {
-      SILC_LOG_ERROR(("Cannot bind socket"));
+      SILC_LOG_ERROR(("Cannot bind socket, error %d", WSAGetLastError()));
       closesocket(sock);
       goto err;
     }
@@ -202,14 +205,12 @@ silc_net_tcp_create_listener(const char **local_ip_addr,
     /* Specify that we are listenning */
     rval = listen(sock, SOMAXCONN);
     if (rval == SOCKET_ERROR) {
-      SILC_LOG_ERROR(("Cannot set socket listenning"));
+      SILC_LOG_ERROR(("Cannot set socket listenning, error %d",
+                    WSAGetLastError()));
       closesocket(sock);
       goto err;
     }
 
-    /* Set the server socket to non-blocking mode.  Dunno if this works. */
-    silc_net_set_socket_nonblock(sock);
-
     /* Schedule for incoming connections */
     silc_schedule_task_add_fd(schedule, sock, silc_net_accept, listener);
 
@@ -234,6 +235,9 @@ void silc_net_close_listener(SilcNetListener listener)
 
   SILC_LOG_DEBUG(("Closing network listener"));
 
+  if (!listener)
+    return;
+
   for (i = 0; i < listener->socks_count; i++) {
     silc_schedule_task_del_by_fd(listener->schedule, listener->socks[i]);
     shutdown(listener->socks[i], 2);
@@ -301,9 +305,6 @@ silc_net_udp_connect(const char *local_ip_addr, int local_port,
     goto err;
   }
 
-  /* Set socket to non-blocking mode */
-  silc_net_set_socket_nonblock(sock);
-
   /* Set to connected state if remote address is provided. */
   if (remote_ip_addr && remote_port) {
     if (!silc_net_set_sockaddr(&server, remote_ip_addr, remote_port))
@@ -348,8 +349,10 @@ int silc_net_udp_receive(SilcStream stream, char *remote_ip_addr,
 
   if (remote_ip_addr && remote_port) {
     if (sock->ipv6) {
+#ifdef HAVE_IPV6
       from = (struct sockaddr *)&s.sin6;
       flen = sizeof(s.sin6);
+#endif /* HAVE_IPV6 */
     } else {
       from = (struct sockaddr *)&s.sin;
       flen = sizeof(s.sin);
@@ -380,13 +383,16 @@ int silc_net_udp_receive(SilcStream stream, char *remote_ip_addr,
   /* Return remote address */
   if (remote_ip_addr && remote_port) {
     if (sock->ipv6) {
+#ifdef HAVE_IPV6
       *remote_port = ntohs(s.sin6.sin6_port);
       inet_ntop(AF_INET6, &s.sin6.sin6_addr, remote_ip_addr,
                remote_ip_addr_size);
+#endif /* HAVE_IPV6 */
     } else {
+      const char *ip = inet_ntoa(s.sin.sin_addr);
+      if (ip)
+       silc_snprintf(remote_ip_addr, remote_ip_addr_size, ip);
       *remote_port = ntohs(s.sin.sin_port);
-      inet_ntop(AF_INET, &s.sin.sin_addr, remote_ip_addr,
-               remote_ip_addr_size);
     }
 
     SILC_LOG_DEBUG(("UDP packet from %s:%d", remote_ip_addr, *remote_port));
@@ -467,19 +473,20 @@ static void silc_net_connect_wait_stream(SilcSocketStreamStatus status,
                                         SilcStream stream, void *context)
 {
   SilcNetConnect conn = context;
+  conn->sop = NULL;
   conn->stream_status = status;
   conn->stream = stream;
-  SILC_FSM_CALL_CONTINUE(&conn->fsm);
+  SILC_FSM_CALL_CONTINUE(&conn->thread);
 }
 
 /* Start connecting.  Create a real thread where we connect. */
 
 SILC_FSM_STATE(silc_net_connect_st_thread)
 {
-  SilcNetConnect conn = context;
+  SilcNetConnect conn = fsm_context;
 
-  /* Connect in real thread as as to not block the application. */
-  silc_fsm_thread_init(&conn->thread, conn, NULL, NULL, TRUE);
+  /* Connect in real thread so as to not block the application. */
+  silc_fsm_thread_init(&conn->thread, fsm, conn, NULL, NULL, TRUE);
   silc_fsm_start(&conn->thread, silc_net_connect_st_start);
 
   /* Wait for the thread to finish */
@@ -505,7 +512,7 @@ SILC_FSM_STATE(silc_net_connect_st_start)
   if (!silc_net_gethostbyname(conn->remote, prefer_ipv6,
                              conn->ip_addr, sizeof(conn->ip_addr))) {
     SILC_LOG_ERROR(("Network (%s) unreachable: could not resolve the "
-                   "host", conn->remote));
+                   "host, error %d", conn->remote, WSAGetLastError()));
 
     /** Network unreachable */
     conn->status = SILC_NET_HOST_UNREACHABLE;
@@ -527,7 +534,7 @@ SILC_FSM_STATE(silc_net_connect_st_start)
     }
 
     /** Cannot create socket */
-    SILC_LOG_ERROR(("Cannot create socket"));
+    SILC_LOG_ERROR(("Cannot create socket, error %d", WSAGetLastError()));
     return SILC_FSM_FINISH;
   }
 
@@ -548,7 +555,7 @@ SILC_FSM_STATE(silc_net_connect_st_start)
       shutdown(sock, 2);
       closesocket(sock);
 
-      /* Retry using an IPv4 adress, if IPv6 didn't work */
+      /* Retry using an IPv4 address, if IPv6 didn't work */
       if (prefer_ipv6 && silc_net_is_ip6(conn->ip_addr)) {
        prefer_ipv6 = FALSE;
        goto retry;
@@ -568,7 +575,8 @@ SILC_FSM_STATE(silc_net_connect_st_start)
        break;
       }
 
-      SILC_LOG_ERROR(("Cannot connect to remote host"));
+      SILC_LOG_ERROR(("Cannot connect to remote host, error %d",
+                     WSAGetLastError()));
       return SILC_FSM_FINISH;
     }
   }
@@ -589,8 +597,8 @@ SILC_FSM_STATE(silc_net_connect_st_start)
   /** Connection created */
   silc_fsm_next(fsm, silc_net_connect_st_stream);
   SILC_FSM_CALL((conn->sop = silc_socket_tcp_stream_create(
-                                    conn->sock, FALSE, FALSE,
-                                    schedule,
+                                    conn->sock, TRUE, FALSE,
+                                    silc_fsm_get_schedule(&conn->fsm),
                                     silc_net_connect_wait_stream, conn)));
 }
 
@@ -615,11 +623,6 @@ SILC_FSM_STATE(silc_net_connect_st_stream)
     return SILC_FSM_FINISH;
   }
 
-  /* Set stream information */
-  silc_socket_stream_set_info(conn->stream,
-                             !silc_net_is_ip(conn->remote) ? conn->remote :
-                             conn->ip_addr, conn->ip_addr, conn->port);
-
   /** Stream created successfully */
   SILC_LOG_DEBUG(("Connected successfully, sock %d", conn->sock));
   conn->status = SILC_NET_OK;
@@ -635,8 +638,6 @@ SILC_FSM_STATE(silc_net_connect_st_finish)
     conn->callback(conn->status, conn->stream, conn->context);
     if (conn->op)
       silc_async_free(conn->op);
-    if (conn->sop)
-      silc_async_free(conn->sop);
   }
 
   return SILC_FSM_FINISH;
@@ -648,8 +649,10 @@ static void silc_net_connect_abort(SilcAsyncOperation op, void *context)
   conn->aborted = TRUE;
 
   /* Abort underlaying stream creation too */
-  if (conn->sop)
+  if (conn->sop) {
     silc_async_abort(conn->sop, NULL, NULL);
+    conn->sop = NULL;
+  }
 }
 
 static void silc_net_connect_destructor(SilcFSM fsm, void *fsm_context,
@@ -727,18 +730,39 @@ void silc_net_close_connection(int sock)
 
 SilcBool silc_net_addr2bin(const char *addr, void *bin, SilcUInt32 bin_len)
 {
-  unsigned long ret;
-
   if (silc_net_is_ip4(addr)) {
     /* IPv4 address */
-    ret = inet_addr(addr);
+    int i = 0, c = 0, d = 0, len = strlen(addr);
+    unsigned char ret[4];
+
+    memset(ret, 0, sizeof(ret));
+    while (len-- > 0) {
+      if (addr[i++] == '.') {
+       ret[c++] = d;
+       d = 0;
+       if (c > 3)
+         return FALSE;
+       continue;
+      }
+
+      if (!isdigit((int)addr[i - 1]))
+       return FALSE;
 
-    if (bin_len < 4)
+      d = 10 * d + addr[i - 1] - '0';
+      if (d > 255)
+       return FALSE;
+    }
+    if (c != 3)
       return FALSE;
+    ret[c] = d;
 
-    memcpy(bin, (unsigned char *)&ret, 4);
-    return ret != INADDR_NONE;
+    if (bin_len < sizeof(ret))
+      return FALSE;
+
+    memcpy(bin, ret, sizeof(ret));
+    return TRUE;
   } else {
+#ifdef HAVE_IPV6
     struct addrinfo hints, *ai;
     SilcSockaddr *s;
 
@@ -758,42 +782,16 @@ SilcBool silc_net_addr2bin(const char *addr, void *bin, SilcUInt32 bin_len)
     }
 
     return TRUE;
+#else
+    return FALSE;
+#endif /* HAVE_IPV6 */
   }
 }
 
 /* Set socket to non-blocking mode. */
 
-int silc_net_set_socket_nonblock(int sock)
+int silc_net_set_socket_nonblock(SilcSocket sock)
 {
   unsigned long on = 1;
   return ioctlsocket(sock, FIONBIO, &on);
 }
-
-/* Init Winsock2. */
-
-SilcBool silc_net_win32_init(void)
-{
-  int ret, sopt = SO_SYNCHRONOUS_NONALERT;
-  WSADATA wdata;
-  WORD ver = MAKEWORD(1, 1);
-
-  ret = WSAStartup(ver, &wdata);
-  if (ret)
-    return FALSE;
-
-  /* Allow using the SOCKET's as file descriptors so that we can poll
-     them with SILC Scheduler. */
-  ret = setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *)&sopt,
-                  sizeof(sopt));
-  if (ret)
-    return FALSE;
-
-  return TRUE;
-}
-
-/* Uninit Winsock2 */
-
-void silc_net_win32_uninit(void)
-{
-  WSACleanup();
-}