/[cvs]/eggdrop1.8/src/net.c
ViewVC logotype

Contents of /eggdrop1.8/src/net.c

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.1.1.1 - (show annotations) (download) (as text) (vendor branch)
Mon Jul 26 21:11:06 2010 UTC (8 years, 10 months ago) by simple
Branch: eggheads
CVS Tags: v1
Changes since 1.1: +0 -0 lines
File MIME type: text/x-chdr
Error occurred while calculating annotation data.
Imported Eggdrop 1.6.20

1 /*
2 * net.c -- handles:
3 * all raw network i/o
4 *
5 * $Id: net.c,v 1.86 2010/07/12 15:40:52 thommey Exp $
6 */
7 /*
8 * This is hereby released into the public domain.
9 * Robey Pointer, robey@netcom.com
10 *
11 * Changes after Feb 23, 1999 Copyright Eggheads Development Team
12 *
13 * Copyright (C) 1999 - 2010 Eggheads Development Team
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
28 */
29
30 #include <fcntl.h>
31 #include "main.h"
32 #include <limits.h>
33 #include <string.h>
34 #include <netdb.h>
35 #include <sys/socket.h>
36 #if HAVE_SYS_SELECT_H
37 # include <sys/select.h>
38 #endif
39 #include <netinet/in.h>
40 #include <arpa/inet.h>
41 #include <errno.h>
42 #if HAVE_UNISTD_H
43 # include <unistd.h>
44 #endif
45 #include <setjmp.h>
46
47 #ifndef HAVE_GETDTABLESIZE
48 # ifdef FD_SETSIZE
49 # define getdtablesize() FD_SETSIZE
50 # else
51 # define getdtablesize() 200
52 # endif
53 #endif
54
55 extern struct dcc_t *dcc;
56 extern int backgrd, use_stderr, resolve_timeout, dcc_total;
57 extern unsigned long otraffic_irc_today, otraffic_bn_today, otraffic_dcc_today,
58 otraffic_filesys_today, otraffic_trans_today,
59 otraffic_unknown_today;
60
61 char hostname[121] = ""; /* Hostname can be specified in the config file.*/
62 char myip[121] = ""; /* IP can be specified in the config file. */
63 char firewall[121] = ""; /* Socks server for firewall. */
64 int firewallport = 1080; /* Default port of socks 4/5 firewalls. */
65 char botuser[21] = "eggdrop"; /* Username of the user running the bot. */
66 int dcc_sanitycheck = 0; /* Do some sanity checking on dcc connections. */
67
68 sock_list *socklist = NULL; /* Enough to be safe. */
69 sigjmp_buf alarmret; /* Env buffer for alarm() returns. */
70
71 /* Types of proxies */
72 #define PROXY_SOCKS 1
73 #define PROXY_SUN 2
74
75
76 /* I need an UNSIGNED long for dcc type stuff
77 */
78 IP my_atoul(char *s)
79 {
80 IP ret = 0;
81
82 while ((*s >= '0') && (*s <= '9')) {
83 ret *= 10;
84 ret += ((*s) - '0');
85 s++;
86 }
87 return ret;
88 }
89
90 int expmem_net()
91 {
92 int i, tot = 0;
93 struct threaddata *td = threaddata();
94
95 for (i = 0; i < td->MAXSOCKS; i++) {
96 if (!(td->socklist[i].flags & (SOCK_UNUSED | SOCK_TCL))) {
97 if (td->socklist[i].handler.sock.inbuf != NULL)
98 tot += strlen(td->socklist[i].handler.sock.inbuf) + 1;
99 if (td->socklist[i].handler.sock.outbuf != NULL)
100 tot += td->socklist[i].handler.sock.outbuflen;
101 }
102 }
103 return tot;
104 }
105
106 /* Get my ip number
107 */
108 IP getmyip()
109 {
110 struct hostent *hp;
111 char s[121];
112 IP ip;
113 struct in_addr *in;
114 if (myip[0]) {
115 if ((myip[strlen(myip) - 1] >= '0') && (myip[strlen(myip) - 1] <= '9'))
116 return (IP) inet_addr(myip);
117 }
118 /* Also could be pre-defined */
119 if (hostname[0])
120 hp = gethostbyname(hostname);
121 else {
122 gethostname(s, 120);
123 hp = gethostbyname(s);
124 }
125 if (hp == NULL)
126 fatal("Hostname self-lookup failed. Please set 'my-ip' in the config "
127 "file.", 0);
128 in = (struct in_addr *) (hp->h_addr_list[0]);
129 ip = (IP) (in->s_addr);
130 return ip;
131 }
132
133 void neterror(char *s)
134 {
135 switch (errno) {
136 case EADDRINUSE:
137 strcpy(s, "Address already in use");
138 break;
139 case EADDRNOTAVAIL:
140 strcpy(s, "Cannot assign requested address");
141 break;
142 case EAFNOSUPPORT:
143 strcpy(s, "Address family not supported");
144 break;
145 case EALREADY:
146 strcpy(s, "Socket already in use");
147 break;
148 case EBADF:
149 strcpy(s, "Socket descriptor is bad");
150 break;
151 case ECONNREFUSED:
152 strcpy(s, "Connection refused");
153 break;
154 case EFAULT:
155 strcpy(s, "Bad address");
156 break;
157 case EINPROGRESS:
158 strcpy(s, "Operation in progress");
159 break;
160 case EINTR:
161 strcpy(s, "Timeout");
162 break;
163 case EINVAL:
164 strcpy(s, "Invalid argument");
165 break;
166 case EISCONN:
167 strcpy(s, "Socket already connected");
168 break;
169 case ENETUNREACH:
170 strcpy(s, "Network unreachable");
171 break;
172 case ENOTSOCK:
173 strcpy(s, "Socket operation on non-socket");
174 break;
175 case ETIMEDOUT:
176 strcpy(s, "Connection timed out");
177 break;
178 case ENOTCONN:
179 strcpy(s, "Socket is not connected");
180 break;
181 case EHOSTUNREACH:
182 strcpy(s, "No route to host");
183 break;
184 case EPIPE:
185 strcpy(s, "Broken pipe");
186 break;
187 #ifdef ECONNRESET
188 case ECONNRESET:
189 strcpy(s, "Connection reset by peer");
190 break;
191 #endif
192 #ifdef EACCES
193 case EACCES:
194 strcpy(s, "Permission denied");
195 break;
196 #endif
197 #ifdef EMFILE
198 case EMFILE:
199 strcpy(s, "Too many open files");
200 break;
201 #endif
202 case 0:
203 strcpy(s, "Error 0");
204 break;
205 default:
206 sprintf(s, "Unforseen error %d", errno);
207 break;
208 }
209 }
210
211 /* Sets/Unsets options for a specific socket.
212 *
213 * Returns: 0 - on success
214 * -1 - socket not found
215 * -2 - illegal operation
216 */
217 int sockoptions(int sock, int operation, int sock_options)
218 {
219 int i;
220 struct threaddata *td = threaddata();
221
222 for (i = 0; i < td->MAXSOCKS; i++)
223 if ((td->socklist[i].sock == sock) &&
224 !(td->socklist[i].flags & SOCK_UNUSED)) {
225 if (operation == EGG_OPTION_SET)
226 td->socklist[i].flags |= sock_options;
227 else if (operation == EGG_OPTION_UNSET)
228 td->socklist[i].flags &= ~sock_options;
229 else
230 return -2;
231 return 0;
232 }
233 return -1;
234 }
235
236 /* Return a free entry in the socket entry
237 */
238 int allocsock(int sock, int options)
239 {
240 int i;
241 struct threaddata *td = threaddata();
242
243 for (i = 0; i < td->MAXSOCKS; i++) {
244 if (td->socklist[i].flags & SOCK_UNUSED) {
245 /* yay! there is table space */
246 td->socklist[i].handler.sock.inbuf = NULL;
247 td->socklist[i].handler.sock.outbuf = NULL;
248 td->socklist[i].handler.sock.inbuflen = 0;
249 td->socklist[i].handler.sock.outbuflen = 0;
250 td->socklist[i].flags = options;
251 td->socklist[i].sock = sock;
252 return i;
253 }
254 }
255 /* Try again if enlarging socketlist works */
256 if (increase_socks_max())
257 return -1;
258 else
259 return allocsock(sock, options);
260 }
261
262 /* Return a free entry in the socket entry for a tcl socket
263 *
264 * alloctclsock() can be called by Tcl threads
265 */
266 int alloctclsock(register int sock, int mask, Tcl_FileProc *proc, ClientData cd)
267 {
268 int f = -1;
269 register int i;
270 struct threaddata *td = threaddata();
271
272 for (i = 0; i < td->MAXSOCKS; i++) {
273 if (td->socklist[i].flags & SOCK_UNUSED) {
274 if (f == -1)
275 f = i;
276 } else if ((td->socklist[i].flags & SOCK_TCL) &&
277 td->socklist[i].sock == sock) {
278 f = i;
279 break;
280 }
281 }
282 if (f != -1) {
283 td->socklist[f].sock = sock;
284 td->socklist[f].flags = SOCK_TCL;
285 td->socklist[f].handler.tclsock.mask = mask;
286 td->socklist[f].handler.tclsock.proc = proc;
287 td->socklist[f].handler.tclsock.cd = cd;
288 return f;
289 }
290 /* Try again if enlarging socketlist works */
291 if (increase_socks_max())
292 return -1;
293 else
294 return alloctclsock(sock, mask, proc, cd);
295 }
296
297 /* Request a normal socket for i/o
298 */
299 void setsock(int sock, int options)
300 {
301 int i = allocsock(sock, options), parm;
302 struct threaddata *td = threaddata();
303
304 if (i == -1) {
305 putlog(LOG_MISC, "*", "Sockettable full.");
306 return;
307 }
308 if (((sock != STDOUT) || backgrd) && !(td->socklist[i].flags & SOCK_NONSOCK)) {
309 parm = 1;
310 setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *) &parm, sizeof(int));
311
312 parm = 0;
313 setsockopt(sock, SOL_SOCKET, SO_LINGER, (void *) &parm, sizeof(int));
314 }
315 if (options & SOCK_LISTEN) {
316 /* Tris says this lets us grab the same port again next time */
317 parm = 1;
318 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *) &parm, sizeof(int));
319 }
320 /* Yay async i/o ! */
321 fcntl(sock, F_SETFL, O_NONBLOCK);
322 }
323
324 int getsock(int options)
325 {
326 int sock = socket(AF_INET, SOCK_STREAM, 0);
327
328 if (sock >= 0)
329 setsock(sock, options);
330 else
331 putlog(LOG_MISC, "*", "Warning: Can't create new socket!");
332 return sock;
333 }
334
335 /* Done with a socket
336 */
337 void killsock(register int sock)
338 {
339 register int i;
340 struct threaddata *td = threaddata();
341
342 /* Ignore invalid sockets. */
343 if (sock < 0)
344 return;
345
346 for (i = 0; i < td->MAXSOCKS; i++) {
347 if ((td->socklist[i].sock == sock) && !(td->socklist[i].flags & SOCK_UNUSED)) {
348 if (!(td->socklist[i].flags & SOCK_TCL)) { /* nothing to free for tclsocks */
349 close(td->socklist[i].sock);
350 if (td->socklist[i].handler.sock.inbuf != NULL) {
351 nfree(td->socklist[i].handler.sock.inbuf);
352 td->socklist[i].handler.sock.inbuf = NULL;
353 }
354 if (td->socklist[i].handler.sock.outbuf != NULL) {
355 nfree(td->socklist[i].handler.sock.outbuf);
356 td->socklist[i].handler.sock.outbuf = NULL;
357 td->socklist[i].handler.sock.outbuflen = 0;
358 }
359 }
360 td->socklist[i].flags = SOCK_UNUSED;
361 return;
362 }
363 }
364 putlog(LOG_MISC, "*", "Warning: Attempt to kill un-allocated socket %d!", sock);
365 }
366
367 /* Done with a tcl socket
368 *
369 * killtclsock() can be called by Tcl threads
370 */
371 void killtclsock(register int sock)
372 {
373 register int i;
374 struct threaddata *td = threaddata();
375
376 if (sock < 0)
377 return;
378
379 for (i = 0; i < td->MAXSOCKS; i++) {
380 if ((td->socklist[i].flags & SOCK_TCL) && td->socklist[i].sock == sock) {
381 td->socklist[i].flags = SOCK_UNUSED;
382 return;
383 }
384 }
385 }
386
387 /* Send connection request to proxy
388 */
389 static int proxy_connect(int sock, char *host, int port, int proxy)
390 {
391 unsigned char x[10];
392 struct hostent *hp;
393 char s[256];
394 int i;
395
396 /* socks proxy */
397 if (proxy == PROXY_SOCKS) {
398 /* numeric IP? */
399 if (host[strlen(host) - 1] >= '0' && host[strlen(host) - 1] <= '9') {
400 IP ip = ((IP) inet_addr(host));
401 egg_memcpy(x, &ip, 4);
402 } else {
403 /* no, must be host.domain */
404 if (!sigsetjmp(alarmret, 1)) {
405 alarm(resolve_timeout);
406 hp = gethostbyname(host);
407 alarm(0);
408 } else
409 hp = NULL;
410 if (hp == NULL) {
411 killsock(sock);
412 return -2;
413 }
414 egg_memcpy(x, hp->h_addr, hp->h_length);
415 }
416 for (i = 0; i < threaddata()->MAXSOCKS; i++)
417 if (!(socklist[i].flags & SOCK_UNUSED) && socklist[i].sock == sock)
418 socklist[i].flags |= SOCK_PROXYWAIT; /* drummer */
419 egg_snprintf(s, sizeof s, "\004\001%c%c%c%c%c%c%s", (port >> 8) % 256,
420 (port % 256), x[0], x[1], x[2], x[3], botuser);
421 tputs(sock, s, strlen(botuser) + 9); /* drummer */
422 } else if (proxy == PROXY_SUN) {
423 egg_snprintf(s, sizeof s, "%s %d\n", host, port);
424 tputs(sock, s, strlen(s)); /* drummer */
425 }
426 return sock;
427 }
428
429 /* Starts a connection attempt to a socket
430 *
431 * If given a normal hostname, this will be resolved to the corresponding
432 * IP address first. PLEASE try to use the non-blocking dns functions
433 * instead and then call this function with the IP address to avoid blocking.
434 *
435 * returns <0 if connection refused:
436 * -1 neterror() type error
437 * -2 can't resolve hostname
438 */
439 int open_telnet_raw(int sock, char *server, int sport)
440 {
441 struct sockaddr_in name;
442 struct hostent *hp;
443 char host[121];
444 int i, port, rc;
445 volatile int proxy;
446
447 /* firewall? use socks */
448 if (firewall[0]) {
449 if (firewall[0] == '!') {
450 proxy = PROXY_SUN;
451 strcpy(host, &firewall[1]);
452 } else {
453 proxy = PROXY_SOCKS;
454 strcpy(host, firewall);
455 }
456 port = firewallport;
457 } else {
458 proxy = 0;
459 strcpy(host, server);
460 port = sport;
461 }
462 egg_bzero((char *) &name, sizeof(struct sockaddr_in));
463
464 name.sin_family = AF_INET;
465 name.sin_addr.s_addr = (myip[0] ? getmyip() : INADDR_ANY);
466 if (bind(sock, (struct sockaddr *) &name, sizeof(name)) < 0) {
467 killsock(sock);
468 return -1;
469 }
470 egg_bzero((char *) &name, sizeof(struct sockaddr_in));
471
472 name.sin_family = AF_INET;
473 name.sin_port = htons(port);
474 /* Numeric IP? */
475 if ((host[strlen(host) - 1] >= '0') && (host[strlen(host) - 1] <= '9'))
476 name.sin_addr.s_addr = inet_addr(host);
477 else {
478 /* No, must be host.domain */
479 debug0("WARNING: open_telnet_raw() is about to block in gethostbyname()!");
480 if (!sigsetjmp(alarmret, 1)) {
481 alarm(resolve_timeout);
482 hp = gethostbyname(host);
483 alarm(0);
484 } else
485 hp = NULL;
486 if (hp == NULL)
487 return -2;
488 egg_memcpy(&name.sin_addr, hp->h_addr, hp->h_length);
489 name.sin_family = hp->h_addrtype;
490 }
491 for (i = 0; i < threaddata()->MAXSOCKS; i++) {
492 if (!(socklist[i].flags & SOCK_UNUSED) && (socklist[i].sock == sock))
493 socklist[i].flags = (socklist[i].flags & ~SOCK_VIRTUAL) | SOCK_CONNECT;
494 }
495 rc = connect(sock, (struct sockaddr *) &name, sizeof(struct sockaddr_in));
496 if (rc < 0) {
497 if (errno == EINPROGRESS) {
498 /* Firewall? announce connect attempt to proxy */
499 if (firewall[0])
500 return proxy_connect(sock, server, sport, proxy);
501 return sock; /* async success! */
502 } else
503 return -1;
504 }
505 /* Synchronous? :/ */
506 if (firewall[0])
507 return proxy_connect(sock, server, sport, proxy);
508 return sock;
509 }
510
511 /* Ordinary non-binary connection attempt */
512 int open_telnet(char *server, int port)
513 {
514 int sock = getsock(0), ret = open_telnet_raw(sock, server, port);
515
516 return ret;
517 }
518
519 /* Returns a socket number for a listening socket that will accept any
520 * connection on a certain address -- port # is returned in port
521 */
522 int open_address_listen(IP addr, int *port)
523 {
524 int sock = 0;
525 socklen_t addrlen;
526 struct sockaddr_in name;
527
528 if (firewall[0]) {
529 /* FIXME: can't do listen port thru firewall yet */
530 putlog(LOG_MISC, "*", "Can't open a listen port (you are using a "
531 "firewall).");
532 return -1;
533 }
534
535 if (getmyip() > 0) {
536 sock = getsock(SOCK_LISTEN);
537 if (sock < 1)
538 return -1;
539
540 egg_bzero((char *) &name, sizeof(struct sockaddr_in));
541 name.sin_family = AF_INET;
542 name.sin_port = htons(*port); /* 0 = just assign us a port */
543 name.sin_addr.s_addr = addr;
544 if (bind(sock, (struct sockaddr *) &name, sizeof(name)) < 0) {
545 killsock(sock);
546 return -1;
547 }
548 /* what port are we on? */
549 addrlen = sizeof(name);
550 if (getsockname(sock, (struct sockaddr *) &name, &addrlen) < 0) {
551 killsock(sock);
552 return -1;
553 }
554 *port = ntohs(name.sin_port);
555 if (listen(sock, 1) < 0) {
556 killsock(sock);
557 return -1;
558 }
559 }
560
561 return sock;
562 }
563
564 /* Returns a socket number for a listening socket that will accept any
565 * connection -- port # is returned in port
566 */
567 inline int open_listen(int *port)
568 {
569 return open_address_listen(myip[0] ? getmyip() : INADDR_ANY, port);
570 }
571
572 /* Returns the given network byte order IP address in the
573 * dotted format - "##.##.##.##"
574 */
575 char *iptostr(IP ip)
576 {
577 struct in_addr a;
578
579 a.s_addr = ip;
580 return inet_ntoa(a);
581 }
582
583 /* Short routine to answer a connect received on a socket made previously
584 * by open_listen ... returns hostname of the caller & the new socket
585 * does NOT dispose of old "public" socket!
586 */
587 int answer(int sock, char *caller, unsigned long *ip, unsigned short *port,
588 int binary)
589 {
590 int new_sock;
591 socklen_t addrlen;
592 struct sockaddr_in from;
593
594 addrlen = sizeof(struct sockaddr);
595 new_sock = accept(sock, (struct sockaddr *) &from, &addrlen);
596
597 if (new_sock < 0)
598 return -1;
599 if (ip != NULL) {
600 *ip = from.sin_addr.s_addr;
601 /* DNS is now done asynchronously. We now only provide the IP address. */
602 strncpyz(caller, iptostr(*ip), 121);
603 *ip = ntohl(*ip);
604 }
605 if (port != NULL)
606 *port = ntohs(from.sin_port);
607 /* Set up all the normal socket crap */
608 setsock(new_sock, (binary ? SOCK_BINARY : 0));
609 return new_sock;
610 }
611
612 /* Like open_telnet, but uses server & port specifications of dcc
613 */
614 int open_telnet_dcc(int sock, char *server, char *port)
615 {
616 int p;
617 unsigned long addr;
618 char sv[500];
619 unsigned char c[4];
620
621 if (port != NULL)
622 p = atoi(port);
623 else
624 p = 2000;
625 if (server != NULL)
626 addr = my_atoul(server);
627 else
628 addr = 0L;
629 if (addr < (1 << 24))
630 return -3; /* fake address */
631 c[0] = (addr >> 24) & 0xff;
632 c[1] = (addr >> 16) & 0xff;
633 c[2] = (addr >> 8) & 0xff;
634 c[3] = addr & 0xff;
635 sprintf(sv, "%u.%u.%u.%u", c[0], c[1], c[2], c[3]);
636 p = open_telnet_raw(sock, sv, p);
637 return p;
638 }
639
640 /* Builds the fd_sets for select(). Eggdrop only cares about readable
641 * sockets, but tcl also cares for writable/exceptions.
642 * preparefdset() can be called by Tcl Threads
643 */
644 int preparefdset(fd_set *fd, sock_list *slist, int slistmax, int tclonly, int tclmask)
645 {
646 int fdtmp, i, foundsocks = 0;
647
648 FD_ZERO(fd);
649 for (i = 0; i < slistmax; i++) {
650 if (!(slist[i].flags & (SOCK_UNUSED | SOCK_VIRTUAL))) {
651 if ((slist[i].sock == STDOUT) && !backgrd)
652 fdtmp = STDIN;
653 else
654 fdtmp = slist[i].sock;
655 /*
656 * Looks like that having more than a call, in the same
657 * program, to the FD_SET macro, triggers a bug in gcc.
658 * SIGBUS crashing binaries used to be produced on a number
659 * (prolly all?) of 64 bits architectures.
660 * Make your best to avoid to make it happen again.
661 *
662 * ITE
663 */
664 if (slist[i].flags & SOCK_TCL) {
665 if (!(slist[i].handler.tclsock.mask & tclmask))
666 continue;
667 } else if (tclonly)
668 continue;
669 foundsocks = 1;
670 FD_SET(fdtmp, fd);
671 }
672 }
673 return foundsocks;
674 }
675
676 /* Attempts to read from all sockets in slist (upper array boundary slistmax-1)
677 * fills s with up to 511 bytes if available, and returns the array index
678 * Also calls all handler procs for Tcl sockets
679 * sockread() can be called by Tcl threads
680 *
681 * on EOF: returns -1, with socket in len
682 * on socket error: returns -2
683 * if nothing is ready: returns -3
684 * tcl sockets busy: returns -5
685 */
686 int sockread(char *s, int *len, sock_list *slist, int slistmax, int tclonly)
687 {
688 struct timeval t;
689 fd_set fdr, fdw, fde;
690 int fds, i, x, have_r, have_w, have_e;
691 int grab = 511, tclsock = -1, events = 0;
692 struct threaddata *td = threaddata();
693
694 fds = getdtablesize();
695 #ifdef FD_SETSIZE
696 if (fds > FD_SETSIZE)
697 fds = FD_SETSIZE; /* Fixes YET ANOTHER freebsd bug!!! */
698 #endif
699
700 have_r = preparefdset(&fdr, slist, slistmax, tclonly, TCL_READABLE);
701 have_w = preparefdset(&fdw, slist, slistmax, 1, TCL_WRITABLE);
702 have_e = preparefdset(&fde, slist, slistmax, 1, TCL_EXCEPTION);
703
704 /* select() may modify the timeval argument - copy it */
705 t.tv_sec = td->blocktime.tv_sec;
706 t.tv_usec = td->blocktime.tv_usec;
707
708 x = select((SELECT_TYPE_ARG1) fds,
709 SELECT_TYPE_ARG234 (have_r ? &fdr : NULL),
710 SELECT_TYPE_ARG234 (have_w ? &fdw : NULL),
711 SELECT_TYPE_ARG234 (have_e ? &fde : NULL),
712 SELECT_TYPE_ARG5 &t);
713 if (x > 0) {
714 /* Something happened */
715 for (i = 0; i < slistmax; i++) {
716 if (!tclonly && ((!(slist[i].flags & (SOCK_UNUSED | SOCK_TCL))) &&
717 ((FD_ISSET(slist[i].sock, &fdr)) ||
718 ((slist[i].sock == STDOUT) && (!backgrd) &&
719 (FD_ISSET(STDIN, &fdr)))))) {
720 if (slist[i].flags & (SOCK_LISTEN | SOCK_CONNECT)) {
721 /* Listening socket -- don't read, just return activity */
722 /* Same for connection attempt */
723 /* (for strong connections, require a read to succeed first) */
724 if (slist[i].flags & SOCK_PROXYWAIT) /* drummer */
725 /* Hang around to get the return code from proxy */
726 grab = 10;
727 else if (!(slist[i].flags & SOCK_STRONGCONN)) {
728 debug1("net: connect! sock %d", slist[i].sock);
729 s[0] = 0;
730 *len = 0;
731 return i;
732 }
733 } else if (slist[i].flags & SOCK_PASS) {
734 s[0] = 0;
735 *len = 0;
736 return i;
737 }
738 errno = 0;
739 if ((slist[i].sock == STDOUT) && !backgrd)
740 x = read(STDIN, s, grab);
741 else
742 x = read(slist[i].sock, s, grab);
743 if (x <= 0) { /* eof */
744 if (errno != EAGAIN) { /* EAGAIN happens when the operation would
745 * block on a non-blocking socket, if the
746 * socket is going to die, it will die later,
747 * otherwise it will connect. */
748 *len = slist[i].sock;
749 slist[i].flags &= ~SOCK_CONNECT;
750 debug1("net: eof!(read) socket %d", slist[i].sock);
751 return -1;
752 } else {
753 debug3("sockread EAGAIN: %d %d (%s)", slist[i].sock, errno,
754 strerror(errno));
755 continue; /* EAGAIN */
756 }
757 }
758 s[x] = 0;
759 *len = x;
760 if (slist[i].flags & SOCK_PROXYWAIT) {
761 debug2("net: socket: %d proxy errno: %d", slist[i].sock, s[1]);
762 slist[i].flags &= ~(SOCK_CONNECT | SOCK_PROXYWAIT);
763 switch (s[1]) {
764 case 90: /* Success */
765 s[0] = 0;
766 *len = 0;
767 return i;
768 case 91: /* Failed */
769 errno = ECONNREFUSED;
770 break;
771 case 92: /* No identd */
772 case 93: /* Identd said wrong username */
773 /* A better error message would be "socks misconfigured"
774 * or "identd not working" but this is simplest.
775 */
776 errno = ENETUNREACH;
777 break;
778 }
779 *len = slist[i].sock;
780 return -1;
781 }
782 return i;
783 } else if (tclsock == -1 && (slist[i].flags & SOCK_TCL)) {
784 events = FD_ISSET(slist[i].sock, &fdr) ? TCL_READABLE : 0;
785 events |= FD_ISSET(slist[i].sock, &fdw) ? TCL_WRITABLE : 0;
786 events |= FD_ISSET(slist[i].sock, &fde) ? TCL_EXCEPTION : 0;
787 events &= slist[i].handler.tclsock.mask;
788 if (events)
789 tclsock = i;
790 }
791 }
792 } else if (x == -1)
793 return -2; /* socket error */
794 else if (!tclonly) {
795 s[0] = 0;
796 *len = 0;
797 }
798 if (tclsock != -1) {
799 (*slist[tclsock].handler.tclsock.proc)(slist[tclsock].handler.tclsock.cd,
800 events);
801 return -5;
802 }
803 return -3;
804 }
805
806 /* sockgets: buffer and read from sockets
807 *
808 * Attempts to read from all registered sockets for up to one second. if
809 * after one second, no complete data has been received from any of the
810 * sockets, 's' will be empty, 'len' will be 0, and sockgets will return -3.
811 * if there is returnable data received from a socket, the data will be
812 * in 's' (null-terminated if non-binary), the length will be returned
813 * in len, and the socket number will be returned.
814 * normal sockets have their input buffered, and each call to sockgets
815 * will return one line terminated with a '\n'. binary sockets are not
816 * buffered and return whatever coems in as soon as it arrives.
817 * listening sockets will return an empty string when a connection comes in.
818 * connecting sockets will return an empty string on a successful connect,
819 * or EOF on a failed connect.
820 * if an EOF is detected from any of the sockets, that socket number will be
821 * put in len, and -1 will be returned.
822 * the maximum length of the string returned is 512 (including null)
823 *
824 * Returns -4 if we handled something that shouldn't be handled by the
825 * dcc functions. Simply ignore it.
826 * Returns -5 if tcl sockets are busy but not eggdrop sockets.
827 */
828
829 int sockgets(char *s, int *len)
830 {
831 char xx[514], *p, *px;
832 int ret, i, data = 0;
833
834 for (i = 0; i < threaddata()->MAXSOCKS; i++) {
835 /* Check for stored-up data waiting to be processed */
836 if (!(socklist[i].flags & (SOCK_UNUSED | SOCK_TCL | SOCK_BUFFER)) &&
837 (socklist[i].handler.sock.inbuf != NULL)) {
838 if (!(socklist[i].flags & SOCK_BINARY)) {
839 /* look for \r too cos windows can't follow RFCs */
840 p = strchr(socklist[i].handler.sock.inbuf, '\n');
841 if (p == NULL)
842 p = strchr(socklist[i].handler.sock.inbuf, '\r');
843 if (p != NULL) {
844 *p = 0;
845 if (strlen(socklist[i].handler.sock.inbuf) > 510)
846 socklist[i].handler.sock.inbuf[510] = 0;
847 strcpy(s, socklist[i].handler.sock.inbuf);
848 px = nmalloc(strlen(p + 1) + 1);
849 strcpy(px, p + 1);
850 nfree(socklist[i].handler.sock.inbuf);
851 if (px[0])
852 socklist[i].handler.sock.inbuf = px;
853 else {
854 nfree(px);
855 socklist[i].handler.sock.inbuf = NULL;
856 }
857 /* Strip CR if this was CR/LF combo */
858 if (s[strlen(s) - 1] == '\r')
859 s[strlen(s) - 1] = 0;
860 *len = strlen(s);
861 return socklist[i].sock;
862 }
863 } else {
864 /* Handling buffered binary data (must have been SOCK_BUFFER before). */
865 if (socklist[i].handler.sock.inbuflen <= 510) {
866 *len = socklist[i].handler.sock.inbuflen;
867 egg_memcpy(s, socklist[i].handler.sock.inbuf, socklist[i].handler.sock.inbuflen);
868 nfree(socklist[i].handler.sock.inbuf);
869 socklist[i].handler.sock.inbuf = NULL;
870 socklist[i].handler.sock.inbuflen = 0;
871 } else {
872 /* Split up into chunks of 510 bytes. */
873 *len = 510;
874 egg_memcpy(s, socklist[i].handler.sock.inbuf, *len);
875 egg_memcpy(socklist[i].handler.sock.inbuf, socklist[i].handler.sock.inbuf + *len, *len);
876 socklist[i].handler.sock.inbuflen -= *len;
877 socklist[i].handler.sock.inbuf = nrealloc(socklist[i].handler.sock.inbuf, socklist[i].handler.sock.inbuflen);
878 }
879 return socklist[i].sock;
880 }
881 }
882 /* Also check any sockets that might have EOF'd during write */
883 if (!(socklist[i].flags & SOCK_UNUSED) && (socklist[i].flags & SOCK_EOFD)) {
884 s[0] = 0;
885 *len = socklist[i].sock;
886 return -1;
887 }
888 }
889 /* No pent-up data of any worth -- down to business */
890 *len = 0;
891 ret = sockread(xx, len, socklist, threaddata()->MAXSOCKS, 0);
892 if (ret < 0) {
893 s[0] = 0;
894 return ret;
895 }
896 /* Binary, listening and passed on sockets don't get buffered. */
897 if (socklist[ret].flags & SOCK_CONNECT) {
898 if (socklist[ret].flags & SOCK_STRONGCONN) {
899 socklist[ret].flags &= ~SOCK_STRONGCONN;
900 /* Buffer any data that came in, for future read. */
901 socklist[ret].handler.sock.inbuflen = *len;
902 socklist[ret].handler.sock.inbuf = nmalloc(*len + 1);
903 /* It might be binary data. You never know. */
904 egg_memcpy(socklist[ret].handler.sock.inbuf, xx, *len);
905 socklist[ret].handler.sock.inbuf[*len] = 0;
906 }
907 socklist[ret].flags &= ~SOCK_CONNECT;
908 s[0] = 0;
909 return socklist[ret].sock;
910 }
911 if (socklist[ret].flags & SOCK_BINARY) {
912 egg_memcpy(s, xx, *len);
913 return socklist[ret].sock;
914 }
915 if (socklist[ret].flags & (SOCK_LISTEN | SOCK_PASS | SOCK_TCL)) {
916 s[0] = 0; /* for the dcc traffic counters in the mainloop */
917 return socklist[ret].sock;
918 }
919 if (socklist[ret].flags & SOCK_BUFFER) {
920 socklist[ret].handler.sock.inbuf = (char *) nrealloc(socklist[ret].handler.sock.inbuf,
921 socklist[ret].handler.sock.inbuflen + *len + 1);
922 egg_memcpy(socklist[ret].handler.sock.inbuf + socklist[ret].handler.sock.inbuflen, xx, *len);
923 socklist[ret].handler.sock.inbuflen += *len;
924 /* We don't know whether it's binary data. Make sure normal strings
925 * will be handled properly later on too. */
926 socklist[ret].handler.sock.inbuf[socklist[ret].handler.sock.inbuflen] = 0;
927 return -4; /* Ignore this one. */
928 }
929 /* Might be necessary to prepend stored-up data! */
930 if (socklist[ret].handler.sock.inbuf != NULL) {
931 p = socklist[ret].handler.sock.inbuf;
932 socklist[ret].handler.sock.inbuf = nmalloc(strlen(p) + strlen(xx) + 1);
933 strcpy(socklist[ret].handler.sock.inbuf, p);
934 strcat(socklist[ret].handler.sock.inbuf, xx);
935 nfree(p);
936 if (strlen(socklist[ret].handler.sock.inbuf) < 512) {
937 strcpy(xx, socklist[ret].handler.sock.inbuf);
938 nfree(socklist[ret].handler.sock.inbuf);
939 socklist[ret].handler.sock.inbuf = NULL;
940 socklist[ret].handler.sock.inbuflen = 0;
941 } else {
942 p = socklist[ret].handler.sock.inbuf;
943 socklist[ret].handler.sock.inbuflen = strlen(p) - 510;
944 socklist[ret].handler.sock.inbuf = nmalloc(socklist[ret].handler.sock.inbuflen + 1);
945 strcpy(socklist[ret].handler.sock.inbuf, p + 510);
946 *(p + 510) = 0;
947 strcpy(xx, p);
948 nfree(p);
949 /* (leave the rest to be post-pended later) */
950 }
951 }
952 /* Look for EOL marker; if it's there, i have something to show */
953 p = strchr(xx, '\n');
954 if (p == NULL)
955 p = strchr(xx, '\r');
956 if (p != NULL) {
957 *p = 0;
958 strcpy(s, xx);
959 memmove(xx, p + 1, strlen(p + 1) + 1);
960 if (s[strlen(s) - 1] == '\r')
961 s[strlen(s) - 1] = 0;
962 data = 1; /* DCC_CHAT may now need to process a blank line */
963 /* NO! */
964 /* if (!s[0]) strcpy(s," "); */
965 } else {
966 s[0] = 0;
967 if (strlen(xx) >= 510) {
968 /* String is too long, so just insert fake \n */
969 strcpy(s, xx);
970 xx[0] = 0;
971 data = 1;
972 }
973 }
974 *len = strlen(s);
975 /* Anything left that needs to be saved? */
976 if (!xx[0]) {
977 if (data)
978 return socklist[ret].sock;
979 else
980 return -3;
981 }
982 /* Prepend old data back */
983 if (socklist[ret].handler.sock.inbuf != NULL) {
984 p = socklist[ret].handler.sock.inbuf;
985 socklist[ret].handler.sock.inbuflen = strlen(p) + strlen(xx);
986 socklist[ret].handler.sock.inbuf = nmalloc(socklist[ret].handler.sock.inbuflen + 1);
987 strcpy(socklist[ret].handler.sock.inbuf, xx);
988 strcat(socklist[ret].handler.sock.inbuf, p);
989 nfree(p);
990 } else {
991 socklist[ret].handler.sock.inbuflen = strlen(xx);
992 socklist[ret].handler.sock.inbuf = nmalloc(socklist[ret].handler.sock.inbuflen + 1);
993 strcpy(socklist[ret].handler.sock.inbuf, xx);
994 }
995 if (data)
996 return socklist[ret].sock;
997 else
998 return -3;
999 }
1000
1001 /* Dump something to a socket
1002 *
1003 * NOTE: Do NOT put Contexts in here if you want DEBUG to be meaningful!!
1004 */
1005 void tputs(register int z, char *s, unsigned int len)
1006 {
1007 register int i, x, idx;
1008 char *p;
1009 static int inhere = 0;
1010
1011 if (z < 0) /* um... HELLO?! sanity check please! */
1012 return;
1013
1014 if (((z == STDOUT) || (z == STDERR)) && (!backgrd || use_stderr)) {
1015 write(z, s, len);
1016 return;
1017 }
1018
1019 for (i = 0; i < threaddata()->MAXSOCKS; i++) {
1020 if (!(socklist[i].flags & SOCK_UNUSED) && (socklist[i].sock == z)) {
1021 for (idx = 0; idx < dcc_total; idx++) {
1022 if ((dcc[idx].sock == z) && dcc[idx].type && dcc[idx].type->name) {
1023 if (!strncmp(dcc[idx].type->name, "BOT", 3))
1024 otraffic_bn_today += len;
1025 else if (!strcmp(dcc[idx].type->name, "SERVER"))
1026 otraffic_irc_today += len;
1027 else if (!strncmp(dcc[idx].type->name, "CHAT", 4))
1028 otraffic_dcc_today += len;
1029 else if (!strncmp(dcc[idx].type->name, "FILES", 5))
1030 otraffic_filesys_today += len;
1031 else if (!strcmp(dcc[idx].type->name, "SEND"))
1032 otraffic_trans_today += len;
1033 else if (!strncmp(dcc[idx].type->name, "GET", 3))
1034 otraffic_trans_today += len;
1035 else
1036 otraffic_unknown_today += len;
1037 break;
1038 }
1039 }
1040
1041 if (socklist[i].handler.sock.outbuf != NULL) {
1042 /* Already queueing: just add it */
1043 p = (char *) nrealloc(socklist[i].handler.sock.outbuf, socklist[i].handler.sock.outbuflen + len);
1044 egg_memcpy(p + socklist[i].handler.sock.outbuflen, s, len);
1045 socklist[i].handler.sock.outbuf = p;
1046 socklist[i].handler.sock.outbuflen += len;
1047 return;
1048 }
1049 /* Try. */
1050 x = write(z, s, len);
1051 if (x == -1)
1052 x = 0;
1053 if (x < len) {
1054 /* Socket is full, queue it */
1055 socklist[i].handler.sock.outbuf = nmalloc(len - x);
1056 egg_memcpy(socklist[i].handler.sock.outbuf, &s[x], len - x);
1057 socklist[i].handler.sock.outbuflen = len - x;
1058 }
1059 return;
1060 }
1061 }
1062 /* Make sure we don't cause a crash by looping here */
1063 if (!inhere) {
1064 inhere = 1;
1065
1066 putlog(LOG_MISC, "*", "!!! writing to nonexistent socket: %d", z);
1067 s[strlen(s) - 1] = 0;
1068 putlog(LOG_MISC, "*", "!-> '%s'", s);
1069
1070 inhere = 0;
1071 }
1072 }
1073
1074 /* tputs might queue data for sockets, let's dump as much of it as
1075 * possible.
1076 */
1077 void dequeue_sockets()
1078 {
1079 int i, x;
1080
1081 int z = 0, fds;
1082 fd_set wfds;
1083 struct timeval tv;
1084
1085 /* ^-- start poptix test code, this should avoid writes to sockets not ready to be written to. */
1086 fds = getdtablesize();
1087
1088 #ifdef FD_SETSIZE
1089 if (fds > FD_SETSIZE)
1090 fds = FD_SETSIZE; /* Fixes YET ANOTHER freebsd bug!!! */
1091 #endif
1092 FD_ZERO(&wfds);
1093 tv.tv_sec = 0;
1094 tv.tv_usec = 0; /* we only want to see if it's ready for writing, no need to actually wait.. */
1095 for (i = 0; i < threaddata()->MAXSOCKS; i++) {
1096 if (!(socklist[i].flags & (SOCK_UNUSED | SOCK_TCL)) &&
1097 socklist[i].handler.sock.outbuf != NULL) {
1098 FD_SET(socklist[i].sock, &wfds);
1099 z = 1;
1100 }
1101 }
1102 if (!z)
1103 return; /* nothing to write */
1104
1105 select((SELECT_TYPE_ARG1) fds, SELECT_TYPE_ARG234 NULL,
1106 SELECT_TYPE_ARG234 &wfds, SELECT_TYPE_ARG234 NULL,
1107 SELECT_TYPE_ARG5 &tv);
1108
1109 /* end poptix */
1110
1111 for (i = 0; i < threaddata()->MAXSOCKS; i++) {
1112 if (!(socklist[i].flags & (SOCK_UNUSED | SOCK_TCL)) &&
1113 (socklist[i].handler.sock.outbuf != NULL) && (FD_ISSET(socklist[i].sock, &wfds))) {
1114 /* Trick tputs into doing the work */
1115 errno = 0;
1116 x = write(socklist[i].sock, socklist[i].handler.sock.outbuf, socklist[i].handler.sock.outbuflen);
1117 if ((x < 0) && (errno != EAGAIN)
1118 #ifdef EBADSLT
1119 && (errno != EBADSLT)
1120 #endif
1121 #ifdef ENOTCONN
1122 && (errno != ENOTCONN)
1123 #endif
1124 ) {
1125 /* This detects an EOF during writing */
1126 debug3("net: eof!(write) socket %d (%s,%d)", socklist[i].sock,
1127 strerror(errno), errno);
1128 socklist[i].flags |= SOCK_EOFD;
1129 } else if (x == socklist[i].handler.sock.outbuflen) {
1130 /* If the whole buffer was sent, nuke it */
1131 nfree(socklist[i].handler.sock.outbuf);
1132 socklist[i].handler.sock.outbuf = NULL;
1133 socklist[i].handler.sock.outbuflen = 0;
1134 } else if (x > 0) {
1135 char *p = socklist[i].handler.sock.outbuf;
1136
1137 /* This removes any sent bytes from the beginning of the buffer */
1138 socklist[i].handler.sock.outbuf = nmalloc(socklist[i].handler.sock.outbuflen - x);
1139 egg_memcpy(socklist[i].handler.sock.outbuf, p + x, socklist[i].handler.sock.outbuflen - x);
1140 socklist[i].handler.sock.outbuflen -= x;
1141 nfree(p);
1142 } else {
1143 debug3("dequeue_sockets(): errno = %d (%s) on %d", errno,
1144 strerror(errno), socklist[i].sock);
1145 }
1146 /* All queued data was sent. Call handler if one exists and the
1147 * dcc entry wants it.
1148 */
1149 if (!socklist[i].handler.sock.outbuf) {
1150 int idx = findanyidx(socklist[i].sock);
1151
1152 if (idx > 0 && dcc[idx].type && dcc[idx].type->outdone)
1153 dcc[idx].type->outdone(idx);
1154 }
1155 }
1156 }
1157 }
1158
1159
1160 /*
1161 * Debugging stuff
1162 */
1163
1164 void tell_netdebug(int idx)
1165 {
1166 int i;
1167 char s[80];
1168
1169 dprintf(idx, "Open sockets:");
1170 for (i = 0; i < threaddata()->MAXSOCKS; i++) {
1171 if (!(socklist[i].flags & SOCK_UNUSED)) {
1172 sprintf(s, " %d", socklist[i].sock);
1173 if (socklist[i].flags & SOCK_BINARY)
1174 strcat(s, " (binary)");
1175 if (socklist[i].flags & SOCK_LISTEN)
1176 strcat(s, " (listen)");
1177 if (socklist[i].flags & SOCK_PASS)
1178 strcat(s, " (passed on)");
1179 if (socklist[i].flags & SOCK_CONNECT)
1180 strcat(s, " (connecting)");
1181 if (socklist[i].flags & SOCK_STRONGCONN)
1182 strcat(s, " (strong)");
1183 if (socklist[i].flags & SOCK_NONSOCK)
1184 strcat(s, " (file)");
1185 if (socklist[i].flags & SOCK_TCL)
1186 strcat(s, " (tcl)");
1187 if (!(socklist[i].flags & SOCK_TCL)) {
1188 if (socklist[i].handler.sock.inbuf != NULL)
1189 sprintf(&s[strlen(s)], " (inbuf: %04X)",
1190 (unsigned int) strlen(socklist[i].handler.sock.inbuf));
1191 if (socklist[i].handler.sock.outbuf != NULL)
1192 sprintf(&s[strlen(s)], " (outbuf: %06lX)", socklist[i].handler.sock.outbuflen);
1193 }
1194 strcat(s, ",");
1195 dprintf(idx, "%s", s);
1196 }
1197 }
1198 dprintf(idx, " done.\n");
1199 }
1200
1201 /* Security-flavoured sanity checking on DCC connections of all sorts can be
1202 * done with this routine. Feed it the proper information from your DCC
1203 * before you attempt the connection, and this will make an attempt at
1204 * figuring out if the connection is really that person, or someone screwing
1205 * around. It's not foolproof, but anything that fails this check probably
1206 * isn't going to work anyway due to masquerading firewalls, NAT routers,
1207 * or bugs in mIRC.
1208 */
1209 int sanitycheck_dcc(char *nick, char *from, char *ipaddy, char *port)
1210 {
1211 /* According to the latest RFC, the clients SHOULD be able to handle
1212 * DNS names that are up to 255 characters long. This is not broken.
1213 */
1214
1215 char badaddress[16];
1216 IP ip = my_atoul(ipaddy);
1217 int prt = atoi(port);
1218
1219 /* It is disabled HERE so we only have to check in *one* spot! */
1220 if (!dcc_sanitycheck)
1221 return 1;
1222
1223 if (prt < 1) {
1224 putlog(LOG_MISC, "*", "ALERT: (%s!%s) specified an impossible port of %u!",
1225 nick, from, prt);
1226 return 0;
1227 }
1228 sprintf(badaddress, "%u.%u.%u.%u", (ip >> 24) & 0xff, (ip >> 16) & 0xff,
1229 (ip >> 8) & 0xff, ip & 0xff);
1230 if (ip < (1 << 24)) {
1231 putlog(LOG_MISC, "*", "ALERT: (%s!%s) specified an impossible IP of %s!",
1232 nick, from, badaddress);
1233 return 0;
1234 }
1235 return 1;
1236 }
1237
1238 int hostsanitycheck_dcc(char *nick, char *from, IP ip, char *dnsname,
1239 char *prt)
1240 {
1241 /* According to the latest RFC, the clients SHOULD be able to handle
1242 * DNS names that are up to 255 characters long. This is not broken.
1243 */
1244 char hostn[256], badaddress[16];
1245
1246 /* It is disabled HERE so we only have to check in *one* spot! */
1247 if (!dcc_sanitycheck)
1248 return 1;
1249 sprintf(badaddress, "%u.%u.%u.%u", (ip >> 24) & 0xff, (ip >> 16) & 0xff,
1250 (ip >> 8) & 0xff, ip & 0xff);
1251 /* These should pad like crazy with zeros, since 120 bytes or so is
1252 * where the routines providing our data currently lose interest. I'm
1253 * using the n-variant in case someone changes that...
1254 */
1255 strncpyz(hostn, extracthostname(from), sizeof hostn);
1256 if (!egg_strcasecmp(hostn, dnsname)) {
1257 putlog(LOG_DEBUG, "*", "DNS information for submitted IP checks out.");
1258 return 1;
1259 }
1260 if (!strcmp(badaddress, dnsname))
1261 putlog(LOG_MISC, "*", "ALERT: (%s!%s) sent a DCC request with bogus IP "
1262 "information of %s port %s. %s does not resolve to %s!", nick, from,
1263 badaddress, prt, from, badaddress);
1264 else
1265 return 1; /* <- usually happens when we have
1266 * a user with an unresolved hostmask! */
1267 return 0;
1268 }
1269
1270 /* Checks wether the referenced socket has data queued.
1271 *
1272 * Returns true if the incoming/outgoing (depending on 'type') queues
1273 * contain data, otherwise false.
1274 */
1275 int sock_has_data(int type, int sock)
1276 {
1277 int ret = 0, i;
1278
1279 for (i = 0; i < threaddata()->MAXSOCKS; i++)
1280 if (!(socklist[i].flags & SOCK_UNUSED) && socklist[i].sock == sock)
1281 break;
1282 if (i < threaddata()->MAXSOCKS) {
1283 switch (type) {
1284 case SOCK_DATA_OUTGOING:
1285 ret = (socklist[i].handler.sock.outbuf != NULL);
1286 break;
1287 case SOCK_DATA_INCOMING:
1288 ret = (socklist[i].handler.sock.inbuf != NULL);
1289 break;
1290 }
1291 } else
1292 debug1("sock_has_data: could not find socket #%d, returning false.", sock);
1293 return ret;
1294 }
1295
1296 /* flush_inbuf():
1297 * checks if there's data in the incoming buffer of an connection
1298 * and flushs the buffer if possible
1299 *
1300 * returns: -1 if the dcc entry wasn't found
1301 * -2 if dcc[idx].type->activity doesn't exist and the data couldn't
1302 * be handled
1303 * 0 if buffer was empty
1304 * otherwise length of flushed buffer
1305 */
1306 int flush_inbuf(int idx)
1307 {
1308 int i, len;
1309 char *inbuf;
1310
1311 Assert((idx >= 0) && (idx < dcc_total));
1312 for (i = 0; i < threaddata()->MAXSOCKS; i++) {
1313 if ((dcc[idx].sock == socklist[i].sock) &&
1314 !(socklist[i].flags & SOCK_UNUSED)) {
1315 len = socklist[i].handler.sock.inbuflen;
1316 if ((len > 0) && socklist[i].handler.sock.inbuf) {
1317 if (dcc[idx].type && dcc[idx].type->activity) {
1318 inbuf = socklist[i].handler.sock.inbuf;
1319 socklist[i].handler.sock.inbuf = NULL;
1320 dcc[idx].type->activity(idx, inbuf, len);
1321 nfree(inbuf);
1322 return len;
1323 } else
1324 return -2;
1325 } else
1326 return 0;
1327 }
1328 }
1329 return -1;
1330 }

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23