fixed WIN32 compatibility (use old connect function without IPv6 and bind support)
[NeonServV5.git] / src / ClientSocket.c
index 898b05fb2a9dc3a0ac27f0597f62e0cb85f39493..db93f9a114236a64b6dc444c66a670ceb058a433 100644 (file)
@@ -22,6 +22,7 @@
 #include "WHOHandler.h"
 #include "HandleInfoHandler.h"
 #include "ssl.h"
+#include "ConfigParser.h"
 
 struct socket_list {
     struct ClientSocket *data;
@@ -43,7 +44,7 @@ static void init_sockets() {
     sockets->count = 0;
 }
 
-struct ClientSocket* create_socket(char *host, int port, char *pass, char *nick, char *ident, char *realname) {
+struct ClientSocket* create_socket(char *host, int port, char *bindto, char *pass, char *nick, char *ident, char *realname) {
     if(sockets == NULL) init_sockets();
     struct ClientSocket *client = malloc(sizeof(*client));
     if (!client)
@@ -53,7 +54,7 @@ struct ClientSocket* create_socket(char *host, int port, char *pass, char *nick,
     }
     client->host = strdup(host);
     client->port = port;
-    printf("Connect: %s:%d\n", client->host, client->port);
+    client->bind = (bindto ? strdup(bindto) : NULL);
     client->pass = (pass == NULL ? NULL : strdup(pass));
     client->nick = strdup(nick);
     client->ident = strdup(ident);
@@ -76,51 +77,120 @@ struct ClientSocket* create_socket(char *host, int port, char *pass, char *nick,
     return client;
 }
 
-#ifdef WIN32
-
+#ifndef WIN32
 int connect_socket(struct ClientSocket *client) {
     if((client->flags & SOCKET_FLAG_CONNECTED)) return 1;
-    struct hostent *host;
-    struct sockaddr_in addr;
     int sock;
-    addr.sin_addr.s_addr = inet_addr(client->host);
-    if (addr.sin_addr.s_addr == INADDR_NONE) {
-        host = gethostbyname(client->host);
-        if(!host) {
-            return SOCKET_ERROR;
-        }
-        memcpy(&(addr.sin_addr), host->h_addr_list[0], 4);
-    }
-    sock = socket(PF_INET, SOCK_STREAM, 0);
-    if (sock == -1)
-    {
-        perror("socket() failed");
+    
+    struct addrinfo hints, *res;
+    struct sockaddr_in *ip4 = NULL;
+    struct sockaddr_in6 *ip6 = NULL;
+    memset (&hints, 0, sizeof (hints));
+    hints.ai_family = PF_UNSPEC;
+    hints.ai_socktype = SOCK_STREAM;
+    hints.ai_flags |= AI_CANONNAME;
+    if (getaddrinfo (client->host, NULL, &hints, &res)) {
         return 0;
     }
-
-    addr.sin_port = htons(client->port);
-    addr.sin_family = AF_INET;
-
-    if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) == -1)
-    {
-        perror("connect() failed");
+    while (res) {
+        switch (res->ai_family) {
+        case AF_INET:
+            ip4 = (struct sockaddr_in *) res->ai_addr;
+            break;
+        case AF_INET6:
+            ip6 = (struct sockaddr_in6 *) res->ai_addr;
+            break;
+        }
+        res = res->ai_next;
+    }
+    
+    if(ip6) {
+        sock = socket(AF_INET6, SOCK_STREAM, 0);
+        if(sock == -1) {
+            perror("socket() failed");
+            return 0;
+        }
+        
+        ip6->sin6_family = AF_INET6;
+        ip6->sin6_port = htons(client->port);
+        
+        struct sockaddr_in6 *ip6vhost = NULL;
+        if (client->bind && !getaddrinfo(client->bind, NULL, &hints, &res)) {
+            while (res) {
+                switch (res->ai_family) {
+                case AF_INET6:
+                    ip6vhost = (struct sockaddr_in6 *) res->ai_addr;
+                    break;
+                }
+                res = res->ai_next;
+            }
+        }
+        if(ip6vhost) {
+            ip6vhost->sin6_family = AF_INET6;
+            ip6vhost->sin6_port = htons(0);
+            bind(sock, (struct sockaddr*)ip6vhost, sizeof(*ip6vhost));
+        }
+        
+        if (connect(sock, (struct sockaddr*)ip6, sizeof(*ip6)) == -1) {
+            perror("connect() failed");
+            return 0;
+        }
+        
+    } else if(ip4) {
+        sock = socket(AF_INET, SOCK_STREAM, 0);
+        if(sock == -1) {
+            perror("socket() failed");
+            return 0;
+        }
+        
+        ip4->sin_family = AF_INET;
+        ip4->sin_port = htons(client->port);
+        
+        struct sockaddr_in *ip4vhost = NULL;
+        if (client->bind && !getaddrinfo(client->bind, NULL, &hints, &res)) {
+            while (res) {
+                switch (res->ai_family) {
+                case AF_INET:
+                    ip4vhost = (struct sockaddr_in *) res->ai_addr;
+                    break;
+                }
+                res = res->ai_next;
+            }
+        }
+        if(ip4vhost) {
+            ip4vhost->sin_family = AF_INET;
+            ip4vhost->sin_port = htons(0);
+            bind(sock, (struct sockaddr*)ip4vhost, sizeof(*ip4vhost));
+        }
+        
+        if (connect(sock, (struct sockaddr*)ip4, sizeof(*ip4)) == -1) {
+            perror("connect() failed");
+            return 0;
+        }
+        
+    } else
         return 0;
+    
+    if(get_int_field("Sockets.NoDelay")) {
+        int flag = 1;
+        if(setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int)) == -1) {
+            perror("setsockopt() failed");
+            return 0;
+        }
     }
-
+    
     client->sock = sock;
     client->flags |= SOCKET_FLAG_CONNECTED | SOCKET_FLAG_RECONNECT;
     client->connection_time = time(0);
-
-
+    
     if(client->flags & SOCKET_FLAG_SSL) {
         ssl_connect(client);
     }
-
-
+    
     //send the IRC Headers
     char sendBuf[512];
     int len;
-
+    
     if(client->pass && strcmp(client->pass, "")) {
         len = sprintf(sendBuf, "PASS :%s\n", client->pass);
         write_socket(client, sendBuf, len);
@@ -129,26 +199,22 @@ int connect_socket(struct ClientSocket *client) {
     write_socket(client, sendBuf, len);
     len = sprintf(sendBuf, "NICK %s\n", client->nick);
     write_socket(client, sendBuf, len);
-
+    
     return 1;
 }
-
 #else
-
 int connect_socket(struct ClientSocket *client) {
     if((client->flags & SOCKET_FLAG_CONNECTED)) return 1;
     struct hostent *host;
     struct sockaddr_in addr;
     int sock;
-    if (!inet_aton(client->host, &addr.sin_addr))
-    {
+    addr.sin_addr.s_addr = inet_addr(client->host);
+    if (addr.sin_addr.s_addr == INADDR_NONE) {
         host = gethostbyname(client->host);
-        if (!host)
-        {
-            perror("gethostbyname() failed");
-            return 0;
+        if(!host) {
+            return SOCKET_ERROR;
         }
-        addr.sin_addr = *(struct in_addr*)host->h_addr;
+        memcpy(&(addr.sin_addr), host->h_addr_list[0], 4);
     }
     sock = socket(PF_INET, SOCK_STREAM, 0);
     if (sock == -1)
@@ -170,10 +236,12 @@ int connect_socket(struct ClientSocket *client) {
     client->flags |= SOCKET_FLAG_CONNECTED | SOCKET_FLAG_RECONNECT;
     client->connection_time = time(0);
 
+
     if(client->flags & SOCKET_FLAG_SSL) {
         ssl_connect(client);
     }
 
+
     //send the IRC Headers
     char sendBuf[512];
     int len;
@@ -186,10 +254,9 @@ int connect_socket(struct ClientSocket *client) {
     write_socket(client, sendBuf, len);
     len = sprintf(sendBuf, "NICK %s\n", client->nick);
     write_socket(client, sendBuf, len);
-    
+
     return 1;
 }
-
 #endif
 
 int close_socket(struct ClientSocket *client) {
@@ -216,7 +283,10 @@ int close_socket(struct ClientSocket *client) {
     if(client->handleinfo_first)
         clear_handleinfoqueue(client);
     free(client->host);
-    free(client->pass);
+    if(client->bind)
+        free(client->bind);
+    if(client->pass)
+        free(client->pass);
     free(client);
     return 1;
 }
@@ -357,7 +427,10 @@ void free_sockets() {
         if(client->queue)
             queue_destroy(client);
         free(client->host);
-        free(client->pass);
+        if(client->bind)
+            free(client->bind);
+        if(client->pass)
+            free(client->pass);
         free(client);
     }
     free(sockets);