/* net.c -- handles: all raw network i/o This is hereby released into the public domain. Robey Pointer, robey@netcom.com */ #if HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #if HAVE_SYS_SELECT_H #include #endif #include #ifndef LINUX /* linux gets wacko if you include both */ #include #endif /* but virtually every other OS NEEDS both */ #include /* is this really necessary? */ #include #include #if HAVE_UNISTD_H #include #endif #include #include "eggdrop.h" #include "proto.h" #if !HAVE_GETDTABLESIZE #ifdef FD_SETSIZE #define getdtablesize() FD_SETSIZE #else #define getdtablesize() 64 #endif #endif #define STDOUT 1 #define STDIN 0 /* context support */ extern int cx_line; extern char cx_file[]; extern char SBUF[]; /* hostname can be specified in the config file */ char hostname[121]=""; /* IP can be specified in the config file */ char myip[121]=""; /* this is used by the net module to keep track of sockets and what's queued on them */ typedef struct { int sock; char flags; char *inbuf; char *outbuf; } sock_list; #define MAXSOCKS MAXDCC+10 sock_list socklist[MAXSOCKS]; /* enough to be safe */ /* i need an UNSIGNED long for dcc type stuff */ unsigned long my_atoul(s) char *s; { unsigned long ret=0L; while ((*s>='0') && (*s<='9')) { ret*=10L; ret+=((*s)-'0'); s++; } return ret; } /* i read somewhere that memcpy() is broken on some machines */ /* it's easy to replace, so i'm not gonna take any chances, because it's */ /* pretty important that it work correctly here */ void my_memcpy(dest,src,len) char *dest,*src; int len; { while (len--) *dest++=*src++; } /* bzero() is bsd-only, so here's one for non-bsd systems */ void my_bzero(dest,len) char *dest; int len; { while (len--) *dest++=0; } /* initialize the socklist */ void init_net() { int i; for (i=0; ih_name); if (strchr(s,'.')!=NULL) return; if (hp->h_aliases[0] == NULL) fatal("Can't determine your hostname!",0); strcpy(s,hp->h_aliases[0]); if (strchr(s,'.')==NULL) fatal("Can't determine your hostname!",0); } /* get my ip number */ unsigned long getmyip() { struct hostent *hp; char s[121]; unsigned long ip; struct in_addr *in; /* could be pre-defined */ if (myip[0]) { if ((myip[strlen(myip)-1] >= '0') && (myip[strlen(myip)-1] <= '9')) return (unsigned long)inet_addr(myip); } gethostname(s,120); hp=gethostbyname(s); if (hp==NULL) fatal("Hostname self-lookup failed.",0); in=(struct in_addr *)(hp->h_addr_list[0]); ip=(unsigned long)(in->s_addr); ip=htonl(ip); return (unsigned long)ip; } void neterror(s) char *s; { switch(errno) { case EADDRINUSE: strcpy(s,"Address already in use"); break; case EADDRNOTAVAIL: strcpy(s,"Address invalid on remote machine"); break; case EAFNOSUPPORT: strcpy(s,"Address family not supported"); break; case EALREADY: strcpy(s,"Socket already in use"); break; case EBADF: strcpy(s,"Socket descriptor is bad"); break; case ECONNREFUSED: strcpy(s,"Connection refused"); break; case EFAULT: strcpy(s,"Namespace segment violation"); break; case EINPROGRESS: strcpy(s,"Operation in progress"); break; case EINTR: strcpy(s,"Timeout"); break; case EINVAL: strcpy(s,"Invalid namespace"); break; case EISCONN: strcpy(s,"Socket already connected"); break; case ENETUNREACH: strcpy(s,"Network unreachable"); break; case ENOTSOCK: strcpy(s,"File descriptor, not a socket"); break; case ETIMEDOUT: strcpy(s,"Connection timed out"); break; case ENOTCONN: strcpy(s,"Socket is not connected"); break; case EHOSTUNREACH: strcpy(s,"Host is unreachable"); break; #ifdef ECONNRESET case ECONNRESET: strcpy(s,"Connection reset by peer"); break; #endif #ifdef EACCES case EACCES: strcpy(s,"Permission denied"); break; #endif case 0: strcpy(s,"Error 0"); break; default: sprintf(s,"Unforseen error %d",errno); break; } } /* request a normal socket for i/o */ void setsock(sock,options) int sock,options; { int i; int parm; for (i=0; i= '0') && (server[strlen(server)-1] <= '9')) name.sin_addr.s_addr=inet_addr(server); else { /* no, must be host.domain */ hp=gethostbyname(server); if (hp==NULL) { killsock(sock); return -2; } my_memcpy((char *)&name.sin_addr,hp->h_addr,hp->h_length); name.sin_family=hp->h_addrtype; } for (i=0; ih_name); return s; } /* short routine to answer a connect received on a socket made previously */ /* by open_listen ... returns hostname of the caller & the new socket */ /* does NOT dispose of old "public" socket! */ int answer(sock,caller,ip,binary) int sock; char *caller; unsigned long *ip; int binary; { int new_sock,addrlen; struct sockaddr_in from; addrlen=sizeof(struct sockaddr); new_sock=accept(sock,(struct sockaddr *)&from,&addrlen); if (new_sock<0) return -1; *ip=from.sin_addr.s_addr; strcpy(caller,hostnamefromip(*ip)); *ip=ntohl(*ip); /* set up all the normal socket crap */ setsock(new_sock,(binary ? SOCK_BINARY : 0)); return new_sock; } /* like open_telnet, but uses server & port specifications of dcc */ int open_telnet_dcc(sock,server,port) int sock; char *server,*port; { int p; unsigned long addr; char sv[121]; unsigned char c[4]; if (port!=NULL) p=atoi(port); else p=2000; if (server!=NULL) addr=my_atoul(server); else addr=0L; if (addr < (1<<24)) return -3; /* fake address */ c[0]=(addr/16777216); addr%=16777216; c[1]=(addr/65536); addr%=65536; c[2]=(addr/256); addr%=256; c[3]=addr; sprintf(sv,"%u.%u.%u.%u",c[0],c[1],c[2],c[3]); /* strcpy(sv,hostnamefromip(addr)); */ p=open_telnet_raw(sock,sv,p); return p; } /* all new replacements for mtgets/mtread */ /* attempts to read from all the sockets in socklist */ /* fills s with up to 511 bytes if available, and returns the array index */ /* on EOF, returns -1, with socket in len */ /* on socket error, returns -2 */ /* if nothing is ready, returns -3 */ int sockread(s,len) char *s; int *len; { fd_set fd; int fds,i,x; struct timeval t; fds=getdtablesize(); #ifdef FD_SETSIZE if (fds>FD_SETSIZE) fds=FD_SETSIZE; /* fixes YET ANOTHER freebsd bug!!! */ #endif /* timeout: 1 sec */ t.tv_sec=1; t.tv_usec=0; FD_ZERO(&fd); for (i=0; i0) { /* something happened */ for (i=0; i 510) socklist[i].inbuf[510]=0; strcpy(s,socklist[i].inbuf); px=(char *)nmalloc(strlen(p+1)+1); strcpy(px,p+1); nfree(socklist[i].inbuf); if (px[0]) socklist[i].inbuf=px; else { nfree(px); socklist[i].inbuf=NULL; } if (s[strlen(s)-1]=='\r') s[strlen(s)-1]=0; *len = strlen(s); /* <-- oh that looks so cute robey! :) */ return socklist[i].sock; } } } /* no pent-up data of any worth -- down to business */ context; *len=0; ret=sockread(xx,len); if (ret<0) { s[0]=0; return ret; } /* binary and listening sockets don't get buffered */ if (socklist[ret].flags & SOCK_CONNECT) { socklist[ret].flags &= ~SOCK_CONNECT; s[0]=0; return socklist[ret].sock; } if (socklist[ret].flags & SOCK_BINARY) { my_memcpy(s,xx,*len); return socklist[ret].sock; } if (socklist[ret].flags & SOCK_LISTEN) return socklist[ret].sock; context; /* might be necessary to prepend stored-up data! */ if (socklist[ret].inbuf != NULL) { p=socklist[ret].inbuf; socklist[ret].inbuf=(char *)nmalloc(strlen(p)+strlen(xx)+1); strcpy(socklist[ret].inbuf,p); strcat(socklist[ret].inbuf,xx); nfree(p); if (strlen(socklist[ret].inbuf) < 512) { strcpy(xx,socklist[ret].inbuf); nfree(socklist[ret].inbuf); socklist[ret].inbuf=NULL; } else { p=socklist[ret].inbuf; socklist[ret].inbuf=(char *)nmalloc(strlen(p)-509); strcpy(socklist[ret].inbuf,p+510); *(p+510)=0; strcpy(xx,p); nfree(p); /* (leave the rest to be post-pended later) */ } } context; /* look for EOL marker; if it's there, i have something to show */ p=strchr(xx,'\n'); if (p!=NULL) { *p=0; strcpy(s,xx); strcpy(xx,p+1); if (s[strlen(s)-1]=='\r') s[strlen(s)-1]=0; } else { s[0]=0; if (strlen(xx)>=510) { /* string is too long, so just insert fake \n */ strcpy(s,xx); xx[0]=0; } } context; /* anything left that needs to be saved? */ if (!xx[0]) { if (s[0]) return socklist[ret].sock; else return -3; } context; /* prepend old data back */ if (socklist[ret].inbuf != NULL) { p=socklist[ret].inbuf; socklist[ret].inbuf=(char *)nmalloc(strlen(p)+strlen(xx)+1); strcpy(socklist[ret].inbuf,xx); strcat(socklist[ret].inbuf,p); nfree(p); } else { socklist[ret].inbuf=(char *)nmalloc(strlen(xx)+1); strcpy(socklist[ret].inbuf,xx); } if (s[0]) return socklist[ret].sock; else return -3; } /* dump something to a socket */ void tputs(z,s) int z; char *s; { int i,x; char *p; if (z<0) return; /* um... HELLO?! sanity check please! */ if ((z==STDOUT) || (z==STDERR)) { write(z,s,strlen(s)); return; } for (i=0; i510) SBUF2[510]=0; /* server can only take so much */ tputs(sock,SBUF2); va_end(va); } /* DEBUGGING STUFF */ void tell_netdebug(idx) int idx; { int i; dprintf(idx,"Open sockets:"); for (i=0; i