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

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

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


Revision 1.1.1.1 - (hide annotations) (download) (as text) (vendor branch)
Mon Jul 26 21:11:06 2010 UTC (9 years, 2 months ago) by simple
Branch: eggheads
CVS Tags: v1
Changes since 1.1: +0 -0 lines
File MIME type: text/x-chdr
Imported Eggdrop 1.6.20

1 simple 1.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