2001-12-12 18:18:38 +01:00
|
|
|
/*
|
|
|
|
* ngIRCd -- The Next Generation IRC Daemon
|
2010-04-23 22:23:51 +02:00
|
|
|
* Copyright (c)2001-2010 Alexander Barton <alex@barton.de>
|
2001-12-12 18:18:38 +01:00
|
|
|
*
|
2002-12-12 13:24:18 +01:00
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
* Please read the file COPYING, README and AUTHORS for more information.
|
2001-12-12 18:18:38 +01:00
|
|
|
*
|
2002-12-12 13:24:18 +01:00
|
|
|
* Connection management
|
2001-12-12 18:18:38 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
2002-12-30 18:14:59 +01:00
|
|
|
#define CONN_MODULE
|
2002-12-30 17:07:23 +01:00
|
|
|
|
2002-03-12 15:37:51 +01:00
|
|
|
#include "portab.h"
|
2008-09-13 15:10:32 +02:00
|
|
|
#include "conf-ssl.h"
|
2005-07-07 20:49:04 +02:00
|
|
|
#include "io.h"
|
2001-12-12 18:18:38 +01:00
|
|
|
|
2002-03-12 15:37:51 +01:00
|
|
|
#include "imp.h"
|
2001-12-12 18:18:38 +01:00
|
|
|
#include <assert.h>
|
2004-10-20 15:47:32 +02:00
|
|
|
#ifdef PROTOTYPES
|
2010-05-18 17:38:12 +02:00
|
|
|
# include <stdarg.h>
|
2004-10-20 15:47:32 +02:00
|
|
|
#else
|
2010-05-18 17:38:12 +02:00
|
|
|
# include <varargs.h>
|
2004-10-20 15:47:32 +02:00
|
|
|
#endif
|
2001-12-12 18:18:38 +01:00
|
|
|
#include <stdio.h>
|
2002-01-01 19:25:44 +01:00
|
|
|
#include <stdlib.h>
|
2001-12-12 18:18:38 +01:00
|
|
|
#include <unistd.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <string.h>
|
2001-12-26 00:15:16 +01:00
|
|
|
#include <sys/socket.h>
|
2001-12-12 18:18:38 +01:00
|
|
|
#include <sys/time.h>
|
2001-12-26 00:15:16 +01:00
|
|
|
#include <sys/types.h>
|
2001-12-26 04:36:57 +01:00
|
|
|
#include <time.h>
|
2001-12-12 18:18:38 +01:00
|
|
|
#include <netinet/in.h>
|
|
|
|
|
2004-01-25 17:06:34 +01:00
|
|
|
#ifdef HAVE_NETINET_IP_H
|
2010-04-23 11:04:15 +02:00
|
|
|
# ifdef HAVE_NETINET_IN_SYSTM_H
|
|
|
|
# include <netinet/in_systm.h>
|
|
|
|
# endif
|
2004-01-25 17:06:34 +01:00
|
|
|
# include <netinet/ip.h>
|
|
|
|
#endif
|
|
|
|
|
2001-12-12 18:18:38 +01:00
|
|
|
#ifdef HAVE_STDINT_H
|
2004-01-25 17:06:34 +01:00
|
|
|
# include <stdint.h> /* e.g. for Mac OS X */
|
2003-03-07 15:35:52 +01:00
|
|
|
#endif
|
|
|
|
|
2003-12-26 16:55:07 +01:00
|
|
|
#ifdef TCPWRAP
|
2004-01-25 17:06:34 +01:00
|
|
|
# include <tcpd.h> /* for TCP Wrappers */
|
2001-12-12 18:18:38 +01:00
|
|
|
#endif
|
|
|
|
|
2005-07-07 20:49:04 +02:00
|
|
|
#include "array.h"
|
2002-12-30 17:07:23 +01:00
|
|
|
#include "defines.h"
|
2002-11-27 00:07:24 +01:00
|
|
|
|
2002-05-27 15:09:26 +02:00
|
|
|
#include "exp.h"
|
|
|
|
#include "conn.h"
|
|
|
|
|
|
|
|
#include "imp.h"
|
2001-12-13 00:32:02 +01:00
|
|
|
#include "ngircd.h"
|
2010-05-18 17:38:12 +02:00
|
|
|
#include "array.h"
|
2001-12-23 23:02:54 +01:00
|
|
|
#include "client.h"
|
2001-12-26 04:20:53 +01:00
|
|
|
#include "conf.h"
|
2008-09-13 15:10:32 +02:00
|
|
|
#include "conn-ssl.h"
|
2002-12-30 17:07:23 +01:00
|
|
|
#include "conn-zip.h"
|
2002-12-30 18:14:59 +01:00
|
|
|
#include "conn-func.h"
|
2001-12-12 18:18:38 +01:00
|
|
|
#include "log.h"
|
2010-05-18 17:38:12 +02:00
|
|
|
#include "ng_ipaddr.h"
|
2001-12-21 23:24:25 +01:00
|
|
|
#include "parse.h"
|
2010-05-18 17:38:12 +02:00
|
|
|
#include "resolve.h"
|
2001-12-13 00:32:02 +01:00
|
|
|
#include "tool.h"
|
2001-12-12 18:18:38 +01:00
|
|
|
|
2002-03-12 15:37:51 +01:00
|
|
|
#include "exp.h"
|
2001-12-12 18:18:38 +01:00
|
|
|
|
|
|
|
|
2002-03-13 00:45:30 +01:00
|
|
|
#define SERVER_WAIT (NONE - 1)
|
2001-12-29 21:17:25 +01:00
|
|
|
|
2009-05-25 22:25:18 +02:00
|
|
|
#define MAX_COMMANDS 3
|
|
|
|
#define MAX_COMMANDS_SERVER 10
|
2010-12-29 14:19:51 +01:00
|
|
|
#define MAX_COMMANDS_SERVICE MAX_COMMANDS_SERVER
|
2009-05-25 22:25:18 +02:00
|
|
|
|
2001-12-13 00:32:02 +01:00
|
|
|
|
2005-07-31 22:13:07 +02:00
|
|
|
static bool Handle_Write PARAMS(( CONN_ID Idx ));
|
2007-05-09 15:21:11 +02:00
|
|
|
static bool Conn_Write PARAMS(( CONN_ID Idx, char *Data, size_t Len ));
|
2005-07-31 22:13:07 +02:00
|
|
|
static int New_Connection PARAMS(( int Sock ));
|
|
|
|
static CONN_ID Socket2Index PARAMS(( int Sock ));
|
|
|
|
static void Read_Request PARAMS(( CONN_ID Idx ));
|
2009-05-25 22:25:18 +02:00
|
|
|
static unsigned int Handle_Buffer PARAMS(( CONN_ID Idx ));
|
2005-07-31 22:13:07 +02:00
|
|
|
static void Check_Connections PARAMS(( void ));
|
|
|
|
static void Check_Servers PARAMS(( void ));
|
|
|
|
static void Init_Conn_Struct PARAMS(( CONN_ID Idx ));
|
|
|
|
static bool Init_Socket PARAMS(( int Sock ));
|
2008-02-26 23:50:35 +01:00
|
|
|
static void New_Server PARAMS(( int Server, ng_ipaddr_t *dest ));
|
2006-03-18 23:27:09 +01:00
|
|
|
static void Simple_Message PARAMS(( int Sock, const char *Msg ));
|
2008-05-19 00:12:41 +02:00
|
|
|
static int NewListener PARAMS(( const char *listen_addr, UINT16 Port ));
|
2010-04-23 23:25:34 +02:00
|
|
|
static void Account_Connection PARAMS((void));
|
|
|
|
|
2001-12-13 00:32:02 +01:00
|
|
|
|
2005-07-07 20:49:04 +02:00
|
|
|
static array My_Listeners;
|
2006-02-16 20:21:57 +01:00
|
|
|
static array My_ConnArray;
|
2010-04-23 23:25:34 +02:00
|
|
|
static size_t NumConnections, NumConnectionsMax, NumConnectionsAccepted;
|
2001-12-13 00:32:02 +01:00
|
|
|
|
2003-12-26 16:55:07 +01:00
|
|
|
#ifdef TCPWRAP
|
2005-03-19 19:43:48 +01:00
|
|
|
int allow_severity = LOG_INFO;
|
|
|
|
int deny_severity = LOG_ERR;
|
2003-03-07 15:35:52 +01:00
|
|
|
#endif
|
|
|
|
|
2005-07-29 11:29:47 +02:00
|
|
|
static void server_login PARAMS((CONN_ID idx));
|
2005-07-07 20:49:04 +02:00
|
|
|
|
2008-09-13 15:10:32 +02:00
|
|
|
#ifdef SSL_SUPPORT
|
|
|
|
extern struct SSLOptions Conf_SSLOptions;
|
|
|
|
static void cb_connserver_login_ssl PARAMS((int sock, short what));
|
|
|
|
static void cb_clientserver_ssl PARAMS((int sock, short what));
|
|
|
|
#endif
|
2009-12-30 23:32:47 +01:00
|
|
|
static void cb_Read_Resolver_Result PARAMS((int sock, UNUSED short what));
|
|
|
|
static void cb_Connect_to_Server PARAMS((int sock, UNUSED short what));
|
2005-07-07 20:49:04 +02:00
|
|
|
static void cb_clientserver PARAMS((int sock, short what));
|
|
|
|
|
2009-12-30 23:35:17 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* IO callback for listening sockets: handle new connections. This callback
|
|
|
|
* gets called when a new non-SSL connection should be accepted.
|
|
|
|
* @param sock Socket descriptor
|
|
|
|
* @param irrelevant (ignored IO specification)
|
|
|
|
*/
|
2005-07-07 20:49:04 +02:00
|
|
|
static void
|
|
|
|
cb_listen(int sock, short irrelevant)
|
|
|
|
{
|
|
|
|
(void) irrelevant;
|
2009-12-30 23:42:43 +01:00
|
|
|
(void) New_Connection(sock);
|
2005-07-07 20:49:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-09-13 15:10:32 +02:00
|
|
|
#ifdef SSL_SUPPORT
|
2009-12-30 23:35:17 +01:00
|
|
|
/**
|
|
|
|
* IO callback for listening SSL sockets: handle new connections. This callback
|
|
|
|
* gets called when a new SSL-enabled connection should be accepted.
|
|
|
|
* @param sock Socket descriptor
|
|
|
|
* @param irrelevant (ignored IO specification)
|
|
|
|
*/
|
2008-09-13 15:10:32 +02:00
|
|
|
static void
|
|
|
|
cb_listen_ssl(int sock, short irrelevant)
|
|
|
|
{
|
|
|
|
int fd;
|
2009-12-30 23:32:47 +01:00
|
|
|
|
2008-09-13 15:10:32 +02:00
|
|
|
(void) irrelevant;
|
|
|
|
fd = New_Connection(sock);
|
|
|
|
if (fd < 0)
|
|
|
|
return;
|
|
|
|
io_event_setcb(My_Connections[fd].sock, cb_clientserver_ssl);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2009-12-30 23:35:17 +01:00
|
|
|
/**
|
|
|
|
* IO callback for new outgoing non-SSL server connections.
|
|
|
|
* @param sock Socket descriptor
|
|
|
|
* @param what IO specification (IO_WANTREAD/IO_WANTWRITE/...)
|
|
|
|
*/
|
2005-07-07 20:49:04 +02:00
|
|
|
static void
|
2005-07-22 23:31:05 +02:00
|
|
|
cb_connserver(int sock, UNUSED short what)
|
2005-07-07 20:49:04 +02:00
|
|
|
{
|
2009-09-12 00:17:42 +02:00
|
|
|
int res, err, server;
|
2005-07-07 20:49:04 +02:00
|
|
|
socklen_t sock_len;
|
|
|
|
CONN_ID idx = Socket2Index( sock );
|
2009-09-12 00:17:42 +02:00
|
|
|
|
2005-07-07 20:49:04 +02:00
|
|
|
if (idx <= NONE) {
|
2006-02-08 18:33:28 +01:00
|
|
|
LogDebug("cb_connserver wants to write on unknown socket?!");
|
2005-07-07 20:49:04 +02:00
|
|
|
io_close(sock);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-09-12 00:17:42 +02:00
|
|
|
assert(what & IO_WANTWRITE);
|
|
|
|
|
|
|
|
/* Make sure that the server is still configured; it could have been
|
|
|
|
* removed in the meantime! */
|
|
|
|
server = Conf_GetServer(idx);
|
|
|
|
if (server < 0) {
|
|
|
|
Log(LOG_ERR, "Connection on socket %d to \"%s\" aborted!",
|
|
|
|
sock, My_Connections[idx].host);
|
|
|
|
Conn_Close(idx, "Connection aborted!", NULL, false);
|
|
|
|
return;
|
|
|
|
}
|
2005-07-07 20:49:04 +02:00
|
|
|
|
|
|
|
/* connect() finished, get result. */
|
2009-09-11 22:52:12 +02:00
|
|
|
sock_len = (socklen_t)sizeof(err);
|
2009-09-12 00:17:42 +02:00
|
|
|
res = getsockopt(My_Connections[idx].sock, SOL_SOCKET, SO_ERROR,
|
|
|
|
&err, &sock_len );
|
|
|
|
assert(sock_len == sizeof(err));
|
2005-07-07 20:49:04 +02:00
|
|
|
|
2005-10-11 21:29:23 +02:00
|
|
|
/* Error while connecting? */
|
|
|
|
if ((res != 0) || (err != 0)) {
|
|
|
|
if (res != 0)
|
|
|
|
Log(LOG_CRIT, "getsockopt (connection %d): %s!",
|
|
|
|
idx, strerror(errno));
|
|
|
|
else
|
|
|
|
Log(LOG_CRIT,
|
|
|
|
"Can't connect socket to \"%s:%d\" (connection %d): %s!",
|
2009-09-12 00:17:42 +02:00
|
|
|
My_Connections[idx].host, Conf_Server[server].port,
|
2005-10-11 21:29:23 +02:00
|
|
|
idx, strerror(err));
|
|
|
|
|
2007-01-23 17:07:19 +01:00
|
|
|
Conn_Close(idx, "Can't connect!", NULL, false);
|
2008-02-26 23:50:35 +01:00
|
|
|
|
2009-09-12 00:17:42 +02:00
|
|
|
if (ng_ipaddr_af(&Conf_Server[server].dst_addr[0])) {
|
2008-02-26 23:50:35 +01:00
|
|
|
/* more addresses to try... */
|
2010-10-27 21:59:51 +02:00
|
|
|
New_Server(server, &Conf_Server[server].dst_addr[0]);
|
2009-09-12 00:17:42 +02:00
|
|
|
/* connection to dst_addr[0] is now in progress, so
|
|
|
|
* remove this address... */
|
|
|
|
Conf_Server[server].dst_addr[0] =
|
|
|
|
Conf_Server[server].dst_addr[1];
|
|
|
|
memset(&Conf_Server[server].dst_addr[1], 0,
|
|
|
|
sizeof(Conf_Server[server].dst_addr[1]));
|
2008-02-26 23:50:35 +01:00
|
|
|
}
|
2005-10-11 21:29:23 +02:00
|
|
|
return;
|
2005-07-07 20:49:04 +02:00
|
|
|
}
|
|
|
|
|
2009-09-12 00:17:42 +02:00
|
|
|
/* connect() succeeded, remove all additional addresses */
|
|
|
|
memset(&Conf_Server[server].dst_addr, 0,
|
|
|
|
sizeof(Conf_Server[server].dst_addr));
|
|
|
|
|
2005-07-07 20:49:04 +02:00
|
|
|
Conn_OPTION_DEL( &My_Connections[idx], CONN_ISCONNECTING );
|
2008-09-13 15:10:32 +02:00
|
|
|
#ifdef SSL_SUPPORT
|
|
|
|
if ( Conn_OPTION_ISSET( &My_Connections[idx], CONN_SSL_CONNECT )) {
|
|
|
|
io_event_setcb( sock, cb_connserver_login_ssl );
|
|
|
|
io_event_add( sock, IO_WANTWRITE|IO_WANTREAD );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif
|
2005-07-29 11:29:47 +02:00
|
|
|
server_login(idx);
|
|
|
|
}
|
|
|
|
|
2005-07-07 20:49:04 +02:00
|
|
|
|
2009-12-30 23:35:17 +01:00
|
|
|
/**
|
|
|
|
* Login to a remote server.
|
|
|
|
* @param idx Connection index
|
|
|
|
*/
|
2005-07-29 11:29:47 +02:00
|
|
|
static void
|
|
|
|
server_login(CONN_ID idx)
|
|
|
|
{
|
2011-01-16 23:24:41 +01:00
|
|
|
Log(LOG_INFO,
|
|
|
|
"Connection %d (socket %d) with \"%s:%d\" established. Now logging in ...",
|
|
|
|
idx, My_Connections[idx].sock, My_Connections[idx].host,
|
|
|
|
Conf_Server[Conf_GetServer(idx)].port);
|
2005-07-07 20:49:04 +02:00
|
|
|
|
|
|
|
io_event_setcb( My_Connections[idx].sock, cb_clientserver);
|
|
|
|
io_event_add( My_Connections[idx].sock, IO_WANTREAD|IO_WANTWRITE);
|
|
|
|
|
|
|
|
/* Send PASS and SERVER command to peer */
|
|
|
|
Conn_WriteStr( idx, "PASS %s %s", Conf_Server[Conf_GetServer( idx )].pwd_out, NGIRCd_ProtoID );
|
|
|
|
Conn_WriteStr( idx, "SERVER %s :%s", Conf_ServerName, Conf_ServerInfo );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-09-13 15:10:32 +02:00
|
|
|
#ifdef SSL_SUPPORT
|
2009-12-30 23:35:17 +01:00
|
|
|
/**
|
|
|
|
* IO callback for new outgoing SSL-enabled server connections.
|
|
|
|
* @param sock Socket descriptor
|
|
|
|
* @param what IO specification (IO_WANTREAD/IO_WANTWRITE/...)
|
|
|
|
*/
|
2008-09-13 15:10:32 +02:00
|
|
|
static void
|
|
|
|
cb_connserver_login_ssl(int sock, short unused)
|
|
|
|
{
|
|
|
|
CONN_ID idx = Socket2Index(sock);
|
|
|
|
|
|
|
|
assert(idx >= 0);
|
|
|
|
if (idx < 0) {
|
|
|
|
io_close(sock);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
(void) unused;
|
|
|
|
switch (ConnSSL_Connect( &My_Connections[idx])) {
|
|
|
|
case 1: break;
|
|
|
|
case 0: LogDebug("ConnSSL_Connect: not ready");
|
|
|
|
return;
|
|
|
|
case -1:
|
2008-11-20 23:50:26 +01:00
|
|
|
Log(LOG_ERR, "SSL connection on socket %d failed!", sock);
|
2008-09-13 15:10:32 +02:00
|
|
|
Conn_Close(idx, "Can't connect!", NULL, false);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-11-20 23:50:26 +01:00
|
|
|
Log( LOG_INFO, "SSL connection %d with \"%s:%d\" established.", idx,
|
2008-09-13 15:10:32 +02:00
|
|
|
My_Connections[idx].host, Conf_Server[Conf_GetServer( idx )].port );
|
|
|
|
|
|
|
|
server_login(idx);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2009-12-30 23:35:17 +01:00
|
|
|
/**
|
|
|
|
* IO callback for established non-SSL client and server connections.
|
|
|
|
* @param sock Socket descriptor
|
|
|
|
* @param what IO specification (IO_WANTREAD/IO_WANTWRITE/...)
|
|
|
|
*/
|
2005-07-07 20:49:04 +02:00
|
|
|
static void
|
|
|
|
cb_clientserver(int sock, short what)
|
|
|
|
{
|
2008-09-13 15:10:32 +02:00
|
|
|
CONN_ID idx = Socket2Index(sock);
|
|
|
|
|
|
|
|
assert(idx >= 0);
|
|
|
|
|
|
|
|
if (idx < 0) {
|
|
|
|
io_close(sock);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#ifdef SSL_SUPPORT
|
2009-12-30 23:32:47 +01:00
|
|
|
if (what & IO_WANTREAD
|
|
|
|
|| (Conn_OPTION_ISSET(&My_Connections[idx], CONN_SSL_WANT_WRITE))) {
|
|
|
|
/* if TLS layer needs to write additional data, call
|
|
|
|
* Read_Request() instead so that SSL/TLS can continue */
|
|
|
|
Read_Request(idx);
|
|
|
|
}
|
2008-09-13 15:10:32 +02:00
|
|
|
#else
|
|
|
|
if (what & IO_WANTREAD)
|
2009-12-30 23:32:47 +01:00
|
|
|
Read_Request(idx);
|
2005-07-07 20:49:04 +02:00
|
|
|
#endif
|
2008-09-13 15:10:32 +02:00
|
|
|
if (what & IO_WANTWRITE)
|
2009-12-30 23:32:47 +01:00
|
|
|
Handle_Write(idx);
|
2008-09-13 15:10:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef SSL_SUPPORT
|
2009-12-30 23:35:17 +01:00
|
|
|
/**
|
|
|
|
* IO callback for established SSL-enabled client and server connections.
|
|
|
|
* @param sock Socket descriptor
|
|
|
|
* @param what IO specification (IO_WANTREAD/IO_WANTWRITE/...)
|
|
|
|
*/
|
2008-09-13 15:10:32 +02:00
|
|
|
static void
|
|
|
|
cb_clientserver_ssl(int sock, short what)
|
|
|
|
{
|
|
|
|
CONN_ID idx = Socket2Index(sock);
|
|
|
|
|
|
|
|
assert(idx >= 0);
|
|
|
|
|
|
|
|
if (idx < 0) {
|
2005-07-07 20:49:04 +02:00
|
|
|
io_close(sock);
|
|
|
|
return;
|
2005-07-09 23:35:20 +02:00
|
|
|
}
|
2005-07-07 20:49:04 +02:00
|
|
|
|
2008-09-13 15:10:32 +02:00
|
|
|
switch (ConnSSL_Accept(&My_Connections[idx])) {
|
2009-12-30 23:32:47 +01:00
|
|
|
case 1:
|
|
|
|
break; /* OK */
|
|
|
|
case 0:
|
|
|
|
return; /* EAGAIN: callback will be invoked again by IO layer */
|
|
|
|
default:
|
2010-05-07 23:25:59 +02:00
|
|
|
Conn_Close(idx, "SSL accept error, closing socket", "SSL accept error", false);
|
2009-12-30 23:32:47 +01:00
|
|
|
return;
|
2008-09-13 15:10:32 +02:00
|
|
|
}
|
2005-07-07 20:49:04 +02:00
|
|
|
if (what & IO_WANTREAD)
|
2008-09-13 15:10:32 +02:00
|
|
|
Read_Request(idx);
|
2005-07-07 20:49:04 +02:00
|
|
|
|
|
|
|
if (what & IO_WANTWRITE)
|
2008-09-13 15:10:32 +02:00
|
|
|
Handle_Write(idx);
|
|
|
|
|
|
|
|
io_event_setcb(sock, cb_clientserver); /* SSL handshake completed */
|
2005-07-07 20:49:04 +02:00
|
|
|
}
|
2008-09-13 15:10:32 +02:00
|
|
|
#endif
|
2005-07-07 20:49:04 +02:00
|
|
|
|
|
|
|
|
2009-12-30 23:35:17 +01:00
|
|
|
/**
|
|
|
|
* Initialite connecion module.
|
|
|
|
*/
|
2005-03-19 19:43:48 +01:00
|
|
|
GLOBAL void
|
|
|
|
Conn_Init( void )
|
2001-12-12 18:18:38 +01:00
|
|
|
{
|
2001-12-14 09:16:47 +01:00
|
|
|
CONN_ID i;
|
2001-12-13 00:32:02 +01:00
|
|
|
|
2002-11-03 00:00:45 +01:00
|
|
|
/* Speicher fuer Verbindungs-Pool anfordern */
|
|
|
|
Pool_Size = CONNECTION_POOL;
|
2008-08-30 15:37:19 +02:00
|
|
|
if ((Conf_MaxConnections > 0) &&
|
|
|
|
(Pool_Size > Conf_MaxConnections))
|
|
|
|
Pool_Size = Conf_MaxConnections;
|
|
|
|
|
2006-05-10 23:24:01 +02:00
|
|
|
if (!array_alloc(&My_ConnArray, sizeof(CONNECTION), (size_t)Pool_Size)) {
|
2010-04-23 22:23:51 +02:00
|
|
|
Log(LOG_EMERG, "Can't allocate memory! [Conn_Init]");
|
|
|
|
exit(1);
|
2002-11-03 00:00:45 +01:00
|
|
|
}
|
|
|
|
|
2006-05-10 23:24:01 +02:00
|
|
|
/* FIXME: My_Connetions/Pool_Size is needed by other parts of the
|
|
|
|
* code; remove them! */
|
2006-02-16 20:21:57 +01:00
|
|
|
My_Connections = (CONNECTION*) array_start(&My_ConnArray);
|
|
|
|
|
|
|
|
LogDebug("Allocated connection pool for %d items (%ld bytes).",
|
2010-04-23 22:23:51 +02:00
|
|
|
array_length(&My_ConnArray, sizeof(CONNECTION)),
|
|
|
|
array_bytes(&My_ConnArray));
|
2006-02-16 20:21:57 +01:00
|
|
|
|
2010-04-23 22:23:51 +02:00
|
|
|
assert(array_length(&My_ConnArray, sizeof(CONNECTION)) >= (size_t)Pool_Size);
|
2006-02-16 20:21:57 +01:00
|
|
|
|
2005-07-07 20:49:04 +02:00
|
|
|
array_free( &My_Listeners );
|
2001-12-26 00:15:16 +01:00
|
|
|
|
2010-04-23 22:23:51 +02:00
|
|
|
for (i = 0; i < Pool_Size; i++)
|
|
|
|
Init_Conn_Struct(i);
|
2001-12-12 18:18:38 +01:00
|
|
|
} /* Conn_Init */
|
|
|
|
|
|
|
|
|
2009-12-30 23:35:17 +01:00
|
|
|
/**
|
|
|
|
* Clean up connection module.
|
|
|
|
*/
|
2005-03-19 19:43:48 +01:00
|
|
|
GLOBAL void
|
|
|
|
Conn_Exit( void )
|
2001-12-12 18:18:38 +01:00
|
|
|
{
|
2001-12-14 09:16:47 +01:00
|
|
|
CONN_ID idx;
|
2001-12-26 00:15:16 +01:00
|
|
|
|
2005-07-07 20:49:04 +02:00
|
|
|
Conn_ExitListeners();
|
2003-04-25 18:47:52 +02:00
|
|
|
|
2008-11-20 23:50:26 +01:00
|
|
|
LogDebug("Shutting down all connections ..." );
|
2005-07-07 20:49:04 +02:00
|
|
|
for( idx = 0; idx < Pool_Size; idx++ ) {
|
|
|
|
if( My_Connections[idx].sock > NONE ) {
|
|
|
|
Conn_Close( idx, NULL, NGIRCd_SignalRestart ?
|
|
|
|
"Server going down (restarting)":"Server going down", true );
|
2001-12-13 00:32:02 +01:00
|
|
|
}
|
|
|
|
}
|
2003-04-25 18:47:52 +02:00
|
|
|
|
2006-02-16 20:21:57 +01:00
|
|
|
array_free(&My_ConnArray);
|
2002-11-03 00:00:45 +01:00
|
|
|
My_Connections = NULL;
|
|
|
|
Pool_Size = 0;
|
2005-07-07 20:49:04 +02:00
|
|
|
io_library_shutdown();
|
2001-12-12 18:18:38 +01:00
|
|
|
} /* Conn_Exit */
|
|
|
|
|
|
|
|
|
2010-07-14 10:27:55 +02:00
|
|
|
/**
|
|
|
|
* Close all sockets (file descriptors) of open connections.
|
|
|
|
* This is useful in forked child processes, for example, to make sure that
|
|
|
|
* they don't hold connections open that the main process wants to close.
|
|
|
|
*/
|
|
|
|
GLOBAL void
|
|
|
|
Conn_CloseAllSockets(void)
|
|
|
|
{
|
|
|
|
CONN_ID idx;
|
|
|
|
|
|
|
|
for(idx = 0; idx < Pool_Size; idx++) {
|
|
|
|
if(My_Connections[idx].sock > NONE)
|
|
|
|
close(My_Connections[idx].sock);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-04-04 23:52:12 +02:00
|
|
|
static unsigned int
|
2008-05-19 00:12:41 +02:00
|
|
|
ports_initlisteners(array *a, const char *listen_addr, void (*func)(int,short))
|
2005-07-29 11:29:47 +02:00
|
|
|
{
|
2007-04-04 23:52:12 +02:00
|
|
|
unsigned int created = 0;
|
2006-05-10 23:24:01 +02:00
|
|
|
size_t len;
|
2005-07-29 11:29:47 +02:00
|
|
|
int fd;
|
|
|
|
UINT16 *port;
|
|
|
|
|
|
|
|
len = array_length(a, sizeof (UINT16));
|
|
|
|
port = array_start(a);
|
2008-05-19 00:12:41 +02:00
|
|
|
while (len--) {
|
|
|
|
fd = NewListener(listen_addr, *port);
|
2005-07-29 11:29:47 +02:00
|
|
|
if (fd < 0) {
|
|
|
|
port++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!io_event_create( fd, IO_WANTREAD, func )) {
|
|
|
|
Log( LOG_ERR, "io_event_create(): Could not add listening fd %d (port %u): %s!",
|
2008-05-19 00:12:41 +02:00
|
|
|
fd, (unsigned int) *port, strerror(errno));
|
2005-07-29 11:29:47 +02:00
|
|
|
close(fd);
|
|
|
|
port++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
created++;
|
|
|
|
port++;
|
|
|
|
}
|
|
|
|
return created;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-12-30 23:35:17 +01:00
|
|
|
/**
|
|
|
|
* Initialize all listening sockets.
|
|
|
|
* @return Number of created listening sockets
|
|
|
|
*/
|
2007-04-04 23:52:12 +02:00
|
|
|
GLOBAL unsigned int
|
2005-03-19 19:43:48 +01:00
|
|
|
Conn_InitListeners( void )
|
2002-11-22 18:58:19 +01:00
|
|
|
{
|
2002-12-30 17:07:23 +01:00
|
|
|
/* Initialize ports on which the server should accept connections */
|
2008-02-26 23:50:35 +01:00
|
|
|
unsigned int created = 0;
|
2008-05-19 00:12:41 +02:00
|
|
|
char *copy, *listen_addr;
|
2002-11-22 18:58:19 +01:00
|
|
|
|
2008-05-19 00:12:41 +02:00
|
|
|
assert(Conf_ListenAddress);
|
|
|
|
|
|
|
|
/* can't use Conf_ListenAddress directly, see below */
|
|
|
|
copy = strdup(Conf_ListenAddress);
|
|
|
|
if (!copy) {
|
|
|
|
Log(LOG_CRIT, "Cannot copy %s: %s", Conf_ListenAddress, strerror(errno));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
listen_addr = strtok(copy, ",");
|
2005-07-29 11:29:47 +02:00
|
|
|
|
2008-05-19 00:12:41 +02:00
|
|
|
while (listen_addr) {
|
|
|
|
ngt_TrimStr(listen_addr);
|
2008-09-13 15:10:32 +02:00
|
|
|
if (*listen_addr) {
|
2008-05-19 00:12:41 +02:00
|
|
|
created += ports_initlisteners(&Conf_ListenPorts, listen_addr, cb_listen);
|
2008-09-13 15:10:32 +02:00
|
|
|
#ifdef SSL_SUPPORT
|
|
|
|
created += ports_initlisteners(&Conf_SSLOptions.ListenPorts, listen_addr, cb_listen_ssl);
|
|
|
|
#endif
|
|
|
|
}
|
2008-05-19 00:12:41 +02:00
|
|
|
|
|
|
|
listen_addr = strtok(NULL, ",");
|
|
|
|
}
|
|
|
|
|
2009-12-30 23:32:47 +01:00
|
|
|
/* Can't free() Conf_ListenAddress here: on REHASH, if the config file
|
2008-05-19 00:12:41 +02:00
|
|
|
* cannot be re-loaded, we'd end up with a NULL Conf_ListenAddress.
|
|
|
|
* Instead, free() takes place in conf.c, before the config file
|
2009-12-30 23:32:47 +01:00
|
|
|
* is being parsed. */
|
2008-05-19 00:12:41 +02:00
|
|
|
free(copy);
|
2009-12-30 23:32:47 +01:00
|
|
|
|
2002-11-22 18:58:19 +01:00
|
|
|
return created;
|
|
|
|
} /* Conn_InitListeners */
|
|
|
|
|
|
|
|
|
2005-03-19 19:43:48 +01:00
|
|
|
GLOBAL void
|
|
|
|
Conn_ExitListeners( void )
|
2002-11-22 18:58:19 +01:00
|
|
|
{
|
2002-12-30 17:07:23 +01:00
|
|
|
/* Close down all listening sockets */
|
2005-07-07 20:49:04 +02:00
|
|
|
int *fd;
|
2005-09-24 04:20:00 +02:00
|
|
|
size_t arraylen;
|
2003-04-25 18:47:52 +02:00
|
|
|
|
2005-07-07 20:49:04 +02:00
|
|
|
arraylen = array_length(&My_Listeners, sizeof (int));
|
2008-11-20 23:50:26 +01:00
|
|
|
Log(LOG_INFO,
|
|
|
|
"Shutting down all listening sockets (%d total) ...", arraylen);
|
2005-09-24 04:20:00 +02:00
|
|
|
fd = array_start(&My_Listeners);
|
2005-07-07 20:49:04 +02:00
|
|
|
while(arraylen--) {
|
2006-05-10 23:24:01 +02:00
|
|
|
assert(fd != NULL);
|
2005-09-24 04:20:00 +02:00
|
|
|
assert(*fd >= 0);
|
|
|
|
io_close(*fd);
|
2006-02-08 18:33:28 +01:00
|
|
|
LogDebug("Listening socket %d closed.", *fd );
|
2005-09-24 04:20:00 +02:00
|
|
|
fd++;
|
2002-11-22 18:58:19 +01:00
|
|
|
}
|
2005-07-07 20:49:04 +02:00
|
|
|
array_free(&My_Listeners);
|
2002-11-22 18:58:19 +01:00
|
|
|
} /* Conn_ExitListeners */
|
|
|
|
|
|
|
|
|
2008-02-26 23:50:35 +01:00
|
|
|
static bool
|
2008-05-19 00:12:41 +02:00
|
|
|
InitSinaddrListenAddr(ng_ipaddr_t *addr, const char *listen_addrstr, UINT16 Port)
|
2007-11-23 17:26:03 +01:00
|
|
|
{
|
2008-02-26 23:50:35 +01:00
|
|
|
bool ret;
|
|
|
|
|
|
|
|
ret = ng_ipaddr_init(addr, listen_addrstr, Port);
|
|
|
|
if (!ret) {
|
2008-05-19 00:12:41 +02:00
|
|
|
assert(listen_addrstr);
|
|
|
|
Log(LOG_CRIT, "Can't bind to [%s]:%u: can't convert ip address \"%s\"",
|
|
|
|
listen_addrstr, Port, listen_addrstr);
|
2008-02-26 23:50:35 +01:00
|
|
|
}
|
|
|
|
return ret;
|
2007-11-23 17:26:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-02-26 23:50:35 +01:00
|
|
|
static void
|
|
|
|
set_v6_only(int af, int sock)
|
2007-11-23 17:26:03 +01:00
|
|
|
{
|
2008-02-26 23:50:35 +01:00
|
|
|
#if defined(IPV6_V6ONLY) && defined(WANT_IPV6)
|
|
|
|
int on = 1;
|
2007-11-23 17:26:03 +01:00
|
|
|
|
2008-02-26 23:50:35 +01:00
|
|
|
if (af != AF_INET6)
|
|
|
|
return;
|
2007-11-23 17:26:03 +01:00
|
|
|
|
2009-09-11 22:52:12 +02:00
|
|
|
if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, (socklen_t)sizeof(on)))
|
2008-02-26 23:50:35 +01:00
|
|
|
Log(LOG_ERR, "Could not set IPV6_V6ONLY: %s", strerror(errno));
|
|
|
|
#else
|
|
|
|
(void)af;
|
|
|
|
(void)sock;
|
|
|
|
#endif
|
2007-11-23 17:26:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-07-12 22:44:46 +02:00
|
|
|
/* return new listening port file descriptor or -1 on failure */
|
2005-07-31 22:13:07 +02:00
|
|
|
static int
|
2008-05-19 00:12:41 +02:00
|
|
|
NewListener(const char *listen_addr, UINT16 Port)
|
2001-12-12 18:18:38 +01:00
|
|
|
{
|
2002-12-30 17:07:23 +01:00
|
|
|
/* Create new listening socket on specified port */
|
2008-02-26 23:50:35 +01:00
|
|
|
ng_ipaddr_t addr;
|
2008-05-19 00:12:41 +02:00
|
|
|
int sock, af;
|
2011-01-09 23:51:30 +01:00
|
|
|
|
2008-05-19 00:12:41 +02:00
|
|
|
if (!InitSinaddrListenAddr(&addr, listen_addr, Port))
|
2008-02-26 23:50:35 +01:00
|
|
|
return -1;
|
2003-04-25 18:47:52 +02:00
|
|
|
|
2008-05-19 00:12:41 +02:00
|
|
|
af = ng_ipaddr_af(&addr);
|
|
|
|
sock = socket(af, SOCK_STREAM, 0);
|
2005-09-24 04:48:46 +02:00
|
|
|
if( sock < 0 ) {
|
2008-05-19 00:12:41 +02:00
|
|
|
Log(LOG_CRIT, "Can't create socket (af %d) : %s!", af, strerror(errno));
|
2005-07-11 16:56:38 +02:00
|
|
|
return -1;
|
2001-12-12 18:18:38 +01:00
|
|
|
}
|
|
|
|
|
2008-02-26 23:50:35 +01:00
|
|
|
set_v6_only(af, sock);
|
|
|
|
|
2008-05-12 18:46:55 +02:00
|
|
|
if (!Init_Socket(sock))
|
|
|
|
return -1;
|
2001-12-13 00:32:02 +01:00
|
|
|
|
2008-02-26 23:50:35 +01:00
|
|
|
if (bind(sock, (struct sockaddr *)&addr, ng_ipaddr_salen(&addr)) != 0) {
|
2008-05-12 18:46:55 +02:00
|
|
|
Log(LOG_CRIT, "Can't bind socket to address %s:%d - %s",
|
|
|
|
ng_ipaddr_tostr(&addr), Port, strerror(errno));
|
|
|
|
close(sock);
|
2005-07-11 16:56:38 +02:00
|
|
|
return -1;
|
2001-12-12 18:18:38 +01:00
|
|
|
}
|
|
|
|
|
2005-09-24 04:48:46 +02:00
|
|
|
if( listen( sock, 10 ) != 0 ) {
|
|
|
|
Log( LOG_CRIT, "Can't listen on socket: %s!", strerror( errno ));
|
2001-12-13 00:32:02 +01:00
|
|
|
close( sock );
|
2005-07-11 16:56:38 +02:00
|
|
|
return -1;
|
2001-12-12 18:18:38 +01:00
|
|
|
}
|
2001-12-13 00:32:02 +01:00
|
|
|
|
2005-09-24 04:48:46 +02:00
|
|
|
/* keep fd in list so we can close it when ngircd restarts/shuts down */
|
2005-07-07 20:49:04 +02:00
|
|
|
if (!array_catb( &My_Listeners,(char*) &sock, sizeof(int) )) {
|
|
|
|
Log( LOG_CRIT, "Can't add socket to My_Listeners array: %s!", strerror( errno ));
|
|
|
|
close( sock );
|
2005-07-11 16:56:38 +02:00
|
|
|
return -1;
|
2005-07-07 20:49:04 +02:00
|
|
|
}
|
2001-12-13 00:32:02 +01:00
|
|
|
|
2011-01-09 23:51:30 +01:00
|
|
|
Log(LOG_INFO, "Now listening on [%s]:%d (socket %d).",
|
|
|
|
ng_ipaddr_tostr(&addr), Port, sock);
|
2005-07-11 16:56:38 +02:00
|
|
|
return sock;
|
|
|
|
} /* NewListener */
|
2001-12-12 18:18:38 +01:00
|
|
|
|
2009-12-30 23:32:47 +01:00
|
|
|
|
2008-09-13 15:10:32 +02:00
|
|
|
#ifdef SSL_SUPPORT
|
|
|
|
/*
|
|
|
|
* SSL/TLS connections require extra treatment:
|
|
|
|
* When either CONN_SSL_WANT_WRITE or CONN_SSL_WANT_READ is set, we
|
|
|
|
* need to take care of that first, before checking read/write buffers.
|
|
|
|
* For instance, while we might have data in our write buffer, the
|
|
|
|
* TLS/SSL protocol might need to read internal data first for TLS/SSL
|
|
|
|
* writes to succeed.
|
|
|
|
*
|
|
|
|
* If this function returns true, such a condition is met and we have
|
|
|
|
* to reverse the condition (check for read even if we've data to write,
|
|
|
|
* do not check for read but writeability even if write-buffer is empty).
|
|
|
|
*/
|
|
|
|
static bool
|
|
|
|
SSL_WantRead(const CONNECTION *c)
|
|
|
|
{
|
|
|
|
if (Conn_OPTION_ISSET(c, CONN_SSL_WANT_READ)) {
|
|
|
|
io_event_add(c->sock, IO_WANTREAD);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
static bool
|
|
|
|
SSL_WantWrite(const CONNECTION *c)
|
|
|
|
{
|
|
|
|
if (Conn_OPTION_ISSET(c, CONN_SSL_WANT_WRITE)) {
|
|
|
|
io_event_add(c->sock, IO_WANTWRITE);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
static inline bool
|
2010-10-24 21:48:32 +02:00
|
|
|
SSL_WantRead(UNUSED const CONNECTION *c)
|
|
|
|
{ return false; }
|
2008-09-13 15:10:32 +02:00
|
|
|
static inline bool
|
2010-10-24 21:48:32 +02:00
|
|
|
SSL_WantWrite(UNUSED const CONNECTION *c)
|
|
|
|
{ return false; }
|
2008-09-13 15:10:32 +02:00
|
|
|
#endif
|
|
|
|
|
2001-12-12 18:18:38 +01:00
|
|
|
|
2008-05-26 21:38:27 +02:00
|
|
|
/**
|
|
|
|
* "Main Loop": Loop until shutdown or restart is signalled.
|
|
|
|
* This function loops until a shutdown or restart of ngIRCd is signalled and
|
|
|
|
* calls io_dispatch() to check for readable and writable sockets every second.
|
|
|
|
* It checks for status changes on pending connections (e. g. when a hostname
|
|
|
|
* has been resolved), checks for "penalties" and timeouts, and handles the
|
|
|
|
* input buffers.
|
|
|
|
*/
|
2005-03-19 19:43:48 +01:00
|
|
|
GLOBAL void
|
2008-05-26 21:38:27 +02:00
|
|
|
Conn_Handler(void)
|
2001-12-12 18:18:38 +01:00
|
|
|
{
|
2005-07-07 20:49:04 +02:00
|
|
|
int i;
|
2009-05-25 22:25:18 +02:00
|
|
|
unsigned int wdatalen, bytes_processed;
|
2001-12-13 02:33:09 +01:00
|
|
|
struct timeval tv;
|
2005-09-24 04:48:46 +02:00
|
|
|
time_t t;
|
2001-12-13 02:33:09 +01:00
|
|
|
|
2008-05-26 21:38:27 +02:00
|
|
|
while (!NGIRCd_SignalQuit && !NGIRCd_SignalRestart) {
|
|
|
|
t = time(NULL);
|
2002-01-02 03:44:36 +01:00
|
|
|
|
2002-12-19 05:35:26 +01:00
|
|
|
/* Check configured servers and established links */
|
2008-05-26 21:38:27 +02:00
|
|
|
Check_Servers();
|
|
|
|
Check_Connections();
|
|
|
|
|
|
|
|
/* Look for non-empty read buffers ... */
|
|
|
|
for (i = 0; i < Pool_Size; i++) {
|
|
|
|
if ((My_Connections[i].sock > NONE)
|
|
|
|
&& (array_bytes(&My_Connections[i].rbuf) > 0)
|
2009-05-25 22:25:18 +02:00
|
|
|
&& (My_Connections[i].delaytime <= t)) {
|
2008-05-26 21:38:27 +02:00
|
|
|
/* ... and try to handle the received data */
|
2009-05-25 22:25:18 +02:00
|
|
|
bytes_processed = Handle_Buffer(i);
|
|
|
|
/* if we processed data, and there might be
|
|
|
|
* more commands in the input buffer, do not
|
|
|
|
* try to read any more data now */
|
|
|
|
if (bytes_processed &&
|
|
|
|
array_bytes(&My_Connections[i].rbuf) > 2) {
|
|
|
|
LogDebug
|
|
|
|
("Throttling connection %d: command limit reached!",
|
|
|
|
i);
|
|
|
|
Conn_SetPenalty(i, 1);
|
|
|
|
}
|
2001-12-26 00:15:16 +01:00
|
|
|
}
|
|
|
|
}
|
2002-03-11 01:04:48 +01:00
|
|
|
|
2008-05-26 21:38:27 +02:00
|
|
|
/* Look for non-empty write buffers ... */
|
|
|
|
for (i = 0; i < Pool_Size; i++) {
|
|
|
|
if (My_Connections[i].sock <= NONE)
|
2005-07-07 20:49:04 +02:00
|
|
|
continue;
|
2005-07-12 22:44:46 +02:00
|
|
|
|
2006-05-10 23:24:01 +02:00
|
|
|
wdatalen = (unsigned int)array_bytes(&My_Connections[i].wbuf);
|
2003-12-26 16:55:07 +01:00
|
|
|
#ifdef ZLIB
|
2008-05-26 21:38:27 +02:00
|
|
|
if (wdatalen > 0 ||
|
|
|
|
array_bytes(&My_Connections[i].zip.wbuf) > 0)
|
2002-11-27 00:07:24 +01:00
|
|
|
#else
|
2008-05-26 21:38:27 +02:00
|
|
|
if (wdatalen > 0)
|
2002-11-27 00:07:24 +01:00
|
|
|
#endif
|
2001-12-26 00:15:16 +01:00
|
|
|
{
|
2008-09-13 15:10:32 +02:00
|
|
|
if (SSL_WantRead(&My_Connections[i]))
|
|
|
|
continue;
|
2008-05-26 21:38:27 +02:00
|
|
|
io_event_add(My_Connections[i].sock,
|
|
|
|
IO_WANTWRITE);
|
2005-04-23 16:28:44 +02:00
|
|
|
}
|
2002-03-02 01:23:32 +01:00
|
|
|
}
|
2001-12-29 21:17:25 +01:00
|
|
|
|
2008-05-26 21:38:27 +02:00
|
|
|
/* Check from which sockets we possibly could read ... */
|
|
|
|
for (i = 0; i < Pool_Size; i++) {
|
|
|
|
if (My_Connections[i].sock <= NONE)
|
2005-07-07 20:49:04 +02:00
|
|
|
continue;
|
2008-09-13 15:10:32 +02:00
|
|
|
#ifdef SSL_SUPPORT
|
|
|
|
if (SSL_WantWrite(&My_Connections[i]))
|
|
|
|
continue; /* TLS/SSL layer needs to write data; deal with this first */
|
|
|
|
#endif
|
2010-05-21 22:48:34 +02:00
|
|
|
if (Proc_InProgress(&My_Connections[i].proc_stat)) {
|
2010-05-21 23:44:20 +02:00
|
|
|
/* Wait for completion of forked subprocess
|
|
|
|
* and ignore the socket in the meantime ... */
|
2008-05-26 21:38:27 +02:00
|
|
|
io_event_del(My_Connections[i].sock,
|
|
|
|
IO_WANTREAD);
|
2005-07-07 20:49:04 +02:00
|
|
|
continue;
|
2002-03-02 01:23:32 +01:00
|
|
|
}
|
2005-07-07 20:49:04 +02:00
|
|
|
|
2008-05-26 21:38:27 +02:00
|
|
|
if (Conn_OPTION_ISSET(&My_Connections[i], CONN_ISCONNECTING))
|
|
|
|
/* Wait for completion of connect() ... */
|
|
|
|
continue;
|
2005-07-07 20:49:04 +02:00
|
|
|
|
2008-05-26 21:38:27 +02:00
|
|
|
if (My_Connections[i].delaytime > t) {
|
|
|
|
/* There is a "penalty time" set: ignore socket! */
|
|
|
|
io_event_del(My_Connections[i].sock,
|
|
|
|
IO_WANTREAD);
|
2005-07-07 20:49:04 +02:00
|
|
|
continue;
|
2001-12-29 21:17:25 +01:00
|
|
|
}
|
2010-05-21 23:44:20 +02:00
|
|
|
|
2008-05-26 21:38:27 +02:00
|
|
|
io_event_add(My_Connections[i].sock, IO_WANTREAD);
|
2001-12-29 21:17:25 +01:00
|
|
|
}
|
|
|
|
|
2008-05-26 21:38:27 +02:00
|
|
|
/* Set the timeout for reading from the network to 1 second,
|
|
|
|
* which is the granularity with witch we handle "penalty
|
|
|
|
* times" for example.
|
|
|
|
* Note: tv_sec/usec are undefined(!) after io_dispatch()
|
|
|
|
* returns, so we have to set it beforce each call to it! */
|
2002-11-23 18:04:07 +01:00
|
|
|
tv.tv_usec = 0;
|
2008-05-26 21:38:27 +02:00
|
|
|
tv.tv_sec = 1;
|
|
|
|
|
|
|
|
/* Wait for activity ... */
|
|
|
|
i = io_dispatch(&tv);
|
|
|
|
if (i == -1 && errno != EINTR) {
|
|
|
|
Log(LOG_EMERG, "Conn_Handler(): io_dispatch(): %s!",
|
|
|
|
strerror(errno));
|
|
|
|
Log(LOG_ALERT, "%s exiting due to fatal errors!",
|
|
|
|
PACKAGE_NAME);
|
|
|
|
exit(1);
|
2001-12-15 01:11:55 +01:00
|
|
|
}
|
2001-12-13 00:32:02 +01:00
|
|
|
}
|
2002-12-19 05:35:26 +01:00
|
|
|
|
2008-05-26 21:38:27 +02:00
|
|
|
if (NGIRCd_SignalQuit)
|
|
|
|
Log(LOG_NOTICE | LOG_snotice, "Server going down NOW!");
|
|
|
|
else if (NGIRCd_SignalRestart)
|
|
|
|
Log(LOG_NOTICE | LOG_snotice, "Server restarting NOW!");
|
2001-12-13 00:32:02 +01:00
|
|
|
} /* Conn_Handler */
|
|
|
|
|
|
|
|
|
2005-07-02 16:36:03 +02:00
|
|
|
/**
|
|
|
|
* Write a text string into the socket of a connection.
|
|
|
|
* This function automatically appends CR+LF to the string and validates that
|
|
|
|
* the result is a valid IRC message (oversized messages are shortened, for
|
|
|
|
* example). Then it calls the Conn_Write() function to do the actual sending.
|
|
|
|
* @param Idx Index fo the connection.
|
|
|
|
* @param Format Format string, see printf().
|
|
|
|
* @return true on success, false otherwise.
|
|
|
|
*/
|
2002-05-30 18:52:20 +02:00
|
|
|
#ifdef PROTOTYPES
|
2005-03-19 19:43:48 +01:00
|
|
|
GLOBAL bool
|
2010-06-26 00:44:37 +02:00
|
|
|
Conn_WriteStr(CONN_ID Idx, const char *Format, ...)
|
2002-05-30 18:52:20 +02:00
|
|
|
#else
|
2005-03-19 19:43:48 +01:00
|
|
|
GLOBAL bool
|
2010-06-26 00:44:37 +02:00
|
|
|
Conn_WriteStr(Idx, Format, va_alist)
|
2002-05-30 18:52:20 +02:00
|
|
|
CONN_ID Idx;
|
2010-06-26 00:44:37 +02:00
|
|
|
const char *Format;
|
2002-05-30 18:52:20 +02:00
|
|
|
va_dcl
|
|
|
|
#endif
|
2001-12-15 01:11:55 +01:00
|
|
|
{
|
2005-03-19 19:43:48 +01:00
|
|
|
char buffer[COMMAND_LEN];
|
2006-03-18 23:27:09 +01:00
|
|
|
size_t len;
|
2005-03-19 19:43:48 +01:00
|
|
|
bool ok;
|
2001-12-23 23:02:54 +01:00
|
|
|
va_list ap;
|
|
|
|
|
2002-11-05 15:18:39 +01:00
|
|
|
assert( Idx > NONE );
|
2002-03-14 14:42:33 +01:00
|
|
|
assert( Format != NULL );
|
2002-05-30 18:52:20 +02:00
|
|
|
|
|
|
|
#ifdef PROTOTYPES
|
2001-12-23 23:02:54 +01:00
|
|
|
va_start( ap, Format );
|
2002-05-30 18:52:20 +02:00
|
|
|
#else
|
|
|
|
va_start( ap );
|
|
|
|
#endif
|
2005-07-07 20:49:04 +02:00
|
|
|
if (vsnprintf( buffer, COMMAND_LEN - 2, Format, ap ) >= COMMAND_LEN - 2 ) {
|
2005-07-02 16:36:03 +02:00
|
|
|
/*
|
|
|
|
* The string that should be written to the socket is longer
|
|
|
|
* than the allowed size of COMMAND_LEN bytes (including both
|
|
|
|
* the CR and LF characters). This can be caused by the
|
|
|
|
* IRC_WriteXXX() functions when the prefix of this server had
|
|
|
|
* to be added to an already "quite long" command line which
|
|
|
|
* has been received from a regular IRC client, for example.
|
|
|
|
*
|
|
|
|
* We are not allowed to send such "oversized" messages to
|
|
|
|
* other servers and clients, see RFC 2812 2.3 and 2813 3.3
|
|
|
|
* ("these messages SHALL NOT exceed 512 characters in length,
|
|
|
|
* counting all characters including the trailing CR-LF").
|
|
|
|
*
|
|
|
|
* So we have a big problem here: we should send more bytes
|
|
|
|
* to the network than we are allowed to and we don't know
|
|
|
|
* the originator (any more). The "old" behaviour of blaming
|
|
|
|
* the receiver ("next hop") is a bad idea (it could be just
|
|
|
|
* an other server only routing the message!), so the only
|
|
|
|
* option left is to shorten the string and to hope that the
|
|
|
|
* result is still somewhat useful ...
|
|
|
|
* -alex-
|
|
|
|
*/
|
|
|
|
|
|
|
|
strcpy (buffer + sizeof(buffer) - strlen(CUT_TXTSUFFIX) - 2 - 1,
|
|
|
|
CUT_TXTSUFFIX);
|
2001-12-15 01:11:55 +01:00
|
|
|
}
|
2001-12-23 23:02:54 +01:00
|
|
|
|
2001-12-25 23:03:47 +01:00
|
|
|
#ifdef SNIFFER
|
2005-07-02 16:36:03 +02:00
|
|
|
if (NGIRCd_Sniffer)
|
|
|
|
Log(LOG_DEBUG, " -> connection %d: '%s'.", Idx, buffer);
|
2001-12-23 23:02:54 +01:00
|
|
|
#endif
|
2001-12-26 00:15:16 +01:00
|
|
|
|
2006-03-18 23:27:09 +01:00
|
|
|
len = strlcat( buffer, "\r\n", sizeof( buffer ));
|
|
|
|
ok = Conn_Write(Idx, buffer, len);
|
2002-12-02 14:19:37 +01:00
|
|
|
My_Connections[Idx].msg_out++;
|
2001-12-24 02:32:33 +01:00
|
|
|
|
2001-12-23 23:02:54 +01:00
|
|
|
va_end( ap );
|
|
|
|
return ok;
|
2001-12-15 01:11:55 +01:00
|
|
|
} /* Conn_WriteStr */
|
|
|
|
|
|
|
|
|
2007-05-09 15:21:11 +02:00
|
|
|
/**
|
2007-05-18 01:34:24 +02:00
|
|
|
* Append Data to the outbound write buffer of a connection.
|
|
|
|
* @param Idx Index of the connection.
|
|
|
|
* @param Data pointer to the data.
|
|
|
|
* @param Len length of Data.
|
2007-05-09 15:21:11 +02:00
|
|
|
* @return true on success, false otherwise.
|
|
|
|
*/
|
|
|
|
static bool
|
2006-05-10 23:24:01 +02:00
|
|
|
Conn_Write( CONN_ID Idx, char *Data, size_t Len )
|
2001-12-15 01:11:55 +01:00
|
|
|
{
|
2007-05-09 10:55:14 +02:00
|
|
|
CLIENT *c;
|
|
|
|
size_t writebuf_limit = WRITEBUFFER_LEN;
|
2002-11-05 15:18:39 +01:00
|
|
|
assert( Idx > NONE );
|
2001-12-15 01:11:55 +01:00
|
|
|
assert( Data != NULL );
|
|
|
|
assert( Len > 0 );
|
|
|
|
|
2007-05-09 10:55:14 +02:00
|
|
|
c = Conn_GetClient(Idx);
|
|
|
|
assert( c != NULL);
|
2007-05-18 01:34:24 +02:00
|
|
|
|
|
|
|
/* Servers do get special write buffer limits, so they can generate
|
|
|
|
* all the messages that are required while peering. */
|
2007-05-09 10:55:14 +02:00
|
|
|
if (Client_Type(c) == CLIENT_SERVER)
|
2007-05-18 01:34:24 +02:00
|
|
|
writebuf_limit = WRITEBUFFER_SLINK_LEN;
|
|
|
|
|
2007-05-09 15:21:11 +02:00
|
|
|
/* Is the socket still open? A previous call to Conn_Write()
|
|
|
|
* may have closed the connection due to a fatal error.
|
2007-05-18 01:34:24 +02:00
|
|
|
* In this case it is sufficient to return an error, as well. */
|
2006-02-08 18:33:28 +01:00
|
|
|
if( My_Connections[Idx].sock <= NONE ) {
|
2007-05-18 01:34:24 +02:00
|
|
|
LogDebug("Skipped write on closed socket (connection %d).", Idx);
|
2005-03-19 19:43:48 +01:00
|
|
|
return false;
|
2002-09-26 17:59:02 +02:00
|
|
|
}
|
|
|
|
|
2003-12-26 16:55:07 +01:00
|
|
|
#ifdef ZLIB
|
2005-04-23 16:28:44 +02:00
|
|
|
if ( Conn_OPTION_ISSET( &My_Connections[Idx], CONN_ZIP )) {
|
2007-05-18 01:34:24 +02:00
|
|
|
/* Compressed link:
|
|
|
|
* Zip_Buffer() does all the dirty work for us: it flushes
|
|
|
|
* the (pre-)compression buffers if required and handles
|
|
|
|
* all error conditions. */
|
|
|
|
if (!Zip_Buffer(Idx, Data, Len))
|
|
|
|
return false;
|
2001-12-15 01:11:55 +01:00
|
|
|
}
|
2002-11-27 00:07:24 +01:00
|
|
|
else
|
|
|
|
#endif
|
2001-12-15 01:11:55 +01:00
|
|
|
{
|
2007-05-18 01:34:24 +02:00
|
|
|
/* Uncompressed link:
|
|
|
|
* Check if outbound buffer has enough space for the data. */
|
|
|
|
if (array_bytes(&My_Connections[Idx].wbuf) + Len >=
|
|
|
|
writebuf_limit) {
|
|
|
|
/* Buffer is full, flush it. Handle_Write deals with
|
|
|
|
* low-level errors, if any. */
|
|
|
|
if (!Handle_Write(Idx))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* When the write buffer is still too big after flushing it,
|
|
|
|
* the connection will be killed. */
|
|
|
|
if (array_bytes(&My_Connections[Idx].wbuf) + Len >=
|
|
|
|
writebuf_limit) {
|
|
|
|
Log(LOG_NOTICE,
|
|
|
|
"Write buffer overflow (connection %d, size %lu byte)!",
|
|
|
|
Idx,
|
|
|
|
(unsigned long)array_bytes(&My_Connections[Idx].wbuf));
|
|
|
|
Conn_Close(Idx, "Write buffer overflow!", NULL, false);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Copy data to write buffer */
|
|
|
|
if (!array_catb(&My_Connections[Idx].wbuf, Data, Len))
|
2005-07-07 20:49:04 +02:00
|
|
|
return false;
|
|
|
|
|
2002-11-27 00:07:24 +01:00
|
|
|
My_Connections[Idx].bytes_out += Len;
|
2001-12-15 01:11:55 +01:00
|
|
|
}
|
2001-12-26 00:15:16 +01:00
|
|
|
|
2002-12-18 14:50:22 +01:00
|
|
|
/* Adjust global write counter */
|
|
|
|
WCounter += Len;
|
|
|
|
|
2005-03-19 19:43:48 +01:00
|
|
|
return true;
|
2001-12-15 01:11:55 +01:00
|
|
|
} /* Conn_Write */
|
|
|
|
|
|
|
|
|
2005-03-19 19:43:48 +01:00
|
|
|
GLOBAL void
|
2009-04-12 01:09:42 +02:00
|
|
|
Conn_Close( CONN_ID Idx, const char *LogMsg, const char *FwdMsg, bool InformClient )
|
2001-12-25 23:03:47 +01:00
|
|
|
{
|
2002-12-27 14:20:13 +01:00
|
|
|
/* Close connection. Open pipes of asyncronous resolver
|
|
|
|
* sub-processes are closed down. */
|
2001-12-25 23:03:47 +01:00
|
|
|
|
2002-01-02 03:44:36 +01:00
|
|
|
CLIENT *c;
|
2005-03-19 19:43:48 +01:00
|
|
|
double in_k, out_k;
|
2008-02-26 23:50:35 +01:00
|
|
|
UINT16 port;
|
2003-12-26 16:55:07 +01:00
|
|
|
#ifdef ZLIB
|
2005-03-19 19:43:48 +01:00
|
|
|
double in_z_k, out_z_k;
|
|
|
|
int in_p, out_p;
|
2002-11-27 00:07:24 +01:00
|
|
|
#endif
|
2002-03-11 01:04:48 +01:00
|
|
|
|
2002-11-05 15:18:39 +01:00
|
|
|
assert( Idx > NONE );
|
2001-12-25 23:03:47 +01:00
|
|
|
|
2003-02-21 20:19:27 +01:00
|
|
|
/* Is this link already shutting down? */
|
2005-04-23 16:28:44 +02:00
|
|
|
if( Conn_OPTION_ISSET( &My_Connections[Idx], CONN_ISCLOSING )) {
|
2003-02-21 20:19:27 +01:00
|
|
|
/* Conn_Close() has been called recursively for this link;
|
2005-06-04 13:49:20 +02:00
|
|
|
* probabe reason: Handle_Write() failed -- see below. */
|
2006-02-08 18:33:28 +01:00
|
|
|
LogDebug("Recursive request to close connection: %d", Idx );
|
2003-02-21 20:19:27 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2004-04-25 16:06:11 +02:00
|
|
|
assert( My_Connections[Idx].sock > NONE );
|
|
|
|
|
2003-02-21 20:19:27 +01:00
|
|
|
/* Mark link as "closing" */
|
2005-04-23 16:28:44 +02:00
|
|
|
Conn_OPTION_ADD( &My_Connections[Idx], CONN_ISCLOSING );
|
2007-04-04 23:52:12 +02:00
|
|
|
|
2008-02-26 23:50:35 +01:00
|
|
|
port = ng_ipaddr_getport(&My_Connections[Idx].addr);
|
2006-07-24 01:05:20 +02:00
|
|
|
Log(LOG_INFO, "Shutting down connection %d (%s) with %s:%d ...", Idx,
|
2008-02-26 23:50:35 +01:00
|
|
|
LogMsg ? LogMsg : FwdMsg, My_Connections[Idx].host, port);
|
2003-02-21 20:19:27 +01:00
|
|
|
|
2002-12-27 14:20:13 +01:00
|
|
|
/* Search client, if any */
|
2006-04-23 12:37:27 +02:00
|
|
|
c = Conn_GetClient( Idx );
|
2002-10-09 15:15:08 +02:00
|
|
|
|
2002-12-27 14:20:13 +01:00
|
|
|
/* Should the client be informed? */
|
2005-08-16 01:02:40 +02:00
|
|
|
if (InformClient) {
|
2002-11-29 14:13:42 +01:00
|
|
|
#ifndef STRICT_RFC
|
2002-12-27 14:20:13 +01:00
|
|
|
/* Send statistics to client if registered as user: */
|
2005-08-16 01:02:40 +02:00
|
|
|
if ((c != NULL) && (Client_Type(c) == CLIENT_USER)) {
|
|
|
|
Conn_WriteStr( Idx,
|
2005-08-29 13:11:15 +02:00
|
|
|
":%s NOTICE %s :%sConnection statistics: client %.1f kb, server %.1f kb.",
|
|
|
|
Client_ID(Client_ThisServer()), Client_ID(c),
|
|
|
|
NOTICE_TXTPREFIX,
|
2005-08-16 01:02:40 +02:00
|
|
|
(double)My_Connections[Idx].bytes_in / 1024,
|
|
|
|
(double)My_Connections[Idx].bytes_out / 1024);
|
2002-10-09 15:15:08 +02:00
|
|
|
}
|
2002-11-29 14:13:42 +01:00
|
|
|
#endif
|
2009-06-05 01:39:33 +02:00
|
|
|
/* Send ERROR to client (see RFC 2812, section 3.1.7) */
|
2005-08-16 01:02:40 +02:00
|
|
|
if (FwdMsg)
|
|
|
|
Conn_WriteStr(Idx, "ERROR :%s", FwdMsg);
|
|
|
|
else
|
2011-01-29 16:05:55 +01:00
|
|
|
Conn_WriteStr(Idx, "ERROR :Closing connection");
|
2002-01-02 03:44:36 +01:00
|
|
|
}
|
2001-12-25 23:03:47 +01:00
|
|
|
|
2005-10-11 21:29:23 +02:00
|
|
|
/* Try to write out the write buffer. Note: Handle_Write() eventually
|
|
|
|
* removes the CLIENT structure associated with this connection if an
|
|
|
|
* error occurs! So we have to re-check if there is still an valid
|
|
|
|
* CLIENT structure after calling Handle_Write() ...*/
|
2005-06-04 13:49:20 +02:00
|
|
|
(void)Handle_Write( Idx );
|
2005-07-12 22:44:46 +02:00
|
|
|
|
2005-10-11 21:29:23 +02:00
|
|
|
/* Search client, if any (re-check!) */
|
2006-04-23 12:37:27 +02:00
|
|
|
c = Conn_GetClient( Idx );
|
2008-09-13 15:10:32 +02:00
|
|
|
#ifdef SSL_SUPPORT
|
|
|
|
if ( Conn_OPTION_ISSET( &My_Connections[Idx], CONN_SSL )) {
|
2008-11-20 23:50:26 +01:00
|
|
|
Log(LOG_INFO, "SSL connection %d shutting down ...", Idx);
|
2008-09-13 15:10:32 +02:00
|
|
|
ConnSSL_Free(&My_Connections[Idx]);
|
|
|
|
}
|
|
|
|
#endif
|
2002-12-27 14:20:13 +01:00
|
|
|
/* Shut down socket */
|
2006-07-24 01:05:20 +02:00
|
|
|
if (! io_close(My_Connections[Idx].sock)) {
|
2005-05-23 01:55:57 +02:00
|
|
|
/* Oops, we can't close the socket!? This is ... ugly! */
|
2006-07-24 01:05:20 +02:00
|
|
|
Log(LOG_CRIT,
|
|
|
|
"Error closing connection %d (socket %d) with %s:%d - %s! (ignored)",
|
|
|
|
Idx, My_Connections[Idx].sock, My_Connections[Idx].host,
|
2008-02-26 23:50:35 +01:00
|
|
|
port, strerror(errno));
|
2001-12-25 23:03:47 +01:00
|
|
|
}
|
2002-12-27 14:20:13 +01:00
|
|
|
|
|
|
|
/* Mark socket as invalid: */
|
2002-10-15 00:21:00 +02:00
|
|
|
My_Connections[Idx].sock = NONE;
|
2001-12-25 23:03:47 +01:00
|
|
|
|
2002-12-27 14:20:13 +01:00
|
|
|
/* If there is still a client, unregister it now */
|
2006-07-24 01:05:20 +02:00
|
|
|
if (c)
|
|
|
|
Client_Destroy(c, LogMsg, FwdMsg, true);
|
2001-12-25 23:03:47 +01:00
|
|
|
|
2002-12-27 14:20:13 +01:00
|
|
|
/* Calculate statistics and log information */
|
2005-03-19 19:43:48 +01:00
|
|
|
in_k = (double)My_Connections[Idx].bytes_in / 1024;
|
|
|
|
out_k = (double)My_Connections[Idx].bytes_out / 1024;
|
2003-12-26 16:55:07 +01:00
|
|
|
#ifdef ZLIB
|
2006-07-24 01:05:20 +02:00
|
|
|
if (Conn_OPTION_ISSET( &My_Connections[Idx], CONN_ZIP)) {
|
2005-03-19 19:43:48 +01:00
|
|
|
in_z_k = (double)My_Connections[Idx].zip.bytes_in / 1024;
|
|
|
|
out_z_k = (double)My_Connections[Idx].zip.bytes_out / 1024;
|
2006-07-24 01:05:20 +02:00
|
|
|
/* Make sure that no division by zero can occur during
|
|
|
|
* the calculation of in_p and out_p: in_z_k and out_z_k
|
|
|
|
* are non-zero, that's guaranteed by the protocol until
|
|
|
|
* compression can be enabled. */
|
|
|
|
if (! in_z_k)
|
|
|
|
in_z_k = in_k;
|
|
|
|
if (! out_z_k)
|
|
|
|
out_z_k = out_k;
|
2005-03-19 19:43:48 +01:00
|
|
|
in_p = (int)(( in_k * 100 ) / in_z_k );
|
|
|
|
out_p = (int)(( out_k * 100 ) / out_z_k );
|
2006-07-24 01:05:20 +02:00
|
|
|
Log(LOG_INFO,
|
|
|
|
"Connection %d with %s:%d closed (in: %.1fk/%.1fk/%d%%, out: %.1fk/%.1fk/%d%%).",
|
2008-02-26 23:50:35 +01:00
|
|
|
Idx, My_Connections[Idx].host, port,
|
2006-07-24 01:05:20 +02:00
|
|
|
in_k, in_z_k, in_p, out_k, out_z_k, out_p);
|
2002-12-27 14:20:13 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
2006-07-24 01:05:20 +02:00
|
|
|
Log(LOG_INFO,
|
|
|
|
"Connection %d with %s:%d closed (in: %.1fk, out: %.1fk).",
|
2008-02-26 23:50:35 +01:00
|
|
|
Idx, My_Connections[Idx].host, port,
|
2006-07-24 01:05:20 +02:00
|
|
|
in_k, out_k);
|
2002-12-27 14:20:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Servers: Modify time of next connect attempt? */
|
2002-12-30 01:01:42 +01:00
|
|
|
Conf_UnsetServer( Idx );
|
2002-01-02 03:44:36 +01:00
|
|
|
|
2003-12-26 16:55:07 +01:00
|
|
|
#ifdef ZLIB
|
2002-12-27 14:20:13 +01:00
|
|
|
/* Clean up zlib, if link was compressed */
|
2005-04-23 16:28:44 +02:00
|
|
|
if ( Conn_OPTION_ISSET( &My_Connections[Idx], CONN_ZIP )) {
|
2002-11-27 00:07:24 +01:00
|
|
|
inflateEnd( &My_Connections[Idx].zip.in );
|
|
|
|
deflateEnd( &My_Connections[Idx].zip.out );
|
2005-07-07 20:49:04 +02:00
|
|
|
array_free(&My_Connections[Idx].zip.rbuf);
|
|
|
|
array_free(&My_Connections[Idx].zip.wbuf);
|
2002-11-27 00:07:24 +01:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2005-07-07 20:49:04 +02:00
|
|
|
array_free(&My_Connections[Idx].rbuf);
|
|
|
|
array_free(&My_Connections[Idx].wbuf);
|
2006-07-24 01:05:20 +02:00
|
|
|
|
2002-12-27 14:20:13 +01:00
|
|
|
/* Clean up connection structure (=free it) */
|
2002-10-15 00:21:00 +02:00
|
|
|
Init_Conn_Struct( Idx );
|
2004-12-22 18:37:41 +01:00
|
|
|
|
2008-08-30 15:37:19 +02:00
|
|
|
assert(NumConnections > 0);
|
|
|
|
if (NumConnections)
|
|
|
|
NumConnections--;
|
2008-11-12 01:23:33 +01:00
|
|
|
LogDebug("Shutdown of connection %d completed, %ld connection%s left.",
|
|
|
|
Idx, NumConnections, NumConnections != 1 ? "s" : "");
|
2001-12-25 23:03:47 +01:00
|
|
|
} /* Conn_Close */
|
|
|
|
|
|
|
|
|
2010-04-23 23:25:34 +02:00
|
|
|
GLOBAL long
|
|
|
|
Conn_Count(void)
|
|
|
|
{
|
|
|
|
return NumConnections;
|
|
|
|
} /* Conn_Count */
|
|
|
|
|
|
|
|
|
|
|
|
GLOBAL long
|
|
|
|
Conn_CountMax(void)
|
|
|
|
{
|
|
|
|
return NumConnectionsMax;
|
|
|
|
} /* Conn_CountMax */
|
|
|
|
|
|
|
|
|
|
|
|
GLOBAL long
|
|
|
|
Conn_CountAccepted(void)
|
|
|
|
{
|
|
|
|
return NumConnectionsAccepted;
|
|
|
|
} /* Conn_CountAccepted */
|
|
|
|
|
|
|
|
|
2010-09-08 02:02:01 +02:00
|
|
|
/**
|
|
|
|
* Synchronize established connections and configured server structures
|
|
|
|
* after a configuration update and store the correct connection IDs, if any.
|
|
|
|
*/
|
2005-03-19 19:43:48 +01:00
|
|
|
GLOBAL void
|
2010-09-08 02:02:01 +02:00
|
|
|
Conn_SyncServerStruct(void)
|
2003-03-27 02:20:22 +01:00
|
|
|
{
|
|
|
|
CLIENT *client;
|
|
|
|
CONN_ID i;
|
2005-03-19 19:43:48 +01:00
|
|
|
int c;
|
2003-03-27 02:20:22 +01:00
|
|
|
|
2010-09-08 02:02:01 +02:00
|
|
|
for (i = 0; i < Pool_Size; i++) {
|
|
|
|
if (My_Connections[i].sock == NONE)
|
2006-02-02 22:00:21 +01:00
|
|
|
continue;
|
2003-03-27 02:20:22 +01:00
|
|
|
|
2010-09-08 02:02:01 +02:00
|
|
|
/* Server link? */
|
|
|
|
client = Conn_GetClient(i);
|
|
|
|
if (!client || Client_Type(client) != CLIENT_SERVER)
|
|
|
|
continue;
|
2003-03-27 02:20:22 +01:00
|
|
|
|
2010-09-08 02:02:01 +02:00
|
|
|
for (c = 0; c < MAX_SERVERS; c++) {
|
2003-03-27 02:20:22 +01:00
|
|
|
/* Configured server? */
|
2010-09-08 02:02:01 +02:00
|
|
|
if (!Conf_Server[c].host[0])
|
|
|
|
continue;
|
2003-03-27 02:20:22 +01:00
|
|
|
|
2010-09-08 02:02:01 +02:00
|
|
|
if (strcasecmp(Conf_Server[c].name, Client_ID(client)) == 0)
|
2006-02-08 16:20:21 +01:00
|
|
|
Conf_Server[c].conn_id = i;
|
2003-03-27 02:20:22 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} /* SyncServerStruct */
|
|
|
|
|
|
|
|
|
2006-05-10 23:24:01 +02:00
|
|
|
/**
|
|
|
|
* Send out data of write buffer; connect new sockets.
|
|
|
|
*/
|
2005-07-31 22:13:07 +02:00
|
|
|
static bool
|
2002-05-27 15:09:26 +02:00
|
|
|
Handle_Write( CONN_ID Idx )
|
2001-12-15 01:11:55 +01:00
|
|
|
{
|
2006-05-10 23:24:01 +02:00
|
|
|
ssize_t len;
|
|
|
|
size_t wdatalen;
|
2001-12-15 01:11:55 +01:00
|
|
|
|
2002-10-15 11:24:54 +02:00
|
|
|
assert( Idx > NONE );
|
2005-07-07 20:49:04 +02:00
|
|
|
if ( My_Connections[Idx].sock < 0 ) {
|
2006-02-08 18:33:28 +01:00
|
|
|
LogDebug("Handle_Write() on closed socket, connection %d", Idx);
|
2005-07-07 20:49:04 +02:00
|
|
|
return false;
|
|
|
|
}
|
2005-09-12 21:10:20 +02:00
|
|
|
assert( My_Connections[Idx].sock > NONE );
|
2002-03-02 01:23:32 +01:00
|
|
|
|
2005-07-07 20:49:04 +02:00
|
|
|
wdatalen = array_bytes(&My_Connections[Idx].wbuf );
|
2006-07-23 17:22:56 +02:00
|
|
|
|
2003-12-26 16:55:07 +01:00
|
|
|
#ifdef ZLIB
|
2007-05-18 01:34:24 +02:00
|
|
|
if (wdatalen == 0) {
|
|
|
|
/* Write buffer is empty, so we try to flush the compression
|
|
|
|
* buffer and get some data to work with from there :-) */
|
|
|
|
if (!Zip_Flush(Idx))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* Now the write buffer most probably has changed: */
|
|
|
|
wdatalen = array_bytes(&My_Connections[Idx].wbuf);
|
2005-07-07 20:49:04 +02:00
|
|
|
}
|
2007-05-18 01:34:24 +02:00
|
|
|
#endif
|
2005-06-04 13:49:20 +02:00
|
|
|
|
2005-09-02 15:28:30 +02:00
|
|
|
if (wdatalen == 0) {
|
2007-05-18 01:34:24 +02:00
|
|
|
/* Still no data, fine. */
|
2005-07-07 20:49:04 +02:00
|
|
|
io_event_del(My_Connections[Idx].sock, IO_WANTWRITE );
|
2005-06-04 13:49:20 +02:00
|
|
|
return true;
|
2005-07-07 20:49:04 +02:00
|
|
|
}
|
2002-11-27 00:07:24 +01:00
|
|
|
|
2006-07-23 17:22:56 +02:00
|
|
|
LogDebug
|
|
|
|
("Handle_Write() called for connection %d, %ld bytes pending ...",
|
|
|
|
Idx, wdatalen);
|
2005-09-02 15:28:30 +02:00
|
|
|
|
2008-09-13 15:10:32 +02:00
|
|
|
#ifdef SSL_SUPPORT
|
|
|
|
if ( Conn_OPTION_ISSET( &My_Connections[Idx], CONN_SSL )) {
|
|
|
|
len = ConnSSL_Write(&My_Connections[Idx], array_start(&My_Connections[Idx].wbuf), wdatalen);
|
|
|
|
} else
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
len = write(My_Connections[Idx].sock,
|
|
|
|
array_start(&My_Connections[Idx].wbuf), wdatalen );
|
|
|
|
}
|
2005-06-04 13:49:20 +02:00
|
|
|
if( len < 0 ) {
|
2005-09-02 15:28:30 +02:00
|
|
|
if (errno == EAGAIN || errno == EINTR)
|
2005-06-04 13:49:20 +02:00
|
|
|
return true;
|
2002-11-20 16:48:41 +01:00
|
|
|
|
2005-09-02 15:28:30 +02:00
|
|
|
Log(LOG_ERR, "Write error on connection %d (socket %d): %s!",
|
|
|
|
Idx, My_Connections[Idx].sock, strerror(errno));
|
|
|
|
Conn_Close(Idx, "Write error!", NULL, false);
|
2005-03-19 19:43:48 +01:00
|
|
|
return false;
|
2001-12-15 01:11:55 +01:00
|
|
|
}
|
2001-12-26 00:15:16 +01:00
|
|
|
|
2005-07-07 20:49:04 +02:00
|
|
|
/* move any data not yet written to beginning */
|
2006-05-10 23:24:01 +02:00
|
|
|
array_moveleft(&My_Connections[Idx].wbuf, 1, (size_t)len);
|
2001-12-26 00:15:16 +01:00
|
|
|
|
2005-03-19 19:43:48 +01:00
|
|
|
return true;
|
2001-12-15 01:11:55 +01:00
|
|
|
} /* Handle_Write */
|
2001-12-13 00:32:02 +01:00
|
|
|
|
|
|
|
|
2008-02-26 23:50:35 +01:00
|
|
|
static int
|
|
|
|
Count_Connections(ng_ipaddr_t *a)
|
|
|
|
{
|
|
|
|
int i, cnt;
|
|
|
|
|
|
|
|
cnt = 0;
|
|
|
|
for (i = 0; i < Pool_Size; i++) {
|
|
|
|
if (My_Connections[i].sock <= NONE)
|
|
|
|
continue;
|
|
|
|
if (ng_ipaddr_ipequal(&My_Connections[i].addr, a))
|
|
|
|
cnt++;
|
|
|
|
}
|
|
|
|
return cnt;
|
|
|
|
} /* Count_Connections */
|
|
|
|
|
|
|
|
|
2009-12-30 23:35:17 +01:00
|
|
|
/**
|
|
|
|
* Initialize new client connection on a listening socket.
|
|
|
|
* @param Sock Listening socket descriptor
|
|
|
|
* @return Accepted socket descriptor or -1 on error
|
|
|
|
*/
|
2005-07-31 22:13:07 +02:00
|
|
|
static int
|
2009-12-30 23:32:47 +01:00
|
|
|
New_Connection(int Sock)
|
2001-12-13 00:32:02 +01:00
|
|
|
{
|
2003-12-26 16:55:07 +01:00
|
|
|
#ifdef TCPWRAP
|
2003-03-07 15:35:52 +01:00
|
|
|
struct request_info req;
|
|
|
|
#endif
|
2008-02-26 23:50:35 +01:00
|
|
|
ng_ipaddr_t new_addr;
|
|
|
|
char ip_str[NG_INET_ADDRSTRLEN];
|
2008-11-19 19:11:39 +01:00
|
|
|
int new_sock, new_sock_len, identsock;
|
2002-05-19 15:05:22 +02:00
|
|
|
CLIENT *c;
|
2006-02-16 20:21:57 +01:00
|
|
|
long cnt;
|
2002-03-11 01:04:48 +01:00
|
|
|
|
2009-12-30 23:32:47 +01:00
|
|
|
assert(Sock > NONE);
|
2008-02-26 23:50:35 +01:00
|
|
|
|
2009-12-30 23:32:47 +01:00
|
|
|
new_sock_len = (int)sizeof(new_addr);
|
2006-05-10 23:24:01 +02:00
|
|
|
new_sock = accept(Sock, (struct sockaddr *)&new_addr,
|
|
|
|
(socklen_t *)&new_sock_len);
|
|
|
|
if (new_sock < 0) {
|
|
|
|
Log(LOG_CRIT, "Can't accept connection: %s!", strerror(errno));
|
2005-07-29 11:29:47 +02:00
|
|
|
return -1;
|
2001-12-13 00:32:02 +01:00
|
|
|
}
|
2010-04-23 23:25:34 +02:00
|
|
|
NumConnectionsAccepted++;
|
2003-04-25 18:47:52 +02:00
|
|
|
|
2008-02-26 23:50:35 +01:00
|
|
|
if (!ng_ipaddr_tostr_r(&new_addr, ip_str)) {
|
|
|
|
Log(LOG_CRIT, "fd %d: Can't convert IP address!", new_sock);
|
|
|
|
Simple_Message(new_sock, "ERROR :Internal Server Error");
|
|
|
|
close(new_sock);
|
2008-08-30 15:37:19 +02:00
|
|
|
return -1;
|
2008-02-26 23:50:35 +01:00
|
|
|
}
|
|
|
|
|
2003-12-26 16:55:07 +01:00
|
|
|
#ifdef TCPWRAP
|
2003-03-07 15:35:52 +01:00
|
|
|
/* Validate socket using TCP Wrappers */
|
2009-12-30 23:32:47 +01:00
|
|
|
request_init(&req, RQ_DAEMON, PACKAGE_NAME, RQ_FILE, new_sock,
|
|
|
|
RQ_CLIENT_SIN, &new_addr, NULL);
|
2004-02-03 21:28:30 +01:00
|
|
|
fromhost(&req);
|
2008-02-26 23:50:35 +01:00
|
|
|
if (!hosts_access(&req)) {
|
2009-12-30 23:32:47 +01:00
|
|
|
Log(deny_severity,
|
|
|
|
"Refused connection from %s (by TCP Wrappers)!", ip_str);
|
|
|
|
Simple_Message(new_sock, "ERROR :Connection refused");
|
|
|
|
close(new_sock);
|
2005-07-29 11:29:47 +02:00
|
|
|
return -1;
|
2003-03-07 15:35:52 +01:00
|
|
|
}
|
|
|
|
#endif
|
2001-12-26 00:15:16 +01:00
|
|
|
|
2009-12-30 23:32:47 +01:00
|
|
|
if (!Init_Socket(new_sock))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* Check global connection limit */
|
|
|
|
if ((Conf_MaxConnections > 0) &&
|
|
|
|
(NumConnections >= (size_t) Conf_MaxConnections)) {
|
|
|
|
Log(LOG_ALERT, "Can't accept connection: limit (%d) reached!",
|
|
|
|
Conf_MaxConnections);
|
|
|
|
Simple_Message(new_sock, "ERROR :Connection limit reached");
|
|
|
|
close(new_sock);
|
2006-02-16 20:21:57 +01:00
|
|
|
return -1;
|
2009-12-30 23:32:47 +01:00
|
|
|
}
|
2008-02-26 23:50:35 +01:00
|
|
|
|
2003-11-05 22:41:01 +01:00
|
|
|
/* Check IP-based connection limit */
|
2008-02-26 23:50:35 +01:00
|
|
|
cnt = Count_Connections(&new_addr);
|
|
|
|
if ((Conf_MaxConnectionsIP > 0) && (cnt >= Conf_MaxConnectionsIP)) {
|
2004-10-05 01:09:04 +02:00
|
|
|
/* Access denied, too many connections from this IP address! */
|
2009-12-30 23:32:47 +01:00
|
|
|
Log(LOG_ERR,
|
|
|
|
"Refused connection from %s: too may connections (%ld) from this IP address!",
|
|
|
|
ip_str, cnt);
|
|
|
|
Simple_Message(new_sock,
|
2011-01-29 16:05:55 +01:00
|
|
|
"ERROR :Connection refused, too many connections from your IP address");
|
2009-12-30 23:32:47 +01:00
|
|
|
close(new_sock);
|
2008-08-30 15:37:19 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2003-04-25 18:47:52 +02:00
|
|
|
|
2009-12-30 23:32:47 +01:00
|
|
|
if (new_sock >= Pool_Size) {
|
2006-05-10 23:24:01 +02:00
|
|
|
if (!array_alloc(&My_ConnArray, sizeof(CONNECTION),
|
2009-12-30 23:32:47 +01:00
|
|
|
(size_t) new_sock)) {
|
|
|
|
Log(LOG_EMERG,
|
|
|
|
"Can't allocate memory! [New_Connection]");
|
|
|
|
Simple_Message(new_sock, "ERROR: Internal error");
|
|
|
|
close(new_sock);
|
2005-07-29 11:29:47 +02:00
|
|
|
return -1;
|
2002-11-03 00:00:45 +01:00
|
|
|
}
|
2006-02-16 20:21:57 +01:00
|
|
|
LogDebug("Bumped connection pool to %ld items (internal: %ld items, %ld bytes)",
|
2009-12-30 23:32:47 +01:00
|
|
|
new_sock, array_length(&My_ConnArray,
|
|
|
|
sizeof(CONNECTION)), array_bytes(&My_ConnArray));
|
2003-04-25 18:47:52 +02:00
|
|
|
|
2002-12-17 12:46:54 +01:00
|
|
|
/* Adjust pointer to new block */
|
2006-02-16 20:21:57 +01:00
|
|
|
My_Connections = array_start(&My_ConnArray);
|
2008-08-30 15:37:19 +02:00
|
|
|
while (Pool_Size <= new_sock)
|
2006-04-29 18:19:46 +02:00
|
|
|
Init_Conn_Struct(Pool_Size++);
|
2001-12-12 18:18:38 +01:00
|
|
|
}
|
2001-12-26 00:15:16 +01:00
|
|
|
|
2006-12-25 02:11:12 +01:00
|
|
|
/* register callback */
|
2009-12-30 23:32:47 +01:00
|
|
|
if (!io_event_create(new_sock, IO_WANTREAD, cb_clientserver)) {
|
|
|
|
Log(LOG_ALERT,
|
|
|
|
"Can't accept connection: io_event_create failed!");
|
2006-12-25 02:11:12 +01:00
|
|
|
Simple_Message(new_sock, "ERROR :Internal error");
|
|
|
|
close(new_sock);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2009-12-30 23:32:47 +01:00
|
|
|
c = Client_NewLocal(new_sock, ip_str, CLIENT_UNKNOWN, false);
|
|
|
|
if (!c) {
|
|
|
|
Log(LOG_ALERT,
|
|
|
|
"Can't accept connection: can't create client structure!");
|
2006-12-25 02:11:12 +01:00
|
|
|
Simple_Message(new_sock, "ERROR :Internal error");
|
|
|
|
io_close(new_sock);
|
2006-12-18 00:04:45 +01:00
|
|
|
return -1;
|
2001-12-23 23:02:54 +01:00
|
|
|
}
|
2001-12-26 00:15:16 +01:00
|
|
|
|
2009-12-30 23:32:47 +01:00
|
|
|
Init_Conn_Struct(new_sock);
|
2006-02-08 16:20:21 +01:00
|
|
|
My_Connections[new_sock].sock = new_sock;
|
|
|
|
My_Connections[new_sock].addr = new_addr;
|
2006-04-23 12:37:27 +02:00
|
|
|
My_Connections[new_sock].client = c;
|
2001-12-13 00:32:02 +01:00
|
|
|
|
2009-04-10 13:22:03 +02:00
|
|
|
/* Set initial hostname to IP address. This becomes overwritten when
|
|
|
|
* the DNS lookup is enabled and succeeds, but is used otherwise. */
|
|
|
|
if (ng_ipaddr_af(&new_addr) != AF_INET)
|
|
|
|
snprintf(My_Connections[new_sock].host,
|
|
|
|
sizeof(My_Connections[new_sock].host), "[%s]", ip_str);
|
|
|
|
else
|
|
|
|
strlcpy(My_Connections[new_sock].host, ip_str,
|
|
|
|
sizeof(My_Connections[new_sock].host));
|
2006-02-08 16:20:21 +01:00
|
|
|
|
2008-02-26 23:50:35 +01:00
|
|
|
Client_SetHostname(c, My_Connections[new_sock].host);
|
2005-09-12 21:10:20 +02:00
|
|
|
|
2009-04-10 13:22:03 +02:00
|
|
|
Log(LOG_INFO, "Accepted connection %d from %s:%d on socket %d.",
|
|
|
|
new_sock, My_Connections[new_sock].host,
|
|
|
|
ng_ipaddr_getport(&new_addr), Sock);
|
|
|
|
|
2008-11-19 19:11:39 +01:00
|
|
|
identsock = new_sock;
|
|
|
|
#ifdef IDENTAUTH
|
config: deprecate NoXX-Options
ngircd unfortunately uses several options using double-negation, e.g.
NoIdent = No, NoPam = No, etc.
This renames all options by dropping the "No" prefix, e.g.
"NoIdent = no" becomes "Ident = yes".
The old options will continue to work, but will cause a warning
message.
Also update man pages and default config.
To prevent silly
'Ident = yes' from appearing in --configtest output in the
'ident support not compiled in and Ident Option not used' case,
make default value depend on feature availability.
If feature is available, enable by default, otherwise disable.
We might consider moving these options to a new
[Feature]
section, or something like that, because none of these options are
essential.
Another possible improvement:
'Ident = yes' option in ngircd.conf causes a warning if ngircd was
built without ident support.
This does not happen with e.g. zeroconf....
2011-01-08 15:56:14 +01:00
|
|
|
if (!Conf_Ident)
|
2008-11-19 19:11:39 +01:00
|
|
|
identsock = -1;
|
|
|
|
#endif
|
config: deprecate NoXX-Options
ngircd unfortunately uses several options using double-negation, e.g.
NoIdent = No, NoPam = No, etc.
This renames all options by dropping the "No" prefix, e.g.
"NoIdent = no" becomes "Ident = yes".
The old options will continue to work, but will cause a warning
message.
Also update man pages and default config.
To prevent silly
'Ident = yes' from appearing in --configtest output in the
'ident support not compiled in and Ident Option not used' case,
make default value depend on feature availability.
If feature is available, enable by default, otherwise disable.
We might consider moving these options to a new
[Feature]
section, or something like that, because none of these options are
essential.
Another possible improvement:
'Ident = yes' option in ngircd.conf causes a warning if ngircd was
built without ident support.
This does not happen with e.g. zeroconf....
2011-01-08 15:56:14 +01:00
|
|
|
if (Conf_DNS)
|
2010-05-21 22:48:34 +02:00
|
|
|
Resolve_Addr(&My_Connections[new_sock].proc_stat, &new_addr,
|
2008-11-19 19:11:39 +01:00
|
|
|
identsock, cb_Read_Resolver_Result);
|
2009-12-30 23:32:47 +01:00
|
|
|
|
2010-04-23 23:25:34 +02:00
|
|
|
Account_Connection();
|
2005-07-29 11:29:47 +02:00
|
|
|
return new_sock;
|
2006-12-18 00:04:45 +01:00
|
|
|
} /* New_Connection */
|
2001-12-13 00:32:02 +01:00
|
|
|
|
|
|
|
|
2010-04-23 23:25:34 +02:00
|
|
|
static void
|
|
|
|
Account_Connection(void)
|
|
|
|
{
|
|
|
|
NumConnections++;
|
|
|
|
if (NumConnections > NumConnectionsMax)
|
|
|
|
NumConnectionsMax = NumConnections;
|
|
|
|
LogDebug("Total number of connections now %lu (max %lu).",
|
|
|
|
NumConnections, NumConnectionsMax);
|
|
|
|
} /* Account_Connection */
|
|
|
|
|
|
|
|
|
2005-07-31 22:13:07 +02:00
|
|
|
static CONN_ID
|
2005-03-19 19:43:48 +01:00
|
|
|
Socket2Index( int Sock )
|
2001-12-13 00:32:02 +01:00
|
|
|
{
|
2006-02-08 16:20:21 +01:00
|
|
|
assert( Sock >= 0 );
|
2001-12-26 00:15:16 +01:00
|
|
|
|
2006-02-08 16:20:21 +01:00
|
|
|
if( Sock >= Pool_Size || My_Connections[Sock].sock != Sock ) {
|
2009-04-21 08:40:10 +02:00
|
|
|
/* the Connection was already closed again, likely due to
|
|
|
|
* an error. */
|
2006-02-16 20:21:57 +01:00
|
|
|
LogDebug("Socket2Index: can't get connection for socket %d!", Sock);
|
2002-10-15 11:24:54 +02:00
|
|
|
return NONE;
|
|
|
|
}
|
2006-02-08 16:20:21 +01:00
|
|
|
return Sock;
|
2001-12-13 00:32:02 +01:00
|
|
|
} /* Socket2Index */
|
|
|
|
|
|
|
|
|
2007-05-18 01:34:24 +02:00
|
|
|
/**
|
|
|
|
* Read data from the network to the read buffer. If an error occures,
|
|
|
|
* the socket of this connection will be shut down.
|
|
|
|
*/
|
2005-07-31 22:13:07 +02:00
|
|
|
static void
|
2002-05-27 15:09:26 +02:00
|
|
|
Read_Request( CONN_ID Idx )
|
2001-12-13 00:32:02 +01:00
|
|
|
{
|
2006-05-10 23:24:01 +02:00
|
|
|
ssize_t len;
|
2009-05-25 22:25:18 +02:00
|
|
|
static const unsigned int maxbps = COMMAND_LEN / 2;
|
2007-05-09 10:55:14 +02:00
|
|
|
char readbuf[READBUFFER_LEN];
|
2009-05-25 22:25:18 +02:00
|
|
|
time_t t;
|
2005-08-28 01:33:10 +02:00
|
|
|
CLIENT *c;
|
2002-11-05 15:18:39 +01:00
|
|
|
assert( Idx > NONE );
|
2002-01-02 03:44:36 +01:00
|
|
|
assert( My_Connections[Idx].sock > NONE );
|
2001-12-26 00:15:16 +01:00
|
|
|
|
2003-12-26 16:55:07 +01:00
|
|
|
#ifdef ZLIB
|
2007-05-17 14:39:25 +02:00
|
|
|
if ((array_bytes(&My_Connections[Idx].rbuf) >= READBUFFER_LEN) ||
|
|
|
|
(array_bytes(&My_Connections[Idx].zip.rbuf) >= READBUFFER_LEN))
|
2002-11-27 00:07:24 +01:00
|
|
|
#else
|
2007-05-17 14:39:25 +02:00
|
|
|
if (array_bytes(&My_Connections[Idx].rbuf) >= READBUFFER_LEN)
|
2002-11-27 00:07:24 +01:00
|
|
|
#endif
|
2002-01-03 03:25:36 +01:00
|
|
|
{
|
2007-05-18 01:34:24 +02:00
|
|
|
/* Read buffer is full */
|
|
|
|
Log(LOG_ERR,
|
|
|
|
"Receive buffer overflow (connection %d): %d bytes!",
|
|
|
|
Idx, array_bytes(&My_Connections[Idx].rbuf));
|
2005-03-19 19:43:48 +01:00
|
|
|
Conn_Close( Idx, "Receive buffer overflow!", NULL, false );
|
2002-01-03 03:25:36 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-09-13 15:10:32 +02:00
|
|
|
#ifdef SSL_SUPPORT
|
|
|
|
if (Conn_OPTION_ISSET(&My_Connections[Idx], CONN_SSL))
|
|
|
|
len = ConnSSL_Read( &My_Connections[Idx], readbuf, sizeof(readbuf));
|
|
|
|
else
|
|
|
|
#endif
|
2007-05-09 10:55:14 +02:00
|
|
|
len = read(My_Connections[Idx].sock, readbuf, sizeof(readbuf));
|
2007-05-18 01:34:24 +02:00
|
|
|
if (len == 0) {
|
2008-02-26 23:50:35 +01:00
|
|
|
Log(LOG_INFO, "%s:%u (%s) is closing the connection ...",
|
|
|
|
My_Connections[Idx].host,
|
|
|
|
(unsigned int) ng_ipaddr_getport(&My_Connections[Idx].addr),
|
|
|
|
ng_ipaddr_tostr(&My_Connections[Idx].addr));
|
2007-05-18 01:34:24 +02:00
|
|
|
Conn_Close(Idx,
|
|
|
|
"Socket closed!", "Client closed connection",
|
|
|
|
false);
|
2001-12-13 02:33:09 +01:00
|
|
|
return;
|
|
|
|
}
|
2005-07-12 22:44:46 +02:00
|
|
|
|
2007-05-18 01:34:24 +02:00
|
|
|
if (len < 0) {
|
2002-11-20 16:48:41 +01:00
|
|
|
if( errno == EAGAIN ) return;
|
2007-05-18 01:34:24 +02:00
|
|
|
Log(LOG_ERR, "Read error on connection %d (socket %d): %s!",
|
|
|
|
Idx, My_Connections[Idx].sock, strerror(errno));
|
|
|
|
Conn_Close(Idx, "Read error!", "Client closed connection",
|
|
|
|
false);
|
2001-12-13 00:32:02 +01:00
|
|
|
return;
|
|
|
|
}
|
2005-07-07 20:49:04 +02:00
|
|
|
#ifdef ZLIB
|
2006-05-10 23:24:01 +02:00
|
|
|
if (Conn_OPTION_ISSET(&My_Connections[Idx], CONN_ZIP)) {
|
|
|
|
if (!array_catb(&My_Connections[Idx].zip.rbuf, readbuf,
|
|
|
|
(size_t) len)) {
|
|
|
|
Log(LOG_ERR,
|
|
|
|
"Could not append recieved data to zip input buffer (connn %d): %d bytes!",
|
|
|
|
Idx, len);
|
|
|
|
Conn_Close(Idx, "Receive buffer overflow!", NULL,
|
|
|
|
false);
|
2005-07-07 20:49:04 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
#endif
|
|
|
|
{
|
2007-05-02 14:34:30 +02:00
|
|
|
if (!array_catb( &My_Connections[Idx].rbuf, readbuf, len)) {
|
2005-07-07 20:49:04 +02:00
|
|
|
Log( LOG_ERR, "Could not append recieved data to input buffer (connn %d): %d bytes!", Idx, len );
|
|
|
|
Conn_Close( Idx, "Receive buffer overflow!", NULL, false );
|
|
|
|
}
|
|
|
|
}
|
2001-12-14 09:16:47 +01:00
|
|
|
|
2005-08-28 01:33:10 +02:00
|
|
|
/* Update connection statistics */
|
2002-10-09 15:15:08 +02:00
|
|
|
My_Connections[Idx].bytes_in += len;
|
2011-01-23 15:14:18 +01:00
|
|
|
My_Connections[Idx].bps += Handle_Buffer(Idx);
|
|
|
|
|
|
|
|
/* Make sure that there is still a valid client registered */
|
|
|
|
c = Conn_GetClient(Idx);
|
|
|
|
if (!c)
|
|
|
|
return;
|
2002-10-09 15:15:08 +02:00
|
|
|
|
2005-08-28 01:33:10 +02:00
|
|
|
/* Update timestamp of last data received if this connection is
|
|
|
|
* registered as a user, server or service connection. Don't update
|
|
|
|
* otherwise, so users have at least Conf_PongTimeout seconds time to
|
2006-05-09 16:49:08 +02:00
|
|
|
* register with the IRC server -- see Check_Connections().
|
2010-08-19 15:58:55 +02:00
|
|
|
* Update "lastping", too, if time shifted backwards ... */
|
2011-01-23 15:14:18 +01:00
|
|
|
if (Client_Type(c) == CLIENT_USER
|
|
|
|
|| Client_Type(c) == CLIENT_SERVER
|
|
|
|
|| Client_Type(c) == CLIENT_SERVICE) {
|
2009-05-25 22:25:18 +02:00
|
|
|
t = time(NULL);
|
|
|
|
if (My_Connections[Idx].lastdata != t)
|
|
|
|
My_Connections[Idx].bps = 0;
|
|
|
|
|
|
|
|
My_Connections[Idx].lastdata = t;
|
2010-08-19 15:58:55 +02:00
|
|
|
if (My_Connections[Idx].lastping > t)
|
|
|
|
My_Connections[Idx].lastping = t;
|
2006-05-09 16:49:08 +02:00
|
|
|
}
|
2005-08-28 01:33:10 +02:00
|
|
|
|
|
|
|
/* Look at the data in the (read-) buffer of this connection */
|
2009-05-25 22:25:18 +02:00
|
|
|
if (Client_Type(c) != CLIENT_SERVER
|
2010-12-29 14:12:34 +01:00
|
|
|
&& Client_Type(c) != CLIENT_UNKNOWNSERVER
|
|
|
|
&& Client_Type(c) != CLIENT_SERVICE
|
2009-05-25 22:25:18 +02:00
|
|
|
&& My_Connections[Idx].bps >= maxbps) {
|
|
|
|
LogDebug("Throttling connection %d: BPS exceeded! (%u >= %u)",
|
|
|
|
Idx, My_Connections[Idx].bps, maxbps);
|
|
|
|
Conn_SetPenalty(Idx, 1);
|
|
|
|
}
|
2001-12-26 00:15:16 +01:00
|
|
|
} /* Read_Request */
|
|
|
|
|
|
|
|
|
2008-05-02 02:14:15 +02:00
|
|
|
/**
|
2008-05-26 23:38:32 +02:00
|
|
|
* Handle all data in the connection read-buffer.
|
2009-05-25 22:25:18 +02:00
|
|
|
* Data is processed until no complete command is left in the read buffer,
|
2010-12-29 14:19:51 +01:00
|
|
|
* or MAX_COMMANDS[_SERVER|_SERVICE] commands were processed.
|
2009-05-25 22:25:18 +02:00
|
|
|
* When a fatal error occurs, the connection is shut down.
|
|
|
|
* @param Idx Index of the connection.
|
|
|
|
* @return number of bytes processed.
|
2008-05-02 02:14:15 +02:00
|
|
|
*/
|
2009-05-25 22:25:18 +02:00
|
|
|
static unsigned int
|
2008-05-02 02:14:15 +02:00
|
|
|
Handle_Buffer(CONN_ID Idx)
|
2001-12-26 00:15:16 +01:00
|
|
|
{
|
2002-10-21 15:45:07 +02:00
|
|
|
#ifndef STRICT_RFC
|
2008-06-11 16:00:38 +02:00
|
|
|
char *ptr1, *ptr2, *first_eol;
|
2002-10-21 15:45:07 +02:00
|
|
|
#endif
|
2005-03-19 19:43:48 +01:00
|
|
|
char *ptr;
|
2006-05-10 23:24:01 +02:00
|
|
|
size_t len, delta;
|
2006-03-18 23:27:09 +01:00
|
|
|
time_t starttime;
|
2003-12-26 16:55:07 +01:00
|
|
|
#ifdef ZLIB
|
2005-03-19 19:43:48 +01:00
|
|
|
bool old_z;
|
2002-11-28 13:17:38 +01:00
|
|
|
#endif
|
2009-05-25 22:25:18 +02:00
|
|
|
unsigned int i, maxcmd = MAX_COMMANDS, len_processed = 0;
|
|
|
|
CLIENT *c;
|
|
|
|
|
|
|
|
c = Conn_GetClient(Idx);
|
|
|
|
assert( c != NULL);
|
|
|
|
|
|
|
|
/* Servers do get special command limits, so they can process
|
|
|
|
* all the messages that are required while peering. */
|
2010-12-29 14:19:51 +01:00
|
|
|
switch (Client_Type(c)) {
|
|
|
|
case CLIENT_SERVER:
|
|
|
|
maxcmd = MAX_COMMANDS_SERVER; break;
|
|
|
|
case CLIENT_SERVICE:
|
|
|
|
maxcmd = MAX_COMMANDS_SERVICE; break;
|
|
|
|
}
|
2001-12-26 00:15:16 +01:00
|
|
|
|
2006-03-18 23:27:09 +01:00
|
|
|
starttime = time(NULL);
|
2009-05-25 22:25:18 +02:00
|
|
|
for (i=0; i < maxcmd; i++) {
|
2003-11-06 00:24:48 +01:00
|
|
|
/* Check penalty */
|
2008-05-02 02:14:15 +02:00
|
|
|
if (My_Connections[Idx].delaytime > starttime)
|
2009-05-25 22:25:18 +02:00
|
|
|
return 0;
|
2003-12-26 16:55:07 +01:00
|
|
|
#ifdef ZLIB
|
2008-05-02 02:14:15 +02:00
|
|
|
/* Unpack compressed data, if compression is in use */
|
|
|
|
if (Conn_OPTION_ISSET(&My_Connections[Idx], CONN_ZIP)) {
|
2008-05-26 23:38:32 +02:00
|
|
|
/* When unzipping fails, Unzip_Buffer() shuts
|
|
|
|
* down the connection itself */
|
2008-05-02 02:14:15 +02:00
|
|
|
if (!Unzip_Buffer(Idx))
|
2009-05-25 22:25:18 +02:00
|
|
|
return 0;
|
2008-05-02 02:14:15 +02:00
|
|
|
}
|
2002-01-03 03:25:36 +01:00
|
|
|
#endif
|
2003-04-25 18:47:52 +02:00
|
|
|
|
2005-07-28 18:13:09 +02:00
|
|
|
if (0 == array_bytes(&My_Connections[Idx].rbuf))
|
2009-05-25 22:25:18 +02:00
|
|
|
break;
|
2005-07-07 20:49:04 +02:00
|
|
|
|
2008-05-02 02:14:15 +02:00
|
|
|
/* Make sure that the buffer is NULL terminated */
|
2008-05-26 23:38:32 +02:00
|
|
|
if (!array_cat0_temporary(&My_Connections[Idx].rbuf)) {
|
|
|
|
Conn_Close(Idx, NULL,
|
|
|
|
"Can't allocate memory [Handle_Buffer]",
|
|
|
|
true);
|
2009-05-25 22:25:18 +02:00
|
|
|
return 0;
|
2008-05-26 23:38:32 +02:00
|
|
|
}
|
2005-07-07 20:49:04 +02:00
|
|
|
|
2008-05-02 02:14:15 +02:00
|
|
|
/* RFC 2812, section "2.3 Messages", 5th paragraph:
|
|
|
|
* "IRC messages are always lines of characters terminated
|
|
|
|
* with a CR-LF (Carriage Return - Line Feed) pair [...]". */
|
|
|
|
delta = 2;
|
|
|
|
ptr = strstr(array_start(&My_Connections[Idx].rbuf), "\r\n");
|
2005-07-07 20:49:04 +02:00
|
|
|
|
2002-11-27 00:07:24 +01:00
|
|
|
#ifndef STRICT_RFC
|
2008-06-11 16:00:38 +02:00
|
|
|
/* Check for non-RFC-compliant request (only CR or LF)?
|
|
|
|
* Unfortunately, there are quite a few clients out there
|
|
|
|
* that do this -- e. g. mIRC, BitchX, and Trillian :-( */
|
|
|
|
ptr1 = strchr(array_start(&My_Connections[Idx].rbuf), '\r');
|
|
|
|
ptr2 = strchr(array_start(&My_Connections[Idx].rbuf), '\n');
|
|
|
|
if (ptr) {
|
|
|
|
/* Check if there is a single CR or LF _before_ the
|
|
|
|
* corerct CR+LF line terminator: */
|
|
|
|
first_eol = ptr1 < ptr2 ? ptr1 : ptr2;
|
|
|
|
if (first_eol < ptr) {
|
|
|
|
/* Single CR or LF before CR+LF found */
|
|
|
|
ptr = first_eol;
|
|
|
|
delta = 1;
|
|
|
|
}
|
|
|
|
} else if (ptr1 || ptr2) {
|
|
|
|
/* No CR+LF terminated command found, but single
|
|
|
|
* CR or LF found ... */
|
2008-05-02 02:14:15 +02:00
|
|
|
if (ptr1 && ptr2)
|
2008-06-11 16:00:38 +02:00
|
|
|
ptr = ptr1 < ptr2 ? ptr1 : ptr2;
|
|
|
|
else
|
|
|
|
ptr = ptr1 ? ptr1 : ptr2;
|
|
|
|
delta = 1;
|
2002-01-03 03:25:36 +01:00
|
|
|
}
|
2002-11-27 00:07:24 +01:00
|
|
|
#endif
|
2003-04-25 18:47:52 +02:00
|
|
|
|
2008-05-02 02:14:15 +02:00
|
|
|
if (!ptr)
|
2009-05-25 22:25:18 +02:00
|
|
|
break;
|
2005-07-07 20:49:04 +02:00
|
|
|
|
2008-05-02 02:14:15 +02:00
|
|
|
/* Complete (=line terminated) request found, handle it! */
|
2005-07-07 20:49:04 +02:00
|
|
|
*ptr = '\0';
|
|
|
|
|
2008-05-02 02:14:15 +02:00
|
|
|
len = ptr - (char *)array_start(&My_Connections[Idx].rbuf) + delta;
|
2005-07-07 20:49:04 +02:00
|
|
|
|
2008-05-02 02:14:15 +02:00
|
|
|
if (len > (COMMAND_LEN - 1)) {
|
|
|
|
/* Request must not exceed 512 chars (incl. CR+LF!),
|
|
|
|
* see RFC 2812. Disconnect Client if this happens. */
|
|
|
|
Log(LOG_ERR,
|
|
|
|
"Request too long (connection %d): %d bytes (max. %d expected)!",
|
|
|
|
Idx, array_bytes(&My_Connections[Idx].rbuf),
|
|
|
|
COMMAND_LEN - 1);
|
|
|
|
Conn_Close(Idx, NULL, "Request too long", true);
|
2009-05-25 22:25:18 +02:00
|
|
|
return 0;
|
2005-07-07 20:49:04 +02:00
|
|
|
}
|
2002-11-28 13:17:38 +01:00
|
|
|
|
2009-09-11 22:52:12 +02:00
|
|
|
len_processed += (unsigned int)len;
|
2008-05-02 02:14:15 +02:00
|
|
|
if (len <= delta) {
|
|
|
|
/* Request is empty (only '\r\n', '\r' or '\n');
|
|
|
|
* delta is 2 ('\r\n') or 1 ('\r' or '\n'), see above */
|
|
|
|
array_moveleft(&My_Connections[Idx].rbuf, 1, len);
|
2009-05-25 22:25:18 +02:00
|
|
|
continue;
|
2005-08-28 01:42:23 +02:00
|
|
|
}
|
2003-12-26 16:55:07 +01:00
|
|
|
#ifdef ZLIB
|
2005-07-07 20:49:04 +02:00
|
|
|
/* remember if stream is already compressed */
|
|
|
|
old_z = My_Connections[Idx].options & CONN_ZIP;
|
2002-11-28 13:17:38 +01:00
|
|
|
#endif
|
|
|
|
|
2005-08-28 18:51:20 +02:00
|
|
|
My_Connections[Idx].msg_in++;
|
2008-05-02 02:14:15 +02:00
|
|
|
if (!Parse_Request
|
|
|
|
(Idx, (char *)array_start(&My_Connections[Idx].rbuf)))
|
2009-05-25 22:25:18 +02:00
|
|
|
return 0; /* error -> connection has been closed */
|
2005-07-12 22:44:46 +02:00
|
|
|
|
2005-08-28 18:51:20 +02:00
|
|
|
array_moveleft(&My_Connections[Idx].rbuf, 1, len);
|
2006-02-16 20:21:57 +01:00
|
|
|
LogDebug("Connection %d: %d bytes left in read buffer.",
|
2008-05-02 02:14:15 +02:00
|
|
|
Idx, array_bytes(&My_Connections[Idx].rbuf));
|
2003-12-26 16:55:07 +01:00
|
|
|
#ifdef ZLIB
|
2008-05-02 02:14:15 +02:00
|
|
|
if ((!old_z) && (My_Connections[Idx].options & CONN_ZIP) &&
|
|
|
|
(array_bytes(&My_Connections[Idx].rbuf) > 0)) {
|
|
|
|
/* The last command activated socket compression.
|
|
|
|
* Data that was read after that needs to be copied
|
|
|
|
* to the unzip buffer for decompression: */
|
|
|
|
if (!array_copy
|
|
|
|
(&My_Connections[Idx].zip.rbuf,
|
2008-05-26 23:38:32 +02:00
|
|
|
&My_Connections[Idx].rbuf)) {
|
|
|
|
Conn_Close(Idx, NULL,
|
|
|
|
"Can't allocate memory [Handle_Buffer]",
|
|
|
|
true);
|
2009-05-25 22:25:18 +02:00
|
|
|
return 0;
|
2008-05-26 23:38:32 +02:00
|
|
|
}
|
2005-07-07 20:49:04 +02:00
|
|
|
|
|
|
|
array_trunc(&My_Connections[Idx].rbuf);
|
2008-05-02 02:14:15 +02:00
|
|
|
LogDebug
|
|
|
|
("Moved already received data (%u bytes) to uncompression buffer.",
|
|
|
|
array_bytes(&My_Connections[Idx].zip.rbuf));
|
2001-12-13 02:33:09 +01:00
|
|
|
}
|
2008-05-02 02:14:15 +02:00
|
|
|
#endif
|
2005-08-28 18:51:20 +02:00
|
|
|
}
|
2009-05-25 22:25:18 +02:00
|
|
|
return len_processed;
|
2001-12-26 00:15:16 +01:00
|
|
|
} /* Handle_Buffer */
|
2001-12-13 02:33:09 +01:00
|
|
|
|
|
|
|
|
2010-09-08 00:42:57 +02:00
|
|
|
/**
|
|
|
|
* Check whether established connections are still alive or not.
|
|
|
|
* If not, play PING-PONG first; and if that doesn't help either,
|
|
|
|
* disconnect the respective peer.
|
|
|
|
*/
|
2005-07-31 22:13:07 +02:00
|
|
|
static void
|
2006-05-09 16:49:08 +02:00
|
|
|
Check_Connections(void)
|
2001-12-26 04:20:53 +01:00
|
|
|
{
|
2002-01-02 03:44:36 +01:00
|
|
|
CLIENT *c;
|
2002-12-30 17:07:23 +01:00
|
|
|
CONN_ID i;
|
2009-04-24 07:01:37 +02:00
|
|
|
char msg[64];
|
2001-12-26 04:20:53 +01:00
|
|
|
|
2006-05-09 16:49:08 +02:00
|
|
|
for (i = 0; i < Pool_Size; i++) {
|
2005-09-11 13:42:48 +02:00
|
|
|
if (My_Connections[i].sock < 0)
|
|
|
|
continue;
|
2002-01-02 03:44:36 +01:00
|
|
|
|
2006-05-09 16:49:08 +02:00
|
|
|
c = Conn_GetClient(i);
|
|
|
|
if (c && ((Client_Type(c) == CLIENT_USER)
|
|
|
|
|| (Client_Type(c) == CLIENT_SERVER)
|
|
|
|
|| (Client_Type(c) == CLIENT_SERVICE))) {
|
2005-07-09 23:35:20 +02:00
|
|
|
/* connected User, Server or Service */
|
2006-05-09 16:49:08 +02:00
|
|
|
if (My_Connections[i].lastping >
|
|
|
|
My_Connections[i].lastdata) {
|
|
|
|
/* We already sent a ping */
|
|
|
|
if (My_Connections[i].lastping <
|
|
|
|
time(NULL) - Conf_PongTimeout) {
|
2001-12-26 04:20:53 +01:00
|
|
|
/* Timeout */
|
2006-05-09 16:49:08 +02:00
|
|
|
LogDebug
|
|
|
|
("Connection %d: Ping timeout: %d seconds.",
|
|
|
|
i, Conf_PongTimeout);
|
2009-04-24 07:01:37 +02:00
|
|
|
snprintf(msg, sizeof(msg), "Ping timeout: %d seconds", Conf_PongTimeout);
|
|
|
|
Conn_Close(i, NULL, msg, true);
|
2001-12-26 04:20:53 +01:00
|
|
|
}
|
2006-05-09 16:49:08 +02:00
|
|
|
} else if (My_Connections[i].lastdata <
|
|
|
|
time(NULL) - Conf_PingTimeout) {
|
|
|
|
/* We need to send a PING ... */
|
|
|
|
LogDebug("Connection %d: sending PING ...", i);
|
|
|
|
My_Connections[i].lastping = time(NULL);
|
|
|
|
Conn_WriteStr(i, "PING :%s",
|
|
|
|
Client_ID(Client_ThisServer()));
|
2001-12-26 04:20:53 +01:00
|
|
|
}
|
2006-05-09 16:49:08 +02:00
|
|
|
} else {
|
2005-08-28 01:33:10 +02:00
|
|
|
/* The connection is not fully established yet, so
|
|
|
|
* we don't do the PING-PONG game here but instead
|
|
|
|
* disconnect the client after "a short time" if it's
|
|
|
|
* still not registered. */
|
|
|
|
|
|
|
|
if (My_Connections[i].lastdata <
|
|
|
|
time(NULL) - Conf_PongTimeout) {
|
2006-05-09 16:49:08 +02:00
|
|
|
LogDebug
|
|
|
|
("Unregistered connection %d timed out ...",
|
|
|
|
i);
|
2005-08-28 01:33:10 +02:00
|
|
|
Conn_Close(i, NULL, "Timeout", false);
|
2002-01-02 03:44:36 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} /* Check_Connections */
|
|
|
|
|
|
|
|
|
2010-09-08 00:42:57 +02:00
|
|
|
/**
|
|
|
|
* Check if further server links should be established.
|
|
|
|
*/
|
2005-07-31 22:13:07 +02:00
|
|
|
static void
|
2010-09-08 00:42:57 +02:00
|
|
|
Check_Servers(void)
|
2002-01-02 03:44:36 +01:00
|
|
|
{
|
2005-03-19 19:43:48 +01:00
|
|
|
int i, n;
|
2005-09-24 04:48:46 +02:00
|
|
|
time_t time_now;
|
2002-02-19 21:05:37 +01:00
|
|
|
|
2010-09-08 00:42:57 +02:00
|
|
|
time_now = time(NULL);
|
|
|
|
|
2002-12-30 01:01:42 +01:00
|
|
|
/* Check all configured servers */
|
2010-09-08 00:42:57 +02:00
|
|
|
for (i = 0; i < MAX_SERVERS; i++) {
|
2010-09-08 00:45:23 +02:00
|
|
|
if (Conf_Server[i].conn_id != NONE)
|
|
|
|
continue; /* Already establishing or connected */
|
2010-09-08 00:42:57 +02:00
|
|
|
if (!Conf_Server[i].host[0] || !Conf_Server[i].port > 0)
|
|
|
|
continue; /* No host and/or port configured */
|
|
|
|
if (Conf_Server[i].flags & CONF_SFLAG_DISABLED)
|
|
|
|
continue; /* Disabled configuration entry */
|
|
|
|
if (Conf_Server[i].lasttry > (time_now - Conf_ConnectRetry))
|
|
|
|
continue; /* We have to wait a little bit ... */
|
2002-03-10 18:50:48 +01:00
|
|
|
|
2002-12-30 01:01:42 +01:00
|
|
|
/* Is there already a connection in this group? */
|
2010-09-08 00:42:57 +02:00
|
|
|
if (Conf_Server[i].group > NONE) {
|
2005-09-02 19:01:23 +02:00
|
|
|
for (n = 0; n < MAX_SERVERS; n++) {
|
2010-09-08 00:42:57 +02:00
|
|
|
if (n == i)
|
|
|
|
continue;
|
2007-06-28 17:13:38 +02:00
|
|
|
if ((Conf_Server[n].conn_id != NONE) &&
|
2010-09-08 00:42:57 +02:00
|
|
|
(Conf_Server[n].group == Conf_Server[i].group))
|
|
|
|
break;
|
2002-03-10 18:50:48 +01:00
|
|
|
}
|
2010-09-08 00:42:57 +02:00
|
|
|
if (n < MAX_SERVERS)
|
|
|
|
continue;
|
2002-01-02 03:44:36 +01:00
|
|
|
}
|
2002-03-11 01:04:48 +01:00
|
|
|
|
2002-12-30 01:01:42 +01:00
|
|
|
/* Okay, try to connect now */
|
2010-12-02 13:40:08 +01:00
|
|
|
Log(LOG_NOTICE,
|
|
|
|
"Preparing to establish a new server link for \"%s\" ...",
|
|
|
|
Conf_Server[i].name);
|
2007-07-21 20:46:28 +02:00
|
|
|
Conf_Server[i].lasttry = time_now;
|
2007-06-28 17:13:38 +02:00
|
|
|
Conf_Server[i].conn_id = SERVER_WAIT;
|
2010-05-18 17:38:12 +02:00
|
|
|
assert(Proc_GetPipeFd(&Conf_Server[i].res_stat) < 0);
|
2010-09-08 00:42:57 +02:00
|
|
|
Resolve_Name(&Conf_Server[i].res_stat, Conf_Server[i].host,
|
|
|
|
cb_Connect_to_Server);
|
2002-01-02 03:44:36 +01:00
|
|
|
}
|
|
|
|
} /* Check_Servers */
|
|
|
|
|
|
|
|
|
2005-07-31 22:13:07 +02:00
|
|
|
static void
|
2008-02-26 23:50:35 +01:00
|
|
|
New_Server( int Server , ng_ipaddr_t *dest)
|
2002-01-02 03:44:36 +01:00
|
|
|
{
|
2003-04-25 18:47:52 +02:00
|
|
|
/* Establish new server link */
|
2008-02-26 23:50:35 +01:00
|
|
|
char ip_str[NG_INET_ADDRSTRLEN];
|
|
|
|
int af_dest, res, new_sock;
|
2002-01-03 03:25:36 +01:00
|
|
|
CLIENT *c;
|
2002-01-02 03:44:36 +01:00
|
|
|
|
2002-11-05 15:18:39 +01:00
|
|
|
assert( Server > NONE );
|
2002-01-02 03:44:36 +01:00
|
|
|
|
2008-02-26 23:50:35 +01:00
|
|
|
if (!ng_ipaddr_tostr_r(dest, ip_str)) {
|
|
|
|
Log(LOG_WARNING, "New_Server: Could not convert IP to string");
|
|
|
|
return;
|
|
|
|
}
|
2002-01-02 03:44:36 +01:00
|
|
|
|
2008-02-26 23:50:35 +01:00
|
|
|
af_dest = ng_ipaddr_af(dest);
|
|
|
|
new_sock = socket(af_dest, SOCK_STREAM, 0);
|
2011-01-16 23:24:41 +01:00
|
|
|
|
|
|
|
Log(LOG_INFO,
|
|
|
|
"Establishing connection for \"%s\" to \"%s:%d\" (%s), socket %d ...",
|
|
|
|
Conf_Server[Server].name, Conf_Server[Server].host,
|
|
|
|
Conf_Server[Server].port, ip_str, new_sock);
|
|
|
|
|
2008-02-26 23:50:35 +01:00
|
|
|
if (new_sock < 0) {
|
2011-01-16 23:24:41 +01:00
|
|
|
Log(LOG_CRIT, "Can't create socket (af %d): %s!",
|
|
|
|
af_dest, strerror(errno));
|
2006-02-08 16:20:21 +01:00
|
|
|
return;
|
2001-12-26 04:20:53 +01:00
|
|
|
}
|
2002-03-02 01:23:32 +01:00
|
|
|
|
2008-02-26 23:50:35 +01:00
|
|
|
if (!Init_Socket(new_sock))
|
|
|
|
return;
|
2007-11-23 17:26:03 +01:00
|
|
|
|
2008-02-26 23:50:35 +01:00
|
|
|
/* is a bind address configured? */
|
|
|
|
res = ng_ipaddr_af(&Conf_Server[Server].bind_addr);
|
|
|
|
/* if yes, bind now. If it fails, warn and let connect() pick a source address */
|
|
|
|
if (res && bind(new_sock, (struct sockaddr *) &Conf_Server[Server].bind_addr,
|
|
|
|
ng_ipaddr_salen(&Conf_Server[Server].bind_addr)))
|
|
|
|
{
|
|
|
|
ng_ipaddr_tostr_r(&Conf_Server[Server].bind_addr, ip_str);
|
|
|
|
Log(LOG_WARNING, "Can't bind socket to %s: %s!", ip_str, strerror(errno));
|
|
|
|
}
|
|
|
|
ng_ipaddr_setport(dest, Conf_Server[Server].port);
|
|
|
|
res = connect(new_sock, (struct sockaddr *) dest, ng_ipaddr_salen(dest));
|
2005-07-11 22:58:05 +02:00
|
|
|
if(( res != 0 ) && ( errno != EINPROGRESS )) {
|
2002-11-11 01:54:25 +01:00
|
|
|
Log( LOG_CRIT, "Can't connect socket: %s!", strerror( errno ));
|
2002-01-02 03:44:36 +01:00
|
|
|
close( new_sock );
|
2006-02-08 16:20:21 +01:00
|
|
|
return;
|
|
|
|
}
|
2007-11-23 17:26:03 +01:00
|
|
|
|
2006-05-10 23:24:01 +02:00
|
|
|
if (!array_alloc(&My_ConnArray, sizeof(CONNECTION), (size_t)new_sock)) {
|
|
|
|
Log(LOG_ALERT,
|
|
|
|
"Cannot allocate memory for server connection (socket %d)",
|
|
|
|
new_sock);
|
2006-02-08 16:20:21 +01:00
|
|
|
close( new_sock );
|
|
|
|
return;
|
2002-01-02 03:44:36 +01:00
|
|
|
}
|
|
|
|
|
2006-02-16 20:21:57 +01:00
|
|
|
My_Connections = array_start(&My_ConnArray);
|
|
|
|
|
|
|
|
assert(My_Connections[new_sock].sock <= 0);
|
2006-02-08 16:20:21 +01:00
|
|
|
|
|
|
|
Init_Conn_Struct(new_sock);
|
|
|
|
|
2008-02-26 23:50:35 +01:00
|
|
|
ng_ipaddr_tostr_r(dest, ip_str);
|
|
|
|
c = Client_NewLocal(new_sock, ip_str, CLIENT_UNKNOWNSERVER, false);
|
|
|
|
if (!c) {
|
2002-01-02 03:44:36 +01:00
|
|
|
Log( LOG_ALERT, "Can't establish connection: can't create client structure!" );
|
2005-07-12 22:44:46 +02:00
|
|
|
close( new_sock );
|
2006-02-08 16:20:21 +01:00
|
|
|
return;
|
2002-01-02 03:44:36 +01:00
|
|
|
}
|
2005-07-12 22:44:46 +02:00
|
|
|
|
2009-05-17 21:32:53 +02:00
|
|
|
/* Conn_Close() decrements this counter again */
|
2010-04-23 23:25:34 +02:00
|
|
|
Account_Connection();
|
2002-01-04 02:20:02 +01:00
|
|
|
Client_SetIntroducer( c, c );
|
2002-04-08 03:17:54 +02:00
|
|
|
Client_SetToken( c, TOKEN_OUTBOUND );
|
2002-03-02 01:23:32 +01:00
|
|
|
|
2003-04-25 18:47:52 +02:00
|
|
|
/* Register connection */
|
2006-02-08 16:20:21 +01:00
|
|
|
Conf_Server[Server].conn_id = new_sock;
|
|
|
|
My_Connections[new_sock].sock = new_sock;
|
2008-02-26 23:50:35 +01:00
|
|
|
My_Connections[new_sock].addr = *dest;
|
2006-04-23 12:37:27 +02:00
|
|
|
My_Connections[new_sock].client = c;
|
2006-02-08 16:20:21 +01:00
|
|
|
strlcpy( My_Connections[new_sock].host, Conf_Server[Server].host,
|
|
|
|
sizeof(My_Connections[new_sock].host ));
|
2002-01-02 03:44:36 +01:00
|
|
|
|
2003-04-25 18:47:52 +02:00
|
|
|
/* Register new socket */
|
2005-07-12 22:44:46 +02:00
|
|
|
if (!io_event_create( new_sock, IO_WANTWRITE, cb_connserver)) {
|
|
|
|
Log( LOG_ALERT, "io_event_create(): could not add fd %d", strerror(errno));
|
2006-02-08 16:20:21 +01:00
|
|
|
Conn_Close( new_sock, "io_event_create() failed", NULL, false );
|
|
|
|
Init_Conn_Struct( new_sock );
|
|
|
|
Conf_Server[Server].conn_id = NONE;
|
2005-07-12 22:44:46 +02:00
|
|
|
}
|
2008-09-13 15:10:32 +02:00
|
|
|
#ifdef SSL_SUPPORT
|
|
|
|
if (Conf_Server[Server].SSLConnect && !ConnSSL_PrepareConnect( &My_Connections[new_sock],
|
|
|
|
&Conf_Server[Server] ))
|
|
|
|
{
|
|
|
|
Log(LOG_ALERT, "Could not initialize SSL for outgoing connection");
|
|
|
|
Conn_Close( new_sock, "Could not initialize SSL for outgoing connection", NULL, false );
|
|
|
|
Init_Conn_Struct( new_sock );
|
|
|
|
Conf_Server[Server].conn_id = NONE;
|
2009-05-17 21:27:27 +02:00
|
|
|
return;
|
2008-09-13 15:10:32 +02:00
|
|
|
}
|
|
|
|
#endif
|
2008-11-12 01:23:33 +01:00
|
|
|
LogDebug("Registered new connection %d on socket %d (%ld in total).",
|
|
|
|
new_sock, My_Connections[new_sock].sock, NumConnections);
|
2006-02-08 16:20:21 +01:00
|
|
|
Conn_OPTION_ADD( &My_Connections[new_sock], CONN_ISCONNECTING );
|
2002-01-02 03:44:36 +01:00
|
|
|
} /* New_Server */
|
2001-12-26 04:20:53 +01:00
|
|
|
|
|
|
|
|
2007-10-04 17:03:55 +02:00
|
|
|
/**
|
|
|
|
* Initialize connection structure.
|
|
|
|
*/
|
2005-07-31 22:13:07 +02:00
|
|
|
static void
|
2007-10-04 17:03:55 +02:00
|
|
|
Init_Conn_Struct(CONN_ID Idx)
|
2001-12-29 21:17:25 +01:00
|
|
|
{
|
2007-10-04 17:03:55 +02:00
|
|
|
time_t now = time(NULL);
|
2001-12-29 21:17:25 +01:00
|
|
|
|
2007-10-04 17:03:55 +02:00
|
|
|
memset(&My_Connections[Idx], 0, sizeof(CONNECTION));
|
2006-02-08 16:20:21 +01:00
|
|
|
My_Connections[Idx].sock = -1;
|
2007-10-04 17:03:55 +02:00
|
|
|
My_Connections[Idx].signon = now;
|
2005-03-20 12:00:31 +01:00
|
|
|
My_Connections[Idx].lastdata = now;
|
|
|
|
My_Connections[Idx].lastprivmsg = now;
|
2010-05-21 22:48:34 +02:00
|
|
|
Proc_InitStruct(&My_Connections[Idx].proc_stat);
|
2001-12-29 21:17:25 +01:00
|
|
|
} /* Init_Conn_Struct */
|
|
|
|
|
|
|
|
|
2005-07-31 22:13:07 +02:00
|
|
|
static bool
|
2005-03-19 19:43:48 +01:00
|
|
|
Init_Socket( int Sock )
|
2002-03-02 01:23:32 +01:00
|
|
|
{
|
2004-01-25 17:06:34 +01:00
|
|
|
/* Initialize socket (set options) */
|
2002-03-02 01:23:32 +01:00
|
|
|
|
2005-03-19 19:43:48 +01:00
|
|
|
int value;
|
2002-03-02 01:23:32 +01:00
|
|
|
|
2005-07-07 20:49:04 +02:00
|
|
|
if (!io_setnonblock(Sock)) {
|
2004-01-25 17:06:34 +01:00
|
|
|
Log( LOG_CRIT, "Can't enable non-blocking mode for socket: %s!", strerror( errno ));
|
2002-03-02 01:23:32 +01:00
|
|
|
close( Sock );
|
2005-03-19 19:43:48 +01:00
|
|
|
return false;
|
2002-03-02 01:23:32 +01:00
|
|
|
}
|
2004-01-25 17:06:34 +01:00
|
|
|
|
|
|
|
/* Don't block this port after socket shutdown */
|
|
|
|
value = 1;
|
|
|
|
if( setsockopt( Sock, SOL_SOCKET, SO_REUSEADDR, &value, (socklen_t)sizeof( value )) != 0 )
|
2002-03-02 01:23:32 +01:00
|
|
|
{
|
2004-01-25 17:06:34 +01:00
|
|
|
Log( LOG_ERR, "Can't set socket option SO_REUSEADDR: %s!", strerror( errno ));
|
|
|
|
/* ignore this error */
|
2002-03-02 01:23:32 +01:00
|
|
|
}
|
|
|
|
|
2004-01-25 17:06:34 +01:00
|
|
|
/* Set type of service (TOS) */
|
2009-12-31 00:55:42 +01:00
|
|
|
#if defined(IPPROTO_IP) && defined(IPTOS_LOWDELAY)
|
2004-01-25 17:06:34 +01:00
|
|
|
value = IPTOS_LOWDELAY;
|
2009-12-31 00:55:42 +01:00
|
|
|
LogDebug("Setting IP_TOS on socket %d to IPTOS_LOWDELAY.", Sock);
|
|
|
|
if (setsockopt(Sock, IPPROTO_IP, IP_TOS, &value,
|
|
|
|
(socklen_t) sizeof(value))) {
|
2010-12-02 13:40:08 +01:00
|
|
|
LogDebug("Can't set socket option IP_TOS: %s!",
|
|
|
|
strerror(errno));
|
2004-01-25 17:06:34 +01:00
|
|
|
/* ignore this error */
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2005-03-19 19:43:48 +01:00
|
|
|
return true;
|
2002-03-02 01:23:32 +01:00
|
|
|
} /* Init_Socket */
|
|
|
|
|
|
|
|
|
2006-02-08 16:20:21 +01:00
|
|
|
static void
|
|
|
|
cb_Connect_to_Server(int fd, UNUSED short events)
|
|
|
|
{
|
|
|
|
/* Read result of resolver sub-process from pipe and start connection */
|
|
|
|
int i;
|
|
|
|
size_t len;
|
2008-02-26 23:50:35 +01:00
|
|
|
ng_ipaddr_t dest_addrs[4]; /* we can handle at most 3; but we read up to
|
|
|
|
four so we can log the 'more than we can handle'
|
2009-09-11 22:51:00 +02:00
|
|
|
condition. First result is tried immediately, rest
|
|
|
|
is saved for later if needed. */
|
2006-02-08 16:20:21 +01:00
|
|
|
|
2006-02-08 18:33:28 +01:00
|
|
|
LogDebug("Resolver: Got forward lookup callback on fd %d, events %d", fd, events);
|
|
|
|
|
2006-02-08 16:20:21 +01:00
|
|
|
for (i=0; i < MAX_SERVERS; i++) {
|
2010-05-18 17:38:12 +02:00
|
|
|
if (Proc_GetPipeFd(&Conf_Server[i].res_stat) == fd )
|
2006-02-08 16:20:21 +01:00
|
|
|
break;
|
|
|
|
}
|
2007-11-23 17:28:37 +01:00
|
|
|
|
2006-02-08 16:20:21 +01:00
|
|
|
if( i >= MAX_SERVERS) {
|
|
|
|
/* Ops, no matching server found?! */
|
|
|
|
io_close( fd );
|
2006-02-16 20:21:57 +01:00
|
|
|
LogDebug("Resolver: Got Forward Lookup callback for unknown server!?");
|
2006-02-08 16:20:21 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Read result from pipe */
|
2010-07-11 16:58:30 +02:00
|
|
|
len = Proc_Read(&Conf_Server[i].res_stat, dest_addrs, sizeof(dest_addrs));
|
2010-12-02 13:38:42 +01:00
|
|
|
if (len == 0) {
|
|
|
|
/* Error resolving hostname: reset server structure */
|
|
|
|
Conf_Server[i].conn_id = NONE;
|
2006-02-08 16:20:21 +01:00
|
|
|
return;
|
2010-12-02 13:38:42 +01:00
|
|
|
}
|
2007-11-23 17:28:37 +01:00
|
|
|
|
2008-02-26 23:50:35 +01:00
|
|
|
assert((len % sizeof(ng_ipaddr_t)) == 0);
|
2006-02-08 16:20:21 +01:00
|
|
|
|
2008-02-26 23:50:35 +01:00
|
|
|
LogDebug("Got result from resolver: %u structs (%u bytes).", len/sizeof(ng_ipaddr_t), len);
|
2007-11-23 17:28:37 +01:00
|
|
|
|
2009-09-11 22:51:00 +02:00
|
|
|
memset(&Conf_Server[i].dst_addr, 0, sizeof(Conf_Server[i].dst_addr));
|
2008-02-26 23:50:35 +01:00
|
|
|
if (len > sizeof(ng_ipaddr_t)) {
|
|
|
|
/* more than one address for this hostname, remember them
|
|
|
|
* in case first address is unreachable/not available */
|
|
|
|
len -= sizeof(ng_ipaddr_t);
|
2009-09-11 22:51:00 +02:00
|
|
|
if (len > sizeof(Conf_Server[i].dst_addr)) {
|
|
|
|
len = sizeof(Conf_Server[i].dst_addr);
|
2008-11-20 23:50:26 +01:00
|
|
|
Log(LOG_NOTICE,
|
|
|
|
"Notice: Resolver returned more IP Addresses for host than we can handle, additional addresses dropped.");
|
2008-02-26 23:50:35 +01:00
|
|
|
}
|
|
|
|
memcpy(&Conf_Server[i].dst_addr, &dest_addrs[1], len);
|
|
|
|
}
|
2006-02-08 16:20:21 +01:00
|
|
|
/* connect() */
|
2008-02-26 23:50:35 +01:00
|
|
|
New_Server(i, dest_addrs);
|
2006-02-08 16:20:21 +01:00
|
|
|
} /* cb_Read_Forward_Lookup */
|
|
|
|
|
|
|
|
|
2005-09-12 21:10:20 +02:00
|
|
|
static void
|
|
|
|
cb_Read_Resolver_Result( int r_fd, UNUSED short events )
|
2001-12-29 21:17:25 +01:00
|
|
|
{
|
2004-05-11 02:01:11 +02:00
|
|
|
/* Read result of resolver sub-process from pipe and update the
|
|
|
|
* apropriate connection/client structure(s): hostname and/or
|
|
|
|
* IDENT user name.*/
|
2001-12-29 21:17:25 +01:00
|
|
|
|
|
|
|
CLIENT *c;
|
2010-06-29 23:38:39 +02:00
|
|
|
CONN_ID i;
|
2005-09-12 21:10:20 +02:00
|
|
|
size_t len;
|
|
|
|
char *identptr;
|
|
|
|
#ifdef IDENTAUTH
|
|
|
|
char readbuf[HOST_LEN + 2 + CLIENT_USER_LEN];
|
|
|
|
#else
|
|
|
|
char readbuf[HOST_LEN + 1];
|
|
|
|
#endif
|
|
|
|
|
2006-02-08 18:33:28 +01:00
|
|
|
LogDebug("Resolver: Got callback on fd %d, events %d", r_fd, events );
|
2010-06-29 23:38:39 +02:00
|
|
|
i = Conn_GetFromProc(r_fd);
|
|
|
|
if (i == NONE) {
|
2003-12-27 14:01:12 +01:00
|
|
|
/* Ops, none found? Probably the connection has already
|
2004-05-11 02:01:11 +02:00
|
|
|
* been closed!? We'll ignore that ... */
|
2005-07-07 20:49:04 +02:00
|
|
|
io_close( r_fd );
|
2006-02-08 18:33:28 +01:00
|
|
|
LogDebug("Resolver: Got callback for unknown connection!?");
|
2001-12-29 21:17:25 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2004-05-11 02:01:11 +02:00
|
|
|
/* Read result from pipe */
|
2010-07-11 16:58:30 +02:00
|
|
|
len = Proc_Read(&My_Connections[i].proc_stat, readbuf, sizeof readbuf -1);
|
2005-12-09 10:26:55 +01:00
|
|
|
if (len == 0)
|
2006-02-08 16:20:21 +01:00
|
|
|
return;
|
2005-07-28 18:13:09 +02:00
|
|
|
|
2005-09-12 21:10:20 +02:00
|
|
|
readbuf[len] = '\0';
|
|
|
|
identptr = strchr(readbuf, '\n');
|
|
|
|
assert(identptr != NULL);
|
|
|
|
if (!identptr) {
|
|
|
|
Log( LOG_CRIT, "Resolver: Got malformed result!");
|
2006-02-08 16:20:21 +01:00
|
|
|
return;
|
2005-07-28 18:13:09 +02:00
|
|
|
}
|
2004-05-11 02:01:11 +02:00
|
|
|
|
2005-09-12 21:10:20 +02:00
|
|
|
*identptr = '\0';
|
2006-02-16 20:21:57 +01:00
|
|
|
LogDebug("Got result from resolver: \"%s\" (%u bytes read).", readbuf, len);
|
2004-05-11 02:01:11 +02:00
|
|
|
/* Okay, we got a complete result: this is a host name for outgoing
|
2005-09-12 21:10:20 +02:00
|
|
|
* connections and a host name and IDENT user name (if enabled) for
|
2005-06-01 23:28:50 +02:00
|
|
|
* incoming connections.*/
|
2006-02-08 16:20:21 +01:00
|
|
|
assert ( My_Connections[i].sock >= 0 );
|
|
|
|
/* Incoming connection. Search client ... */
|
2006-04-23 12:37:27 +02:00
|
|
|
c = Conn_GetClient( i );
|
2006-02-08 16:20:21 +01:00
|
|
|
assert( c != NULL );
|
|
|
|
|
2010-02-11 00:01:53 +01:00
|
|
|
/* Only update client information of unregistered clients.
|
|
|
|
* Note: user commands (e. g. WEBIRC) are always read _after_ reading
|
|
|
|
* the resolver results, so we don't have to worry to override settings
|
|
|
|
* from these commands here. */
|
|
|
|
if(Client_Type(c) == CLIENT_UNKNOWN) {
|
|
|
|
strlcpy(My_Connections[i].host, readbuf,
|
|
|
|
sizeof(My_Connections[i].host));
|
|
|
|
Client_SetHostname(c, readbuf);
|
2003-12-27 14:01:12 +01:00
|
|
|
#ifdef IDENTAUTH
|
2006-02-08 16:20:21 +01:00
|
|
|
++identptr;
|
|
|
|
if (*identptr) {
|
2007-12-07 22:19:01 +01:00
|
|
|
Log(LOG_INFO, "IDENT lookup for connection %d: \"%s\".", i, identptr);
|
|
|
|
Client_SetUser(c, identptr, true);
|
2006-02-08 16:20:21 +01:00
|
|
|
} else {
|
2007-12-07 22:19:01 +01:00
|
|
|
Log(LOG_INFO, "IDENT lookup for connection %d: no result.", i);
|
2003-12-27 14:01:12 +01:00
|
|
|
}
|
2006-02-08 16:20:21 +01:00
|
|
|
#endif
|
|
|
|
}
|
2004-05-11 02:01:11 +02:00
|
|
|
#ifdef DEBUG
|
|
|
|
else Log( LOG_DEBUG, "Resolver: discarding result for already registered connection %d.", i );
|
2003-12-27 14:01:12 +01:00
|
|
|
#endif
|
2005-09-12 21:10:20 +02:00
|
|
|
} /* cb_Read_Resolver_Result */
|
2001-12-29 21:17:25 +01:00
|
|
|
|
2002-01-02 03:44:36 +01:00
|
|
|
|
2010-04-09 20:08:47 +02:00
|
|
|
/**
|
|
|
|
* Write a "simple" (error) message to a socket.
|
|
|
|
* The message is sent without using the connection write buffers, without
|
|
|
|
* compression/encryption, and even without any error reporting. It is
|
|
|
|
* designed for error messages of e.g. New_Connection(). */
|
2005-07-31 22:13:07 +02:00
|
|
|
static void
|
2010-04-09 20:08:47 +02:00
|
|
|
Simple_Message(int Sock, const char *Msg)
|
2003-03-07 18:16:49 +01:00
|
|
|
{
|
2005-06-12 19:21:46 +02:00
|
|
|
char buf[COMMAND_LEN];
|
2006-04-23 12:37:27 +02:00
|
|
|
size_t len;
|
2010-04-09 20:08:47 +02:00
|
|
|
|
|
|
|
assert(Sock > NONE);
|
|
|
|
assert(Msg != NULL);
|
|
|
|
|
|
|
|
strlcpy(buf, Msg, sizeof buf - 2);
|
|
|
|
len = strlcat(buf, "\r\n", sizeof buf);
|
|
|
|
if (write(Sock, buf, len) < 0) {
|
|
|
|
/* Because this function most probably got called to log
|
|
|
|
* an error message, any write error is ignored here to
|
|
|
|
* avoid an endless loop. But casting the result of write()
|
|
|
|
* to "void" doesn't satisfy the GNU C code attribute
|
|
|
|
* "warn_unused_result" which is used by some versions of
|
|
|
|
* glibc (e.g. 2.11.1), therefore this silly error
|
|
|
|
* "handling" code here :-( */
|
|
|
|
return;
|
|
|
|
}
|
2003-03-07 18:16:49 +01:00
|
|
|
} /* Simple_Error */
|
|
|
|
|
|
|
|
|
2009-12-30 23:35:17 +01:00
|
|
|
/**
|
|
|
|
* Get CLIENT structure that belongs to a local connection identified by its
|
|
|
|
* index number. Each connection belongs to a client by definition, so it is
|
|
|
|
* not required that the caller checks for NULL return values.
|
|
|
|
* @param Idx Connection index number
|
|
|
|
* @return Pointer to CLIENT structure
|
|
|
|
*/
|
2006-04-23 12:37:27 +02:00
|
|
|
GLOBAL CLIENT *
|
|
|
|
Conn_GetClient( CONN_ID Idx )
|
|
|
|
{
|
|
|
|
CONNECTION *c;
|
|
|
|
|
2009-12-30 23:32:47 +01:00
|
|
|
assert(Idx >= 0);
|
2006-05-10 23:24:01 +02:00
|
|
|
c = array_get(&My_ConnArray, sizeof (CONNECTION), (size_t)Idx);
|
2006-04-23 12:37:27 +02:00
|
|
|
assert(c != NULL);
|
|
|
|
return c ? c->client : NULL;
|
|
|
|
}
|
2005-07-07 20:49:04 +02:00
|
|
|
|
2010-07-11 15:15:23 +02:00
|
|
|
/**
|
|
|
|
* Get PROC_STAT sub-process structure of a connection.
|
|
|
|
* @param Idx Connection index number
|
|
|
|
* @return PROC_STAT structure
|
|
|
|
*/
|
|
|
|
GLOBAL PROC_STAT *
|
|
|
|
Conn_GetProcStat(CONN_ID Idx)
|
|
|
|
{
|
|
|
|
CONNECTION *c;
|
|
|
|
|
|
|
|
assert(Idx >= 0);
|
|
|
|
c = array_get(&My_ConnArray, sizeof (CONNECTION), (size_t)Idx);
|
|
|
|
assert(c != NULL);
|
|
|
|
return &c->proc_stat;
|
|
|
|
} /* Conn_GetProcStat */
|
|
|
|
|
2009-12-30 23:32:47 +01:00
|
|
|
|
2010-06-29 23:38:39 +02:00
|
|
|
/**
|
|
|
|
* Get CONN_ID from file descriptor associated to a subprocess structure.
|
|
|
|
* @param fd File descriptor
|
|
|
|
* @return CONN_ID or NONE (-1)
|
|
|
|
*/
|
|
|
|
GLOBAL CONN_ID
|
|
|
|
Conn_GetFromProc(int fd)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
assert(fd > 0);
|
|
|
|
for (i = 0; i < Pool_Size; i++) {
|
|
|
|
if ((My_Connections[i].sock != NONE)
|
|
|
|
&& (Proc_GetPipeFd(&My_Connections[i].proc_stat) == fd))
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
return NONE;
|
|
|
|
} /* Conn_GetFromProc */
|
|
|
|
|
|
|
|
|
2008-09-13 15:10:32 +02:00
|
|
|
#ifdef SSL_SUPPORT
|
2009-12-30 23:35:17 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Get information about used SSL chiper.
|
|
|
|
* @param Idx Connection index number
|
|
|
|
* @param buf Buffer for returned information text
|
|
|
|
* @param len Size of return buffer "buf"
|
|
|
|
* @return true on success, false otherwise
|
|
|
|
*/
|
2008-09-13 15:10:32 +02:00
|
|
|
GLOBAL bool
|
|
|
|
Conn_GetCipherInfo(CONN_ID Idx, char *buf, size_t len)
|
|
|
|
{
|
2009-05-04 23:51:24 +02:00
|
|
|
if (Idx < 0)
|
|
|
|
return false;
|
|
|
|
assert(Idx < (int) array_length(&My_ConnArray, sizeof(CONNECTION)));
|
2008-09-13 15:10:32 +02:00
|
|
|
return ConnSSL_GetCipherInfo(&My_Connections[Idx], buf, len);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-12-30 23:35:17 +01:00
|
|
|
/**
|
|
|
|
* Check if a connection is SSL-enabled or not.
|
|
|
|
* @param Idx Connection index number
|
|
|
|
* @return true if connection is SSL-enabled, false otherwise.
|
|
|
|
*/
|
2008-09-13 15:10:32 +02:00
|
|
|
GLOBAL bool
|
|
|
|
Conn_UsesSSL(CONN_ID Idx)
|
|
|
|
{
|
2009-05-04 23:51:24 +02:00
|
|
|
if (Idx < 0)
|
|
|
|
return false;
|
|
|
|
assert(Idx < (int) array_length(&My_ConnArray, sizeof(CONNECTION)));
|
2008-09-13 15:10:32 +02:00
|
|
|
return Conn_OPTION_ISSET(&My_Connections[Idx], CONN_SSL);
|
|
|
|
}
|
2009-12-30 23:32:47 +01:00
|
|
|
|
2008-09-13 15:10:32 +02:00
|
|
|
#endif
|
2009-09-11 22:52:12 +02:00
|
|
|
|
|
|
|
|
2010-09-10 21:11:25 +02:00
|
|
|
#ifdef DEBUG
|
|
|
|
|
|
|
|
GLOBAL void
|
|
|
|
Conn_DebugDump(void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
Log(LOG_DEBUG, "Connection status:");
|
|
|
|
for (i = 0; i < Pool_Size; i++) {
|
|
|
|
if (My_Connections[i].sock == NONE)
|
|
|
|
continue;
|
|
|
|
Log(LOG_DEBUG,
|
|
|
|
" - %d: host=%s, lastdata=%ld, lastping=%ld, delaytime=%ld, flag=%d, options=%d, bps=%d, client=%s",
|
|
|
|
My_Connections[i].sock, My_Connections[i].host,
|
|
|
|
My_Connections[i].lastdata, My_Connections[i].lastping,
|
|
|
|
My_Connections[i].delaytime, My_Connections[i].flag,
|
|
|
|
My_Connections[i].options, My_Connections[i].bps,
|
|
|
|
My_Connections[i].client ? Client_ID(My_Connections[i].client) : "-");
|
|
|
|
}
|
|
|
|
} /* Conn_DumpClients */
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2001-12-12 18:18:38 +01:00
|
|
|
/* -eof- */
|