/* NET.C net functions especially for bots Robey Pointer, rpointe@eng.clemson.edu */ #include #include #include #include #include #include #include #include #include #include /* this is used by mtgets to store up data from various sockets until a \n is received -- set this relatively high so it won't have to throw away any data -- making this greater than or equal to the number of open sockets you expect to have at any given time is the smart way to go */ #define TABLESIZE 25 /* puts full hostname in s */ void getmyhostname(s) char *s; { struct hostent *hp; gethostname(s,80); hp=gethostbyname(s); if (hp==NULL) fatal("Can't find your hostname."); strcpy(s,hp->h_name); if (strchr(s,'.')==NULL) strcpy(s,hp->h_aliases[0]); } /* get my ip number */ unsigned long getmyip() { struct hostent *hp; char s[121]; unsigned long ip; struct in_addr *in; gethostname(s,80); hp=gethostbyname(s); if (hp==NULL) fatal("Can't find your hostname."); in=(struct in_addr *)(hp->h_addr_list[0]); ip=(unsigned long)(in->s_addr); return 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,"Signal canceled connection"); 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; case 0: strcpy(s,"Error 0"); break; default: sprintf(s,"Unforseen error %d",errno); break; } } /* connects to socket & returns file descriptor */ /* returns <0 if connection refused: */ /* -1 connection refused */ /* -2 can't resolve hostname */ int open_telnet(server,port) char *server; int port; { int sock,number,i; struct sockaddr_in name; struct hostent *hp; sock=socket(AF_INET,SOCK_STREAM,0); if (sock<0) fatal("Can't open a socket at all."); bzero(&name,sizeof(struct sockaddr_in)); name.sin_family=AF_INET; name.sin_port=port; number=1; i=strlen(server)-1; while ((server[i]!='.') && (i!=0)) { if ((server[i]<'0') || (server[i]>'9')) number=0; i--; } if (number) { unsigned char *p,*p1; unsigned long a; p1=(unsigned char *)&a; p1[0]=atoi(server); p=(unsigned char *)strchr(server,'.'); if (p!=NULL) p1[1]=atoi(p+1); if (p!=NULL) { p=(unsigned char *)strchr(p+1,'.'); if (p!=NULL) p1[2]=(char)atoi(p+1); } if (p!=NULL) { p=(unsigned char *)strchr(p+1,'.'); if (p!=NULL) p1[3]=(char)atoi(p+1); } if (p!=NULL) name.sin_addr.s_addr=a; else { close(sock); return -2; } } else { hp=gethostbyname(server); if (hp==NULL) { close(sock); return -2; } bcopy(hp->h_addr,&name.sin_addr.s_addr,hp->h_length); } if (connect(sock,(struct sockaddr *)&name,sizeof(struct sockaddr_in)) <0) { close(sock); sock=-1; } return sock; } /* returns a socket number for a listening socket that will accept any */ /* connection -- port # is returned in port */ int open_listen(port) int *port; { int sock,addrlen; struct sockaddr_in name; sock=socket(AF_INET,SOCK_STREAM,0); if (sock<0) fatal("Can't open a socket at all."); name.sin_family=AF_INET; name.sin_port=(*port); /* 0 = just assign us a port */ name.sin_addr.s_addr=INADDR_ANY; if (bind(sock,(struct sockaddr *)&name,sizeof(name))<0) { close(sock); return -1; } /* what port are we on? */ addrlen=sizeof(name); if (getsockname(sock,(struct sockaddr *)&name,&addrlen)<0) { close(sock); return -1; } *port=name.sin_port; if (listen(sock,1)<0) { close(sock); return -1; } return sock; } /* given network-style IP address, return hostname */ /* hostname will be "##.##.##.##" format if there was an error */ char *hostnamefromip(ip) unsigned long ip; { static char name[121]; struct hostent *hp; unsigned long addr=ip; unsigned char *p; hp=gethostbyaddr((char *)&addr,sizeof(addr),AF_INET); if (hp==NULL) { p=(unsigned char *)&addr; sprintf(name,"%u.%u.%u.%u",p[0],p[1],p[2],p[3]); } else strcpy(name,hp->h_name); return name; } /* 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) int sock; char *caller; { int new_sock,addrlen; struct sockaddr_in from; unsigned long ip; 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)); return new_sock; } /* like open_telnet, but uses server & port specifications of dcc */ int open_telnet_dcc(server,port) char *server,*port; { int p; unsigned long addr; char sv[121]; if (port!=NULL) p=atoi(port); else p=2000; if (server!=NULL) addr=atol(server); else addr=0L; strcpy(sv,hostnamefromip(addr)); return open_telnet(sv,p); } /* mtread: uh... see mtgets for info. this is just part of that. */ int mtread(socks,sockl,s,len) int socks,sockl[]; char *s; int *len; { fd_set fd; int i,j,k; struct timeval t; i=getdtablesize(); t.tv_sec=1; t.tv_usec=0; FD_ZERO(&fd); for (j=0; j0) FD_SET(sockl[j],&fd); else FD_SET(-sockl[j],&fd); } if (select(i,&fd,NULL,NULL,&t) > 0) { for (j=0; j0) *len = k; else *len = 1; return -1; } if (k>0) return k; else return 1; } } } else { s[0]=0; *len = 0; } return 0; } /* returns number of bytes read, or 0 if nothing received in past 1 second */ /* or -1 on eof (single-socket version of mtread) */ int tread(sock,s) int sock; char *s; { fd_set fd; int i; struct timeval t; i=getdtablesize(); t.tv_sec=1; t.tv_usec=0; FD_ZERO(&fd); FD_SET(sock,&fd); if (select(i,&fd,NULL,NULL,&t) > 0) { i=read(sock,s,511); s[i]=0; if (i==0) return -1; else return i; } else { s[0]=0; return 0; } } /* mtgets: a strange and complex function with four parameters: socks - number of items in sockl sockl - array of integers, these are the sockets to attempt reading from s - (char *) where mtgets puts the string len - (int *) attempts to read from all the sockets listed up to one second. if after one second, no complete data has been received from any of the sockets, s will be empty, len will be 0, and mtgets will return 0. mtgets will only return data from a socket when it gets an entire line terminated with a '\n', unless the socket is negative. for example, if you put -8 in the sockl array, it will return the first data it gets from socket 8, whether or not there's a '\n' in it. if there is returnable data received from any socket in the sockl array, the data will be in s (null-terminated if ascii), the length will be returned in len, and the socket number (positive) will be returned. if an EOF is detected from any of the sockets, that socket number will be put in len, and -1 will be returned. YOU MUST initialize the function first by calling it like so: mtgets(0,NULL,NULL,NULL); * the maximum length of the string returned is 512 (including null) * mtgets stores pent-up data in static buffers that it mallocs as it needs them (does not waste memory) -- see the #define at the top of this file to set the number of buffers available */ int mtgets(socks,sockl,s,len) int socks,sockl[]; char *s; int *len; { static char *bf[TABLESIZE]; static int bfs[TABLESIZE]; char xx[512]; char *p; int ret,i,j; if (socks==0) { for (i=0; i<20; i++) { bf[i]=NULL; bfs[i]=0; } return 0; } for (i=0; i<20; i++) if (bf[i]!=NULL) { p=strchr(bf[i],'\n'); if (p!=NULL) { j=bfs[i]; *p=0; strcpy(s,bf[i]); strcpy(xx,p+1); free(bf[i]); if (xx[0]) { bf[i]=(char *)malloc(strlen(xx)+1); strcpy(bf[i],xx); } else { bf[i]=NULL; bfs[i]=0; } if (s[strlen(s)-1]=='\r') s[strlen(s)-1]=0; *len = strlen(s); return j; } } *len=0; ret=mtread(socks,sockl,xx,len); if (ret<=0) { s[0]=0; return ret; } for (i=0; i