]> arthur.barton.de Git - ngircd-alex.git/blob - src/ngircd/conn.c
Fix server reconnection
[ngircd-alex.git] / src / ngircd / conn.c
1 /*
2  * ngIRCd -- The Next Generation IRC Daemon
3  * Copyright (c)2001-2013 Alexander Barton (alex@barton.de) and Contributors.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  * Please read the file COPYING, README and AUTHORS for more information.
10  */
11
12 #undef DEBUG_BUFFER
13
14 #define CONN_MODULE
15
16 #include "portab.h"
17 #include "conf-ssl.h"
18 #include "io.h"
19
20 /**
21  * @file
22  * Connection management
23  */
24
25 #include "imp.h"
26 #include <assert.h>
27 #ifdef PROTOTYPES
28 # include <stdarg.h>
29 #else
30 # include <varargs.h>
31 #endif
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <errno.h>
36 #include <string.h>
37 #include <sys/socket.h>
38 #include <sys/time.h>
39 #include <sys/types.h>
40 #include <time.h>
41 #include <netinet/in.h>
42
43 #ifdef HAVE_NETINET_IP_H
44 # ifdef HAVE_NETINET_IN_SYSTM_H
45 #  include <netinet/in_systm.h>
46 # endif
47 # include <netinet/ip.h>
48 #endif
49
50 #ifdef TCPWRAP
51 # include <tcpd.h>                      /* for TCP Wrappers */
52 #endif
53
54 #include "array.h"
55 #include "defines.h"
56
57 #include "exp.h"
58 #include "conn.h"
59
60 #include "imp.h"
61 #include "ngircd.h"
62 #include "array.h"
63 #include "client.h"
64 #include "class.h"
65 #include "conf.h"
66 #include "conn-encoding.h"
67 #include "conn-ssl.h"
68 #include "conn-zip.h"
69 #include "conn-func.h"
70 #include "log.h"
71 #include "ng_ipaddr.h"
72 #include "parse.h"
73 #include "resolve.h"
74 #include "tool.h"
75
76 #include "exp.h"
77
78
79 #define SERVER_WAIT (NONE - 1)
80
81 #define MAX_COMMANDS 3
82 #define MAX_COMMANDS_SERVER_MIN 10
83 #define MAX_COMMANDS_SERVICE 10
84
85 #define SD_LISTEN_FDS_START 3
86
87
88 static bool Handle_Write PARAMS(( CONN_ID Idx ));
89 static bool Conn_Write PARAMS(( CONN_ID Idx, char *Data, size_t Len ));
90 static int New_Connection PARAMS(( int Sock, bool IsSSL ));
91 static CONN_ID Socket2Index PARAMS(( int Sock ));
92 static void Read_Request PARAMS(( CONN_ID Idx ));
93 static unsigned int Handle_Buffer PARAMS(( CONN_ID Idx ));
94 static void Check_Connections PARAMS(( void ));
95 static void Check_Servers PARAMS(( void ));
96 static void Init_Conn_Struct PARAMS(( CONN_ID Idx ));
97 static bool Init_Socket PARAMS(( int Sock ));
98 static void New_Server PARAMS(( int Server, ng_ipaddr_t *dest ));
99 static void Simple_Message PARAMS(( int Sock, const char *Msg ));
100 static int NewListener PARAMS(( const char *listen_addr, UINT16 Port ));
101 static void Account_Connection PARAMS((void));
102
103
104 static array My_Listeners;
105 static array My_ConnArray;
106 static size_t NumConnections, NumConnectionsMax, NumConnectionsAccepted;
107
108 #ifdef TCPWRAP
109 int allow_severity = LOG_INFO;
110 int deny_severity = LOG_ERR;
111 #endif
112
113 static void server_login PARAMS((CONN_ID idx));
114
115 #ifdef SSL_SUPPORT
116 extern struct SSLOptions Conf_SSLOptions;
117 static void cb_connserver_login_ssl PARAMS((int sock, short what));
118 static void cb_clientserver_ssl PARAMS((int sock, short what));
119 #endif
120 static void cb_Read_Resolver_Result PARAMS((int sock, UNUSED short what));
121 static void cb_Connect_to_Server PARAMS((int sock, UNUSED short what));
122 static void cb_clientserver PARAMS((int sock, short what));
123
124 time_t idle_t = 0;
125
126
127 /**
128  * Get number of sockets available from systemd(8).
129  *
130  * ngIRCd needs to implement its own sd_listen_fds(3) function and can't
131  * use the one provided by systemd itself, because the sockets will be
132  * used in a forked child process with a new PID, and this would trigger
133  * an error in the standard implementation.
134  *
135  * @return Number of sockets available, -1 if sockets have already been
136  *         initialized, or 0 when no sockets have been passed.
137  */
138 static int
139 my_sd_listen_fds(void)
140 {
141         const char *e;
142         int count;
143
144         /* Check if LISTEN_PID exists; but we ignore the result, because
145          * normally ngircd forks a child before checking this, and therefore
146          * the PID set in the environment is always wrong ... */
147         e = getenv("LISTEN_PID");
148         if (!e || !*e)
149                 return 0;
150
151         e = getenv("LISTEN_FDS");
152         if (!e || !*e)
153                 return -1;
154         count = atoi(e);
155         unsetenv("LISTEN_FDS");
156
157         return count;
158 }
159
160
161 /**
162  * IO callback for listening sockets: handle new connections. This callback
163  * gets called when a new non-SSL connection should be accepted.
164  *
165  * @param sock          Socket descriptor.
166  * @param irrelevant    (ignored IO specification)
167  */
168 static void
169 cb_listen(int sock, short irrelevant)
170 {
171         (void) irrelevant;
172         (void) New_Connection(sock, false);
173 }
174
175
176 #ifdef SSL_SUPPORT
177 /**
178  * IO callback for listening SSL sockets: handle new connections. This callback
179  * gets called when a new SSL-enabled connection should be accepted.
180  *
181  * @param sock          Socket descriptor.
182  * @param irrelevant    (ignored IO specification)
183  */
184 static void
185 cb_listen_ssl(int sock, short irrelevant)
186 {
187         int fd;
188
189         (void) irrelevant;
190         fd = New_Connection(sock, true);
191         if (fd < 0)
192                 return;
193         io_event_setcb(My_Connections[fd].sock, cb_clientserver_ssl);
194 }
195 #endif
196
197
198 /**
199  * IO callback for new outgoing non-SSL server connections.
200  *
201  * @param sock  Socket descriptor.
202  * @param what  IO specification (IO_WANTREAD/IO_WANTWRITE/...).
203  */
204 static void
205 cb_connserver(int sock, UNUSED short what)
206 {
207         int res, err, server;
208         socklen_t sock_len;
209         CONN_ID idx = Socket2Index( sock );
210
211         if (idx <= NONE) {
212                 LogDebug("cb_connserver wants to write on unknown socket?!");
213                 io_close(sock);
214                 return;
215         }
216
217         assert(what & IO_WANTWRITE);
218
219         /* Make sure that the server is still configured; it could have been
220          * removed in the meantime! */
221         server = Conf_GetServer(idx);
222         if (server < 0) {
223                 Log(LOG_ERR, "Connection on socket %d to \"%s\" aborted!",
224                     sock, My_Connections[idx].host);
225                 Conn_Close(idx, "Connection aborted", NULL, false);
226                 return;
227         }
228
229         /* connect() finished, get result. */
230         sock_len = (socklen_t)sizeof(err);
231         res = getsockopt(My_Connections[idx].sock, SOL_SOCKET, SO_ERROR,
232                          &err, &sock_len );
233         assert(sock_len == sizeof(err));
234
235         /* Error while connecting? */
236         if ((res != 0) || (err != 0)) {
237                 if (res != 0)
238                         Log(LOG_CRIT, "getsockopt (connection %d): %s!",
239                             idx, strerror(errno));
240                 else
241                         Log(LOG_CRIT,
242                             "Can't connect socket to \"%s:%d\" (connection %d): %s!",
243                             My_Connections[idx].host, Conf_Server[server].port,
244                             idx, strerror(err));
245
246                 Conn_Close(idx, "Can't connect", NULL, false);
247
248                 if (ng_ipaddr_af(&Conf_Server[server].dst_addr[0])) {
249                         /* more addresses to try... */
250                         New_Server(server, &Conf_Server[server].dst_addr[0]);
251                         /* connection to dst_addr[0] is now in progress, so
252                          * remove this address... */
253                         Conf_Server[server].dst_addr[0] =
254                                 Conf_Server[server].dst_addr[1];
255                         memset(&Conf_Server[server].dst_addr[1], 0,
256                                sizeof(Conf_Server[server].dst_addr[1]));
257                 }
258                 return;
259         }
260
261         /* connect() succeeded, remove all additional addresses */
262         memset(&Conf_Server[server].dst_addr, 0,
263                sizeof(Conf_Server[server].dst_addr));
264
265         Conn_OPTION_DEL( &My_Connections[idx], CONN_ISCONNECTING );
266 #ifdef SSL_SUPPORT
267         if ( Conn_OPTION_ISSET( &My_Connections[idx], CONN_SSL_CONNECT )) {
268                 io_event_setcb( sock, cb_connserver_login_ssl );
269                 io_event_add( sock, IO_WANTWRITE|IO_WANTREAD );
270                 return;
271         }
272 #endif
273         server_login(idx);
274 }
275
276
277 /**
278  * Login to a remote server.
279  *
280  * @param idx   Connection index.
281  */
282 static void
283 server_login(CONN_ID idx)
284 {
285         Log(LOG_INFO,
286             "Connection %d (socket %d) with \"%s:%d\" established. Now logging in ...",
287             idx, My_Connections[idx].sock, My_Connections[idx].host,
288             Conf_Server[Conf_GetServer(idx)].port);
289
290         io_event_setcb( My_Connections[idx].sock, cb_clientserver);
291         io_event_add( My_Connections[idx].sock, IO_WANTREAD|IO_WANTWRITE);
292
293         /* Send PASS and SERVER command to peer */
294         Conn_WriteStr( idx, "PASS %s %s", Conf_Server[Conf_GetServer( idx )].pwd_out, NGIRCd_ProtoID );
295         Conn_WriteStr( idx, "SERVER %s :%s", Conf_ServerName, Conf_ServerInfo );
296 }
297
298
299 #ifdef SSL_SUPPORT
300 /**
301  * IO callback for new outgoing SSL-enabled server connections.
302  *
303  * @param sock          Socket descriptor.
304  * @param unused        (ignored IO specification)
305  */
306 static void
307 cb_connserver_login_ssl(int sock, short unused)
308 {
309         CONN_ID idx = Socket2Index(sock);
310
311         assert(idx >= 0);
312         if (idx < 0) {
313                 io_close(sock);
314                 return;
315         }
316         (void) unused;
317         switch (ConnSSL_Connect( &My_Connections[idx])) {
318         case 1: break;
319         case 0: LogDebug("ConnSSL_Connect: not ready");
320                 return;
321         case -1:
322                 Log(LOG_ERR, "SSL connection on socket %d failed!", sock);
323                 Conn_Close(idx, "Can't connect", NULL, false);
324                 return;
325         }
326
327         Log( LOG_INFO, "SSL connection %d with \"%s:%d\" established.", idx,
328                         My_Connections[idx].host, Conf_Server[Conf_GetServer( idx )].port );
329
330         server_login(idx);
331 }
332 #endif
333
334
335 /**
336  * IO callback for established non-SSL client and server connections.
337  *
338  * @param sock  Socket descriptor.
339  * @param what  IO specification (IO_WANTREAD/IO_WANTWRITE/...).
340  */
341 static void
342 cb_clientserver(int sock, short what)
343 {
344         CONN_ID idx = Socket2Index(sock);
345
346         assert(idx >= 0);
347
348         if (idx < 0) {
349                 io_close(sock);
350                 return;
351         }
352 #ifdef SSL_SUPPORT
353         if (what & IO_WANTREAD
354             || (Conn_OPTION_ISSET(&My_Connections[idx], CONN_SSL_WANT_WRITE))) {
355                 /* if TLS layer needs to write additional data, call
356                  * Read_Request() instead so that SSL/TLS can continue */
357                 Read_Request(idx);
358         }
359 #else
360         if (what & IO_WANTREAD)
361                 Read_Request(idx);
362 #endif
363         if (what & IO_WANTWRITE)
364                 Handle_Write(idx);
365 }
366
367
368 #ifdef SSL_SUPPORT
369 /**
370  * IO callback for new SSL-enabled client and server connections.
371  *
372  * @param sock  Socket descriptor.
373  * @param what  IO specification (IO_WANTREAD/IO_WANTWRITE/...).
374  */
375 static void
376 cb_clientserver_ssl(int sock, UNUSED short what)
377 {
378         CONN_ID idx = Socket2Index(sock);
379
380         assert(idx >= 0);
381
382         if (idx < 0) {
383                 io_close(sock);
384                 return;
385         }
386
387         switch (ConnSSL_Accept(&My_Connections[idx])) {
388         case 1:
389                 break;  /* OK */
390         case 0:
391                 return; /* EAGAIN: callback will be invoked again by IO layer */
392         default:
393                 Conn_Close(idx,
394                            "SSL accept error, closing socket", "SSL accept error",
395                            false);
396                 return;
397         }
398
399         io_event_setcb(sock, cb_clientserver);  /* SSL handshake completed */
400 }
401 #endif
402
403
404 /**
405  * Initialize connection module.
406  */
407 GLOBAL void
408 Conn_Init( void )
409 {
410         CONN_ID i;
411
412         Pool_Size = CONNECTION_POOL;
413         if ((Conf_MaxConnections > 0) &&
414                 (Pool_Size > Conf_MaxConnections))
415                         Pool_Size = Conf_MaxConnections;
416
417         if (!array_alloc(&My_ConnArray, sizeof(CONNECTION), (size_t)Pool_Size)) {
418                 Log(LOG_EMERG, "Can't allocate memory! [Conn_Init]");
419                 exit(1);
420         }
421
422         /* FIXME: My_Connetions/Pool_Size is needed by other parts of the
423          * code; remove them! */
424         My_Connections = (CONNECTION*) array_start(&My_ConnArray);
425
426         LogDebug("Allocated connection pool for %d items (%ld bytes).",
427                 array_length(&My_ConnArray, sizeof(CONNECTION)),
428                 array_bytes(&My_ConnArray));
429
430         assert(array_length(&My_ConnArray, sizeof(CONNECTION)) >= (size_t)Pool_Size);
431         
432         array_free( &My_Listeners );
433
434         for (i = 0; i < Pool_Size; i++)
435                 Init_Conn_Struct(i);
436 } /* Conn_Init */
437
438
439 /**
440  * Clean up connection module.
441  */
442 GLOBAL void
443 Conn_Exit( void )
444 {
445         CONN_ID idx;
446
447         Conn_ExitListeners();
448
449         LogDebug("Shutting down all connections ..." );
450         for( idx = 0; idx < Pool_Size; idx++ ) {
451                 if( My_Connections[idx].sock > NONE ) {
452                         Conn_Close( idx, NULL, NGIRCd_SignalRestart ?
453                                 "Server going down (restarting)":"Server going down", true );
454                 }
455         }
456
457         array_free(&My_ConnArray);
458         My_Connections = NULL;
459         Pool_Size = 0;
460         io_library_shutdown();
461 } /* Conn_Exit */
462
463
464 /**
465  * Close all sockets (file descriptors) of open connections.
466  * This is useful in forked child processes, for example, to make sure that
467  * they don't hold connections open that the main process wants to close.
468  */
469 GLOBAL void
470 Conn_CloseAllSockets(int ExceptOf)
471 {
472         CONN_ID idx;
473
474         for(idx = 0; idx < Pool_Size; idx++) {
475                 if(My_Connections[idx].sock > NONE &&
476                    My_Connections[idx].sock != ExceptOf)
477                         close(My_Connections[idx].sock);
478         }
479 }
480
481
482 /**
483  * Initialize listening ports.
484  *
485  * @param a             Array containing the ports the daemon should listen on.
486  * @param listen_addr   Address the socket should listen on (can be "0.0.0.0").
487  * @param func          IO callback function to register.
488  * @returns             Number of listening sockets created.
489  */
490 static unsigned int
491 Init_Listeners(array *a, const char *listen_addr, void (*func)(int,short))
492 {
493         unsigned int created = 0;
494         size_t len;
495         int fd;
496         UINT16 *port;
497
498         len = array_length(a, sizeof (UINT16));
499         port = array_start(a);
500         while (len--) {
501                 fd = NewListener(listen_addr, *port);
502                 if (fd < 0) {
503                         port++;
504                         continue;
505                 }
506                 if (!io_event_create( fd, IO_WANTREAD, func )) {
507                         Log(LOG_ERR,
508                             "io_event_create(): Can't add fd %d (port %u): %s!",
509                             fd, (unsigned int) *port, strerror(errno));
510                         close(fd);
511                         port++;
512                         continue;
513                 }
514                 created++;
515                 port++;
516         }
517         return created;
518 }
519
520
521 /**
522  * Initialize all listening sockets.
523  *
524  * @returns     Number of created listening sockets
525  */
526 GLOBAL unsigned int
527 Conn_InitListeners( void )
528 {
529         /* Initialize ports on which the server should accept connections */
530         unsigned int created = 0;
531         char *af_str, *copy, *listen_addr;
532         int count, fd, i, addr_len;
533         ng_ipaddr_t addr;
534
535         assert(Conf_ListenAddress);
536
537         count = my_sd_listen_fds();
538         if (count < 0) {
539                 Log(LOG_INFO,
540                     "Not re-initializing listening sockets of systemd(8) ...");
541                 return 0;
542         }
543         if (count > 0) {
544                 /* systemd(8) passed sockets to us, so don't try to initialize
545                  * listening sockets on our own but use the passed ones */
546                 LogDebug("Initializing %d systemd sockets ...", count);
547                 for (i = 0; i < count; i++) {
548                         fd = SD_LISTEN_FDS_START + i;
549                         addr_len = (int)sizeof(addr);
550                         getsockname(fd, (struct sockaddr *)&addr, (socklen_t*)&addr_len);
551 #ifdef WANT_IPV6
552                         if (addr.sin4.sin_family != AF_INET && addr.sin4.sin_family != AF_INET6)
553 #else
554                         if (addr.sin4.sin_family != AF_INET)
555 #endif
556                         {
557                                 /* Socket is of unsupported type! For example, systemd passed in
558                                  * an IPv6 socket but ngIRCd isn't compiled with IPv6 support. */
559                                 switch (addr.sin4.sin_family)
560                                 {
561                                         case AF_UNSPEC: af_str = "AF_UNSPEC"; break;
562                                         case AF_UNIX: af_str = "AF_UNIX"; break;
563                                         case AF_INET: af_str = "AF_INET"; break;
564 #ifdef AF_INET6
565                                         case AF_INET6: af_str = "AF_INET6"; break;
566 #endif
567 #ifdef AF_NETLINK
568                                         case AF_NETLINK: af_str = "AF_NETLINK"; break;
569 #endif
570                                         default: af_str = "unknown"; break;
571                                 }
572                                 Log(LOG_CRIT,
573                                     "Socket %d is of unsupported type \"%s\" (%d), have to ignore it!",
574                                     fd, af_str, addr.sin4.sin_family);
575                                 close(fd);
576                                 continue;
577                         }
578
579                         Init_Socket(fd);
580                         if (!io_event_create(fd, IO_WANTREAD, cb_listen)) {
581                                 Log(LOG_ERR,
582                                     "io_event_create(): Can't add fd %d: %s!",
583                                     fd, strerror(errno));
584                                 continue;
585                         }
586                         Log(LOG_INFO,
587                             "Initialized socket %d from systemd(8): %s:%d.", fd,
588                             ng_ipaddr_tostr(&addr), ng_ipaddr_getport(&addr));
589                         created++;
590                 }
591                 return created;
592         }
593
594         /* not using systemd socket activation, initialize listening sockets: */
595
596         /* can't use Conf_ListenAddress directly, see below */
597         copy = strdup(Conf_ListenAddress);
598         if (!copy) {
599                 Log(LOG_CRIT, "Cannot copy %s: %s", Conf_ListenAddress,
600                     strerror(errno));
601                 return 0;
602         }
603         listen_addr = strtok(copy, ",");
604
605         while (listen_addr) {
606                 ngt_TrimStr(listen_addr);
607                 if (*listen_addr) {
608                         created += Init_Listeners(&Conf_ListenPorts,
609                                                   listen_addr, cb_listen);
610 #ifdef SSL_SUPPORT
611                         created += Init_Listeners(&Conf_SSLOptions.ListenPorts,
612                                                   listen_addr, cb_listen_ssl);
613 #endif
614                 }
615
616                 listen_addr = strtok(NULL, ",");
617         }
618
619         /* Can't free() Conf_ListenAddress here: on REHASH, if the config file
620          * cannot be re-loaded, we'd end up with a NULL Conf_ListenAddress.
621          * Instead, free() takes place in conf.c, before the config file
622          * is being parsed. */
623         free(copy);
624
625         return created;
626 } /* Conn_InitListeners */
627
628
629 /**
630  * Shut down all listening sockets.
631  */
632 GLOBAL void
633 Conn_ExitListeners( void )
634 {
635         /* Close down all listening sockets */
636         int *fd;
637         size_t arraylen;
638
639         /* Get number of listening sockets to shut down. There can be none
640          * if ngIRCd has been "socket activated" by systemd. */
641         arraylen = array_length(&My_Listeners, sizeof (int));
642         if (arraylen < 1)
643                 return;
644
645         Log(LOG_INFO,
646             "Shutting down all listening sockets (%d total) ...", arraylen);
647         fd = array_start(&My_Listeners);
648         while(arraylen--) {
649                 assert(fd != NULL);
650                 assert(*fd >= 0);
651                 io_close(*fd);
652                 LogDebug("Listening socket %d closed.", *fd );
653                 fd++;
654         }
655         array_free(&My_Listeners);
656 } /* Conn_ExitListeners */
657
658
659 /**
660  * Bind a socket to a specific (source) address.
661  *
662  * @param addr                  Address structure.
663  * @param listen_addrstr        Source address as string.
664  * @param Port                  Port number.
665  * @returns                     true on success, false otherwise.
666  */
667 static bool
668 InitSinaddrListenAddr(ng_ipaddr_t *addr, const char *listen_addrstr, UINT16 Port)
669 {
670         bool ret;
671
672         ret = ng_ipaddr_init(addr, listen_addrstr, Port);
673         if (!ret) {
674                 assert(listen_addrstr);
675                 Log(LOG_CRIT, "Can't bind to [%s]:%u: can't convert ip address \"%s\"!",
676                                                 listen_addrstr, Port, listen_addrstr);
677         }
678         return ret;
679 }
680
681
682 /**
683  * Set a socket to "IPv6 only". If the given socket doesn't belong to the
684  * AF_INET6 family, or the operating system doesn't support this functionality,
685  * this function retruns silently.
686  *
687  * @param af    Address family of the socket.
688  * @param sock  Socket handle.
689  */
690 static void
691 set_v6_only(int af, int sock)
692 {
693 #if defined(IPV6_V6ONLY) && defined(WANT_IPV6)
694         int on = 1;
695
696         if (af != AF_INET6)
697                 return;
698
699         if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, (socklen_t)sizeof(on)))
700                 Log(LOG_ERR, "Could not set IPV6_V6ONLY: %s", strerror(errno));
701 #else
702         (void)af;
703         (void)sock;
704 #endif
705 }
706
707
708 /**
709  * Initialize new listening port.
710  *
711  * @param listen_addr   Local address to bind the socet to (can be 0.0.0.0).
712  * @param Port          Port number on which the new socket should be listening.
713  * @returns             file descriptor of the socket or -1 on failure.
714  */
715 static int
716 NewListener(const char *listen_addr, UINT16 Port)
717 {
718         /* Create new listening socket on specified port */
719         ng_ipaddr_t addr;
720         int sock, af;
721
722         if (!InitSinaddrListenAddr(&addr, listen_addr, Port))
723                 return -1;
724
725         af = ng_ipaddr_af(&addr);
726         sock = socket(af, SOCK_STREAM, 0);
727         if (sock < 0) {
728                 Log(LOG_CRIT, "Can't create socket (af %d) : %s!", af,
729                     strerror(errno));
730                 return -1;
731         }
732
733         set_v6_only(af, sock);
734
735         if (!Init_Socket(sock))
736                 return -1;
737
738         if (bind(sock, (struct sockaddr *)&addr, ng_ipaddr_salen(&addr)) != 0) {
739                 Log(LOG_CRIT, "Can't bind socket to address %s:%d - %s!",
740                     ng_ipaddr_tostr(&addr), Port, strerror(errno));
741                 close(sock);
742                 return -1;
743         }
744
745         if (listen(sock, 10) != 0) {
746                 Log(LOG_CRIT, "Can't listen on socket: %s!", strerror(errno));
747                 close(sock);
748                 return -1;
749         }
750
751         /* keep fd in list so we can close it when ngircd restarts/shuts down */
752         if (!array_catb(&My_Listeners, (char *)&sock, sizeof(int))) {
753                 Log(LOG_CRIT, "Can't add socket to My_Listeners array: %s!",
754                     strerror(errno));
755                 close(sock);
756                 return -1;
757         }
758
759         Log(LOG_INFO, "Now listening on [%s]:%d (socket %d).",
760             ng_ipaddr_tostr(&addr), Port, sock);
761         return sock;
762 } /* NewListener */
763
764
765 #ifdef SSL_SUPPORT
766
767 /**
768  * Check if SSL library needs to read SSL-protocol related data.
769  *
770  * SSL/TLS connections require extra treatment:
771  * When either CONN_SSL_WANT_WRITE or CONN_SSL_WANT_READ is set, we
772  * need to take care of that first, before checking read/write buffers.
773  * For instance, while we might have data in our write buffer, the
774  * TLS/SSL protocol might need to read internal data first for TLS/SSL
775  * writes to succeed.
776  *
777  * If this function returns true, such a condition is met and we have
778  * to reverse the condition (check for read even if we've data to write,
779  * do not check for read but writeability even if write-buffer is empty).
780  *
781  * @param c     Connection to check.
782  * @returns     true if SSL-library has to read protocol data.
783  */
784 static bool
785 SSL_WantRead(const CONNECTION *c)
786 {
787         if (Conn_OPTION_ISSET(c, CONN_SSL_WANT_READ)) {
788                 io_event_add(c->sock, IO_WANTREAD);
789                 return true;
790         }
791         return false;
792 }
793
794 /**
795  * Check if SSL library needs to write SSL-protocol related data.
796  *
797  * Please see description of SSL_WantRead() for full description!
798  *
799  * @param c     Connection to check.
800  * @returns     true if SSL-library has to write protocol data.
801  */
802 static bool
803 SSL_WantWrite(const CONNECTION *c)
804 {
805         if (Conn_OPTION_ISSET(c, CONN_SSL_WANT_WRITE)) {
806                 io_event_add(c->sock, IO_WANTWRITE);
807                 return true;
808         }
809         return false;
810 }
811
812 #else
813
814 static inline bool
815 SSL_WantRead(UNUSED const CONNECTION *c)
816 { return false; }
817
818 static inline bool
819 SSL_WantWrite(UNUSED const CONNECTION *c)
820 { return false; }
821
822 #endif
823
824
825 /**
826  * "Main Loop": Loop until shutdown or restart is signalled.
827  *
828  * This function loops until a shutdown or restart of ngIRCd is signalled and
829  * calls io_dispatch() to check for readable and writable sockets every second.
830  * It checks for status changes on pending connections (e. g. when a hostname
831  * has been resolved), checks for "penalties" and timeouts, and handles the
832  * input buffers.
833  */
834 GLOBAL void
835 Conn_Handler(void)
836 {
837         int i;
838         unsigned int wdatalen, bytes_processed;
839         struct timeval tv;
840         time_t t;
841
842         while (!NGIRCd_SignalQuit && !NGIRCd_SignalRestart) {
843                 t = time(NULL);
844
845                 /* Check configured servers and established links */
846                 Check_Servers();
847                 Check_Connections();
848
849                 /* Expire outdated class/list items */
850                 Class_Expire();
851
852                 /* Look for non-empty read buffers ... */
853                 for (i = 0; i < Pool_Size; i++) {
854                         if ((My_Connections[i].sock > NONE)
855                             && (array_bytes(&My_Connections[i].rbuf) > 0)) {
856                                 /* ... and try to handle the received data */
857                                 bytes_processed = Handle_Buffer(i);
858                                 /* if we processed data, and there might be
859                                  * more commands in the input buffer, do not
860                                  * try to read any more data now */
861                                 if (bytes_processed &&
862                                     array_bytes(&My_Connections[i].rbuf) > 2) {
863                                         LogDebug
864                                             ("Throttling connection %d: command limit reached!",
865                                              i);
866                                         Conn_SetPenalty(i, 1);
867                                 }
868                         }
869                 }
870
871                 /* Look for non-empty write buffers ... */
872                 for (i = 0; i < Pool_Size; i++) {
873                         if (My_Connections[i].sock <= NONE)
874                                 continue;
875
876                         wdatalen = (unsigned int)array_bytes(&My_Connections[i].wbuf);
877 #ifdef ZLIB
878                         if (wdatalen > 0 ||
879                             array_bytes(&My_Connections[i].zip.wbuf) > 0)
880 #else
881                         if (wdatalen > 0)
882 #endif
883                         {
884                                 if (SSL_WantRead(&My_Connections[i]))
885                                         continue;
886                                 io_event_add(My_Connections[i].sock,
887                                              IO_WANTWRITE);
888                         }
889                 }
890
891                 /* Check from which sockets we possibly could read ... */
892                 for (i = 0; i < Pool_Size; i++) {
893                         if (My_Connections[i].sock <= NONE)
894                                 continue;
895 #ifdef SSL_SUPPORT
896                         if (SSL_WantWrite(&My_Connections[i]))
897                                 continue; /* TLS/SSL layer needs to write data; deal with this first */
898 #endif
899                         if (Proc_InProgress(&My_Connections[i].proc_stat)) {
900                                 /* Wait for completion of forked subprocess
901                                  * and ignore the socket in the meantime ... */
902                                 io_event_del(My_Connections[i].sock,
903                                              IO_WANTREAD);
904                                 continue;
905                         }
906
907                         if (Conn_OPTION_ISSET(&My_Connections[i], CONN_ISCONNECTING))
908                                 /* Wait for completion of connect() ... */
909                                 continue;
910
911                         if (My_Connections[i].delaytime > t) {
912                                 /* There is a "penalty time" set: ignore socket! */
913                                 io_event_del(My_Connections[i].sock,
914                                              IO_WANTREAD);
915                                 continue;
916                         }
917
918                         io_event_add(My_Connections[i].sock, IO_WANTREAD);
919                 }
920
921                 /* Set the timeout for reading from the network to 1 second,
922                  * which is the granularity with witch we handle "penalty
923                  * times" for example.
924                  * Note: tv_sec/usec are undefined(!) after io_dispatch()
925                  * returns, so we have to set it before each call to it! */
926                 tv.tv_usec = 0;
927                 tv.tv_sec = 1;
928
929                 /* Wait for activity ... */
930                 i = io_dispatch(&tv);
931                 if (i == -1 && errno != EINTR) {
932                         Log(LOG_EMERG, "Conn_Handler(): io_dispatch(): %s!",
933                             strerror(errno));
934                         Log(LOG_ALERT, "%s exiting due to fatal errors!",
935                             PACKAGE_NAME);
936                         exit(1);
937                 }
938
939                 /* Should ngIRCd timeout when idle? */
940                 if (Conf_IdleTimeout > 0 && NumConnectionsAccepted > 0
941                     && idle_t > 0 && time(NULL) - idle_t >= Conf_IdleTimeout) {
942                         LogDebug("Server idle timeout reached: %d second%s. Initiating shutdown ...",
943                                  Conf_IdleTimeout,
944                                  Conf_IdleTimeout == 1 ? "" : "s");
945                         NGIRCd_SignalQuit = true;
946                 }
947         }
948
949         if (NGIRCd_SignalQuit)
950                 Log(LOG_NOTICE | LOG_snotice, "Server going down NOW!");
951         else if (NGIRCd_SignalRestart)
952                 Log(LOG_NOTICE | LOG_snotice, "Server restarting NOW!");
953 } /* Conn_Handler */
954
955
956 /**
957  * Write a text string into the socket of a connection.
958  *
959  * This function automatically appends CR+LF to the string and validates that
960  * the result is a valid IRC message (oversized messages are shortened, for
961  * example). Then it calls the Conn_Write() function to do the actual sending.
962  *
963  * @param Idx           Index fo the connection.
964  * @param Format        Format string, see printf().
965  * @returns             true on success, false otherwise.
966  */
967 #ifdef PROTOTYPES
968 GLOBAL bool
969 Conn_WriteStr(CONN_ID Idx, const char *Format, ...)
970 #else
971 GLOBAL bool 
972 Conn_WriteStr(Idx, Format, va_alist)
973 CONN_ID Idx;
974 const char *Format;
975 va_dcl
976 #endif
977 {
978         char buffer[COMMAND_LEN];
979 #ifdef ICONV
980         char *ptr, *message;
981 #endif
982         size_t len;
983         bool ok;
984         va_list ap;
985
986         assert( Idx > NONE );
987         assert( Format != NULL );
988
989 #ifdef PROTOTYPES
990         va_start( ap, Format );
991 #else
992         va_start( ap );
993 #endif
994         if (vsnprintf( buffer, COMMAND_LEN - 2, Format, ap ) >= COMMAND_LEN - 2 ) {
995                 /*
996                  * The string that should be written to the socket is longer
997                  * than the allowed size of COMMAND_LEN bytes (including both
998                  * the CR and LF characters). This can be caused by the
999                  * IRC_WriteXXX() functions when the prefix of this server had
1000                  * to be added to an already "quite long" command line which
1001                  * has been received from a regular IRC client, for example.
1002                  * 
1003                  * We are not allowed to send such "oversized" messages to
1004                  * other servers and clients, see RFC 2812 2.3 and 2813 3.3
1005                  * ("these messages SHALL NOT exceed 512 characters in length,
1006                  * counting all characters including the trailing CR-LF").
1007                  *
1008                  * So we have a big problem here: we should send more bytes
1009                  * to the network than we are allowed to and we don't know
1010                  * the originator (any more). The "old" behavior of blaming
1011                  * the receiver ("next hop") is a bad idea (it could be just
1012                  * an other server only routing the message!), so the only
1013                  * option left is to shorten the string and to hope that the
1014                  * result is still somewhat useful ...
1015                  *                                                   -alex-
1016                  */
1017
1018                 strcpy (buffer + sizeof(buffer) - strlen(CUT_TXTSUFFIX) - 2 - 1,
1019                         CUT_TXTSUFFIX);
1020         }
1021
1022 #ifdef ICONV
1023         ptr = strchr(buffer + 1, ':');
1024         if (ptr) {
1025                 ptr++;
1026                 message = Conn_EncodingTo(Idx, ptr);
1027                 if (message != ptr)
1028                         strlcpy(ptr, message, sizeof(buffer) - (ptr - buffer));
1029         }
1030 #endif
1031
1032 #ifdef SNIFFER
1033         if (NGIRCd_Sniffer)
1034                 Log(LOG_DEBUG, " -> connection %d: '%s'.", Idx, buffer);
1035 #endif
1036
1037         len = strlcat( buffer, "\r\n", sizeof( buffer ));
1038         ok = Conn_Write(Idx, buffer, len);
1039         My_Connections[Idx].msg_out++;
1040
1041         va_end( ap );
1042         return ok;
1043 } /* Conn_WriteStr */
1044
1045 GLOBAL char*
1046 Conn_Password( CONN_ID Idx )
1047 {
1048         assert( Idx > NONE );
1049         if (My_Connections[Idx].pwd == NULL)
1050                 return (char*)"\0";
1051         else
1052                 return My_Connections[Idx].pwd;
1053 } /* Conn_Password */
1054
1055 GLOBAL void
1056 Conn_SetPassword( CONN_ID Idx, const char *Pwd )
1057 {
1058         assert( Idx > NONE );
1059
1060         if (My_Connections[Idx].pwd)
1061                 free(My_Connections[Idx].pwd);
1062
1063         My_Connections[Idx].pwd = strdup(Pwd);
1064         if (My_Connections[Idx].pwd == NULL) {
1065                 Log(LOG_EMERG, "Can't allocate memory! [Conn_SetPassword]");
1066                 exit(1);
1067         }
1068 } /* Conn_SetPassword */
1069
1070 /**
1071  * Append Data to the outbound write buffer of a connection.
1072  *
1073  * @param Idx   Index of the connection.
1074  * @param Data  pointer to the data.
1075  * @param Len   length of Data.
1076  * @returns     true on success, false otherwise.
1077  */
1078 static bool
1079 Conn_Write( CONN_ID Idx, char *Data, size_t Len )
1080 {
1081         CLIENT *c;
1082         size_t writebuf_limit = WRITEBUFFER_MAX_LEN;
1083         assert( Idx > NONE );
1084         assert( Data != NULL );
1085         assert( Len > 0 );
1086
1087         /* Is the socket still open? A previous call to Conn_Write()
1088          * may have closed the connection due to a fatal error.
1089          * In this case it is sufficient to return an error, as well. */
1090         if (My_Connections[Idx].sock <= NONE) {
1091                 LogDebug("Skipped write on closed socket (connection %d).", Idx);
1092                 return false;
1093         }
1094
1095         /* Make sure that there still exists a CLIENT structure associated
1096          * with this connection and check if this is a server or not: */
1097         c = Conn_GetClient(Idx);
1098         if (c) {
1099                 /* Servers do get special write buffer limits, so they can
1100                  * generate all the messages that are required while peering. */
1101                 if (Client_Type(c) == CLIENT_SERVER)
1102                         writebuf_limit = WRITEBUFFER_SLINK_LEN;
1103         } else
1104                 LogDebug("Write on socket without client (connection %d)!?", Idx);
1105
1106 #ifdef ZLIB
1107         if ( Conn_OPTION_ISSET( &My_Connections[Idx], CONN_ZIP )) {
1108                 /* Compressed link:
1109                  * Zip_Buffer() does all the dirty work for us: it flushes
1110                  * the (pre-)compression buffers if required and handles
1111                  * all error conditions. */
1112                 if (!Zip_Buffer(Idx, Data, Len))
1113                         return false;
1114         }
1115         else
1116 #endif
1117         {
1118                 /* Uncompressed link:
1119                  * Check if outbound buffer has enough space for the data. */
1120                 if (array_bytes(&My_Connections[Idx].wbuf) + Len >=
1121                     WRITEBUFFER_FLUSH_LEN) {
1122                         /* Buffer is full, flush it. Handle_Write deals with
1123                          * low-level errors, if any. */
1124                         if (!Handle_Write(Idx))
1125                                 return false;
1126                 }
1127
1128                 /* When the write buffer is still too big after flushing it,
1129                  * the connection will be killed. */
1130                 if (array_bytes(&My_Connections[Idx].wbuf) + Len >=
1131                     writebuf_limit) {
1132                         Log(LOG_NOTICE,
1133                             "Write buffer space exhausted (connection %d, limit is %lu bytes, %lu bytes new, %lu bytes pending)",
1134                             Idx, writebuf_limit, Len,
1135                             (unsigned long)array_bytes(&My_Connections[Idx].wbuf));
1136                         Conn_Close(Idx, "Write buffer space exhausted", NULL, false);
1137                         return false;
1138                 }
1139
1140                 /* Copy data to write buffer */
1141                 if (!array_catb(&My_Connections[Idx].wbuf, Data, Len))
1142                         return false;
1143
1144                 My_Connections[Idx].bytes_out += Len;
1145         }
1146
1147         /* Adjust global write counter */
1148         WCounter += Len;
1149
1150         return true;
1151 } /* Conn_Write */
1152
1153
1154 /**
1155  * Shut down a connection.
1156  *
1157  * @param Idx           Connection index.
1158  * @param LogMsg        Message to write to the log or NULL. If no LogMsg
1159  *                      is given, the FwdMsg is logged.
1160  * @param FwdMsg        Message to forward to remote servers.
1161  * @param InformClient  If true, inform the client on the connection which is
1162  *                      to be shut down of the reason (FwdMsg) and send
1163  *                      connection statistics before disconnecting it.
1164  */
1165 GLOBAL void
1166 Conn_Close( CONN_ID Idx, const char *LogMsg, const char *FwdMsg, bool InformClient )
1167 {
1168         /* Close connection. Open pipes of asynchronous resolver
1169          * sub-processes are closed down. */
1170
1171         CLIENT *c;
1172         double in_k, out_k;
1173         UINT16 port;
1174 #ifdef ZLIB
1175         double in_z_k, out_z_k;
1176         int in_p, out_p;
1177 #endif
1178
1179         assert( Idx > NONE );
1180
1181         /* Is this link already shutting down? */
1182         if( Conn_OPTION_ISSET( &My_Connections[Idx], CONN_ISCLOSING )) {
1183                 /* Conn_Close() has been called recursively for this link;
1184                  * probable reason: Handle_Write() failed -- see below. */
1185                 LogDebug("Recursive request to close connection %d!", Idx );
1186                 return;
1187         }
1188
1189         assert( My_Connections[Idx].sock > NONE );
1190
1191         /* Mark link as "closing" */
1192         Conn_OPTION_ADD( &My_Connections[Idx], CONN_ISCLOSING );
1193
1194         port = ng_ipaddr_getport(&My_Connections[Idx].addr);
1195         Log(LOG_INFO, "Shutting down connection %d (%s) with \"%s:%d\" ...", Idx,
1196             LogMsg ? LogMsg : FwdMsg, My_Connections[Idx].host, port);
1197
1198         /* Search client, if any */
1199         c = Conn_GetClient( Idx );
1200
1201         /* Should the client be informed? */
1202         if (InformClient) {
1203 #ifndef STRICT_RFC
1204                 /* Send statistics to client if registered as user: */
1205                 if ((c != NULL) && (Client_Type(c) == CLIENT_USER)) {
1206                         Conn_WriteStr( Idx,
1207                          ":%s NOTICE %s :%sConnection statistics: client %.1f kb, server %.1f kb.",
1208                          Client_ID(Client_ThisServer()), Client_ID(c),
1209                          NOTICE_TXTPREFIX,
1210                          (double)My_Connections[Idx].bytes_in / 1024,
1211                          (double)My_Connections[Idx].bytes_out / 1024);
1212                 }
1213 #endif
1214                 /* Send ERROR to client (see RFC 2812, section 3.1.7) */
1215                 if (FwdMsg)
1216                         Conn_WriteStr(Idx, "ERROR :%s", FwdMsg);
1217                 else
1218                         Conn_WriteStr(Idx, "ERROR :Closing connection");
1219         }
1220
1221         /* Try to write out the write buffer. Note: Handle_Write() eventually
1222          * removes the CLIENT structure associated with this connection if an
1223          * error occurs! So we have to re-check if there is still an valid
1224          * CLIENT structure after calling Handle_Write() ...*/
1225         (void)Handle_Write( Idx );
1226
1227         /* Search client, if any (re-check!) */
1228         c = Conn_GetClient( Idx );
1229 #ifdef SSL_SUPPORT
1230         if ( Conn_OPTION_ISSET( &My_Connections[Idx], CONN_SSL )) {
1231                 LogDebug("SSL connection %d shutting down ...", Idx);
1232                 ConnSSL_Free(&My_Connections[Idx]);
1233         }
1234 #endif
1235         /* Shut down socket */
1236         if (! io_close(My_Connections[Idx].sock)) {
1237                 /* Oops, we can't close the socket!? This is ... ugly! */
1238                 Log(LOG_CRIT,
1239                     "Error closing connection %d (socket %d) with %s:%d - %s! (ignored)",
1240                     Idx, My_Connections[Idx].sock, My_Connections[Idx].host,
1241                     port, strerror(errno));
1242         }
1243
1244         /* Mark socket as invalid: */
1245         My_Connections[Idx].sock = NONE;
1246
1247         /* If there is still a client, unregister it now */
1248         if (c)
1249                 Client_Destroy(c, LogMsg, FwdMsg, true);
1250
1251         /* Calculate statistics and log information */
1252         in_k = (double)My_Connections[Idx].bytes_in / 1024;
1253         out_k = (double)My_Connections[Idx].bytes_out / 1024;
1254 #ifdef ZLIB
1255         if (Conn_OPTION_ISSET( &My_Connections[Idx], CONN_ZIP)) {
1256                 in_z_k = (double)My_Connections[Idx].zip.bytes_in / 1024;
1257                 out_z_k = (double)My_Connections[Idx].zip.bytes_out / 1024;
1258                 /* Make sure that no division by zero can occur during
1259                  * the calculation of in_p and out_p: in_z_k and out_z_k
1260                  * are non-zero, that's guaranteed by the protocol until
1261                  * compression can be enabled. */
1262                 if (! in_z_k)
1263                         in_z_k = in_k;
1264                 if (! out_z_k)
1265                         out_z_k = out_k;
1266                 in_p = (int)(( in_k * 100 ) / in_z_k );
1267                 out_p = (int)(( out_k * 100 ) / out_z_k );
1268                 Log(LOG_INFO,
1269                     "Connection %d with \"%s:%d\" closed (in: %.1fk/%.1fk/%d%%, out: %.1fk/%.1fk/%d%%).",
1270                     Idx, My_Connections[Idx].host, port,
1271                     in_k, in_z_k, in_p, out_k, out_z_k, out_p);
1272         }
1273         else
1274 #endif
1275         {
1276                 Log(LOG_INFO,
1277                     "Connection %d with \"%s:%d\" closed (in: %.1fk, out: %.1fk).",
1278                     Idx, My_Connections[Idx].host, port,
1279                     in_k, out_k);
1280         }
1281
1282         /* Servers: Modify time of next connect attempt? */
1283         Conf_UnsetServer( Idx );
1284
1285 #ifdef ZLIB
1286         /* Clean up zlib, if link was compressed */
1287         if ( Conn_OPTION_ISSET( &My_Connections[Idx], CONN_ZIP )) {
1288                 inflateEnd( &My_Connections[Idx].zip.in );
1289                 deflateEnd( &My_Connections[Idx].zip.out );
1290                 array_free(&My_Connections[Idx].zip.rbuf);
1291                 array_free(&My_Connections[Idx].zip.wbuf);
1292         }
1293 #endif
1294
1295         array_free(&My_Connections[Idx].rbuf);
1296         array_free(&My_Connections[Idx].wbuf);
1297         if (My_Connections[Idx].pwd != NULL)
1298                 free(My_Connections[Idx].pwd);
1299
1300         /* Clean up connection structure (=free it) */
1301         Init_Conn_Struct( Idx );
1302
1303         assert(NumConnections > 0);
1304         if (NumConnections)
1305                 NumConnections--;
1306         LogDebug("Shutdown of connection %d completed, %ld connection%s left.",
1307                  Idx, NumConnections, NumConnections != 1 ? "s" : "");
1308
1309         idle_t = NumConnections > 0 ? 0 : time(NULL);
1310 } /* Conn_Close */
1311
1312
1313 /**
1314  * Get current number of connections.
1315  *
1316  * @returns     Number of current connections.
1317  */
1318 GLOBAL long
1319 Conn_Count(void)
1320 {
1321         return NumConnections;
1322 } /* Conn_Count */
1323
1324
1325 /**
1326  * Get number of maximum simultaneous connections.
1327  *
1328  * @returns     Number of maximum simultaneous connections.
1329  */
1330 GLOBAL long
1331 Conn_CountMax(void)
1332 {
1333         return NumConnectionsMax;
1334 } /* Conn_CountMax */
1335
1336
1337 /**
1338  * Get number of connections accepted since the daemon startet.
1339  *
1340  * @returns     Number of connections accepted.
1341  */
1342 GLOBAL long
1343 Conn_CountAccepted(void)
1344 {
1345         return NumConnectionsAccepted;
1346 } /* Conn_CountAccepted */
1347
1348
1349 /**
1350  * Synchronize established connections and configured server structures
1351  * after a configuration update and store the correct connection IDs, if any.
1352  */
1353 GLOBAL void
1354 Conn_SyncServerStruct(void)
1355 {
1356         CLIENT *client;
1357         CONN_ID i;
1358         int c;
1359
1360         for (i = 0; i < Pool_Size; i++) {
1361                 if (My_Connections[i].sock == NONE)
1362                         continue;
1363
1364                 /* Server link? */
1365                 client = Conn_GetClient(i);
1366                 if (!client || Client_Type(client) != CLIENT_SERVER)
1367                         continue;
1368
1369                 for (c = 0; c < MAX_SERVERS; c++) {
1370                         /* Configured server? */
1371                         if (!Conf_Server[c].host[0])
1372                                 continue;
1373
1374                         if (strcasecmp(Conf_Server[c].name, Client_ID(client)) == 0)
1375                                 Conf_Server[c].conn_id = i;
1376                 }
1377         }
1378 } /* SyncServerStruct */
1379
1380
1381 /**
1382  * Get IP address string of a connection.
1383  *
1384  * @param Idx Connection index.
1385  * @return Pointer to a global buffer containing the IP address as string.
1386  */
1387 GLOBAL const char *
1388 Conn_GetIPAInfo(CONN_ID Idx)
1389 {
1390         assert(Idx > NONE);
1391         return ng_ipaddr_tostr(&My_Connections[Idx].addr);
1392 }
1393
1394
1395 /**
1396  * Send out data of write buffer; connect new sockets.
1397  *
1398  * @param Idx   Connection index.
1399  * @returns     true on success, false otherwise.
1400  */
1401 static bool
1402 Handle_Write( CONN_ID Idx )
1403 {
1404         ssize_t len;
1405         size_t wdatalen;
1406
1407         assert( Idx > NONE );
1408         if ( My_Connections[Idx].sock < 0 ) {
1409                 LogDebug("Handle_Write() on closed socket, connection %d", Idx);
1410                 return false;
1411         }
1412         assert( My_Connections[Idx].sock > NONE );
1413
1414         wdatalen = array_bytes(&My_Connections[Idx].wbuf );
1415
1416 #ifdef ZLIB
1417         if (wdatalen == 0) {
1418                 /* Write buffer is empty, so we try to flush the compression
1419                  * buffer and get some data to work with from there :-) */
1420                 if (!Zip_Flush(Idx))
1421                         return false;
1422
1423                 /* Now the write buffer most probably has changed: */
1424                 wdatalen = array_bytes(&My_Connections[Idx].wbuf);
1425         }
1426 #endif
1427
1428         if (wdatalen == 0) {
1429                 /* Still no data, fine. */
1430                 io_event_del(My_Connections[Idx].sock, IO_WANTWRITE );
1431                 return true;
1432         }
1433
1434 #ifdef DEBUG_BUFFER
1435         LogDebug
1436             ("Handle_Write() called for connection %d, %ld bytes pending ...",
1437              Idx, wdatalen);
1438 #endif
1439
1440 #ifdef SSL_SUPPORT
1441         if ( Conn_OPTION_ISSET( &My_Connections[Idx], CONN_SSL )) {
1442                 len = ConnSSL_Write(&My_Connections[Idx], array_start(&My_Connections[Idx].wbuf), wdatalen);
1443         } else
1444 #endif
1445         {
1446                 len = write(My_Connections[Idx].sock,
1447                             array_start(&My_Connections[Idx].wbuf), wdatalen );
1448         }
1449         if( len < 0 ) {
1450                 if (errno == EAGAIN || errno == EINTR)
1451                         return true;
1452
1453                 if (!Conn_OPTION_ISSET(&My_Connections[Idx], CONN_ISCLOSING))
1454                         Log(LOG_ERR,
1455                             "Write error on connection %d (socket %d): %s!",
1456                             Idx, My_Connections[Idx].sock, strerror(errno));
1457                 else
1458                         LogDebug("Recursive write error on connection %d (socket %d): %s!",
1459                                  Idx, My_Connections[Idx].sock, strerror(errno));
1460                 Conn_Close(Idx, "Write error", NULL, false);
1461                 return false;
1462         }
1463
1464         /* move any data not yet written to beginning */
1465         array_moveleft(&My_Connections[Idx].wbuf, 1, (size_t)len);
1466
1467         return true;
1468 } /* Handle_Write */
1469
1470
1471 /**
1472  * Count established connections to a specific IP address.
1473  *
1474  * @returns     Number of established connections.
1475  */
1476 static int
1477 Count_Connections(ng_ipaddr_t *a)
1478 {
1479         int i, cnt;
1480
1481         cnt = 0;
1482         for (i = 0; i < Pool_Size; i++) {
1483                 if (My_Connections[i].sock <= NONE)
1484                         continue;
1485                 if (ng_ipaddr_ipequal(&My_Connections[i].addr, a))
1486                         cnt++;
1487         }
1488         return cnt;
1489 } /* Count_Connections */
1490
1491
1492 /**
1493  * Initialize new client connection on a listening socket.
1494  *
1495  * @param Sock  Listening socket descriptor.
1496  * @param IsSSL true if this socket expects SSL-encrypted data.
1497  * @returns     Accepted socket descriptor or -1 on error.
1498  */
1499 static int
1500 New_Connection(int Sock, UNUSED bool IsSSL)
1501 {
1502 #ifdef TCPWRAP
1503         struct request_info req;
1504 #endif
1505         ng_ipaddr_t new_addr;
1506         char ip_str[NG_INET_ADDRSTRLEN];
1507         int new_sock, new_sock_len;
1508         CLIENT *c;
1509         long cnt;
1510
1511         assert(Sock > NONE);
1512
1513         LogDebug("Accepting new connection on socket %d ...", Sock);
1514
1515         new_sock_len = (int)sizeof(new_addr);
1516         new_sock = accept(Sock, (struct sockaddr *)&new_addr,
1517                           (socklen_t *)&new_sock_len);
1518         if (new_sock < 0) {
1519                 Log(LOG_CRIT, "Can't accept connection: %s!", strerror(errno));
1520                 return -1;
1521         }
1522         NumConnectionsAccepted++;
1523
1524         if (!ng_ipaddr_tostr_r(&new_addr, ip_str)) {
1525                 Log(LOG_CRIT, "fd %d: Can't convert IP address!", new_sock);
1526                 Simple_Message(new_sock, "ERROR :Internal Server Error");
1527                 close(new_sock);
1528                 return -1;
1529         }
1530
1531 #ifdef TCPWRAP
1532         /* Validate socket using TCP Wrappers */
1533         request_init(&req, RQ_DAEMON, PACKAGE_NAME, RQ_FILE, new_sock,
1534                      RQ_CLIENT_SIN, &new_addr, NULL);
1535         fromhost(&req);
1536         if (!hosts_access(&req)) {
1537                 Log(deny_severity,
1538                     "Refused connection from %s (by TCP Wrappers)!", ip_str);
1539                 Simple_Message(new_sock, "ERROR :Connection refused");
1540                 close(new_sock);
1541                 return -1;
1542         }
1543 #endif
1544
1545         if (!Init_Socket(new_sock))
1546                 return -1;
1547
1548         /* Check global connection limit */
1549         if ((Conf_MaxConnections > 0) &&
1550             (NumConnections >= (size_t) Conf_MaxConnections)) {
1551                 Log(LOG_ALERT, "Can't accept connection: limit (%d) reached!",
1552                     Conf_MaxConnections);
1553                 Simple_Message(new_sock, "ERROR :Connection limit reached");
1554                 close(new_sock);
1555                 return -1;
1556         }
1557
1558         /* Check IP-based connection limit */
1559         cnt = Count_Connections(&new_addr);
1560         if ((Conf_MaxConnectionsIP > 0) && (cnt >= Conf_MaxConnectionsIP)) {
1561                 /* Access denied, too many connections from this IP address! */
1562                 Log(LOG_ERR,
1563                     "Refused connection from %s: too may connections (%ld) from this IP address!",
1564                     ip_str, cnt);
1565                 Simple_Message(new_sock,
1566                                "ERROR :Connection refused, too many connections from your IP address");
1567                 close(new_sock);
1568                 return -1;
1569         }
1570
1571         if (new_sock >= Pool_Size) {
1572                 if (!array_alloc(&My_ConnArray, sizeof(CONNECTION),
1573                                  (size_t) new_sock)) {
1574                         Log(LOG_EMERG,
1575                             "Can't allocate memory! [New_Connection]");
1576                         Simple_Message(new_sock, "ERROR: Internal error");
1577                         close(new_sock);
1578                         return -1;
1579                 }
1580                 LogDebug("Bumped connection pool to %ld items (internal: %ld items, %ld bytes)",
1581                          new_sock, array_length(&My_ConnArray,
1582                          sizeof(CONNECTION)), array_bytes(&My_ConnArray));
1583
1584                 /* Adjust pointer to new block */
1585                 My_Connections = array_start(&My_ConnArray);
1586                 while (Pool_Size <= new_sock)
1587                         Init_Conn_Struct(Pool_Size++);
1588         }
1589
1590         /* register callback */
1591         if (!io_event_create(new_sock, IO_WANTREAD, cb_clientserver)) {
1592                 Log(LOG_ALERT,
1593                     "Can't accept connection: io_event_create failed!");
1594                 Simple_Message(new_sock, "ERROR :Internal error");
1595                 close(new_sock);
1596                 return -1;
1597         }
1598
1599         c = Client_NewLocal(new_sock, NULL, CLIENT_UNKNOWN, false);
1600         if (!c) {
1601                 Log(LOG_ALERT,
1602                     "Can't accept connection: can't create client structure!");
1603                 Simple_Message(new_sock, "ERROR :Internal error");
1604                 io_close(new_sock);
1605                 return -1;
1606         }
1607
1608         Init_Conn_Struct(new_sock);
1609         My_Connections[new_sock].sock = new_sock;
1610         My_Connections[new_sock].addr = new_addr;
1611         My_Connections[new_sock].client = c;
1612
1613         /* Set initial hostname to IP address. This becomes overwritten when
1614          * the DNS lookup is enabled and succeeds, but is used otherwise. */
1615         if (ng_ipaddr_af(&new_addr) != AF_INET)
1616                 snprintf(My_Connections[new_sock].host,
1617                          sizeof(My_Connections[new_sock].host), "[%s]", ip_str);
1618         else
1619                 strlcpy(My_Connections[new_sock].host, ip_str,
1620                         sizeof(My_Connections[new_sock].host));
1621
1622         Client_SetHostname(c, My_Connections[new_sock].host);
1623
1624         Log(LOG_INFO, "Accepted connection %d from \"%s:%d\" on socket %d.",
1625             new_sock, My_Connections[new_sock].host,
1626             ng_ipaddr_getport(&new_addr), Sock);
1627         Account_Connection();
1628
1629 #ifdef SSL_SUPPORT
1630         /* Delay connection initalization until SSL handshake is finished */
1631         if (!IsSSL)
1632 #endif
1633                 Conn_StartLogin(new_sock);
1634
1635         return new_sock;
1636 } /* New_Connection */
1637
1638
1639 /**
1640  * Finish connection initialization, start resolver subprocess.
1641  *
1642  * @param Idx Connection index.
1643  */
1644 GLOBAL void
1645 Conn_StartLogin(CONN_ID Idx)
1646 {
1647         int ident_sock = -1;
1648
1649         assert(Idx >= 0);
1650
1651         /* Nothing to do if DNS (and resolver subprocess) is disabled */
1652         if (!Conf_DNS)
1653                 return;
1654
1655 #ifdef IDENTAUTH
1656         /* Should we make an IDENT request? */
1657         if (Conf_Ident)
1658                 ident_sock = My_Connections[Idx].sock;
1659 #endif
1660
1661         if (Conf_NoticeAuth) {
1662                 /* Send "NOTICE AUTH" messages to the client */
1663 #ifdef IDENTAUTH
1664                 if (Conf_Ident)
1665                         (void)Conn_WriteStr(Idx,
1666                                 "NOTICE AUTH :*** Looking up your hostname and checking ident");
1667                 else
1668 #endif
1669                         (void)Conn_WriteStr(Idx,
1670                                 "NOTICE AUTH :*** Looking up your hostname");
1671                 /* Send buffered data to the client, but break on errors
1672                  * because Handle_Write() would have closed the connection
1673                  * again in this case! */
1674                 if (!Handle_Write(Idx))
1675                         return;
1676         }
1677
1678         Resolve_Addr(&My_Connections[Idx].proc_stat, &My_Connections[Idx].addr,
1679                      ident_sock, cb_Read_Resolver_Result);
1680 }
1681
1682
1683 /**
1684  * Update global connection counters.
1685  */
1686 static void
1687 Account_Connection(void)
1688 {
1689         NumConnections++;
1690         idle_t = 0;
1691         if (NumConnections > NumConnectionsMax)
1692                 NumConnectionsMax = NumConnections;
1693         LogDebug("Total number of connections now %lu (max %lu).",
1694                  NumConnections, NumConnectionsMax);
1695 } /* Account_Connection */
1696
1697
1698 /**
1699  * Translate socket handle into connection index.
1700  *
1701  * @param Sock  Socket handle.
1702  * @returns     Connecion index or NONE, if no connection could be found.
1703  */
1704 static CONN_ID
1705 Socket2Index( int Sock )
1706 {
1707         assert( Sock >= 0 );
1708
1709         if( Sock >= Pool_Size || My_Connections[Sock].sock != Sock ) {
1710                 /* the Connection was already closed again, likely due to
1711                  * an error. */
1712                 LogDebug("Socket2Index: can't get connection for socket %d!", Sock);
1713                 return NONE;
1714         }
1715         return Sock;
1716 } /* Socket2Index */
1717
1718
1719 /**
1720  * Read data from the network to the read buffer. If an error occurs,
1721  * the socket of this connection will be shut down.
1722  *
1723  * @param Idx   Connection index.
1724  */
1725 static void
1726 Read_Request( CONN_ID Idx )
1727 {
1728         ssize_t len;
1729         static const unsigned int maxbps = COMMAND_LEN / 2;
1730         char readbuf[READBUFFER_LEN];
1731         time_t t;
1732         CLIENT *c;
1733         assert( Idx > NONE );
1734         assert( My_Connections[Idx].sock > NONE );
1735
1736 #ifdef ZLIB
1737         if ((array_bytes(&My_Connections[Idx].rbuf) >= READBUFFER_LEN) ||
1738                 (array_bytes(&My_Connections[Idx].zip.rbuf) >= READBUFFER_LEN))
1739 #else
1740         if (array_bytes(&My_Connections[Idx].rbuf) >= READBUFFER_LEN)
1741 #endif
1742         {
1743                 /* Read buffer is full */
1744                 Log(LOG_ERR,
1745                     "Receive buffer space exhausted (connection %d): %d bytes",
1746                     Idx, array_bytes(&My_Connections[Idx].rbuf));
1747                 Conn_Close(Idx, "Receive buffer space exhausted", NULL, false);
1748                 return;
1749         }
1750
1751 #ifdef SSL_SUPPORT
1752         if (Conn_OPTION_ISSET(&My_Connections[Idx], CONN_SSL))
1753                 len = ConnSSL_Read( &My_Connections[Idx], readbuf, sizeof(readbuf));
1754         else
1755 #endif
1756         len = read(My_Connections[Idx].sock, readbuf, sizeof(readbuf));
1757         if (len == 0) {
1758                 LogDebug("Client \"%s:%u\" is closing connection %d ...",
1759                          My_Connections[Idx].host,
1760                          ng_ipaddr_tostr(&My_Connections[Idx].addr), Idx);
1761                 Conn_Close(Idx, NULL, "Client closed connection", false);
1762                 return;
1763         }
1764
1765         if (len < 0) {
1766                 if( errno == EAGAIN ) return;
1767                 Log(LOG_ERR, "Read error on connection %d (socket %d): %s!",
1768                     Idx, My_Connections[Idx].sock, strerror(errno));
1769                 Conn_Close(Idx, "Read error", "Client closed connection",
1770                            false);
1771                 return;
1772         }
1773 #ifdef ZLIB
1774         if (Conn_OPTION_ISSET(&My_Connections[Idx], CONN_ZIP)) {
1775                 if (!array_catb(&My_Connections[Idx].zip.rbuf, readbuf,
1776                                 (size_t) len)) {
1777                         Log(LOG_ERR,
1778                             "Could not append received data to zip input buffer (connection %d): %d bytes!",
1779                             Idx, len);
1780                         Conn_Close(Idx, "Receive buffer space exhausted", NULL,
1781                                    false);
1782                         return;
1783                 }
1784         } else
1785 #endif
1786         {
1787                 if (!array_catb( &My_Connections[Idx].rbuf, readbuf, len)) {
1788                         Log(LOG_ERR,
1789                             "Could not append received data to input buffer (connection %d): %d bytes!",
1790                             Idx, len);
1791                         Conn_Close(Idx, "Receive buffer space exhausted", NULL, false );
1792                 }
1793         }
1794
1795         /* Update connection statistics */
1796         My_Connections[Idx].bytes_in += len;
1797         My_Connections[Idx].bps += Handle_Buffer(Idx);
1798
1799         /* Make sure that there is still a valid client registered */
1800         c = Conn_GetClient(Idx);
1801         if (!c)
1802                 return;
1803
1804         /* Update timestamp of last data received if this connection is
1805          * registered as a user, server or service connection. Don't update
1806          * otherwise, so users have at least Conf_PongTimeout seconds time to
1807          * register with the IRC server -- see Check_Connections().
1808          * Update "lastping", too, if time shifted backwards ... */
1809         if (Client_Type(c) == CLIENT_USER
1810             || Client_Type(c) == CLIENT_SERVER
1811             || Client_Type(c) == CLIENT_SERVICE) {
1812                 t = time(NULL);
1813                 if (My_Connections[Idx].lastdata != t)
1814                         My_Connections[Idx].bps = 0;
1815
1816                 My_Connections[Idx].lastdata = t;
1817                 if (My_Connections[Idx].lastping > t)
1818                         My_Connections[Idx].lastping = t;
1819         }
1820
1821         /* Look at the data in the (read-) buffer of this connection */
1822         if (Client_Type(c) != CLIENT_SERVER
1823             && Client_Type(c) != CLIENT_UNKNOWNSERVER
1824             && Client_Type(c) != CLIENT_SERVICE
1825             && My_Connections[Idx].bps >= maxbps) {
1826                 LogDebug("Throttling connection %d: BPS exceeded! (%u >= %u)",
1827                          Idx, My_Connections[Idx].bps, maxbps);
1828                 Conn_SetPenalty(Idx, 1);
1829         }
1830 } /* Read_Request */
1831
1832
1833 /**
1834  * Handle all data in the connection read-buffer.
1835  *
1836  * Data is processed until no complete command is left in the read buffer,
1837  * or MAX_COMMANDS[_SERVER|_SERVICE] commands were processed.
1838  * When a fatal error occurs, the connection is shut down.
1839  *
1840  * @param Idx   Index of the connection.
1841  * @returns     Number of bytes processed.
1842  */
1843 static unsigned int
1844 Handle_Buffer(CONN_ID Idx)
1845 {
1846 #ifndef STRICT_RFC
1847         char *ptr1, *ptr2, *first_eol;
1848 #endif
1849         char *ptr;
1850         size_t len, delta;
1851         time_t starttime;
1852 #ifdef ZLIB
1853         bool old_z;
1854 #endif
1855         unsigned int i, maxcmd = MAX_COMMANDS, len_processed = 0;
1856         CLIENT *c;
1857
1858         c = Conn_GetClient(Idx);
1859         starttime = time(NULL);
1860
1861         assert(c != NULL);
1862
1863         /* Servers get special command limits that depend on the user count */
1864         switch (Client_Type(c)) {
1865             case CLIENT_SERVER:
1866                 maxcmd = (int)(Client_UserCount() / 5)
1867                        + MAX_COMMANDS_SERVER_MIN;
1868                 /* Allow servers to handle even more commands while peering
1869                  * to speed up server login and network synchronization. */
1870                 if (Conn_LastPing(Idx) == 0)
1871                         maxcmd *= 5;
1872                 break;
1873             case CLIENT_SERVICE:
1874                 maxcmd = MAX_COMMANDS_SERVICE; break;
1875         }
1876
1877         for (i=0; i < maxcmd; i++) {
1878                 /* Check penalty */
1879                 if (My_Connections[Idx].delaytime > starttime)
1880                         return 0;
1881 #ifdef ZLIB
1882                 /* Unpack compressed data, if compression is in use */
1883                 if (Conn_OPTION_ISSET(&My_Connections[Idx], CONN_ZIP)) {
1884                         /* When unzipping fails, Unzip_Buffer() shuts
1885                          * down the connection itself */
1886                         if (!Unzip_Buffer(Idx))
1887                                 return 0;
1888                 }
1889 #endif
1890
1891                 if (0 == array_bytes(&My_Connections[Idx].rbuf))
1892                         break;
1893
1894                 /* Make sure that the buffer is NULL terminated */
1895                 if (!array_cat0_temporary(&My_Connections[Idx].rbuf)) {
1896                         Conn_Close(Idx, NULL,
1897                                    "Can't allocate memory [Handle_Buffer]",
1898                                    true);
1899                         return 0;
1900                 }
1901
1902                 /* RFC 2812, section "2.3 Messages", 5th paragraph:
1903                  * "IRC messages are always lines of characters terminated
1904                  * with a CR-LF (Carriage Return - Line Feed) pair [...]". */
1905                 delta = 2;
1906                 ptr = strstr(array_start(&My_Connections[Idx].rbuf), "\r\n");
1907
1908 #ifndef STRICT_RFC
1909                 /* Check for non-RFC-compliant request (only CR or LF)?
1910                  * Unfortunately, there are quite a few clients out there
1911                  * that do this -- e. g. mIRC, BitchX, and Trillian :-( */
1912                 ptr1 = strchr(array_start(&My_Connections[Idx].rbuf), '\r');
1913                 ptr2 = strchr(array_start(&My_Connections[Idx].rbuf), '\n');
1914                 if (ptr) {
1915                         /* Check if there is a single CR or LF _before_ the
1916                          * corerct CR+LF line terminator:  */
1917                         first_eol = ptr1 < ptr2 ? ptr1 : ptr2;
1918                         if (first_eol < ptr) {
1919                                 /* Single CR or LF before CR+LF found */
1920                                 ptr = first_eol;
1921                                 delta = 1;
1922                         }
1923                 } else if (ptr1 || ptr2) {
1924                         /* No CR+LF terminated command found, but single
1925                          * CR or LF found ... */
1926                         if (ptr1 && ptr2)
1927                                 ptr = ptr1 < ptr2 ? ptr1 : ptr2;
1928                         else
1929                                 ptr = ptr1 ? ptr1 : ptr2;
1930                         delta = 1;
1931                 }
1932 #endif
1933
1934                 if (!ptr)
1935                         break;
1936
1937                 /* Complete (=line terminated) request found, handle it! */
1938                 *ptr = '\0';
1939
1940                 len = ptr - (char *)array_start(&My_Connections[Idx].rbuf) + delta;
1941
1942                 if (len > (COMMAND_LEN - 1)) {
1943                         /* Request must not exceed 512 chars (incl. CR+LF!),
1944                          * see RFC 2812. Disconnect Client if this happens. */
1945                         Log(LOG_ERR,
1946                             "Request too long (connection %d): %d bytes (max. %d expected)!",
1947                             Idx, array_bytes(&My_Connections[Idx].rbuf),
1948                             COMMAND_LEN - 1);
1949                         Conn_Close(Idx, NULL, "Request too long", true);
1950                         return 0;
1951                 }
1952
1953                 len_processed += (unsigned int)len;
1954                 if (len <= delta) {
1955                         /* Request is empty (only '\r\n', '\r' or '\n');
1956                          * delta is 2 ('\r\n') or 1 ('\r' or '\n'), see above */
1957                         array_moveleft(&My_Connections[Idx].rbuf, 1, len);
1958                         continue;
1959                 }
1960 #ifdef ZLIB
1961                 /* remember if stream is already compressed */
1962                 old_z = My_Connections[Idx].options & CONN_ZIP;
1963 #endif
1964
1965                 My_Connections[Idx].msg_in++;
1966                 if (!Parse_Request
1967                     (Idx, (char *)array_start(&My_Connections[Idx].rbuf)))
1968                         return 0; /* error -> connection has been closed */
1969
1970                 array_moveleft(&My_Connections[Idx].rbuf, 1, len);
1971 #ifdef DEBUG_BUFFER
1972                 LogDebug("Connection %d: %d bytes left in read buffer.",
1973                          Idx, array_bytes(&My_Connections[Idx].rbuf));
1974 #endif
1975 #ifdef ZLIB
1976                 if ((!old_z) && (My_Connections[Idx].options & CONN_ZIP) &&
1977                     (array_bytes(&My_Connections[Idx].rbuf) > 0)) {
1978                         /* The last command activated socket compression.
1979                          * Data that was read after that needs to be copied
1980                          * to the unzip buffer for decompression: */
1981                         if (!array_copy
1982                             (&My_Connections[Idx].zip.rbuf,
1983                              &My_Connections[Idx].rbuf)) {
1984                                 Conn_Close(Idx, NULL,
1985                                            "Can't allocate memory [Handle_Buffer]",
1986                                            true);
1987                                 return 0;
1988                         }
1989
1990                         array_trunc(&My_Connections[Idx].rbuf);
1991                         LogDebug
1992                             ("Moved already received data (%u bytes) to uncompression buffer.",
1993                              array_bytes(&My_Connections[Idx].zip.rbuf));
1994                 }
1995 #endif
1996         }
1997         return len_processed;
1998 } /* Handle_Buffer */
1999
2000
2001 /**
2002  * Check whether established connections are still alive or not.
2003  * If not, play PING-PONG first; and if that doesn't help either,
2004  * disconnect the respective peer.
2005  */
2006 static void
2007 Check_Connections(void)
2008 {
2009         CLIENT *c;
2010         CONN_ID i;
2011         char msg[64];
2012
2013         for (i = 0; i < Pool_Size; i++) {
2014                 if (My_Connections[i].sock < 0)
2015                         continue;
2016
2017                 c = Conn_GetClient(i);
2018                 if (c && ((Client_Type(c) == CLIENT_USER)
2019                           || (Client_Type(c) == CLIENT_SERVER)
2020                           || (Client_Type(c) == CLIENT_SERVICE))) {
2021                         /* connected User, Server or Service */
2022                         if (My_Connections[i].lastping >
2023                             My_Connections[i].lastdata) {
2024                                 /* We already sent a ping */
2025                                 if (My_Connections[i].lastping <
2026                                     time(NULL) - Conf_PongTimeout) {
2027                                         /* Timeout */
2028                                         snprintf(msg, sizeof(msg),
2029                                                  "Ping timeout: %d seconds",
2030                                                  Conf_PongTimeout);
2031                                         LogDebug("Connection %d: %s.", i, msg);
2032                                         Conn_Close(i, NULL, msg, true);
2033                                 }
2034                         } else if (My_Connections[i].lastdata <
2035                                    time(NULL) - Conf_PingTimeout) {
2036                                 /* We need to send a PING ... */
2037                                 LogDebug("Connection %d: sending PING ...", i);
2038                                 Conn_UpdatePing(i);
2039                                 Conn_WriteStr(i, "PING :%s",
2040                                               Client_ID(Client_ThisServer()));
2041                         }
2042                 } else {
2043                         /* The connection is not fully established yet, so
2044                          * we don't do the PING-PONG game here but instead
2045                          * disconnect the client after "a short time" if it's
2046                          * still not registered. */
2047
2048                         if (My_Connections[i].lastdata <
2049                             time(NULL) - Conf_PongTimeout) {
2050                                 LogDebug
2051                                     ("Unregistered connection %d timed out ...",
2052                                      i);
2053                                 Conn_Close(i, NULL, "Timeout", false);
2054                         }
2055                 }
2056         }
2057 } /* Check_Connections */
2058
2059
2060 /**
2061  * Check if further server links should be established.
2062  */
2063 static void
2064 Check_Servers(void)
2065 {
2066         int i, n;
2067         time_t time_now;
2068
2069         time_now = time(NULL);
2070
2071         /* Check all configured servers */
2072         for (i = 0; i < MAX_SERVERS; i++) {
2073                 if (Conf_Server[i].conn_id != NONE)
2074                         continue;       /* Already establishing or connected */
2075                 if (!Conf_Server[i].host[0] || !Conf_Server[i].port > 0)
2076                         continue;       /* No host and/or port configured */
2077                 if (Conf_Server[i].flags & CONF_SFLAG_DISABLED)
2078                         continue;       /* Disabled configuration entry */
2079                 if (Conf_Server[i].lasttry > (time_now - Conf_ConnectRetry))
2080                         continue;       /* We have to wait a little bit ... */
2081
2082                 /* Is there already a connection in this group? */
2083                 if (Conf_Server[i].group > NONE) {
2084                         for (n = 0; n < MAX_SERVERS; n++) {
2085                                 if (n == i)
2086                                         continue;
2087                                 if ((Conf_Server[n].conn_id != NONE) &&
2088                                     (Conf_Server[n].group == Conf_Server[i].group))
2089                                         break;
2090                         }
2091                         if (n < MAX_SERVERS)
2092                                 continue;
2093                 }
2094
2095                 /* Okay, try to connect now */
2096                 Log(LOG_NOTICE,
2097                     "Preparing to establish a new server link for \"%s\" ...",
2098                     Conf_Server[i].name);
2099                 Conf_Server[i].lasttry = time_now;
2100                 Conf_Server[i].conn_id = SERVER_WAIT;
2101                 assert(Proc_GetPipeFd(&Conf_Server[i].res_stat) < 0);
2102                 Resolve_Name(&Conf_Server[i].res_stat, Conf_Server[i].host,
2103                              cb_Connect_to_Server);
2104         }
2105 } /* Check_Servers */
2106
2107
2108 /**
2109  * Establish a new outgoing server connection.
2110  *
2111  * @param Server        Configuration index of the server.
2112  * @param dest          Destination IP address to connect to.
2113  */
2114 static void
2115 New_Server( int Server , ng_ipaddr_t *dest)
2116 {
2117         /* Establish new server link */
2118         char ip_str[NG_INET_ADDRSTRLEN];
2119         int af_dest, res, new_sock;
2120         CLIENT *c;
2121
2122         assert( Server > NONE );
2123
2124         /* Make sure that the remote server hasn't re-linked to this server
2125          * asynchronously on its own */
2126         if (Conf_Server[Server].conn_id > NONE) {
2127                 Log(LOG_INFO,
2128                         "Connection to \"%s\" meanwhile re-established, aborting preparation.");
2129                 return;
2130         }
2131
2132         if (!ng_ipaddr_tostr_r(dest, ip_str)) {
2133                 Log(LOG_WARNING, "New_Server: Could not convert IP to string");
2134                 Conf_Server[Server].conn_id = NONE;
2135                 return;
2136         }
2137
2138         af_dest = ng_ipaddr_af(dest);
2139         new_sock = socket(af_dest, SOCK_STREAM, 0);
2140
2141         Log(LOG_INFO,
2142             "Establishing connection for \"%s\" to \"%s:%d\" (%s), socket %d ...",
2143             Conf_Server[Server].name, Conf_Server[Server].host,
2144             Conf_Server[Server].port, ip_str, new_sock);
2145
2146         if (new_sock < 0) {
2147                 Log(LOG_CRIT, "Can't create socket (af %d): %s!",
2148                     af_dest, strerror(errno));
2149                 Conf_Server[Server].conn_id = NONE;
2150                 return;
2151         }
2152
2153         if (!Init_Socket(new_sock)) {
2154                 Conf_Server[Server].conn_id = NONE;
2155                 return;
2156         }
2157
2158         /* is a bind address configured? */
2159         res = ng_ipaddr_af(&Conf_Server[Server].bind_addr);
2160         /* if yes, bind now. If it fails, warn and let connect() pick a source address */
2161         if (res && bind(new_sock, (struct sockaddr *) &Conf_Server[Server].bind_addr,
2162                                 ng_ipaddr_salen(&Conf_Server[Server].bind_addr)))
2163         {
2164                 ng_ipaddr_tostr_r(&Conf_Server[Server].bind_addr, ip_str);
2165                 Log(LOG_WARNING, "Can't bind socket to %s: %s!", ip_str, strerror(errno));
2166         }
2167         ng_ipaddr_setport(dest, Conf_Server[Server].port);
2168         res = connect(new_sock, (struct sockaddr *) dest, ng_ipaddr_salen(dest));
2169         if(( res != 0 ) && ( errno != EINPROGRESS )) {
2170                 Log( LOG_CRIT, "Can't connect socket: %s!", strerror( errno ));
2171                 close( new_sock );
2172                 Conf_Server[Server].conn_id = NONE;
2173                 return;
2174         }
2175
2176         if (!array_alloc(&My_ConnArray, sizeof(CONNECTION), (size_t)new_sock)) {
2177                 Log(LOG_ALERT,
2178                     "Cannot allocate memory for server connection (socket %d)",
2179                     new_sock);
2180                 close( new_sock );
2181                 Conf_Server[Server].conn_id = NONE;
2182                 return;
2183         }
2184
2185         if (!io_event_create( new_sock, IO_WANTWRITE, cb_connserver)) {
2186                 Log(LOG_ALERT, "io_event_create(): could not add fd %d", strerror(errno));
2187                 close(new_sock);
2188                 Conf_Server[Server].conn_id = NONE;
2189                 return;
2190         }
2191
2192         My_Connections = array_start(&My_ConnArray);
2193
2194         assert(My_Connections[new_sock].sock <= 0);
2195
2196         Init_Conn_Struct(new_sock);
2197
2198         ng_ipaddr_tostr_r(dest, ip_str);
2199         c = Client_NewLocal(new_sock, ip_str, CLIENT_UNKNOWNSERVER, false);
2200         if (!c) {
2201                 Log( LOG_ALERT, "Can't establish connection: can't create client structure!" );
2202                 io_close(new_sock);
2203                 Conf_Server[Server].conn_id = NONE;
2204                 return;
2205         }
2206
2207         /* Conn_Close() decrements this counter again */
2208         Account_Connection();
2209         Client_SetIntroducer( c, c );
2210         Client_SetToken( c, TOKEN_OUTBOUND );
2211
2212         /* Register connection */
2213         if (!Conf_SetServer(Server, new_sock))
2214                 return;
2215         My_Connections[new_sock].sock = new_sock;
2216         My_Connections[new_sock].addr = *dest;
2217         My_Connections[new_sock].client = c;
2218         strlcpy( My_Connections[new_sock].host, Conf_Server[Server].host,
2219                                 sizeof(My_Connections[new_sock].host ));
2220
2221 #ifdef SSL_SUPPORT
2222         if (Conf_Server[Server].SSLConnect && !ConnSSL_PrepareConnect( &My_Connections[new_sock],
2223                                                                 &Conf_Server[Server] ))
2224         {
2225                 Log(LOG_ALERT, "Could not initialize SSL for outgoing connection");
2226                 Conn_Close( new_sock, "Could not initialize SSL for outgoing connection", NULL, false );
2227                 Init_Conn_Struct( new_sock );
2228                 Conf_Server[Server].conn_id = NONE;
2229                 return;
2230         }
2231 #endif
2232         LogDebug("Registered new connection %d on socket %d (%ld in total).",
2233                  new_sock, My_Connections[new_sock].sock, NumConnections);
2234         Conn_OPTION_ADD( &My_Connections[new_sock], CONN_ISCONNECTING );
2235 } /* New_Server */
2236
2237
2238 /**
2239  * Initialize connection structure.
2240  *
2241  * @param Idx   Connection index.
2242  */
2243 static void
2244 Init_Conn_Struct(CONN_ID Idx)
2245 {
2246         time_t now = time(NULL);
2247
2248         memset(&My_Connections[Idx], 0, sizeof(CONNECTION));
2249         My_Connections[Idx].sock = -1;
2250         My_Connections[Idx].signon = now;
2251         My_Connections[Idx].lastdata = now;
2252         My_Connections[Idx].lastprivmsg = now;
2253         Proc_InitStruct(&My_Connections[Idx].proc_stat);
2254
2255 #ifdef ICONV
2256         My_Connections[Idx].iconv_from = (iconv_t)(-1);
2257         My_Connections[Idx].iconv_to = (iconv_t)(-1);
2258 #endif
2259 } /* Init_Conn_Struct */
2260
2261
2262 /**
2263  * Initialize options of a new socket.
2264  *
2265  * For example, we try to set socket options SO_REUSEADDR and IPTOS_LOWDELAY.
2266  * The socket is automatically closed if a fatal error is encountered.
2267  *
2268  * @param Sock  Socket handle.
2269  * @returns false if socket was closed due to fatal error.
2270  */
2271 static bool
2272 Init_Socket( int Sock )
2273 {
2274         int value;
2275
2276         if (!io_setnonblock(Sock)) {
2277                 Log( LOG_CRIT, "Can't enable non-blocking mode for socket: %s!", strerror( errno ));
2278                 close( Sock );
2279                 return false;
2280         }
2281
2282         /* Don't block this port after socket shutdown */
2283         value = 1;
2284         if( setsockopt( Sock, SOL_SOCKET, SO_REUSEADDR, &value, (socklen_t)sizeof( value )) != 0 )
2285         {
2286                 Log( LOG_ERR, "Can't set socket option SO_REUSEADDR: %s!", strerror( errno ));
2287                 /* ignore this error */
2288         }
2289
2290         /* Set type of service (TOS) */
2291 #if defined(IPPROTO_IP) && defined(IPTOS_LOWDELAY)
2292         value = IPTOS_LOWDELAY;
2293         if (setsockopt(Sock, IPPROTO_IP, IP_TOS, &value,
2294                        (socklen_t) sizeof(value))) {
2295                 LogDebug("Can't set socket option IP_TOS: %s!",
2296                          strerror(errno));
2297                 /* ignore this error */
2298         } else
2299                 LogDebug("IP_TOS on socket %d has been set to IPTOS_LOWDELAY.",
2300                          Sock);
2301 #endif
2302
2303         return true;
2304 } /* Init_Socket */
2305
2306
2307 /**
2308  * Read results of a resolver sub-process and try to initiate a new server
2309  * connection.
2310  *
2311  * @param fd            File descriptor of the pipe to the sub-process.
2312  * @param events        (ignored IO specification)
2313  */
2314 static void
2315 cb_Connect_to_Server(int fd, UNUSED short events)
2316 {
2317         /* Read result of resolver sub-process from pipe and start connection */
2318         int i;
2319         size_t len;
2320         ng_ipaddr_t dest_addrs[4];      /* we can handle at most 3; but we read up to
2321                                            four so we can log the 'more than we can handle'
2322                                            condition. First result is tried immediately, rest
2323                                            is saved for later if needed. */
2324
2325         LogDebug("Resolver: Got forward lookup callback on fd %d, events %d", fd, events);
2326
2327         for (i=0; i < MAX_SERVERS; i++) {
2328                   if (Proc_GetPipeFd(&Conf_Server[i].res_stat) == fd )
2329                           break;
2330         }
2331
2332         if( i >= MAX_SERVERS) {
2333                 /* Ops, no matching server found?! */
2334                 io_close( fd );
2335                 LogDebug("Resolver: Got Forward Lookup callback for unknown server!?");
2336                 return;
2337         }
2338
2339         /* Read result from pipe */
2340         len = Proc_Read(&Conf_Server[i].res_stat, dest_addrs, sizeof(dest_addrs));
2341         Proc_Close(&Conf_Server[i].res_stat);
2342         if (len == 0) {
2343                 /* Error resolving hostname: reset server structure */
2344                 Conf_Server[i].conn_id = NONE;
2345                 return;
2346         }
2347
2348         assert((len % sizeof(ng_ipaddr_t)) == 0);
2349
2350         LogDebug("Got result from resolver: %u structs (%u bytes).", len/sizeof(ng_ipaddr_t), len);
2351
2352         memset(&Conf_Server[i].dst_addr, 0, sizeof(Conf_Server[i].dst_addr));
2353         if (len > sizeof(ng_ipaddr_t)) {
2354                 /* more than one address for this hostname, remember them
2355                  * in case first address is unreachable/not available */
2356                 len -= sizeof(ng_ipaddr_t);
2357                 if (len > sizeof(Conf_Server[i].dst_addr)) {
2358                         len = sizeof(Conf_Server[i].dst_addr);
2359                         Log(LOG_NOTICE,
2360                                 "Notice: Resolver returned more IP Addresses for host than we can handle, additional addresses dropped.");
2361                 }
2362                 memcpy(&Conf_Server[i].dst_addr, &dest_addrs[1], len);
2363         }
2364         /* connect() */
2365         New_Server(i, dest_addrs);
2366 } /* cb_Read_Forward_Lookup */
2367
2368
2369 /**
2370  * Read results of a resolver sub-process from the pipe and update the
2371  * appropriate connection/client structure(s): hostname and/or IDENT user name.
2372  *
2373  * @param r_fd          File descriptor of the pipe to the sub-process.
2374  * @param events        (ignored IO specification)
2375  */
2376 static void
2377 cb_Read_Resolver_Result( int r_fd, UNUSED short events )
2378 {
2379         CLIENT *c;
2380         CONN_ID i;
2381         size_t len;
2382         char *identptr;
2383 #ifdef IDENTAUTH
2384         char readbuf[HOST_LEN + 2 + CLIENT_USER_LEN];
2385         char *ptr;
2386 #else
2387         char readbuf[HOST_LEN + 1];
2388 #endif
2389
2390         LogDebug("Resolver: Got callback on fd %d, events %d", r_fd, events );
2391         i = Conn_GetFromProc(r_fd);
2392         if (i == NONE) {
2393                 /* Ops, none found? Probably the connection has already
2394                  * been closed!? We'll ignore that ... */
2395                 io_close( r_fd );
2396                 LogDebug("Resolver: Got callback for unknown connection!?");
2397                 return;
2398         }
2399
2400         /* Read result from pipe */
2401         len = Proc_Read(&My_Connections[i].proc_stat, readbuf, sizeof readbuf -1);
2402         Proc_Close(&My_Connections[i].proc_stat);
2403         if (len == 0)
2404                 return;
2405
2406         readbuf[len] = '\0';
2407         identptr = strchr(readbuf, '\n');
2408         assert(identptr != NULL);
2409         if (!identptr) {
2410                 Log( LOG_CRIT, "Resolver: Got malformed result!");
2411                 return;
2412         }
2413
2414         *identptr = '\0';
2415         LogDebug("Got result from resolver: \"%s\" (%u bytes read).", readbuf, len);
2416         /* Okay, we got a complete result: this is a host name for outgoing
2417          * connections and a host name and IDENT user name (if enabled) for
2418          * incoming connections.*/
2419         assert ( My_Connections[i].sock >= 0 );
2420         /* Incoming connection. Search client ... */
2421         c = Conn_GetClient( i );
2422         assert( c != NULL );
2423
2424         /* Only update client information of unregistered clients.
2425          * Note: user commands (e. g. WEBIRC) are always read _after_ reading
2426          * the resolver results, so we don't have to worry to override settings
2427          * from these commands here. */
2428         if(Client_Type(c) == CLIENT_UNKNOWN) {
2429                 strlcpy(My_Connections[i].host, readbuf,
2430                         sizeof(My_Connections[i].host));
2431                 Client_SetHostname(c, readbuf);
2432                 if (Conf_NoticeAuth)
2433                         (void)Conn_WriteStr(i,
2434                                         "NOTICE AUTH :*** Found your hostname: %s",
2435                                         My_Connections[i].host);
2436 #ifdef IDENTAUTH
2437                 ++identptr;
2438                 if (*identptr) {
2439                         ptr = identptr;
2440                         while (*ptr) {
2441                                 if ((*ptr < '0' || *ptr > '9') &&
2442                                     (*ptr < 'A' || *ptr > 'Z') &&
2443                                     (*ptr < 'a' || *ptr > 'z'))
2444                                         break;
2445                                 ptr++;
2446                         }
2447                         if (*ptr) {
2448                                 /* Erroneous IDENT reply */
2449                                 Log(LOG_NOTICE,
2450                                     "Got invalid IDENT reply for connection %d! Ignored.",
2451                                     i);
2452                         } else {
2453                                 Log(LOG_INFO,
2454                                     "IDENT lookup for connection %d: \"%s\".",
2455                                     i, identptr);
2456                                 Client_SetUser(c, identptr, true);
2457                         }
2458                         if (Conf_NoticeAuth) {
2459                                 (void)Conn_WriteStr(i,
2460                                         "NOTICE AUTH :*** Got %sident response%s%s",
2461                                         *ptr ? "invalid " : "",
2462                                         *ptr ? "" : ": ",
2463                                         *ptr ? "" : identptr);
2464                         }
2465                 } else if(Conf_Ident) {
2466                         Log(LOG_INFO, "IDENT lookup for connection %d: no result.", i);
2467                         if (Conf_NoticeAuth)
2468                                 (void)Conn_WriteStr(i,
2469                                         "NOTICE AUTH :*** No ident response");
2470                 }
2471 #endif
2472
2473                 if (Conf_NoticeAuth) {
2474                         /* Send buffered data to the client, but break on
2475                          * errors because Handle_Write() would have closed
2476                          * the connection again in this case! */
2477                         if (!Handle_Write(i))
2478                                 return;
2479                 }
2480
2481                 Class_HandleServerBans(c);
2482         }
2483 #ifdef DEBUG
2484         else
2485                 LogDebug("Resolver: discarding result for already registered connection %d.", i);
2486 #endif
2487 } /* cb_Read_Resolver_Result */
2488
2489
2490 /**
2491  * Write a "simple" (error) message to a socket.
2492  *
2493  * The message is sent without using the connection write buffers, without
2494  * compression/encryption, and even without any error reporting. It is
2495  * designed for error messages of e.g. New_Connection().
2496  *
2497  * @param Sock  Socket handle.
2498  * @param Msg   Message string to send.
2499  */
2500 static void
2501 Simple_Message(int Sock, const char *Msg)
2502 {
2503         char buf[COMMAND_LEN];
2504         size_t len;
2505
2506         assert(Sock > NONE);
2507         assert(Msg != NULL);
2508
2509         strlcpy(buf, Msg, sizeof buf - 2);
2510         len = strlcat(buf, "\r\n", sizeof buf);
2511         if (write(Sock, buf, len) < 0) {
2512                 /* Because this function most probably got called to log
2513                  * an error message, any write error is ignored here to
2514                  * avoid an endless loop. But casting the result of write()
2515                  * to "void" doesn't satisfy the GNU C code attribute
2516                  * "warn_unused_result" which is used by some versions of
2517                  * glibc (e.g. 2.11.1), therefore this silly error
2518                  * "handling" code here :-( */
2519                 return;
2520         }
2521 } /* Simple_Error */
2522
2523
2524 /**
2525  * Get CLIENT structure that belongs to a local connection identified by its
2526  * index number. Each connection belongs to a client by definition, so it is
2527  * not required that the caller checks for NULL return values.
2528  *
2529  * @param Idx   Connection index number.
2530  * @returns     Pointer to CLIENT structure.
2531  */
2532 GLOBAL CLIENT *
2533 Conn_GetClient( CONN_ID Idx ) 
2534 {
2535         CONNECTION *c;
2536
2537         assert(Idx >= 0);
2538         c = array_get(&My_ConnArray, sizeof (CONNECTION), (size_t)Idx);
2539         assert(c != NULL);
2540         return c ? c->client : NULL;
2541 }
2542
2543 /**
2544  * Get PROC_STAT sub-process structure of a connection.
2545  *
2546  * @param Idx   Connection index number.
2547  * @returns     PROC_STAT structure.
2548  */
2549 GLOBAL PROC_STAT *
2550 Conn_GetProcStat(CONN_ID Idx)
2551 {
2552         CONNECTION *c;
2553
2554         assert(Idx >= 0);
2555         c = array_get(&My_ConnArray, sizeof (CONNECTION), (size_t)Idx);
2556         assert(c != NULL);
2557         return &c->proc_stat;
2558 } /* Conn_GetProcStat */
2559
2560
2561 /**
2562  * Get CONN_ID from file descriptor associated to a subprocess structure.
2563  *
2564  * @param fd    File descriptor.
2565  * @returns     CONN_ID or NONE (-1).
2566  */
2567 GLOBAL CONN_ID
2568 Conn_GetFromProc(int fd)
2569 {
2570         int i;
2571
2572         assert(fd > 0);
2573         for (i = 0; i < Pool_Size; i++) {
2574                 if ((My_Connections[i].sock != NONE)
2575                     && (Proc_GetPipeFd(&My_Connections[i].proc_stat) == fd))
2576                         return i;
2577         }
2578         return NONE;
2579 } /* Conn_GetFromProc */
2580
2581
2582 #ifndef STRICT_RFC
2583
2584 GLOBAL long
2585 Conn_GetAuthPing(CONN_ID Idx)
2586 {
2587         assert (Idx != NONE);
2588         return My_Connections[Idx].auth_ping;
2589 } /* Conn_GetAuthPing */
2590
2591 GLOBAL void
2592 Conn_SetAuthPing(CONN_ID Idx, long ID)
2593 {
2594         assert (Idx != NONE);
2595         My_Connections[Idx].auth_ping = ID;
2596 } /* Conn_SetAuthPing */
2597
2598 #endif
2599
2600
2601 #ifdef SSL_SUPPORT
2602
2603 /**
2604  * Get information about used SSL cipher.
2605  *
2606  * @param Idx   Connection index number.
2607  * @param buf   Buffer for returned information text.
2608  * @param len   Size of return buffer "buf".
2609  * @returns     true on success, false otherwise.
2610  */
2611 GLOBAL bool
2612 Conn_GetCipherInfo(CONN_ID Idx, char *buf, size_t len)
2613 {
2614         if (Idx < 0)
2615                 return false;
2616         assert(Idx < (int) array_length(&My_ConnArray, sizeof(CONNECTION)));
2617         return ConnSSL_GetCipherInfo(&My_Connections[Idx], buf, len);
2618 }
2619
2620
2621 /**
2622  * Check if a connection is SSL-enabled or not.
2623  *
2624  * @param Idx   Connection index number.
2625  * @return      true if connection is SSL-enabled, false otherwise.
2626  */
2627 GLOBAL bool
2628 Conn_UsesSSL(CONN_ID Idx)
2629 {
2630         if (Idx < 0)
2631                 return false;
2632         assert(Idx < (int) array_length(&My_ConnArray, sizeof(CONNECTION)));
2633         return Conn_OPTION_ISSET(&My_Connections[Idx], CONN_SSL);
2634 }
2635
2636
2637 GLOBAL char *
2638 Conn_GetCertFp(CONN_ID Idx)
2639 {
2640         if (Idx < 0)
2641                 return NULL;
2642         assert(Idx < (int) array_length(&My_ConnArray, sizeof(CONNECTION)));
2643         return ConnSSL_GetCertFp(&My_Connections[Idx]);
2644 }
2645
2646
2647 GLOBAL bool
2648 Conn_SetCertFp(CONN_ID Idx, const char *fingerprint)
2649 {
2650         if (Idx < 0)
2651                 return false;
2652         assert(Idx < (int) array_length(&My_ConnArray, sizeof(CONNECTION)));
2653         return ConnSSL_SetCertFp(&My_Connections[Idx], fingerprint);
2654 }
2655 #else
2656 GLOBAL bool
2657 Conn_UsesSSL(UNUSED CONN_ID Idx)
2658 {
2659         return false;
2660 }
2661
2662
2663 GLOBAL char *
2664 Conn_GetCertFp(UNUSED CONN_ID Idx)
2665 {
2666         return NULL;
2667 }
2668
2669
2670 GLOBAL bool
2671 Conn_SetCertFp(UNUSED CONN_ID Idx, UNUSED const char *fingerprint)
2672 {
2673         return true;
2674 }
2675 #endif
2676
2677
2678 #ifdef DEBUG
2679
2680 /**
2681  * Dump internal state of the "connection module".
2682  */
2683 GLOBAL void
2684 Conn_DebugDump(void)
2685 {
2686         int i;
2687
2688         Log(LOG_DEBUG, "Connection status:");
2689         for (i = 0; i < Pool_Size; i++) {
2690                 if (My_Connections[i].sock == NONE)
2691                         continue;
2692                 Log(LOG_DEBUG,
2693                     " - %d: host=%s, lastdata=%ld, lastping=%ld, delaytime=%ld, flag=%d, options=%d, bps=%d, client=%s",
2694                     My_Connections[i].sock, My_Connections[i].host,
2695                     My_Connections[i].lastdata, My_Connections[i].lastping,
2696                     My_Connections[i].delaytime, My_Connections[i].flag,
2697                     My_Connections[i].options, My_Connections[i].bps,
2698                     My_Connections[i].client ? Client_ID(My_Connections[i].client) : "-");
2699         }
2700 } /* Conn_DumpClients */
2701
2702 #endif
2703
2704
2705 /* -eof- */