Merged silc_1_1_branch to trunk.
[silc.git] / lib / silcutil / unix / silcunixnet.c
index f7ddb18db0449e86f623301246c150b295856dc2..e0befdc19979ca325a83cd39b6da9015e34a28f8 100644 (file)
@@ -21,6 +21,8 @@
 #include "silc.h"
 #include "silcnet.h"
 
+/************************** Types and definitions ***************************/
+
 #ifdef HAVE_IPV6
 #define SIZEOF_SOCKADDR(so) ((so).sa.sa_family == AF_INET6 ?   \
   sizeof(so.sin6) : sizeof(so.sin))
@@ -36,6 +38,8 @@ typedef union {
 #endif
 } SilcSockaddr;
 
+/************************ Static utility functions **************************/
+
 static SilcBool silc_net_set_sockaddr(SilcSockaddr *addr, const char *ip_addr,
                                      int port)
 {
@@ -81,6 +85,8 @@ static SilcBool silc_net_set_sockaddr(SilcSockaddr *addr, const char *ip_addr,
   return TRUE;
 }
 
+/****************************** TCP Listener ********************************/
+
 /* Deliver new stream to upper layer */
 
 static void silc_net_accept_stream(SilcSocketStreamStatus status,
@@ -108,7 +114,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 */
@@ -137,10 +142,8 @@ silc_net_tcp_create_listener(const char **local_ip_addr,
     goto err;
 
   listener = silc_calloc(1, sizeof(*listener));
-  if (!listener) {
-    callback(SILC_NET_NO_MEMORY, NULL, context);
+  if (!listener)
     return NULL;
-  }
   listener->schedule = schedule;
   listener->callback = callback;
   listener->context = context;
@@ -149,24 +152,20 @@ silc_net_tcp_create_listener(const char **local_ip_addr,
 
   if (local_ip_count > 0) {
     listener->socks = silc_calloc(local_ip_count, sizeof(*listener->socks));
-    if (!listener->socks) {
-      callback(SILC_NET_NO_MEMORY, NULL, context);
+    if (!listener->socks)
       return NULL;
-    }
   } else {
     listener->socks = silc_calloc(1, sizeof(*listener->socks));
-    if (!listener->socks) {
-      callback(SILC_NET_NO_MEMORY, NULL, context);
+    if (!listener->socks)
       return NULL;
-    }
 
     local_ip_count = 1;
   }
 
   /* Bind to local addresses */
   for (i = 0; i < local_ip_count; i++) {
-    SILC_LOG_DEBUG(("Binding to local address %s",
-                   local_ip_addr ? local_ip_addr[i] : ipany));
+    SILC_LOG_DEBUG(("Binding to local address %s:%d",
+                   local_ip_addr ? local_ip_addr[i] : ipany, port));
 
     /* Set sockaddr for server */
     if (!silc_net_set_sockaddr(&server,
@@ -185,13 +184,15 @@ silc_net_tcp_create_listener(const char **local_ip_addr,
     rval = silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
     if (rval < 0) {
       SILC_LOG_ERROR(("Cannot set socket options: %s", strerror(errno)));
+      close(sock);
       goto err;
     }
 
     /* Bind the listener socket */
     rval = bind(sock, &server.sa, SIZEOF_SOCKADDR(server));
     if (rval < 0) {
-      SILC_LOG_DEBUG(("Cannot bind socket: %s", strerror(errno)));
+      SILC_LOG_ERROR(("Cannot bind socket: %s", strerror(errno)));
+      close(sock);
       goto err;
     }
 
@@ -199,6 +200,7 @@ silc_net_tcp_create_listener(const char **local_ip_addr,
     rval = listen(sock, 64);
     if (rval < 0) {
       SILC_LOG_ERROR(("Cannot set socket listenning: %s", strerror(errno)));
+      close(sock);
       goto err;
     }
 
@@ -216,8 +218,6 @@ silc_net_tcp_create_listener(const char **local_ip_addr,
   return listener;
 
  err:
-  if (callback)
-    callback(SILC_NET_ERROR, NULL, context);
   if (listener)
     silc_net_close_listener(listener);
   return NULL;
@@ -241,6 +241,8 @@ void silc_net_close_listener(SilcNetListener listener)
   silc_free(listener);
 }
 
+/******************************* UDP Stream *********************************/
+
 /* Create UDP stream */
 
 SilcStream
@@ -295,9 +297,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))
@@ -312,17 +311,23 @@ silc_net_udp_connect(const char *local_ip_addr, int local_port,
 
   /* Set send and receive buffer size */
 #ifdef SO_SNDBUF
-  rval = silc_net_set_socket_opt(sock, SOL_SOCKET, SO_SNDBUF, 65535);
+  rval = silc_net_set_socket_opt(sock, SOL_SOCKET, SO_SNDBUF, 765535);
   if (rval < 0) {
-    SILC_LOG_ERROR(("Cannot set socket options: %s", strerror(errno)));
-    goto err;
+    rval = silc_net_set_socket_opt(sock, SOL_SOCKET, SO_SNDBUF, 65535);
+    if (rval < 0) {
+      SILC_LOG_ERROR(("Cannot set socket options: %s", strerror(errno)));
+      goto err;
+    }
   }
 #endif /* SO_SNDBUF */
 #ifdef SO_RCVBUF
-  rval = silc_net_set_socket_opt(sock, SOL_SOCKET, SO_RCVBUF, 65535);
+  rval = silc_net_set_socket_opt(sock, SOL_SOCKET, SO_RCVBUF, 765535);
   if (rval < 0) {
-    SILC_LOG_ERROR(("Cannot set socket options: %s", strerror(errno)));
-    goto err;
+    rval = silc_net_set_socket_opt(sock, SOL_SOCKET, SO_RCVBUF, 65535);
+    if (rval < 0) {
+      SILC_LOG_ERROR(("Cannot set socket options: %s", strerror(errno)));
+      goto err;
+    }
   }
 #endif /* SO_RCVBUF */
 
@@ -446,6 +451,8 @@ int silc_net_udp_send(SilcStream stream,
   return ret;
 }
 
+/******************************* TCP Stream *********************************/
+
 /* Asynchronous TCP/IP connecting */
 
 typedef struct {
@@ -476,7 +483,6 @@ SILC_TASK_CALLBACK(silc_net_connect_wait)
 {
   SilcNetConnect conn = context;
   SILC_FSM_EVENT_SIGNAL(&conn->event);
-  silc_schedule_task_del_by_fd(schedule, conn->sock);
 }
 
 SILC_FSM_STATE(silc_net_connect_st_start)
@@ -544,18 +550,15 @@ SILC_FSM_STATE(silc_net_connect_st_start)
   rval = connect(sock, &desthost.sa, SIZEOF_SOCKADDR(desthost));
   if (rval < 0) {
     if (errno != EINPROGRESS) {
-      /* retry using an IPv4 adress, if IPv6 didn't work */
-      if (prefer_ipv6 && silc_net_is_ip6(conn->ip_addr)) {
-        shutdown(sock, 2);
-        close(sock);
+      shutdown(sock, 2);
+      close(sock);
 
+      /* Retry using an IPv4 adress, if IPv6 didn't work */
+      if (prefer_ipv6 && silc_net_is_ip6(conn->ip_addr)) {
         prefer_ipv6 = FALSE;
         goto retry;
       }
 
-      shutdown(sock, 2);
-      close(sock);
-
       /** Cannot connect to remote host */
       SILC_LOG_ERROR(("Cannot connect to remote host: %s", strerror(errno)));
       silc_fsm_next(fsm, silc_net_connect_st_finish);
@@ -588,6 +591,7 @@ 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);
@@ -601,6 +605,8 @@ SILC_FSM_STATE(silc_net_connect_st_connected)
 
   if (conn->aborted) {
     /** Aborted */
+    silc_schedule_unset_listen_fd(schedule, conn->sock);
+    silc_schedule_task_del_by_fd(schedule, conn->sock);
     silc_fsm_next(fsm, silc_net_connect_st_finish);
     return SILC_FSM_CONTINUE;
   }
@@ -608,8 +614,8 @@ SILC_FSM_STATE(silc_net_connect_st_connected)
   ret = silc_net_get_socket_opt(conn->sock, SOL_SOCKET, SO_ERROR,
                                &opt, &optlen);
 
-  silc_schedule_task_del_by_fd(schedule, conn->sock);
   silc_schedule_unset_listen_fd(schedule, conn->sock);
+  silc_schedule_task_del_by_fd(schedule, conn->sock);
 
   if (ret != 0 || opt != 0) {
     if (conn->retry) {
@@ -622,29 +628,30 @@ SILC_FSM_STATE(silc_net_connect_st_connected)
     }
 
 #if defined(ECONNREFUSED)
-    if (errno == ECONNREFUSED)
+    if (opt == ECONNREFUSED)
       conn->status = SILC_NET_CONNECTION_REFUSED;
 #endif /* ECONNREFUSED */
 #if defined(ETIMEDOUT)
-    if (errno == ETIMEDOUT)
+    if (opt == ETIMEDOUT)
       conn->status = SILC_NET_CONNECTION_TIMEOUT;
 #endif /* ETIMEDOUT */
 #if defined(ENETUNREACH)
-    if (errno == ENETUNREACH)
+    if (opt == ENETUNREACH)
       conn->status = SILC_NET_HOST_UNREACHABLE;
 #endif /* ENETUNREACH */
 
     /** Connecting failed */
-    SILC_LOG_DEBUG(("Connecting failed"));
+    SILC_LOG_DEBUG(("Connecting failed, error %s", strerror(opt)));
     silc_fsm_next(fsm, silc_net_connect_st_finish);
     return SILC_FSM_CONTINUE;
   }
 
+  SILC_LOG_DEBUG(("TCP connection established"));
+
   /** 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, schedule,
                                     silc_net_connect_wait_stream, conn)));
 }
 
@@ -670,11 +677,6 @@ SILC_FSM_STATE(silc_net_connect_st_stream)
     return SILC_FSM_CONTINUE;
   }
 
-  /* 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;
@@ -691,8 +693,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;
@@ -704,8 +704,10 @@ static void silc_net_connect_abort(SilcAsyncOperation op, void *context)
   conn->aborted = TRUE;
 
   /* Abort underlaying stream creation too */
-  if (conn->sop)
-    silc_async_abort(conn->op, NULL, NULL);
+  if (conn->sop) {
+    silc_async_abort(conn->sop, NULL, NULL);
+    conn->sop = NULL;
+  }
 }
 
 static void silc_net_connect_destructor(SilcFSM fsm, void *fsm_context,