1 /*
2   net.c
3 
4   - Updated : Completely dynamic allocation now (Brendan Grieve)
5 */
6 
7 
8 /* i read somewhere that memcpy() is broken on some machines */
9 /* it's easy to replace, so i'm not gonna take any chances, because it's
10 */
11 /* pretty important that it work correctly here */
my_memcpy(dest,src,len)12 void my_memcpy(dest,src,len)
13 char *dest,*src; int len;
14 {
15   while (len--) *dest++=*src++;
16 }
17 
18 /* bzero() is bsd-only, so here's one for non-bsd systems */
my_bzero(dest,len)19 void my_bzero(dest,len)
20 char *dest; int len;
21 {
22   while (len--) *dest++=0;
23 }
24 
25 /* initialize the socklist */
init_net()26 void init_net()
27 {
28 
29   socklist=NULL;
30 }
31 
32 
expmem_net()33 int expmem_net()
34 {
35   int tot=0;
36   struct sock_list *slist;
37 
38   slist=socklist;
39   while(slist!=NULL)
40     {
41       if (!(slist->flags & SOCK_UNUSED))
42         {
43           if (slist->inbuf != NULL) tot+=strlen(slist->inbuf)+1;
44           if (slist->outbuf != NULL) tot+=strlen(slist->outbuf)+1;
45         }
46       slist=slist->next;
47     }
48   return tot;
49 }
50 
51 /* puts full hostname in s */
getmyhostname(s)52 void getmyhostname(s)
53 char *s;
54 {
55   struct hostent *hp; char *p;
56 
57   p=getenv("HOSTNAME"); if (p!=NULL) {
58     strcpy(s,p); if (strchr(s,'.')!=NULL) return;
59   }
60   gethostname(s,80);
61   if (strchr(s,'.')!=NULL) return;
62   hp=gethostbyname(s);
63   if (hp==NULL)
64     fatal("Hostname self-lookup failed.",0);
65   strcpy(s,hp->h_name);
66   if (strchr(s,'.')!=NULL) return;
67   if (hp->h_aliases[0] == NULL)
68     fatal("Can't determine your hostname!",0);
69   strcpy(s,hp->h_aliases[0]);
70   if (strchr(s,'.')==NULL)
71     fatal("Can't determine your hostname!",0);
72 }
73 
74 /* get my ip number */
getmyip()75 IP getmyip()
76 {
77   struct hostent *hp; char s[121]; IP ip; struct in_addr *in;
78 
79   gethostname(s,120);
80   hp=gethostbyname(s);
81 
82   if (hp==NULL) fatal("Hostname self-lookup failed.",0);
83   in=(struct in_addr *)(hp->h_addr_list[0]);
84   ip=(IP)(in->s_addr);
85   return ip;
86 }
87 
neterror(s)88 void neterror(s)
89 char *s;
90 {
91   switch(errno) {
92   case EADDRINUSE:
93     strcpy(s,"Address already in use"); break;
94   case EADDRNOTAVAIL:
95     strcpy(s,"Address invalid on remote machine"); break;
96   case EAFNOSUPPORT:
97     strcpy(s,"Address family not supported"); break;
98   case EALREADY:
99     strcpy(s,"Socket already in use"); break;
100   case EBADF:
101     strcpy(s,"Socket descriptor is bad"); break;
102   case ECONNREFUSED:
103     strcpy(s,"Connection refused"); break;
104   case EFAULT:
105     strcpy(s,"Namespace segment violation"); break;
106   case EINPROGRESS:
107     strcpy(s,"Operation in progress"); break;
108   case EINTR:
109     strcpy(s,"Timeout"); break;
110   case EINVAL:
111     strcpy(s,"Invalid namespace"); break;
112   case EISCONN:
113     strcpy(s,"Socket already connected"); break;
114   case ENETUNREACH:
115     strcpy(s,"Network unreachable"); break;
116   case ENOTSOCK:
117     strcpy(s,"File descriptor, not a socket"); break;
118   case ETIMEDOUT:
119     strcpy(s,"Connection timed out"); break;
120   case ENOTCONN:
121     strcpy(s,"Socket is not connected"); break;
122   case EHOSTUNREACH:
123     strcpy(s,"Host is unreachable"); break;
124   case EPIPE:
125     strcpy(s,"Broken pipe"); break;
126 #ifdef ECONNRESET
127   case ECONNRESET:
128     strcpy(s,"Connection reset by peer"); break;
129 #endif
130 #ifdef EACCES
131   case EACCES:
132     strcpy(s,"Permission denied"); break;
133 #endif
134   case 0:
135     strcpy(s,"Error 0"); break;
136   default:
137     sprintf(s,"Unforseen error %d",errno); break;
138   }
139 }
140 
141 /* request a normal socket for i/o */
setsock(sock,options)142 void setsock(sock,options)
143 int sock,options;
144 {
145   int parm;
146   struct sock_list *slist;
147 
148   slist= malloc(sizeof(struct sock_list));
149   slist->next=socklist;
150   socklist=slist;
151 
152   socklist->inbuf=socklist->outbuf=NULL;
153   socklist->flags=options;
154   socklist->sock=sock;
155   if ( !(socklist->flags &SOCK_NONSOCK)) {
156       parm=1; setsockopt(sock,SOL_SOCKET,SO_KEEPALIVE,(void *)&parm,sizeof(int));
157       parm=0; setsockopt(sock,SOL_SOCKET,SO_LINGER,(void *)&parm,sizeof(int));
158     }
159   if (options & SOCK_LISTEN) {
160     /* Tris says this lets us grab the same port again next time */
161     parm=1; setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(void *)&parm,
162                        sizeof(int));
163   }
164   /* yay async i/o ! */
165   fcntl(sock,F_SETFL,O_NONBLOCK);
166   return;
167 }
168 
169 
getsock(options)170 int getsock(options)
171 int options;
172 {
173   int sock=socket(AF_INET,SOCK_STREAM,0);
174   if (sock<0) fatal("Can't open a socket at all!",0);
175   setsock(sock,options); return sock;
176 }
177 
178 /* done with a socket */
killsock(sock)179 void killsock(sock)
180 int sock;
181 {
182   struct sock_list *slist,*oslist;
183   dequeue_sockets();
184 
185   oslist=NULL;
186   slist=socklist;
187   while (slist!=NULL) {
188 
189     if (slist->sock==sock) {
190       close(slist->sock);
191       if (slist->inbuf != NULL) nfree(slist->inbuf);
192       if (slist->outbuf != NULL) nfree(slist->outbuf);
193       slist->flags=SOCK_UNUSED;
194       if (oslist == NULL)
195         {
196           socklist=slist->next;
197           free(slist);
198         }
199       else
200         {
201           oslist->next=slist->next;
202           free(slist);
203         }
204       return;
205     }
206     oslist=slist;
207     slist=slist->next;
208   }
209 }
210 
211 /* Connects and binds to a specific port+address */
212 /* Returns -1 if fail, or port # is return in port, and returns socket number */
open_listen_socket(port,bindip)213 int open_listen_socket(port,bindip)
214 int *port; char *bindip;
215 {
216   int sock,addrlen; struct sockaddr_in name;
217 
218   sock=getsock(SOCK_LISTEN);
219   my_bzero((char *)&name,sizeof(struct sockaddr_in));
220   name.sin_family=AF_INET;
221   name.sin_port=htons(*port);   /* 0 = just assign us a port */
222   name.sin_addr.s_addr=getip(bindip);
223   if (bind(sock,(struct sockaddr *)&name,sizeof(name))<0) {
224 printf("ERROR\n");
225     killsock(sock); return -1;
226   }
227   /* what port are we on? */
228   addrlen=sizeof(name);
229   if (getsockname(sock,(struct sockaddr *)&name,&addrlen)<0) {
230 printf("ERROR\n");
231     killsock(sock); return -1;
232   }
233   *port=ntohs(name.sin_port);
234   if (listen(sock,5)<0) { printf("Erk\n"); killsock(sock); return -1; }
235   return sock;
236 }
237 
238 /* returns a socket number for a listening socket that will accept any */
239 /* connection -- port # is returned in port */
open_listen(port)240 int open_listen(port)
241 int *port;
242 {
243   return(open_listen_socket(port,"0.0.0.0"));
244 
245 }
246 
247 /* given network-style IP address, return hostname */
248 /* hostname will be "##.##.##.##" format if there was an error */
hostnamefromip(ip)249 char *hostnamefromip(ip)
250 unsigned long ip;
251 {
252   struct hostent *hp; unsigned long addr=ip;
253   unsigned char *p; static char s[121];
254 /*  alarm(10);*/
255   hp=gethostbyaddr((char *)&addr,sizeof(addr),AF_INET); /*alarm(0);*/
256   if (hp==NULL) {
257     p=(unsigned char *)&addr;
258     sprintf(s,"%u.%u.%u.%u",p[0],p[1],p[2],p[3]);
259     return s;
260   }
261   strcpy(s,hp->h_name); return s;
262 }
263 
264 /* short routine to answer a connect received on a socket made previously
265 */
266 /* by open_listen ... returns hostname of the caller & the new socket */
267 /* does NOT dispose of old "public" socket! */
answer(sock,caller,ip,binary)268 int answer(sock,caller,ip,binary)
269 int sock; char *caller; unsigned long *ip; int binary;
270 {
271   int new_sock,addrlen; struct sockaddr_in from;
272   addrlen=sizeof(struct sockaddr);
273   new_sock=accept(sock,(struct sockaddr *)&from,&addrlen);
274   if (new_sock<0) return -1;
275   *ip=from.sin_addr.s_addr;
276   strcpy(caller,hostnamefromip(*ip));
277   *ip=ntohl(*ip);
278   /* set up all the normal socket crap */
279   setsock(new_sock,(binary ? SOCK_BINARY : 0));
280   return new_sock;
281 }
282 
283 /* attempts to read from all the sockets in socklist */
284 /* fills s with up to 1023 bytes if available, and returns 0 */
285 /* on EOF, returns -1, with socket in len */
286 /* on socket error, returns -2 */
287 /* if nothing is ready, returns -3 */
sockread(s,len,socket_list)288 int sockread(s,len,socket_list)
289 char *s; int *len;struct sock_list **socket_list;
290 {
291   fd_set fd; int fds,x;
292   struct timeval t;
293   int grab=1023;
294   struct sock_list *slist;
295   *socket_list=NULL;
296   fds=getdtablesize();
297 #ifdef FD_SETSIZE
298   if (fds>FD_SETSIZE) fds=FD_SETSIZE;    /* fixes YET ANOTHER freebsd
299 bug!!! */
300 #endif
301   /* timeout: 1 sec */
302   t.tv_sec=1; t.tv_usec=0; FD_ZERO(&fd);
303   slist=socklist;
304   while(slist!=NULL) {
305       if (!(slist->flags & SOCK_UNUSED)) {
306         FD_SET(slist->sock,&fd);
307       slist=slist->next;
308     }
309   }
310 #ifdef HPUX
311   x=select(fds,(int *)&fd,(int *)NULL,(int *)NULL,&t);
312 #else
313   x=select(fds,&fd,NULL,NULL,&t);
314 #endif
315   if (x>0) {
316     /* something happened */
317     slist=socklist;
318     while(slist!=NULL) {
319       if ((!(slist->flags & SOCK_UNUSED)) &&
320           ((FD_ISSET(slist->sock,&fd)) )) {
321         if (slist->flags & (SOCK_LISTEN|SOCK_CONNECT)) {
322           /* listening socket -- don't read, just return activity */
323           /* same for connection attempt */
324           if (!(slist->flags & SOCK_STRONGCONN)) {
325             s[0]=0; *len=0;
326             *socket_list=slist;
327             return 0;
328           }
329           /* (for strong connections, require a read to succeed first) */
330 
331         }
332         x=read(slist->sock,s,grab);
333         if (x<=0) {   /* eof */
334           *len=slist->sock;
335           slist->flags &= ~SOCK_CONNECT;
336           return -1;
337         }
338         s[x]=0; *len=x;
339         *socket_list=slist;
340         return 0;
341       }
342       slist=slist->next;
343     }
344 
345   }
346   else if (x==-1) return -2;   /* socket error */
347   else {
348     s[0]=0; *len = 0;
349   }
350   return -3;
351 }
352 
353 
354 /* sockgets: buffer and read from sockets
355 
356    attempts to read from all registered sockets for up to one second.  if
357      after one second, no complete data has been received from any of the
358      sockets, 's' will be empty, 'len' will be 0, and sockgets will return
359      -3.
360    if there is returnable data received from a socket, the data will be
361      in 's' (null-terminated if non-binary), the length will be returned
362      in len, and the socket number will be returned.
363    normal sockets have their input buffered, and each call to sockgets
364      will return one line terminated with a '\n'.  binary sockets are not
365      buffered and return whatever coems in as soon as it arrives.
366    listening sockets will return an empty string when a connection comes
367 in.
368      connecting sockets will return an empty string on a successful
369 connect,
370      or EOF on a failed connect.
371    if an EOF is detected from any of the sockets, that socket number will
372 be
373      put in len, and -1 will be returned.
374 
375    * the maximum length of the string returned is 1024 (including null)
376 */
377 
sockgets(s,len)378 int sockgets(s,len)
379 char *s; int *len;
380 {
381   char xx[1026],*p,*px; int ret;
382   struct sock_list *slist;
383 
384   /* check for stored-up data waiting to be processed */
385   slist=socklist;
386   while(slist!=NULL) {
387     if (!(slist->flags & SOCK_UNUSED) && (slist->inbuf != NULL)) {
388       /* look for \r too cos windows can't follow RFCs */
389       p=strchr(slist->inbuf,'\xff');
390       if (p==NULL) p=strchr(slist->inbuf,'\n');
391       if (p!=NULL) {
392         *p=0;
393         if (strlen(slist->inbuf) > 1022) slist->inbuf[1022]=0;
394         strcpy(s,slist->inbuf);
395         px=(char *)nmalloc(strlen(p+1)+1); strcpy(px,p+1);
396         nfree(slist->inbuf);
397         if (px[0]) slist->inbuf=px;
398         else { nfree(px); slist->inbuf=NULL; }
399         /* strip CR if this was CR/LF combo */
400         /* strip FF */
401         if (s[strlen(s)]=='\xff') s[strlen(s)]=0;
402         if (s[strlen(s)]=='\n') s[strlen(s)]=0;
403         *len = strlen(s);       /* <-- oh that looks so cute robey! :) */
404         return slist->sock;
405       }
406     }
407     slist=slist->next;
408   }
409   /* no pent-up data of any worth -- down to business */
410   *len=0;
411   slist=NULL;
412   ret=sockread(xx,len,&slist);
413   if (ret<0) { s[0]=0; return ret; }
414   /* binary and listening sockets don't get buffered */
415   if (slist->flags & SOCK_CONNECT) {
416     if (slist->flags & SOCK_STRONGCONN) {
417       slist->flags &= ~SOCK_STRONGCONN;
418       /* buffer any data that came in, for future read */
419 /*      slist->inbuf=(char *)nmalloc(strlen(xx)+1);
420       strcpy(slist->inbuf,xx);*/
421     }
422     slist->flags &= ~SOCK_CONNECT;
423     s[0]=0; return slist->sock;
424   }
425   if (slist->flags & SOCK_BINARY) {
426     my_memcpy(s,xx,*len);
427     return slist->sock;
428   }
429   if (slist->flags & SOCK_LISTEN) return slist->sock;
430   /* might be necessary to prepend stored-up data! */
431   if (slist->inbuf != NULL) {
432     p=slist->inbuf;
433     slist->inbuf=(char *)nmalloc(strlen(p)+strlen(xx)+1);
434     strcpy(slist->inbuf,p); strcat(slist->inbuf,xx);
435     nfree(p);
436     if (strlen(slist->inbuf) < 1024) {
437       strcpy(xx,slist->inbuf);
438       nfree(slist->inbuf); slist->inbuf=NULL;
439     }
440     else {
441       p=slist->inbuf;
442       slist->inbuf=(char *)nmalloc(strlen(p)-1021);
443       strcpy(slist->inbuf,p+1022); *(p+1022)=0; strcpy(xx,p);
444 nfree(p);
445       /* (leave the rest to be post-pended later) */
446     }
447   }
448   /* look for EOL marker; if it's there, i have something to show */
449   p=strchr(xx,'\xff');
450 /*  if (p==NULL) p=strchr(xx,'\r');*/
451   if (p==NULL) p=strchr(xx,'\n');
452   if (p!=NULL) {
453     *p=0; strcpy(s,xx); strcpy(xx,p+1);
454 /*    if (s[strlen(s)-1]=='\r') s[strlen(s)-1]=0;*/
455     if (s[strlen(s)]=='\xff') s[strlen(s)]=0;
456     if (s[strlen(s)]=='\n') s[strlen(s)]=0;
457   }
458   else {
459     s[0]=0;
460     if (strlen(xx)>=1022) {
461       /* string is too long, so just insert fake \n */
462       strcpy(s,xx); xx[0]=0;
463     }
464   }
465 
466   *len = strlen(s);
467   /* anything left that needs to be saved? */
468   if (!xx[0]) { if (s[0]) return slist->sock; else return -3; }
469 
470   /* prepend old data back */
471   if (slist->inbuf != NULL) {
472     p=slist->inbuf;
473     slist->inbuf=(char *)nmalloc(strlen(p)+strlen(xx)+1);
474     strcpy(slist->inbuf,xx); strcat(slist->inbuf,p);
475     nfree(p);
476   }
477   else {
478     slist->inbuf=(char *)nmalloc(strlen(xx)+1);
479     strcpy(slist->inbuf,xx);
480   }
481   if (s[0]) return slist->sock; else return -3;
482 }
483 
484 
485 /* dump something to a socket */
tputs(z,s)486 void tputs(z,s)
487 int z; char *s;
488 {
489   int x; char *p;
490   struct sock_list *slist;
491   if (z<0) return;   /* um... HELLO?!  sanity check please! */
492 
493   slist=socklist;
494   while(slist!=NULL) {
495     if (!(slist->flags & SOCK_UNUSED) && (slist->sock==z)) {
496       if (slist->outbuf != NULL) {
497         /* already queueing: just add it */
498         p=(char *)nmalloc(strlen(slist->outbuf)+strlen(s)+1);
499         strcpy(p,slist->outbuf); strcat(p,s);
500         nfree(slist->outbuf); slist->outbuf=p;
501         return;
502       }
503 
504       x=write(z,s,strlen(s));
505       if (x==(-1)) x=0;
506       if (x < strlen(s)) {
507         /* socket is full, queue it */
508         slist->outbuf=(char *)nmalloc(strlen(s)-x+1);
509         strcpy(slist->outbuf,&s[x]);
510       }
511       return;
512     }
513     slist=slist->next;
514   }
515 }
516 
517 /* tputs might queue data for sockets, let's dump as much of it as */
518 /* possible */
dequeue_sockets()519 void dequeue_sockets()
520 {
521   char *p;
522   struct sock_list *slist;
523 
524   slist=socklist;
525   while(slist!=NULL) {
526     if (!(slist->flags & SOCK_UNUSED) && (slist->outbuf != NULL)) {
527       /* trick tputs into doing the work */
528       p=slist->outbuf;
529       slist->outbuf=NULL;
530       tputs(slist->sock,p); nfree(p);
531     }
532     slist=slist->next;
533   }
534 }
535 
536 /* like fprintf, but instead of preceding the format string with a FILE
537    pointer, precede with a socket number */
538 /* please stop using this one except for server output.  dcc output
539    should now use dprintf(idx,"format",[params]);   */
tprintf(int sock,char * format,...)540 void tprintf(int sock, char *format, ...)
541 {
542   va_list va; static char SBUF2[1050];
543   va_start(va, format);
544   vsprintf(SBUF2,format,va);
545   if (strlen(SBUF2)>1022)
546  {
547     SBUF2[1022]=0;   /* server can only take so much */
548  }
549   tputs(sock,SBUF2);
550   if (strlen(SBUF2) > 3) lvprintf(10,"Tprintf(%d): %s\n", sock, SBUF2);
551   va_end(va);
552 }
553 
554 
getip(char * s)555 IP getip(char *s)
556 {
557   struct hostent *hp; IP ip; struct in_addr *in;
558 
559   hp=gethostbyname(s);
560 
561   if (hp==NULL)
562     ip=0;
563   else
564     {
565       in=(struct in_addr *)(hp->h_addr_list[0]);
566       ip=(IP)(in->s_addr);
567     }
568   return ip;
569 }
570 
571