updates.
[silc.git] / lib / silcutil / unix / silcunixnet.c
index de1b1e339f9e5db90238f24ca8462797fa194322..72d47641fe8777299ffdc9ca80ba35735d0f5ac9 100644 (file)
@@ -28,7 +28,7 @@
    If argument `ip_addr' is NULL `any' address will be used. Returns 
    the created socket or -1 on error. */
 
-int silc_net_create_server(int port, char *ip_addr)
+int silc_net_create_server(int port, const char *ip_addr)
 {
   int sock, rval;
   struct sockaddr_in server;
@@ -37,7 +37,7 @@ int silc_net_create_server(int port, char *ip_addr)
   SILC_LOG_DEBUG(("Creating a new server listener"));
 
   /* Create the socket */
-  sock = socket(PF_INET, SOCK_STREAM, 0);
+  sock = socket(AF_INET, SOCK_STREAM, 0);
   if (sock < 0) {
     SILC_LOG_ERROR(("Cannot create socket: %s", strerror(errno)));
     return -1;
@@ -52,20 +52,21 @@ int silc_net_create_server(int port, char *ip_addr)
 
   /* Set the socket information for bind() */
   memset(&server, 0, sizeof(server));
-  server.sin_family = PF_INET;
+  server.sin_family = AF_INET;
   if (port)
     server.sin_port = htons(port);
 
   /* Convert IP address to network byte order */
-  if (ip_addr)
+  if (ip_addr) {
     silc_net_addr2bin(ip_addr, (unsigned char *)&server.sin_addr.s_addr, len);
+  }
   else
     server.sin_addr.s_addr = INADDR_ANY;
 
   /* Bind the server socket */
   rval = bind(sock, (struct sockaddr *)&server, sizeof(server));
   if (rval < 0) {
-    SILC_LOG_ERROR(("Cannot bind socket: %s", strerror(errno)));
+    SILC_LOG_DEBUG(("Cannot bind socket: %s", strerror(errno)));
     return -1;
   }
 
@@ -98,7 +99,8 @@ void silc_net_close_server(int sock)
    socket or -1 on error. This blocks the process while trying to create
    the connection. */
 
-int silc_net_create_connection(int port, char *host)
+int silc_net_create_connection(const char *local_ip, int port, 
+                              const char *host)
 {
   int sock, rval;
   struct hostent *dest;
@@ -109,23 +111,46 @@ int silc_net_create_connection(int port, char *host)
   /* Do host lookup */
   dest = gethostbyname(host);
   if (!dest) {
-    SILC_LOG_ERROR(("Network (%s) unreachable", host));
+    SILC_LOG_ERROR(("Network (%s) unreachable: could not resolve the "
+                   "IP address", host));
     return -1;
   }
 
   /* Set socket information */
   memset(&desthost, 0, sizeof(desthost));
   desthost.sin_port = htons(port);
-  desthost.sin_family = PF_INET;
+  desthost.sin_family = AF_INET;
   memcpy(&desthost.sin_addr, dest->h_addr_list[0], sizeof(desthost.sin_addr));
 
   /* Create the connection socket */
-  sock = socket(PF_INET, SOCK_STREAM, 0);
+  sock = socket(AF_INET, SOCK_STREAM, 0);
   if (sock < 0) {
     SILC_LOG_ERROR(("Cannot create socket: %s", strerror(errno)));
     return -1;
   }
 
+  /* Bind to the local address if provided */
+  if (local_ip) {
+    struct sockaddr_in local;
+    int local_len = sizeof(local.sin_addr);
+
+    /* Set the socket information for bind() */
+    memset(&local, 0, sizeof(local));
+    local.sin_family = AF_INET;
+
+    /* Convert IP address to network byte order */
+    silc_net_addr2bin(local_ip, (unsigned char *)&local.sin_addr.s_addr, 
+                     local_len);
+
+    /* Bind the local socket */
+    rval = bind(sock, (struct sockaddr *)&local, sizeof(local));
+    if (rval < 0) {
+      SILC_LOG_ERROR(("Cannot connect to remote host: "
+                     "cannot bind socket: %s", strerror(errno)));
+      return -1;
+    }
+  }
+
   /* Connect to the host */
   rval = connect(sock, (struct sockaddr *)&desthost, sizeof(desthost));
   if (rval < 0) {
@@ -136,7 +161,9 @@ int silc_net_create_connection(int port, char *host)
   }
 
   /* Set appropriate options */
+#if defined(TCP_NODELAY)
   silc_net_set_socket_opt(sock, IPPROTO_TCP, TCP_NODELAY, 1);
+#endif
   silc_net_set_socket_opt(sock, SOL_SOCKET, SO_KEEPALIVE, 1);
 
   SILC_LOG_DEBUG(("Connection created"));
@@ -149,7 +176,8 @@ int silc_net_create_connection(int port, char *host)
    connection returns directly. To get the result of the connect() one
    must select() the socket and read the result after it's ready. */
 
-int silc_net_create_connection_async(int port, char *host)
+int silc_net_create_connection_async(const char *local_ip, int port, 
+                                    const char *host)
 {
   int sock, rval;
   struct hostent *dest;
@@ -161,23 +189,46 @@ int silc_net_create_connection_async(int port, char *host)
   /* Do host lookup */
   dest = gethostbyname(host);
   if (!dest) {
-    SILC_LOG_ERROR(("Network (%s) unreachable", host));
+    SILC_LOG_ERROR(("Network (%s) unreachable: could not resolve the "
+                   "IP address", host));
     return -1;
   }
 
   /* Set socket information */
   memset(&desthost, 0, sizeof(desthost));
   desthost.sin_port = htons(port);
-  desthost.sin_family = PF_INET;
+  desthost.sin_family = AF_INET;
   memcpy(&desthost.sin_addr, dest->h_addr_list[0], sizeof(desthost.sin_addr));
 
   /* Create the connection socket */
-  sock = socket(PF_INET, SOCK_STREAM, 0);
+  sock = socket(AF_INET, SOCK_STREAM, 0);
   if (sock < 0) {
     SILC_LOG_ERROR(("Cannot create socket: %s", strerror(errno)));
     return -1;
   }
 
+  /* Bind to the local address if provided */
+  if (local_ip) {
+    struct sockaddr_in local;
+    int local_len = sizeof(local.sin_addr);
+
+    /* Set the socket information for bind() */
+    memset(&local, 0, sizeof(local));
+    local.sin_family = AF_INET;
+
+    /* Convert IP address to network byte order */
+    silc_net_addr2bin(local_ip, (unsigned char *)&local.sin_addr.s_addr, 
+                     local_len);
+
+    /* Bind the local socket */
+    rval = bind(sock, (struct sockaddr *)&local, sizeof(local));
+    if (rval < 0) {
+      SILC_LOG_ERROR(("Cannot connect to remote host: "
+                     "cannot bind socket: %s", strerror(errno)));
+      return -1;
+    }
+  }
+
   /* Set the socket to non-blocking mode */
   silc_net_set_socket_nonblock(sock);
 
@@ -193,7 +244,9 @@ int silc_net_create_connection_async(int port, char *host)
   }
 
   /* Set appropriate options */
+#if defined(TCP_NODELAY)
   silc_net_set_socket_opt(sock, IPPROTO_TCP, TCP_NODELAY, 1);
+#endif
   silc_net_set_socket_opt(sock, SOL_SOCKET, SO_KEEPALIVE, 1);
 
   SILC_LOG_DEBUG(("Connection operation in progress"));
@@ -218,8 +271,7 @@ int silc_net_set_socket_nonblock(int sock)
 /* Converts the IP number string from numbers-and-dots notation to
    binary form. */
 
-bool silc_net_addr2bin(const char *addr, unsigned char *bin,
-                      uint32 bin_len)
+bool silc_net_addr2bin(const char *addr, void *bin, uint32 bin_len)
 {
   struct in_addr tmp;
   int ret;
@@ -229,7 +281,6 @@ bool silc_net_addr2bin(const char *addr, unsigned char *bin,
   if (bin_len < 4)
     return FALSE;
 
-  SILC_PUT32_LSB(tmp.s_addr, bin);
-
+  memcpy(bin, (unsigned char *)&tmp.s_addr, 4);
   return ret != 0;
 }