1 /*
2  * ----------------------------------------------------------------
3  * ircproxy - Client I/O Functions
4  * ----------------------------------------------------------------
5  * Copyright (C) 1997-2009 Jonas Kvinge
6  *
7  * This file is part of ircproxy.
8  *
9  * ircproxy is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * ircproxy is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with ircproxy.  If not, see <http://www.gnu.org/licenses/>.
21  *
22  * Additional permission under GNU GPL version 3 section 7
23  *
24  * If you modify ircproxy, or any covered work, by linking or
25  * combining it with openssl (or a modified version of that library),
26  * containing parts covered by the terms of the OpenSSL License and the
27  * SSLeay License, the licensors of ircproxy grant you additional
28  * permission to convey the resulting work.
29  *
30  * $Id: client_io.c 54 2009-03-18 18:23:29Z jonasio $
31  *
32  */
33 
34 #define CLIENT_IO_C
35 
36 #define NEED_SYS_TYPES_H 1		/* Extra types */
37 #define NEED_SYS_PARAM_H 1		/* Some systems need this */
38 #define NEED_LIMITS_H 0			/* Kernel limits */
39 #define NEED_STDARG_H 1			/* va_list, etc */
40 #define NEED_ERRNO_H 1			/* errno */
41 #define NEED_CTYPE_H 0			/* isdigit(), etc */
42 #define NEED_NETINET_IN_H 1		/* in_addr, sockaddr_in, etc */
43 #define NEED_ARPA_INET_H 1		/* inet_ntoa(), inet_aton(), etc */
44 #define NEED_STDIO_H 1			/* Standard C UNIX functions */
45 #define NEED_STDLIB_H 1			/* malloc(), exit(), atoi(), etc */
46 #define NEED_TIME_H 1			/* time(), etc */
47 #define NEED_SYSCTL_H 0			/* sysctl(), etc */
48 #define NEED_SYS_STAT_H 0		/* chmod(), mkdir(), etc */
49 #define NEED_SYS_UIO_H 0		/* iovec, etc */
50 #define NEED_FCNTL_H 1			/* open(), creat(), fcntl(), etc */
51 #define NEED_SYS_IOCTL_H 0		/* ioctl(), etc */
52 #define NEED_SYS_FILIO_H 0		/* Solaris need this for ioctl(), etc */
53 #define NEED_UNISTD_H 1			/* Unix standard functions */
54 #define NEED_STRING_H 1			/* C string functions */
55 #define NEED_SIGNAL_H 0			/* Signal functions */
56 #define NEED_SYS_SOCKET_H 1		/* Socket functions */
57 #define NEED_NETDB_H 1			/* Network database functions */
58 #define NEED_ARPA_NAMESER_H 0		/* Nameserver definitions */
59 #define NEED_GETUSERPW_HEADERS 0 	/* Functions to retrive system passwords */
60 #define NEED_ARES 1			/* Functions needed for ares */
61 #define NEED_SSL 1			/* Needed for SSL support */
62 
63 #include "includes.h"
64 #include "irc.h"
65 
66 #include "client.h"
67 #include "client_io.h"
68 
69 #if SSL_SUPPORT
70 #include "client_io_ssl.h"
71 #endif /* SSL_SUPPORT */
72 
73 #include "client_connection.h"
74 #include "client_parser.h"
75 #include "client_auth.h"
76 
77 /* VARIABLES - JONAS (31.07.2001) */
78 
79 extern struct Client_Struct *Client_Head;
80 
81 /* CLIENT_FDS FUNCTION - JONAS (22.07.2001) */
82 
client_fds(fd_set * ReadFDS,fd_set * WriteFDS,unsigned long int * FDS)83 void client_fds(fd_set *ReadFDS, fd_set *WriteFDS, unsigned long int *FDS) {
84 
85   struct Client_Struct *ClientS = NULL;
86   struct Client_Struct *ClientS_DEL = NULL;
87   time_t Duration = 0;
88 
89   for (ClientS = Client_Head ; ClientS != NULL ;) {
90 
91     if ((Host_IsResolved(ClientS->ResolveFlags)) && (Client_IsSocket(ClientS))) {
92       if (Client_IsVerified(ClientS)) {
93         if (Client_IsSentPing(ClientS)) {
94           Duration = (NOW - ClientS->SentPingTime);
95           if (Duration >= CLIENT_PINGTIMEOUT) { client_close(ClientS, "No response from client in %s, closing connection to client.", strduration(Duration)); }
96         }
97         else {
98           Duration = (NOW - ClientS->LastRecvTime);
99           if (Duration >= CLIENT_IDLETIMEBEFOREPING) {
100             ClientS->SentPingTime = NOW;
101             Client_SetSentPing(ClientS);
102             client_addsend(ClientS, "PING :ircproxy");
103           }
104         }
105       }
106       else {
107         Duration = (NOW - ClientS->Time);
108         if (Duration >= CLIENT_VERIFYTIMEOUT) { client_close(ClientS, "No response from client in %s while waiting for PASS/NICK/USER, closing connection to client.", strduration(Duration)); }
109       }
110     }
111 
112     if (Client_IsSentError(ClientS)) {
113       Duration = (NOW - ClientS->SentErrorTime);
114       if (Duration >= CLIENT_ERRORTIMEOUT) { client_cleanup(ClientS, "Disconnecting client %s (%s): Timeout while closing connection.", ClientS->HostName, ClientS->HostIPS); }
115     }
116 
117     if ((Client_IsSocket(ClientS)) && (Host_IsResolved(ClientS->ResolveFlags))) {
118       FD_SET(ClientS->FD, ReadFDS);
119       if (ClientS->SendBuffer != NULL) { FD_SET(ClientS->FD, WriteFDS); }
120     }
121 
122     if ((!Client_IsSocket(ClientS)) && (!Host_IsResolving(ClientS->ResolveFlags))) {
123       ClientS_DEL = ClientS;
124       ClientS = ClientS->Next;
125       client_rem(ClientS_DEL);
126       continue;
127     }
128     ClientS = ClientS->Next;
129 
130   }
131 
132 }
133 
134 /* CLIENT_IO FUNCTION - JONAS (01.07.2000) */
135 
client_io(fd_set * ReadFDS,fd_set * WriteFDS,unsigned long int * FDS)136 void client_io(fd_set *ReadFDS, fd_set *WriteFDS, unsigned long int *FDS) {
137 
138   struct Client_Struct *ClientS = NULL;
139 
140   for (ClientS = Client_Head ; ClientS != NULL ; ClientS = ClientS->Next) {
141 
142     assert(*FDS >= 0);
143     if (*FDS <= 0) { return; }
144 
145     if (Client_IsSocket(ClientS)) {
146       if (FD_ISSET(ClientS->FD, ReadFDS)) { *FDS = *FDS - 1; }
147       if (FD_ISSET(ClientS->FD, WriteFDS)) { *FDS = *FDS - 1; }
148     }
149 
150 
151     if (Client_IsSocket(ClientS)) {
152       if (FD_ISSET(ClientS->FD, ReadFDS)) {
153 #if SSL_SUPPORT
154         if (Client_IsSSL(ClientS)) { client_recv_ssl(ClientS); }
155         else {
156 #endif /* SSL_SUPPORT */
157           client_recv(ClientS);
158 #if SSL_SUPPORT
159         }
160 #endif /* SSL_SUPPORT */
161       }
162     }
163     if (Client_IsSocket(ClientS)) {
164       if (FD_ISSET(ClientS->FD, WriteFDS)) {
165 #if SSL_SUPPORT
166         if (Client_IsSSL(ClientS)) { client_send_ssl(ClientS); }
167         else {
168 #endif /* SSL_SUPPORT */
169           client_send(ClientS);
170 #if SSL_SUPPORT
171         }
172 #endif /* SSL_SUPPORT */
173       }
174     }
175   }
176 
177 }
178 
179 /* CLIENT_RECV FUNCTION - JONAS (01.07.2000) */
180 
client_recv(struct Client_Struct * ClientS)181 void client_recv(struct Client_Struct *ClientS) {
182 
183   signed long int Result = 0;
184   unsigned long int OldLen = 0;
185   unsigned long int NewLen = 0;
186   char RecvBuffer[RECVBUFFERLEN+1] = "";
187   char *RecvBufferPT = NULL;
188 
189   assert(ClientS != NULL);
190 
191   ClientS->LastRecvTime = NOW;
192 
193   do {
194     memset(&RecvBuffer, 0, sizeof(RecvBuffer));
195     Result = recv(ClientS->FD, RecvBuffer, RECVBUFFERLEN, MSG_NOSIGNAL);
196     if (Result <= ERROR) {
197       if ((errno == EAGAIN) || (errno == EWOULDBLOCK) || (errno == EINTR)) { break; }
198       client_cleanup(ClientS, "Read error to client %s (%s): [%d] %s", ClientS->HostName, ClientS->HostIPS, errno, strerror(errno));
199       return;
200     }
201     if (Result == 0) {
202       if (ClientS->RecvBuffer != NULL) { client_parse(ClientS); }
203       client_cleanup(ClientS, "EOF to client %s (%s).", ClientS->HostName, ClientS->HostIPS);
204       return;
205     }
206     if (ClientS->RecvBuffer == NULL) { OldLen = 0; }
207     else { OldLen = strlen(ClientS->RecvBuffer); }
208     NewLen = OldLen + Result + 1;
209     RecvBufferPT = realloc(ClientS->RecvBuffer, NewLen);
210     if (RecvBufferPT == NULL) {
211       client_close(ClientS, "Memory allocation failure: [%d] %s", errno, strerror(errno));
212       return;
213     }
214     ClientS->RecvBuffer = RecvBufferPT;
215     RecvBufferPT += OldLen;
216     strcpy(RecvBufferPT, RecvBuffer);
217   }
218   while (Result >= RECVBUFFERLEN);
219 
220   if (Client_IsSentError(ClientS)) { return; }
221 
222   client_parse(ClientS);
223 
224 }
225 
226 /* CLIENT_SEND FUNCTION - JONAS (01.07.2000) */
227 
client_send(struct Client_Struct * ClientS)228 void client_send(struct Client_Struct *ClientS) {
229 
230   char *SendBufferPT = NULL;
231   char SendBuffer[SENDBUFFERLEN+1] = "";
232   unsigned long int SendLen = 0;
233   unsigned long int SentLen = 0;
234   signed long int Result = 0;
235 
236   assert(ClientS != NULL);
237 
238   for (SendBufferPT = ClientS->SendBuffer ; *SendBufferPT != '\0' ; SendBufferPT += SentLen) {
239     SendLen = strlen(SendBufferPT);
240     if (SendLen > SENDBUFFERLEN) { SendLen = SENDBUFFERLEN; }
241     memset(&SendBuffer, 0, sizeof(SendBuffer));
242     strncpy(SendBuffer, SendBufferPT, SendLen);
243     Result = send(ClientS->FD, SendBuffer, SendLen, MSG_NOSIGNAL);
244     if (Result <= ERROR) {
245       if ((errno == EAGAIN) || (errno == EWOULDBLOCK) || (errno == EINTR) || (errno == ENOMEM) || (errno == ENOBUFS)) {
246         unsigned long int Len = 0;
247         sysprint(BITMASK_MAIN, "Write error to client %s (%s): [%d] %s", ClientS->HostName, ClientS->HostIPS, errno, strerror(errno));
248         /*
249          * EAGAIN/EWOULDBLOCK - THE SOCKET IMPLEMENTATION CAN'T HANDLE MORE DATA.
250          * EINTR - INTERRUPTED BY A SIGNAL.
251          * ENOMEM - NO MEMORY LEFT.
252          * ENOBUFS - NO BUFFER SPACE AVAILABLE.
253          *
254          * COPY WHATS LEFT TO THE THE START OF THE SENDBUFFER, REALLOCATE THE MEMORY AND BAIL OUT - JONAS (01.12.1999)
255          *
256          */
257         Len = strlen(SendBufferPT) + 1;
258         memmove(ClientS->SendBuffer, SendBufferPT, Len);
259         SendBufferPT = realloc(ClientS->SendBuffer, Len);
260         assert(SendBufferPT != NULL);
261         ClientS->SendBuffer = SendBufferPT;
262         return;
263       }
264       client_cleanup(ClientS, "Write error to client %s (%s): [%d] %s", ClientS->HostName, ClientS->HostIPS, errno, strerror(errno));
265       return;
266     }
267     SentLen = Result;
268     if (SentLen < SendLen) {
269       unsigned long int Len = 0;
270       sysprint(BITMASK_MAIN, "Partial write to client %s (%s), sent %ld of %ld.", ClientS->HostName, ClientS->HostIPS, SentLen, SendLen);
271       SendBufferPT += SentLen;
272       Len = strlen(SendBufferPT) + 1;
273       memmove(ClientS->SendBuffer, SendBufferPT, Len);
274       SendBufferPT = realloc(ClientS->SendBuffer, Len);
275       assert(SendBufferPT != NULL);
276       ClientS->SendBuffer = SendBufferPT;
277       return;
278     }
279 #if 0
280     assert(SentLen == SendLen);
281 #endif
282   }
283 
284   FREE(ClientS->SendBuffer);
285 
286   if (Client_IsSentError(ClientS)) { client_cleanup(ClientS, "Successfully closed connection to client %s (%s).", ClientS->HostName, ClientS->HostIPS); }
287 
288 }
289