X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fngircd%2Fconn.c;h=4df1e9e4f88e644b3df309f5bb1007c2aee44be3;hb=3d49fa5bffac43f2fcf535c8b1aedae732d1f9f5;hp=731647d9cda3f5dd7576bbfbebb4e885657c8ee2;hpb=536538968c6d2cd22669d4622a83d32f95d4eb55;p=ngircd-alex.git diff --git a/src/ngircd/conn.c b/src/ngircd/conn.c index 731647d9..4df1e9e4 100644 --- a/src/ngircd/conn.c +++ b/src/ngircd/conn.c @@ -1,6 +1,6 @@ /* * ngIRCd -- The Next Generation IRC Daemon - * Copyright (c)2001-2009 Alexander Barton (alex@barton.de) + * Copyright (c)2001-2010 Alexander Barton * * 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 @@ -21,9 +21,9 @@ #include "imp.h" #include #ifdef PROTOTYPES -# include +# include #else -# include +# include #endif #include #include @@ -37,6 +37,9 @@ #include #ifdef HAVE_NETINET_IP_H +# ifdef HAVE_NETINET_IN_SYSTM_H +# include +# endif # include #endif @@ -50,20 +53,23 @@ #include "array.h" #include "defines.h" -#include "resolve.h" #include "exp.h" #include "conn.h" #include "imp.h" #include "ngircd.h" +#include "array.h" #include "client.h" #include "conf.h" #include "conn-ssl.h" #include "conn-zip.h" #include "conn-func.h" #include "log.h" +#include "ng_ipaddr.h" #include "parse.h" +#include "proc.h" +#include "resolve.h" #include "tool.h" #ifdef ZEROCONF @@ -92,10 +98,12 @@ static bool Init_Socket PARAMS(( int Sock )); static void New_Server PARAMS(( int Server, ng_ipaddr_t *dest )); static void Simple_Message PARAMS(( int Sock, const char *Msg )); static int NewListener PARAMS(( const char *listen_addr, UINT16 Port )); +static void Account_Connection PARAMS((void)); + static array My_Listeners; static array My_ConnArray; -static size_t NumConnections; +static size_t NumConnections, NumConnectionsMax, NumConnectionsAccepted; #ifdef TCPWRAP int allow_severity = LOG_INFO; @@ -109,37 +117,51 @@ 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 -static void cb_Read_Resolver_Result PARAMS(( int sock, UNUSED short what)); -static void cb_Connect_to_Server PARAMS(( int sock, UNUSED short what)); +static void cb_Read_Resolver_Result PARAMS((int sock, UNUSED short what)); +static void cb_Connect_to_Server PARAMS((int sock, UNUSED short what)); static void cb_clientserver PARAMS((int sock, short what)); + +/** + * 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) + */ static void cb_listen(int sock, short irrelevant) { (void) irrelevant; - if (New_Connection( sock ) >= 0) - NumConnections++; - LogDebug("Total number of connections now %ld.", NumConnections); + (void) New_Connection(sock); } #ifdef SSL_SUPPORT +/** + * 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) + */ static void cb_listen_ssl(int sock, short irrelevant) { int fd; + (void) irrelevant; fd = New_Connection(sock); if (fd < 0) return; - - NumConnections++; - LogDebug("Total number of connections now %ld.", NumConnections); io_event_setcb(My_Connections[fd].sock, cb_clientserver_ssl); } #endif +/** + * IO callback for new outgoing non-SSL server connections. + * @param sock Socket descriptor + * @param what IO specification (IO_WANTREAD/IO_WANTWRITE/...) + */ static void cb_connserver(int sock, UNUSED short what) { @@ -213,6 +235,10 @@ cb_connserver(int sock, UNUSED short what) } +/** + * Login to a remote server. + * @param idx Connection index + */ static void server_login(CONN_ID idx) { @@ -229,6 +255,11 @@ server_login(CONN_ID idx) #ifdef SSL_SUPPORT +/** + * IO callback for new outgoing SSL-enabled server connections. + * @param sock Socket descriptor + * @param what IO specification (IO_WANTREAD/IO_WANTWRITE/...) + */ static void cb_connserver_login_ssl(int sock, short unused) { @@ -258,6 +289,11 @@ cb_connserver_login_ssl(int sock, short unused) #endif +/** + * IO callback for established non-SSL client and server connections. + * @param sock Socket descriptor + * @param what IO specification (IO_WANTREAD/IO_WANTWRITE/...) + */ static void cb_clientserver(int sock, short what) { @@ -270,18 +306,27 @@ cb_clientserver(int sock, short what) return; } #ifdef SSL_SUPPORT - if (what & IO_WANTREAD || (Conn_OPTION_ISSET(&My_Connections[idx], CONN_SSL_WANT_WRITE))) - Read_Request( idx ); /* if TLS layer needs to write additional data, call Read_Request instead so SSL/TLS can continue */ + 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); + } #else if (what & IO_WANTREAD) - Read_Request( idx ); + Read_Request(idx); #endif if (what & IO_WANTWRITE) - Handle_Write( idx ); + Handle_Write(idx); } #ifdef SSL_SUPPORT +/** + * IO callback for established SSL-enabled client and server connections. + * @param sock Socket descriptor + * @param what IO specification (IO_WANTREAD/IO_WANTWRITE/...) + */ static void cb_clientserver_ssl(int sock, short what) { @@ -295,11 +340,13 @@ cb_clientserver_ssl(int sock, short what) } switch (ConnSSL_Accept(&My_Connections[idx])) { - case 1: break; /* OK */ - case 0: return; /* EAGAIN: this callback will be invoked again by the io layer */ - default: - Conn_Close( idx, "Socket closed!", "SSL accept error", false ); - return; + case 1: + break; /* OK */ + case 0: + return; /* EAGAIN: callback will be invoked again by IO layer */ + default: + Conn_Close(idx, "SSL accept error, closing socket", "SSL accept error", false); + return; } if (what & IO_WANTREAD) Read_Request(idx); @@ -312,6 +359,9 @@ cb_clientserver_ssl(int sock, short what) #endif +/** + * Initialite connecion module. + */ GLOBAL void Conn_Init( void ) { @@ -324,8 +374,8 @@ Conn_Init( void ) Pool_Size = Conf_MaxConnections; if (!array_alloc(&My_ConnArray, sizeof(CONNECTION), (size_t)Pool_Size)) { - Log( LOG_EMERG, "Can't allocate memory! [Conn_Init]" ); - exit( 1 ); + Log(LOG_EMERG, "Can't allocate memory! [Conn_Init]"); + exit(1); } /* FIXME: My_Connetions/Pool_Size is needed by other parts of the @@ -333,20 +383,21 @@ Conn_Init( void ) My_Connections = (CONNECTION*) array_start(&My_ConnArray); LogDebug("Allocated connection pool for %d items (%ld bytes).", - array_length(&My_ConnArray, sizeof( CONNECTION )), array_bytes(&My_ConnArray)); + array_length(&My_ConnArray, sizeof(CONNECTION)), + array_bytes(&My_ConnArray)); - assert( array_length(&My_ConnArray, sizeof( CONNECTION )) >= (size_t) Pool_Size); + assert(array_length(&My_ConnArray, sizeof(CONNECTION)) >= (size_t)Pool_Size); array_free( &My_Listeners ); - /* Connection-Struktur initialisieren */ - for( i = 0; i < Pool_Size; i++ ) Init_Conn_Struct( i ); - - /* Global write counter */ - WCounter = 0; + for (i = 0; i < Pool_Size; i++) + Init_Conn_Struct(i); } /* Conn_Init */ +/** + * Clean up connection module. + */ GLOBAL void Conn_Exit( void ) { @@ -399,6 +450,10 @@ ports_initlisteners(array *a, const char *listen_addr, void (*func)(int,short)) } +/** + * Initialize all listening sockets. + * @return Number of created listening sockets + */ GLOBAL unsigned int Conn_InitListeners( void ) { @@ -433,13 +488,12 @@ Conn_InitListeners( void ) listen_addr = strtok(NULL, ","); } - /* - * can't free() Conf_ListenAddress here. On /REHASH, if the config file + /* Can't free() Conf_ListenAddress here: on REHASH, if the config file * cannot be re-loaded, we'd end up with a NULL Conf_ListenAddress. * Instead, free() takes place in conf.c, before the config file - * is being parsed. - */ + * is being parsed. */ free(copy); + return created; } /* Conn_InitListeners */ @@ -582,6 +636,7 @@ NewListener(const char *listen_addr, UINT16 Port) return sock; } /* NewListener */ + #ifdef SSL_SUPPORT /* * SSL/TLS connections require extra treatment: @@ -700,8 +755,9 @@ Conn_Handler(void) if (SSL_WantWrite(&My_Connections[i])) continue; /* TLS/SSL layer needs to write data; deal with this first */ #endif - if (Resolve_INPROGRESS(&My_Connections[i].res_stat)) { - /* Wait for completion of resolver sub-process ... */ + if (Proc_InProgress(&My_Connections[i].proc_stat)) { + /* Wait for completion of forked subprocess + * and ignore the socket in the meantime ... */ io_event_del(My_Connections[i].sock, IO_WANTREAD); continue; @@ -717,6 +773,7 @@ Conn_Handler(void) IO_WANTREAD); continue; } + io_event_add(My_Connections[i].sock, IO_WANTREAD); } @@ -757,12 +814,12 @@ Conn_Handler(void) */ #ifdef PROTOTYPES GLOBAL bool -Conn_WriteStr( CONN_ID Idx, char *Format, ... ) +Conn_WriteStr(CONN_ID Idx, const char *Format, ...) #else GLOBAL bool -Conn_WriteStr( Idx, Format, va_alist ) +Conn_WriteStr(Idx, Format, va_alist) CONN_ID Idx; -char *Format; +const char *Format; va_dcl #endif { @@ -1018,9 +1075,9 @@ Conn_Close( CONN_ID Idx, const char *LogMsg, const char *FwdMsg, bool InformClie in_k, out_k); } - /* cancel running resolver */ - if (Resolve_INPROGRESS(&My_Connections[Idx].res_stat)) - Resolve_Shutdown(&My_Connections[Idx].res_stat); + /* Kill possibly running subprocess */ + if (Proc_InProgress(&My_Connections[Idx].proc_stat)) + Proc_Kill(&My_Connections[Idx].proc_stat); /* Servers: Modify time of next connect attempt? */ Conf_UnsetServer( Idx ); @@ -1049,6 +1106,27 @@ Conn_Close( CONN_ID Idx, const char *LogMsg, const char *FwdMsg, bool InformClie } /* Conn_Close */ +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 */ + + GLOBAL void Conn_SyncServerStruct( void ) { @@ -1163,12 +1241,14 @@ Count_Connections(ng_ipaddr_t *a) } /* Count_Connections */ +/** + * Initialize new client connection on a listening socket. + * @param Sock Listening socket descriptor + * @return Accepted socket descriptor or -1 on error + */ static int -New_Connection( int Sock ) +New_Connection(int Sock) { - /* Neue Client-Verbindung von Listen-Socket annehmen und - * CLIENT-Struktur anlegen. */ - #ifdef TCPWRAP struct request_info req; #endif @@ -1178,16 +1258,16 @@ New_Connection( int Sock ) CLIENT *c; long cnt; - assert( Sock > NONE ); - /* Connection auf Listen-Socket annehmen */ - new_sock_len = (int)sizeof(new_addr); + assert(Sock > NONE); + new_sock_len = (int)sizeof(new_addr); 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)); return -1; } + NumConnectionsAccepted++; if (!ng_ipaddr_tostr_r(&new_addr, ip_str)) { Log(LOG_CRIT, "fd %d: Can't convert IP address!", new_sock); @@ -1198,49 +1278,56 @@ New_Connection( int Sock ) #ifdef TCPWRAP /* Validate socket using TCP Wrappers */ - request_init( &req, RQ_DAEMON, PACKAGE_NAME, RQ_FILE, new_sock, RQ_CLIENT_SIN, &new_addr, NULL ); + request_init(&req, RQ_DAEMON, PACKAGE_NAME, RQ_FILE, new_sock, + RQ_CLIENT_SIN, &new_addr, NULL); fromhost(&req); if (!hosts_access(&req)) { - Log (deny_severity, "Refused connection from %s (by TCP Wrappers)!", ip_str); - Simple_Message( new_sock, "ERROR :Connection refused" ); - close( new_sock ); + Log(deny_severity, + "Refused connection from %s (by TCP Wrappers)!", ip_str); + Simple_Message(new_sock, "ERROR :Connection refused"); + close(new_sock); return -1; } #endif - /* Socket initialisieren */ - if (!Init_Socket( new_sock )) + 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); return -1; + } /* Check IP-based connection limit */ cnt = Count_Connections(&new_addr); if ((Conf_MaxConnectionsIP > 0) && (cnt >= Conf_MaxConnectionsIP)) { /* Access denied, too many connections from this IP address! */ - Log( LOG_ERR, "Refused connection from %s: too may connections (%ld) from this IP address!", ip_str, cnt); - Simple_Message( new_sock, "ERROR :Connection refused, too many connections from your IP address!" ); - close( new_sock ); - return -1; - } - - 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 ); + Log(LOG_ERR, + "Refused connection from %s: too may connections (%ld) from this IP address!", + ip_str, cnt); + Simple_Message(new_sock, + "ERROR :Connection refused, too many connections from your IP address!"); + close(new_sock); return -1; } - if( new_sock >= Pool_Size ) { + if (new_sock >= Pool_Size) { if (!array_alloc(&My_ConnArray, sizeof(CONNECTION), - (size_t)new_sock)) { - Log( LOG_EMERG, "Can't allocate memory! [New_Connection]" ); - Simple_Message( new_sock, "ERROR: Internal error" ); - close( new_sock ); + (size_t) new_sock)) { + Log(LOG_EMERG, + "Can't allocate memory! [New_Connection]"); + Simple_Message(new_sock, "ERROR: Internal error"); + close(new_sock); return -1; } LogDebug("Bumped connection pool to %ld items (internal: %ld items, %ld bytes)", - new_sock, array_length(&My_ConnArray, sizeof(CONNECTION)), array_bytes(&My_ConnArray)); + new_sock, array_length(&My_ConnArray, + sizeof(CONNECTION)), array_bytes(&My_ConnArray)); /* Adjust pointer to new block */ My_Connections = array_start(&My_ConnArray); @@ -1249,22 +1336,24 @@ New_Connection( int Sock ) } /* register callback */ - if (!io_event_create( new_sock, IO_WANTREAD, cb_clientserver)) { - Log(LOG_ALERT, "Can't accept connection: io_event_create failed!"); + if (!io_event_create(new_sock, IO_WANTREAD, cb_clientserver)) { + Log(LOG_ALERT, + "Can't accept connection: io_event_create failed!"); Simple_Message(new_sock, "ERROR :Internal error"); close(new_sock); return -1; } - c = Client_NewLocal(new_sock, ip_str, CLIENT_UNKNOWN, false ); - if( ! c ) { - Log(LOG_ALERT, "Can't accept connection: can't create client structure!"); + c = Client_NewLocal(new_sock, ip_str, CLIENT_UNKNOWN, false); + if (!c) { + Log(LOG_ALERT, + "Can't accept connection: can't create client structure!"); Simple_Message(new_sock, "ERROR :Internal error"); io_close(new_sock); return -1; } - Init_Conn_Struct( new_sock ); + Init_Conn_Struct(new_sock); My_Connections[new_sock].sock = new_sock; My_Connections[new_sock].addr = new_addr; My_Connections[new_sock].client = c; @@ -1290,13 +1379,25 @@ New_Connection( int Sock ) identsock = -1; #endif if (!Conf_NoDNS) - Resolve_Addr(&My_Connections[new_sock].res_stat, &new_addr, + Resolve_Addr(&My_Connections[new_sock].proc_stat, &new_addr, identsock, cb_Read_Resolver_Result); - Conn_SetPenalty(new_sock, 4); + + Account_Connection(); return new_sock; } /* New_Connection */ +static void +Account_Connection(void) +{ + NumConnections++; + if (NumConnections > NumConnectionsMax) + NumConnectionsMax = NumConnections; + LogDebug("Total number of connections now %lu (max %lu).", + NumConnections, NumConnectionsMax); +} /* Account_Connection */ + + static CONN_ID Socket2Index( int Sock ) { @@ -1662,7 +1763,7 @@ Check_Servers( void ) /* Okay, try to connect now */ Conf_Server[i].lasttry = time_now; Conf_Server[i].conn_id = SERVER_WAIT; - assert(Resolve_Getfd(&Conf_Server[i].res_stat) < 0); + assert(Proc_GetPipeFd(&Conf_Server[i].res_stat) < 0); Resolve_Name(&Conf_Server[i].res_stat, Conf_Server[i].host, cb_Connect_to_Server); } } /* Check_Servers */ @@ -1736,7 +1837,7 @@ New_Server( int Server , ng_ipaddr_t *dest) } /* Conn_Close() decrements this counter again */ - NumConnections++; + Account_Connection(); Client_SetIntroducer( c, c ); Client_SetToken( c, TOKEN_OUTBOUND ); @@ -1785,7 +1886,7 @@ Init_Conn_Struct(CONN_ID Idx) My_Connections[Idx].signon = now; My_Connections[Idx].lastdata = now; My_Connections[Idx].lastprivmsg = now; - Resolve_Init(&My_Connections[Idx].res_stat); + Proc_InitStruct(&My_Connections[Idx].proc_stat); } /* Init_Conn_Struct */ @@ -1811,12 +1912,13 @@ Init_Socket( int Sock ) } /* Set type of service (TOS) */ -#if defined(IP_TOS) && defined(IPTOS_LOWDELAY) +#if defined(IPPROTO_IP) && defined(IPTOS_LOWDELAY) value = IPTOS_LOWDELAY; - LogDebug("Setting option IP_TOS on socket %d to IPTOS_LOWDELAY (%d).", Sock, value ); - if( setsockopt( Sock, SOL_IP, IP_TOS, &value, (socklen_t)sizeof( value )) != 0 ) - { - Log( LOG_ERR, "Can't set socket option IP_TOS: %s!", strerror( errno )); + LogDebug("Setting IP_TOS on socket %d to IPTOS_LOWDELAY.", Sock); + if (setsockopt(Sock, IPPROTO_IP, IP_TOS, &value, + (socklen_t) sizeof(value))) { + Log(LOG_ERR, "Can't set socket option IP_TOS: %s!", + strerror(errno)); /* ignore this error */ } #endif @@ -1825,7 +1927,6 @@ Init_Socket( int Sock ) } /* Init_Socket */ - static void cb_Connect_to_Server(int fd, UNUSED short events) { @@ -1840,7 +1941,7 @@ cb_Connect_to_Server(int fd, UNUSED short events) LogDebug("Resolver: Got forward lookup callback on fd %d, events %d", fd, events); for (i=0; i < MAX_SERVERS; i++) { - if (Resolve_Getfd(&Conf_Server[i].res_stat) == fd ) + if (Proc_GetPipeFd(&Conf_Server[i].res_stat) == fd ) break; } @@ -1885,7 +1986,7 @@ cb_Read_Resolver_Result( int r_fd, UNUSED short events ) * IDENT user name.*/ CLIENT *c; - int i; + CONN_ID i; size_t len; char *identptr; #ifdef IDENTAUTH @@ -1895,14 +1996,8 @@ cb_Read_Resolver_Result( int r_fd, UNUSED short events ) #endif LogDebug("Resolver: Got callback on fd %d, events %d", r_fd, events ); - - /* Search associated connection ... */ - for( i = 0; i < Pool_Size; i++ ) { - if(( My_Connections[i].sock != NONE ) - && ( Resolve_Getfd(&My_Connections[i].res_stat) == r_fd )) - break; - } - if( i >= Pool_Size ) { + i = Conn_GetFromProc(r_fd); + if (i == NONE) { /* Ops, none found? Probably the connection has already * been closed!? We'll ignore that ... */ io_close( r_fd ); @@ -1911,7 +2006,7 @@ cb_Read_Resolver_Result( int r_fd, UNUSED short events ) } /* Read result from pipe */ - len = Resolve_Read(&My_Connections[i].res_stat, readbuf, sizeof readbuf -1); + len = Resolve_Read(&My_Connections[i].proc_stat, readbuf, sizeof readbuf -1); if (len == 0) return; @@ -1933,10 +2028,14 @@ cb_Read_Resolver_Result( int r_fd, UNUSED short events ) c = Conn_GetClient( i ); assert( c != NULL ); - /* Only update client information of unregistered clients */ - if( Client_Type( c ) == CLIENT_UNKNOWN ) { - strlcpy(My_Connections[i].host, readbuf, sizeof( My_Connections[i].host)); - Client_SetHostname( c, readbuf); + /* 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); #ifdef IDENTAUTH ++identptr; if (*identptr) { @@ -1955,41 +2054,83 @@ cb_Read_Resolver_Result( int r_fd, UNUSED short events ) } /* cb_Read_Resolver_Result */ +/** + * 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(). */ static void -Simple_Message( int Sock, const char *Msg ) +Simple_Message(int Sock, const char *Msg) { char buf[COMMAND_LEN]; size_t len; - /* Write "simple" message to socket, without using compression - * or even the connection write buffers. Used e.g. for error - * messages by New_Connection(). */ - assert( Sock > NONE ); - assert( Msg != NULL ); - - strlcpy( buf, Msg, sizeof buf - 2); - len = strlcat( buf, "\r\n", sizeof buf); - (void)write(Sock, buf, len); + + 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; + } } /* Simple_Error */ +/** + * 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 + */ GLOBAL CLIENT * Conn_GetClient( CONN_ID Idx ) { - /* return Client-Structure that belongs to the local Connection Idx. - * If none is found, return NULL. - */ CONNECTION *c; - assert( Idx >= 0 ); + assert(Idx >= 0); c = array_get(&My_ConnArray, sizeof (CONNECTION), (size_t)Idx); - assert(c != NULL); - return c ? c->client : NULL; } + +/** + * 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 */ + + #ifdef SSL_SUPPORT -/* we cannot access My_Connections in irc-info.c */ + +/** + * 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 + */ GLOBAL bool Conn_GetCipherInfo(CONN_ID Idx, char *buf, size_t len) { @@ -2000,6 +2141,11 @@ Conn_GetCipherInfo(CONN_ID Idx, char *buf, size_t len) } +/** + * Check if a connection is SSL-enabled or not. + * @param Idx Connection index number + * @return true if connection is SSL-enabled, false otherwise. + */ GLOBAL bool Conn_UsesSSL(CONN_ID Idx) { @@ -2008,6 +2154,7 @@ Conn_UsesSSL(CONN_ID Idx) assert(Idx < (int) array_length(&My_ConnArray, sizeof(CONNECTION))); return Conn_OPTION_ISSET(&My_Connections[Idx], CONN_SSL); } + #endif