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