1 /*  GNU Thales - IRC to Relational Database Gateway
2  *  Copyright (C) 2002 Lucas Nussbaum <lucas@lucas-nussbaum.net>
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
18 
19 #include "thales.h"
20 #include "log.h"
21 
22 extern int debug;
23 
24 /*************************************************************************/
25 /*************************************************************************/
26 
27 /* Read from a socket with buffering. */
28 
29 static char read_netbuf[NET_BUFSIZE];
30 static char *read_curpos = read_netbuf;	/* Next byte to return */
31 static char *read_bufend = read_netbuf;	/* Next position for data from socket */
32 static char *const read_buftop = read_netbuf + NET_BUFSIZE;
33 int total_read = 0;
34 
35 
36 /* Return amount of data in read buffer. */
37 
read_buffer_len()38 int read_buffer_len()
39 {
40 	if (read_bufend >= read_curpos)
41 		return read_bufend - read_curpos;
42 	else
43 		return (read_bufend + NET_BUFSIZE) - read_curpos;
44 }
45 
46 
47 /* Read data. */
48 
buffered_read(int fd,char * buf,int len)49 static int buffered_read(int fd, char *buf, int len)
50 {
51 	int nread, left = len;
52 	fd_set fds;
53 	struct timeval tv = { 0, 0 };
54 	int errno_save = errno;
55 
56 	if (fd < 0)
57 	{
58 		errno = EBADF;
59 		return -1;
60 	}
61 	while (left > 0)
62 	{
63 		struct timeval *tvptr = (read_bufend == read_curpos ? NULL : &tv);
64 		FD_ZERO(&fds);
65 		FD_SET(fd, &fds);
66 		while (read_bufend != read_curpos - 1
67 				 && !(read_curpos == read_netbuf
68 						&& read_bufend == read_buftop - 1)
69 				 && select(fd + 1, &fds, 0, 0, tvptr) == 1)
70 		{
71 			int maxread;
72 			tvptr = &tv;			  /* don't wait next time */
73 			if (read_bufend < read_curpos)	/* wrapped around? */
74 				maxread = (read_curpos - 1) - read_bufend;
75 			else if (read_curpos == read_netbuf)
76 				maxread = read_buftop - read_bufend - 1;
77 			else
78 				maxread = read_buftop - read_bufend;
79 			nread = read(fd, read_bufend, maxread);
80 			errno_save = errno;
81 			if (debug >= 3)
82 				mylog("debug: buffered_read wanted %d, got %d", maxread, nread);
83 			if (nread <= 0)
84 				break;
85 			read_bufend += nread;
86 			if (read_bufend == read_buftop)
87 				read_bufend = read_netbuf;
88 		}
89 		if (read_curpos == read_bufend)	/* No more data on socket */
90 			break;
91 		/* See if we can gobble up the rest of the buffer. */
92 		if (read_curpos + left >= read_buftop && read_bufend < read_curpos)
93 		{
94 			nread = read_buftop - read_curpos;
95 			memcpy(buf, read_curpos, nread);
96 			buf += nread;
97 			left -= nread;
98 			read_curpos = read_netbuf;
99 		}
100 		/* Now everything we need is in a single chunk at read_curpos. */
101 		if (read_bufend > read_curpos && read_bufend - read_curpos < left)
102 			nread = read_bufend - read_curpos;
103 		else
104 			nread = left;
105 		if (nread)
106 		{
107 			memcpy(buf, read_curpos, nread);
108 			buf += nread;
109 			left -= nread;
110 			read_curpos += nread;
111 		}
112 	}
113 	total_read += len - left;
114 	if (debug >= 4)
115 	{
116 		mylog("debug: buffered_read(%d,%p,%d) returning %d",
117 			 fd, buf, len, len - left);
118 	}
119 	errno = errno_save;
120 	return len - left;
121 }
122 
123 /* Optimized version of the above for reading a single character; returns
124  * the character in an int or EOF, like fgetc(). */
125 
buffered_read_one(int fd)126 static int buffered_read_one(int fd)
127 {
128 	int nread;
129 	fd_set fds;
130 	struct timeval tv = { 0, 0 };
131 	char c;
132 	struct timeval *tvptr = (read_bufend == read_curpos ? NULL : &tv);
133 	int errno_save = errno;
134 
135 	if (fd < 0)
136 	{
137 		errno = EBADF;
138 		return -1;
139 	}
140 	FD_ZERO(&fds);
141 	FD_SET(fd, &fds);
142 	while (read_bufend != read_curpos - 1
143 			 && !(read_curpos == read_netbuf
144 					&& read_bufend == read_buftop - 1)
145 			 && select(fd + 1, &fds, 0, 0, tvptr) == 1)
146 	{
147 		int maxread;
148 		tvptr = &tv;				  /* don't wait next time */
149 		if (read_bufend < read_curpos)	/* wrapped around? */
150 			maxread = (read_curpos - 1) - read_bufend;
151 		else if (read_curpos == read_netbuf)
152 			maxread = read_buftop - read_bufend - 1;
153 		else
154 			maxread = read_buftop - read_bufend;
155 		nread = read(fd, read_bufend, maxread);
156 		errno_save = errno;
157 		if (debug >= 3)
158 			mylog("debug: buffered_read_one wanted %d, got %d", maxread, nread);
159 		if (nread <= 0)
160 			break;
161 		read_bufend += nread;
162 		if (read_bufend == read_buftop)
163 			read_bufend = read_netbuf;
164 	}
165 	if (read_curpos == read_bufend)
166 	{									  /* No more data on socket */
167 		if (debug >= 4)
168 			mylog("debug: buffered_read_one(%d) returning %d", fd, EOF);
169 		errno = errno_save;
170 		return EOF;
171 	}
172 	c = *read_curpos++;
173 	if (read_curpos == read_buftop)
174 		read_curpos = read_netbuf;
175 	total_read++;
176 	if (debug >= 4)
177 		mylog("debug: buffered_read_one(%d) returning %d", fd, c);
178 	return (int) c & 0xFF;
179 }
180 
181 /*************************************************************************/
182 
183 /* Write to a socket with buffering.  Note that this assumes only one
184  * socket. */
185 
186 static char write_netbuf[NET_BUFSIZE];
187 static char *write_curpos = write_netbuf;	/* Next byte to write to socket */
188 static char *write_bufend = write_netbuf;	/* Next position for data to socket */
189 static char *const write_buftop = write_netbuf + NET_BUFSIZE;
190 static int write_fd = -1;
191 int total_written;
192 
193 
194 /* Return amount of data in write buffer. */
195 
write_buffer_len()196 int write_buffer_len()
197 {
198 	if (write_bufend >= write_curpos)
199 		return write_bufend - write_curpos;
200 	else
201 		return (write_bufend + NET_BUFSIZE) - write_curpos;
202 }
203 
204 
205 /* Helper routine to try and write up to one chunk of data from the buffer
206  * to the socket.  Return how much was written. */
207 
flush_write_buffer(int wait)208 static int flush_write_buffer(int wait)
209 {
210 	fd_set fds;
211 	struct timeval tv = { 0, 0 };
212 	int errno_save = errno;
213 
214 	if (write_bufend == write_curpos || write_fd == -1)
215 		return 0;
216 	FD_ZERO(&fds);
217 	FD_SET(write_fd, &fds);
218 	if (select(write_fd + 1, 0, &fds, 0, wait ? NULL : &tv) == 1)
219 	{
220 		int maxwrite, nwritten;
221 		if (write_curpos > write_bufend)	/* wrapped around? */
222 			maxwrite = write_buftop - write_curpos;
223 		else if (write_bufend == write_netbuf)
224 			maxwrite = write_buftop - write_curpos - 1;
225 		else
226 			maxwrite = write_bufend - write_curpos;
227 		nwritten = write(write_fd, write_curpos, maxwrite);
228 		errno_save = errno;
229 		if (debug >= 3)
230 			mylog("debug: flush_write_buffer wanted %d, got %d", maxwrite,
231 				 nwritten);
232 		if (nwritten > 0)
233 		{
234 			write_curpos += nwritten;
235 			if (write_curpos == write_buftop)
236 				write_curpos = write_netbuf;
237 			total_written += nwritten;
238 			return nwritten;
239 		}
240 	}
241 	errno = errno_save;
242 	return 0;
243 }
244 
245 
246 /* Write data. */
247 
buffered_write(int fd,char * buf,int len)248 static int buffered_write(int fd, char *buf, int len)
249 {
250 	int nwritten, left = len;
251 	int errno_save = errno;
252 
253 	if (fd < 0)
254 	{
255 		errno = EBADF;
256 		return -1;
257 	}
258 	write_fd = fd;
259 
260 	while (left > 0)
261 	{
262 
263 		/* Don't try putting anything in the buffer if it's full. */
264 		if (write_curpos != write_bufend + 1 &&
265 			 (write_curpos != write_netbuf
266 			  || write_bufend != write_buftop - 1))
267 		{
268 			/* See if we need to write up to the end of the buffer. */
269 			if (write_bufend + left >= write_buftop
270 				 && write_curpos <= write_bufend)
271 			{
272 				nwritten = write_buftop - write_bufend;
273 				memcpy(write_bufend, buf, nwritten);
274 				buf += nwritten;
275 				left -= nwritten;
276 				write_bufend = write_netbuf;
277 			}
278 			/* Now we can copy a single chunk to write_bufend. */
279 			if (write_curpos > write_bufend
280 				 && write_curpos - write_bufend - 1 < left)
281 				nwritten = write_curpos - write_bufend - 1;
282 			else
283 				nwritten = left;
284 			if (nwritten)
285 			{
286 				memcpy(write_bufend, buf, nwritten);
287 				buf += nwritten;
288 				left -= nwritten;
289 				write_bufend += nwritten;
290 			}
291 		}
292 
293 		/* Now write to the socket as much as we can. */
294 		if (write_curpos == write_bufend + 1 ||
295 			 (write_curpos == write_netbuf
296 			  && write_bufend == write_buftop - 1))
297 			flush_write_buffer(1);
298 		else
299 			flush_write_buffer(0);
300 		errno_save = errno;
301 		if (write_curpos == write_bufend + 1 ||
302 			 (write_curpos == write_netbuf
303 			  && write_bufend == write_buftop - 1))
304 		{
305 			/* Write failed on full buffer */
306 			break;
307 		}
308 	}
309 
310 	if (debug >= 4)
311 	{
312 		mylog("debug: buffered_write(%d,%p,%d) returning %d",
313 			 fd, buf, len, len - left);
314 	}
315 	errno = errno_save;
316 	return len - left;
317 }
318 
319 /* Optimized version of the above for writing a single character; returns
320  * the character in an int or EOF, like fputc().  Commented out because it
321  * isn't currently used. */
322 
323 #if 0
324 static int buffered_write_one(int c, int fd)
325 {
326 	struct timeval tv = { 0, 0 };
327 
328 	if (fd < 0)
329 	{
330 		errno = EBADF;
331 		return -1;
332 	}
333 	write_fd = fd;
334 
335 	/* Try to flush the buffer if it's full. */
336 	if (write_curpos == write_bufend + 1 ||
337 		 (write_curpos == write_netbuf && write_bufend == write_buftop - 1))
338 	{
339 		flush_write_buffer(1);
340 		if (write_curpos == write_bufend + 1 ||
341 			 (write_curpos == write_netbuf
342 			  && write_bufend == write_buftop - 1))
343 		{
344 			/* Write failed */
345 			if (debug >= 4)
346 				mylog("debug: buffered_write_one(%d) returning %d", fd, EOF);
347 			return EOF;
348 		}
349 	}
350 
351 	/* Write the character. */
352 	*write_bufend++ = c;
353 	if (write_bufend == write_buftop)
354 		write_bufend = write_netbuf;
355 
356 	/* Move it to the socket if we can. */
357 	flush_write_buffer(0);
358 
359 	if (debug >= 4)
360 		mylog("debug: buffered_write_one(%d) returning %d", fd, c);
361 	return (int) c & 0xFF;
362 }
363 #endif /* 0 */
364 
365 /*************************************************************************/
366 /*************************************************************************/
367 
368 static int lastchar = EOF;
369 
sgetc(int s)370 int sgetc(int s)
371 {
372 	int c;
373 
374 	if (lastchar != EOF)
375 	{
376 		c = lastchar;
377 		lastchar = EOF;
378 		return c;
379 	}
380 	return buffered_read_one(s);
381 }
382 
sungetc(int c,int s)383 int sungetc(int c, int s)
384 {
385 	return lastchar = c;
386 }
387 
388 /*************************************************************************/
389 
390 /* If connection was broken, return NULL.  If the read timed out, return
391  * (char *)-1.
392  */
393 
sgets(char * buf,int len,int s)394 char *sgets(char *buf, int len, int s)
395 {
396 	int c = 0;
397 	struct timeval tv;
398 	fd_set fds;
399 	char *ptr = buf;
400 
401 	if (len == 0)
402 		return NULL;
403 	FD_SET(s, &fds);
404 	tv.tv_sec = 5;
405 	tv.tv_usec = 0;
406 	while (read_buffer_len() == 0 &&
407 			 (c = select(s + 1, &fds, NULL, NULL, &tv)) < 0)
408 	{
409 		if (errno != EINTR)
410 			break;
411 	}
412 	if (read_buffer_len() == 0 && c == 0)
413 		return (char *) -1;
414 	c = sgetc(s);
415 	while (--len && (*ptr++ = c) != '\n' && (c = sgetc(s)) >= 0)
416 		;
417 	if (c < 0)
418 		return NULL;
419 	*ptr = 0;
420 	return buf;
421 }
422 
423 /*************************************************************************/
424 
425 /* sgets2:  Read a line of text from a socket, and strip newline and
426  *          carriage return characters from the end of the line.
427  */
428 
sgets2(char * buf,int len,int s)429 char *sgets2(char *buf, int len, int s)
430 {
431 	char *str = sgets(buf, len, s);
432 
433 	if (!str || str == (char *) -1)
434 		return str;
435 	str = buf + strlen(buf) - 1;
436 	if (*str == '\n')
437 		*str-- = 0;
438 	if (*str == '\r')
439 		*str = 0;
440 	return buf;
441 }
442 
443 /*************************************************************************/
444 
445 /* Read from a socket.  (Use this instead of read() because it has
446  * buffering.) */
447 
sread(int s,char * buf,int len)448 int sread(int s, char *buf, int len)
449 {
450 	return buffered_read(s, buf, len);
451 }
452 
453 /*************************************************************************/
454 
sputs(char * str,int s)455 int sputs(char *str, int s)
456 {
457 	return buffered_write(s, str, strlen(str));
458 }
459 
460 /*************************************************************************/
461 
sockprintf(int s,char * fmt,...)462 int sockprintf(int s, char *fmt, ...)
463 {
464 	va_list args;
465 	char buf[16384];				  /* Really huge, to try and avoid truncation */
466 
467 	va_start(args, fmt);
468 	return buffered_write(s, buf, vsnprintf(buf, sizeof(buf), fmt, args));
469 }
470 
471 
472 /*************************************************************************/
473 
474 /* lhost/lport specify the local side of the connection.  If they are not
475  * given (lhost==NULL, lport==0), then they are left free to vary.
476  */
477 
conn(const char * host,int port,const char * lhost,int lport)478 int conn(const char *host, int port, const char *lhost, int lport)
479 {
480 	struct hostent *hp;
481 	struct sockaddr_in sa, lsa;
482 	int sock;
483 
484 	memset(&lsa, 0, sizeof(lsa));
485 	if (lhost)
486 	{
487 		if ((hp = gethostbyname(lhost)) != NULL)
488 		{
489 			memcpy((char *) &lsa.sin_addr, hp->h_addr, hp->h_length);
490 			lsa.sin_family = hp->h_addrtype;
491 		}
492 		else
493 		{
494 			lhost = NULL;
495 		}
496 	}
497 	if (lport)
498 		lsa.sin_port = htons((unsigned short) lport);
499 
500 	memset(&sa, 0, sizeof(sa));
501 	if (!(hp = gethostbyname(host)))
502 		return -1;
503 	memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
504 	sa.sin_family = hp->h_addrtype;
505 	sa.sin_port = htons((unsigned short) port);
506 
507 	if ((sock = socket(sa.sin_family, SOCK_STREAM, 0)) < 0)
508 		return -1;
509 
510 	if ((lhost || lport)
511 		 && bind(sock, (struct sockaddr *) &lsa, sizeof(lsa)) < 0)
512 	{
513 		int errno_save = errno;
514 		close(sock);
515 		errno = errno_save;
516 		return -1;
517 	}
518 
519 	if (connect(sock, (struct sockaddr *) &sa, sizeof(sa)) < 0)
520 	{
521 		int errno_save = errno;
522 		close(sock);
523 		errno = errno_save;
524 		return -1;
525 	}
526 
527 	return sock;
528 }
529 
530 /*************************************************************************/
531 
disconn(int s)532 void disconn(int s)
533 {
534 	shutdown(s, 2);
535 	close(s);
536 }
537 
538 /*************************************************************************/
539