added experimental multi thread support
[NeonServV5.git] / src / ClientSocket.c
1 /* ClientSocket.c - NeonServ v5.3
2  * Copyright (C) 2011-2012  Philipp Kreil (pk910)
3  * 
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  * 
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  * 
14  * You should have received a copy of the GNU General Public License 
15  * along with this program. If not, see <http://www.gnu.org/licenses/>. 
16  */
17
18 #include "ClientSocket.h"
19 #include "IRCParser.h"
20 #include "UserNode.h"
21 #include "IRCQueue.h"
22 #include "WHOHandler.h"
23 #include "HandleInfoHandler.h"
24 #include "ssl.h"
25 #include "ConfigParser.h"
26 #include "version.h"
27
28 struct socket_list {
29     struct ClientSocket *data;
30     unsigned count;
31 };
32
33 #ifdef HAVE_THREADS
34 static pthread_mutex_t synchronized;
35 #endif
36
37 //the magic list :P
38 static struct socket_list *sockets = NULL;
39 static char buffer[BUF_SIZ];
40
41 void init_sockets() {
42     THREAD_MUTEX_INIT(synchronized);
43     
44     sockets = malloc(sizeof(*sockets));
45     if (!sockets)
46     {
47         perror("malloc() failed");
48         return;
49     }
50     sockets->data = NULL;
51     sockets->count = 0;
52 }
53
54 struct ClientSocket* create_socket(char *host, int port, char *bindto, char *pass, char *nick, char *ident, char *realname) {
55     struct ClientSocket *client = malloc(sizeof(*client));
56     if (!client)
57     {
58         perror("malloc() failed");
59         return NULL;
60     }
61     client->host = strdup(host);
62     client->port = port;
63     client->bind = (bindto ? strdup(bindto) : NULL);
64     client->pass = (pass == NULL ? NULL : strdup(pass));
65     client->nick = strdup(nick);
66     client->ident = strdup(ident);
67     client->realname = strdup(realname);
68     client->user = NULL;
69     client->flags = 0;
70     client->bufferpos = 0;
71     client->traffic_in = 0;
72     client->traffic_out = 0;
73     client->connection_time = 0;
74         client->botid = 0;
75     client->clientid = 0;
76     client->queue = NULL;
77     client->whoqueue_first = NULL;
78     client->whoqueue_last = NULL;
79     client->handleinfo_first = NULL;
80     client->handleinfo_last = NULL;
81     SYNCHRONIZE(synchronized);
82     client->next = sockets->data;
83     sockets->data = client;
84     DESYNCHRONIZE(synchronized);
85     return client;
86 }
87
88 static int _connect_socket(struct ClientSocket *client);
89
90 int connect_socket(struct ClientSocket *client) {
91     SYNCHRONIZE(synchronized);
92     int ret = _connect_socket(client);
93     DESYNCHRONIZE(synchronized);
94     return ret;
95 }
96
97 #ifndef WIN32
98 static int _connect_socket(struct ClientSocket *client) {
99     if((client->flags & SOCKET_FLAG_CONNECTED)) return 1;
100     int sock;
101     
102     struct addrinfo hints, *res;
103     struct sockaddr_in *ip4 = NULL;
104     struct sockaddr_in6 *ip6 = NULL;
105     memset (&hints, 0, sizeof (hints));
106     hints.ai_family = PF_UNSPEC;
107     hints.ai_socktype = SOCK_STREAM;
108     hints.ai_flags |= AI_CANONNAME;
109     if (getaddrinfo (client->host, NULL, &hints, &res)) {
110         return 0;
111     }
112     while (res) {
113         switch (res->ai_family) {
114         case AF_INET:
115             ip4 = (struct sockaddr_in *) res->ai_addr;
116             break;
117         case AF_INET6:
118             ip6 = (struct sockaddr_in6 *) res->ai_addr;
119             break;
120         }
121         res = res->ai_next;
122     }
123     
124     if(ip6) {
125         sock = socket(AF_INET6, SOCK_STREAM, 0);
126         if(sock == -1) {
127             perror("socket() failed");
128             return 0;
129         }
130         
131         ip6->sin6_family = AF_INET6;
132         ip6->sin6_port = htons(client->port);
133         
134         struct sockaddr_in6 *ip6vhost = NULL;
135         if (client->bind && !getaddrinfo(client->bind, NULL, &hints, &res)) {
136             while (res) {
137                 switch (res->ai_family) {
138                 case AF_INET6:
139                     ip6vhost = (struct sockaddr_in6 *) res->ai_addr;
140                     break;
141                 }
142                 res = res->ai_next;
143             }
144         }
145         if(ip6vhost) {
146             ip6vhost->sin6_family = AF_INET6;
147             ip6vhost->sin6_port = htons(0);
148             bind(sock, (struct sockaddr*)ip6vhost, sizeof(*ip6vhost));
149         }
150         
151         if (connect(sock, (struct sockaddr*)ip6, sizeof(*ip6)) == -1) {
152             perror("connect() failed");
153             return 0;
154         }
155         
156     } else if(ip4) {
157         sock = socket(AF_INET, SOCK_STREAM, 0);
158         if(sock == -1) {
159             perror("socket() failed");
160             return 0;
161         }
162         
163         ip4->sin_family = AF_INET;
164         ip4->sin_port = htons(client->port);
165         
166         struct sockaddr_in *ip4vhost = NULL;
167         if (client->bind && !getaddrinfo(client->bind, NULL, &hints, &res)) {
168             while (res) {
169                 switch (res->ai_family) {
170                 case AF_INET:
171                     ip4vhost = (struct sockaddr_in *) res->ai_addr;
172                     break;
173                 }
174                 res = res->ai_next;
175             }
176         }
177         if(ip4vhost) {
178             ip4vhost->sin_family = AF_INET;
179             ip4vhost->sin_port = htons(0);
180             bind(sock, (struct sockaddr*)ip4vhost, sizeof(*ip4vhost));
181         }
182         
183         if (connect(sock, (struct sockaddr*)ip4, sizeof(*ip4)) == -1) {
184             perror("connect() failed");
185             return 0;
186         }
187         
188     } else
189         return 0;
190     
191     if(get_int_field("Sockets.NoDelay")) {
192         int flag = 1;
193         if(setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int)) == -1) {
194             perror("setsockopt() failed");
195             return 0;
196         }
197     }
198     
199     client->sock = sock;
200     client->flags |= SOCKET_FLAG_CONNECTED | SOCKET_FLAG_RECONNECT;
201     client->connection_time = time(0);
202     
203     if(client->flags & SOCKET_FLAG_SSL) {
204         ssl_connect(client);
205         client->flags |= SOCKET_FLAG_HAVE_SSL;
206     } else
207         client->flags &= ~SOCKET_FLAG_HAVE_SSL;
208     
209     //send the IRC Headers
210     char sendBuf[512];
211     int len;
212     
213     if(client->pass && strcmp(client->pass, "")) {
214         len = sprintf(sendBuf, "PASS :%s\n", client->pass);
215         write_socket(client, sendBuf, len);
216     }
217     len = sprintf(sendBuf, "USER %s 0 0 :%s\n", client->ident, client->realname);
218     write_socket(client, sendBuf, len);
219     len = sprintf(sendBuf, "NICK %s\n", client->nick);
220     write_socket(client, sendBuf, len);
221     
222     return 1;
223 }
224 #else
225 static int connect_socket(struct ClientSocket *client) {
226     if((client->flags & SOCKET_FLAG_CONNECTED)) return 1;
227     struct hostent *host;
228     struct sockaddr_in addr;
229     int sock;
230     addr.sin_addr.s_addr = inet_addr(client->host);
231     if (addr.sin_addr.s_addr == INADDR_NONE) {
232         host = gethostbyname(client->host);
233         if(!host) {
234             return SOCKET_ERROR;
235         }
236         memcpy(&(addr.sin_addr), host->h_addr_list[0], 4);
237     }
238     sock = socket(PF_INET, SOCK_STREAM, 0);
239     if (sock == -1)
240     {
241         perror("socket() failed");
242         return 0;
243     }
244
245     addr.sin_port = htons(client->port);
246     addr.sin_family = AF_INET;
247
248     if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) == -1)
249     {
250         perror("connect() failed");
251         return 0;
252     }
253
254     client->sock = sock;
255     client->flags |= SOCKET_FLAG_CONNECTED | SOCKET_FLAG_RECONNECT;
256     client->connection_time = time(0);
257
258
259     if(client->flags & SOCKET_FLAG_SSL) {
260         ssl_connect(client);
261         client->flags |= SOCKET_FLAG_HAVE_SSL;
262     } else
263         client->flags &= ~SOCKET_FLAG_HAVE_SSL;
264
265     //send the IRC Headers
266     char sendBuf[512];
267     int len;
268
269     if(client->pass && strcmp(client->pass, "")) {
270         len = sprintf(sendBuf, "PASS :%s\n", client->pass);
271         write_socket(client, sendBuf, len);
272     }
273     len = sprintf(sendBuf, "USER %s 0 0 :%s\n", client->ident, client->realname);
274     write_socket(client, sendBuf, len);
275     len = sprintf(sendBuf, "NICK %s\n", client->nick);
276     write_socket(client, sendBuf, len);
277
278     return 1;
279 }
280 #endif
281
282 int close_socket(struct ClientSocket *client) {
283     if(client == NULL) return 0;
284     if((client->flags & SOCKET_FLAG_CONNECTED)) {
285         char quitbuf[MAXLEN];
286         int quitlen = sprintf(quitbuf, "QUIT :[NeonServ %s.%d] disconnect requested.\n", NEONSERV_VERSION, patchlevel);
287         write_socket_force(client, quitbuf, quitlen);
288     }
289     client->flags &= ~(SOCKET_FLAG_READY | SOCKET_FLAG_RECONNECT);
290     client->flags |= SOCKET_FLAG_QUITTED | SOCKET_FLAG_DEAD;
291     return 1;
292 }
293
294 int disconnect_socket(struct ClientSocket *client) {
295     if(client == NULL) return 0;
296     if((client->flags & SOCKET_FLAG_CONNECTED)) {
297         char quitbuf[MAXLEN];
298         int quitlen = sprintf(quitbuf, "QUIT :[NeonServ %s.%d] disconnect requested.\n", NEONSERV_VERSION, patchlevel);
299         write_socket_force(client, quitbuf, quitlen);
300     }
301     client->flags &= ~(SOCKET_FLAG_READY | SOCKET_FLAG_RECONNECT);
302     client->flags |= SOCKET_FLAG_QUITTED;
303     return 1;
304 }
305
306 static void destroy_socket(struct ClientSocket *client, int free_socket) {
307     SYNCHRONIZE(synchronized);
308     if((client->flags & SOCKET_FLAG_CONNECTED)) {
309         close(client->sock);
310         bot_disconnect(client);
311     }
312     if(client->flags & SOCKET_FLAG_HAVE_SSL)
313         ssl_disconnect(client);
314     if(client->queue)
315         queue_destroy(client);
316     if(client->whoqueue_first)
317         clear_whoqueue(client);
318     if(client->handleinfo_first)
319         clear_handleinfoqueue(client);
320     client->flags &= ~(SOCKET_FLAG_CONNECTED | SOCKET_FLAG_READY | SOCKET_FLAG_HAVE_SSL);
321     if(free_socket) {
322         struct ClientSocket *sock, *last_sock = NULL;
323         for (sock = sockets->data; sock; sock = sock->next) {
324             if(sock == client) {
325                 if(last_sock)
326                     last_sock->next = sock->next;
327                 else
328                     sockets->data = sock->next;
329                 sockets->count--;
330                 break;
331             } else
332                 last_sock = sock;
333         }
334         free(client->host);
335         if(client->bind)
336             free(client->bind);
337         if(client->pass)
338             free(client->pass);
339         free(client);
340     } else if(client->flags & SOCKET_FLAG_FAST_JUMP) {
341         client->flags &= ~SOCKET_FLAG_FAST_JUMP;
342         connect_socket(client);
343     }
344     DESYNCHRONIZE(synchronized);
345 }
346
347 int write_socket_force(struct ClientSocket *client, char* msg, int len) {
348     SYNCHRONIZE(synchronized);
349     printf("[send %d] %s", len, msg);
350     if(!(client->flags & SOCKET_FLAG_HAVE_SSL) || ssl_write(client, msg, len) == -2) {
351         #ifdef WIN32
352         send(client->sock, msg, len, 0);
353         #else
354         write(client->sock, msg, len);
355         #endif
356     }
357     client->traffic_out += len;
358     DESYNCHRONIZE(synchronized);
359     return 1;
360 }
361
362 int write_socket(struct ClientSocket *client, char* msg, int len) {
363     if(!(client && (client->flags & SOCKET_FLAG_CONNECTED))) return 0;
364     if(client->flags & SOCKET_FLAG_USE_QUEUE)
365         return queue_add(client, msg, len);
366     else
367         return write_socket_force(client, msg, len);
368 }
369
370 void socket_loop(int timeout_seconds) {
371     if(sockets == NULL) return;
372     int is_synchronized = 1;
373     SYNCHRONIZE(synchronized);
374     fd_set fds;
375     struct timeval timeout;
376     struct ClientSocket *sock, *next;
377     int ret = 0, bytes, i;
378     
379     FD_ZERO(&fds);
380     for (sock = sockets->data; sock; sock = sock->next) {
381         if(!(sock->flags & SOCKET_FLAG_CONNECTED)) continue; //skip disconnected sockets
382         FD_SET(sock->sock, &fds);
383         if(sock->sock > ret)
384             ret = sock->sock;
385     }
386     timeout.tv_sec = timeout_seconds;
387     timeout.tv_usec = 0;
388     ret = select(ret + 1, &fds, NULL, NULL, &timeout);
389     if(ret == 0) {
390         DEDESYNCHRONIZE(synchronized);
391         return;
392     }
393     for (sock = sockets->data; sock; sock = next) {
394         next = sock->next;
395         if((sock->flags & (SOCKET_FLAG_CONNECTED | SOCKET_FLAG_QUITTED)) == SOCKET_FLAG_CONNECTED && FD_ISSET(sock->sock, &fds)) {
396             if(sock->bufferpos != 0) {
397                 if(!(sock->flags & SOCKET_FLAG_HAVE_SSL) || (bytes = ssl_read(sock, buffer, sizeof(buffer))) == -2) {
398                     #ifdef WIN32
399                     bytes = recv(sock->sock, buffer, sizeof(buffer), 0);
400                     #else
401                     bytes = read(sock->sock, buffer, sizeof(buffer));
402                     #endif
403                 }
404                 if(bytes > 0) {
405                     for(i = 0; i < bytes; i++) {
406                         if(sock->bufferpos + i == BUF_SIZ*2) break; //buffer overflow
407                         sock->buffer[sock->bufferpos + i] = buffer[i];
408                     }
409                     sock->bufferpos += i;
410                 }
411             } else {
412                 if(!(sock->flags & SOCKET_FLAG_HAVE_SSL) || (bytes = ssl_read(sock, sock->buffer, sizeof(sock->buffer))) == -2) {
413                     #ifdef WIN32
414                     bytes = recv(sock->sock, sock->buffer, sizeof(sock->buffer), 0);
415                     #else
416                     bytes = read(sock->sock, sock->buffer, sizeof(sock->buffer));
417                     #endif
418                 }
419                 if(bytes > 0)
420                     sock->bufferpos = bytes;
421             }
422             if(bytes <= 0) {
423                 //error
424                 sock->flags |= SOCKET_FLAG_QUITTED;
425             } else {
426                 sock->traffic_in += bytes;
427                 is_synchronized = 0;
428                 DESYNCHRONIZE(synchronized);
429                 int used = parse_lines(sock, sock->buffer, sock->bufferpos);
430                 if(used == sock->bufferpos + 1) {
431                     //used all bytes so just reset the bufferpos
432                     sock->bufferpos = 0;
433                 } else {
434                     for(i = 0; i < sock->bufferpos - used; i++) {
435                         sock->buffer[i] = sock->buffer[i+used];
436                     }
437                     sock->bufferpos -= used;
438                 }
439                 #ifdef HAVE_THREADS
440                 FD_ZERO(&fds); //zero out all other pending sockets here (we have other threads receiving from them)
441                 #endif
442             }
443         } else if((sock->flags & (SOCKET_FLAG_CONNECTED | SOCKET_FLAG_RECONNECT)) == SOCKET_FLAG_RECONNECT) {
444             if(time(0) - sock->connection_time >= SOCKET_RECONNECT_TIME) {
445                 connect_socket(sock);
446             }
447         }
448         if((sock->flags & SOCKET_FLAG_QUITTED)) {
449             sock->flags &= ~SOCKET_FLAG_QUITTED;
450             destroy_socket(sock, (sock->flags & SOCKET_FLAG_DEAD));
451         }
452     }
453     if(is_synchronized) {
454         DESYNCHRONIZE(synchronized);
455     }
456 }
457
458 void
459 putsock(struct ClientSocket *client, const char *text, ...)
460 {
461     va_list arg_list;
462     char sendBuf[MAXLEN];
463     int pos;
464     if (!(client && (client->flags & SOCKET_FLAG_CONNECTED))) return;
465     sendBuf[0] = '\0';
466     va_start(arg_list, text);
467     pos = vsnprintf(sendBuf, MAXLEN - 2, text, arg_list);
468     va_end(arg_list);
469     if (pos < 0 || pos > (MAXLEN - 2)) pos = MAXLEN - 2;
470     sendBuf[pos] = '\n';
471     sendBuf[pos+1] = '\0';
472     write_socket(client, sendBuf, pos+1);
473 }
474
475 struct ClientSocket* getBots(int flags, struct ClientSocket* last_bot) {
476     struct ClientSocket *sock = (last_bot ? last_bot->next : sockets->data);
477     if(sock == NULL) return NULL;
478     for (; sock; sock = sock->next) {
479         if(!flags || (sock->flags & flags) == flags)
480             return sock;
481     }
482     return NULL;
483 }
484
485 void free_sockets() {
486     if(!sockets) return;
487     struct ClientSocket *client, *next;
488     for (client = sockets->data; client; client = next) {
489         next = client->next;
490         if((client->flags & SOCKET_FLAG_CONNECTED))
491             close(client->sock);
492         if(client->flags & SOCKET_FLAG_HAVE_SSL)
493             ssl_disconnect(client);
494         if(client->queue)
495             queue_destroy(client);
496         free(client->host);
497         if(client->bind)
498             free(client->bind);
499         if(client->pass)
500             free(client->pass);
501         free(client);
502     }
503     free(sockets);
504     sockets = NULL;
505 }