updates.
[silc.git] / lib / silcutil / unix / silcunixnet.c
index 7b2ef02dcd0bc550be79cb8e238270b2cdd443ba..4a97ee314e7daf765d4101cf9b70b1d6f1f749ef 100644 (file)
@@ -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,7 +52,7 @@ 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);
 
@@ -84,6 +84,8 @@ int silc_net_create_server(int port, char *ip_addr)
   return sock;
 }
 
+/* Closes the server by closing the socket connection. */
+
 void silc_net_close_server(int sock)
 {
   shutdown(sock, 2);
@@ -96,7 +98,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;
@@ -107,23 +110,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) {
@@ -134,7 +160,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"));
@@ -147,7 +175,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;
@@ -159,23 +188,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);
 
@@ -191,7 +243,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"));
@@ -199,7 +253,7 @@ int silc_net_create_connection_async(int port, char *host)
   return sock;
 }
 
-/* Closes the connection */
+/* Closes the connection by closing the socket connection. */
 
 void silc_net_close_connection(int sock)
 {
@@ -231,3 +285,22 @@ bool silc_net_addr2bin(const char *addr, unsigned char *bin,
 
   return ret != 0;
 }
+
+/* Converts the IP number string from numbers-and-dots notation to
+   binary form in network byte order. */
+
+bool silc_net_addr2bin_ne(const char *addr, unsigned char *bin,
+                         uint32 bin_len)
+{
+  struct in_addr tmp;
+  int ret;
+
+  ret = inet_aton(addr, &tmp);
+
+  if (bin_len < 4)
+    return FALSE;
+
+  SILC_PUT32_MSB(tmp.s_addr, bin);
+
+  return ret != 0;
+}