source: abuse/trunk/src/net/tcpip.cpp @ 94

Last change on this file since 94 was 94, checked in by Sam Hocevar, 14 years ago
  • Prevent a crash if create_listen_socket() fails.
File size: 14.8 KB
Line 
1/*
2 *  Abuse - dark 2D side-scrolling platform game
3 *  Copyright (c) 1995 Crack dot Com
4 *
5 *  This software was released into the Public Domain. As with most public
6 *  domain software, no warranty is made or implied by Crack dot Com or
7 *  Jonathan Clark.
8 */
9
10#include "config.h"
11
12#ifdef _AIX
13#include <strings.h>
14#endif
15#include <ctype.h>
16
17#if (defined(__APPLE__) && !defined(__MACH__))
18#   include "GUSI.h"
19#endif
20#include "tcpip.hpp"
21
22extern tcpip_protocol tcpip;
23
24//#define TCPIP_DEBUG
25
26//{{{ net logging stuff
27/*
28FILE *log_file=NULL;
29extern int net_start();
30void net_log(char *st, void *buf, long size)
31{
32   
33  if (!log_file)
34  {
35    if (net_start())
36      log_file=fopen("client.log","wb");
37    else
38      log_file=fopen("server.log","wb");
39  }
40
41
42    fprintf(log_file,"%s%d - ",st,size);
43    int i;
44    for (i=0;i<size;i++)
45      if (isprint(*((unsigned char *)buf+i)))
46        fprintf(log_file,"%c",*((unsigned char *)buf+i));
47      else fprintf(log_file,"~");
48
49    fprintf(log_file," : ");
50
51    for (i=0;i<size;i++)
52    fprintf(log_file,"%02x, ",*((unsigned char *)buf+i),*((unsigned char *)buf+i));
53    fprintf(log_file,"\n");
54    fflush(log_file);
55
56} */
57//}}}
58
59////////////////////////////////////////////////////////////////////////
60//
61//  unix_fd methods
62//
63
64int unix_fd::read(void *buf, int size, net_address **addr)
65//{{{
66{
67  int tr=::read(fd,(char*)buf,size);
68  if (addr) *addr=NULL;
69  return tr;
70}
71//}}}///////////////////////////////////
72
73int unix_fd::write(void const *buf, int size, net_address *addr)
74//{{{
75{
76  if (addr) fprintf(stderr,"Cannot change address for this socket type\n");
77  return ::write(fd,(char*)buf,size);
78}
79//}}}///////////////////////////////////
80
81void unix_fd::broadcastable()
82//{{{
83{
84  int zz;
85  if (setsockopt(fd,SOL_SOCKET,SO_BROADCAST,(char *)&zz,sizeof(zz))<0)
86  {
87    fprintf(stderr,"could not set socket option broadcast");
88    return;
89  }
90}
91//}}}///////////////////////////////////
92
93////////////////////////////////////////////////////////////////////////
94//
95//  tcpip_protocol methods
96//
97
98net_address *tcpip_protocol::get_local_address()
99//{{{
100{
101#if 0
102        struct hostent *l_hn=gethostent();
103
104        ip_address *a=new ip_address();
105        memset(&a->addr,0,sizeof(a->addr));
106        memcpy(&a->addr.sin_addr,*l_hn->h_addr_list,4); 
107
108        return a; 
109#else
110  char my_name[100];                                            // check to see if this address is 'hostname'
111  gethostname(my_name,100);
112  //ip_address *ret = 0;
113 
114  if (my_name[0]<'0' || my_name[0]>'9')
115  {
116        struct hostent *l_hn=gethostbyname(my_name);
117       
118        if (l_hn)
119        {
120                ip_address *a=new ip_address();
121                memset(&a->addr,0,sizeof(a->addr));
122                memcpy(&a->addr.sin_addr,*l_hn->h_addr_list,4); 
123       
124                return a;
125          }
126          else
127          {
128                  printf("Enter ip address:");
129                  fgets(my_name, sizeof( my_name ), stdin );
130          }
131        } 
132
133  char tmp[4];
134  char const *np;
135  sockaddr_in host;
136 
137  np = my_name;
138  for (int i=0; i<4; i++)
139  {
140    int num = 0;
141    while (*np)
142    {
143      if (*np=='.')
144      {
145        np++;
146        break;
147      }
148      num = num*10 + *np - '0';
149      np++;
150    }
151    tmp[i] = num;
152  }
153 
154  memset( (char*) &host,0, sizeof(host));
155  host.sin_family = AF_INET;
156  host.sin_addr.s_addr = htonl(INADDR_ANY);
157  memcpy(&host.sin_addr,tmp,sizeof(in_addr));
158 
159        return new ip_address(&host);
160#endif
161}
162//}}}///////////////////////////////////
163
164net_address *tcpip_protocol::get_node_address(char const *&server_name,
165                                                                                                                                                                                        int def_port, int force_port)
166//{{{
167{
168    sockaddr_in host;
169
170    if (server_name[0]>='0' && server_name[0]<='9')
171    {
172        char tmp[4];
173        char const *np;
174         
175          np = server_name;
176          for (int i=0; i<4; i++)
177          {
178            int num = 0;
179            while (*np && *np!=':')
180            {
181              if (*np=='.')
182              {
183                np++;
184                break;
185              }
186              num = num*10 + *np - '0';
187              np++;
188            }
189            tmp[i] = num;
190            if (*np == ':' & !force_port)
191            {
192                int x;
193              if (sscanf(np+1,"%d",&x)==1)
194                def_port=x;
195                  }
196          }
197         
198          memset( (char*) &host,0, sizeof(host));
199          host.sin_family = AF_INET;
200          host.sin_port = htons(def_port);
201          host.sin_addr.s_addr = htonl(INADDR_ANY);
202          memcpy(&host.sin_addr,tmp,sizeof(in_addr));
203         
204          return new ip_address(&host);
205        }
206        else
207        {
208          char name[256], *np;
209
210          np=name;
211          while (*server_name && *server_name!=':' && *server_name!='/')
212            *(np++)=*(server_name)++;
213          *np=0;
214          if (*server_name==':')
215          {
216            server_name++;
217            char port[256],*p;
218            p=port;
219            while (*server_name && *server_name!='/')
220              *(p++)=*(server_name++);
221            *p=0;
222            int x;
223            if (!force_port)
224            {
225              if (sscanf(port,"%d",&x)==1) def_port=x;
226              else return 0;
227            }
228          }
229       
230          if (*server_name=='/') server_name++;
231       
232          hostent *hp=gethostbyname(name);
233          if (!hp)
234          {
235            fprintf(stderr,"unable to locate server named '%s'\n",name);
236            return 0;
237          }
238         
239          memset( (char*) &host,0, sizeof(host));
240          host.sin_family = AF_INET;
241          host.sin_port = htons(def_port);
242          host.sin_addr.s_addr = htonl(INADDR_ANY);
243          memcpy(&host.sin_addr,hp->h_addr,hp->h_length);
244        }
245  return new ip_address(&host);
246}
247//}}}///////////////////////////////////
248
249net_socket *tcpip_protocol::connect_to_server(net_address *addr, net_socket::socket_type sock_type)
250//{{{
251{
252  if (addr->protocol_type()!=net_address::IP)
253  {
254    fprintf(stderr,"Procotol type not supported in the executable\n");
255    return NULL;
256  }
257
258  int socket_fd=socket(AF_INET,sock_type==net_socket::SOCKET_SECURE ? SOCK_STREAM : SOCK_DGRAM,0);
259  if (socket_fd<0)
260  {
261    fprintf(stderr,"unable to create socket (too many open files?)\n");
262    return 0;
263  }
264
265#if (defined(__APPLE__) && !defined(__MACH__))
266  int zz;
267  if (setsockopt(socket_fd,SOL_SOCKET,SO_REUSEADDR,(char *)&zz,sizeof(zz))<0)
268  {
269    fprintf(stderr,"could not set socket option reuseaddr");
270    return 0;
271  }
272#endif
273   
274  if (connect(socket_fd, (struct sockaddr *) &((ip_address *)addr)->addr, sizeof( ((ip_address *)addr)->addr ))==-1)
275  {
276    fprintf(stderr,"unable to connect\n");
277    close(socket_fd);
278    return 0;
279  }
280
281  if (sock_type==net_socket::SOCKET_SECURE)
282    return new tcp_socket(socket_fd);
283  else
284    return new udp_socket(socket_fd);
285}
286//}}}///////////////////////////////////
287
288net_socket *tcpip_protocol::create_listen_socket(int port, net_socket::socket_type sock_type)
289//{{{
290{
291  int socket_fd=socket(AF_INET,sock_type==net_socket::SOCKET_SECURE ? SOCK_STREAM : SOCK_DGRAM,0);
292  if (socket_fd<0)
293  {
294    fprintf(stderr,"unable to create socket (too many open files?)\n");
295    return 0;
296  }
297
298#if (defined(__APPLE__) && !defined(__MACH__))
299  int zz;
300  if (setsockopt(socket_fd,SOL_SOCKET,SO_REUSEADDR,(char *)&zz,sizeof(zz))<0)
301  {
302    fprintf(stderr,"could not set socket option reuseaddr");
303    return 0;
304  }
305#endif
306
307  net_socket *s;
308  if (sock_type==net_socket::SOCKET_SECURE)
309    s=new tcp_socket(socket_fd);
310  else s=new udp_socket(socket_fd);
311  if (s->listen(port)==0)
312  {   
313    delete s;
314    return 0;
315  }
316
317  return s;
318}
319//}}}///////////////////////////////////
320
321net_socket *tcpip_protocol::start_notify(int port, void *data, int len)
322//{{{
323{
324        if (responder)
325        {
326                delete responder;
327                delete bcast;
328                responder = 0;
329        }
330       
331        int resp_len = strlen(notify_response);
332  notify_len = len + resp_len + 1;
333  strcpy(notify_data,notify_response);
334        notify_data[resp_len] = '.';
335  memcpy(notify_data+resp_len+1,data,len);
336 
337  // create notifier socket
338#ifdef TCPIP_DEBUG
339        fprintf(stderr,"Creating notifier on port %d\n",port);
340#endif
341  notifier = create_listen_socket(port, net_socket::SOCKET_FAST);
342 
343  if (notifier)
344  {
345    notifier->read_selectable();
346    notifier->write_unselectable();
347  }
348  else
349                fprintf(stderr,"Couldn't start notifier\n");
350 
351  return notifier;
352}
353//}}}///////////////////////////////////
354
355void tcpip_protocol::end_notify()
356//{{{
357{
358  if (notifier)
359    delete notifier;
360  notifier = 0;
361
362  notify_len = 0;
363}
364//}}}///////////////////////////////////
365
366int tcpip_protocol::handle_notification()
367//{{{
368{
369  if (!notifier)
370    return 0;
371   
372  if (notifier->ready_to_read())
373  {
374    char buf[513];
375    int len;
376    // got a notification request "broadcast"
377    ip_address *addr;
378    net_address *tmp;
379
380#ifdef TCPIP_DEBUG
381                printf("Notifier: ");
382#endif
383
384    len = notifier->read(buf, 512, &tmp);
385    addr = (ip_address *)tmp;
386#ifdef TCPIP_DEBUG
387                if (len>0) {
388                        buf[len] = 0;
389                        printf("[%s] ",buf);
390                }
391#endif
392    if (addr && len>0)
393    {
394                        buf[len] = 0;
395      if  (strcmp(buf, notify_signature)==0) {
396#ifdef TCPIP_DEBUG
397                                char s[256];
398                                addr->store_string(s,256);
399                                printf("responding to %s",s);
400#endif
401        // send notification data to requester
402        notifier->write(notify_data,notify_len,addr);
403                        }
404       
405      delete addr;
406    }
407#ifdef TCPIP_DEBUG
408                printf("\n");
409#endif
410    return 1;
411  }
412  if (notifier->error())
413  {
414    fprintf(stderr,"Error on notification socket!\n");
415    return 1;
416  }
417
418  return 0;
419}
420//}}}///////////////////////////////////
421
422net_address *tcpip_protocol::find_address(int port, char *name)
423//{{{
424{
425  // name should be a 256 byte buffer
426        char s[256];
427
428        end_notify();
429
430    if (!responder)
431    {
432//#ifdef TCPIP_DEBUG
433        fprintf(stderr,"Creating responder on port %d\n",port);
434//#endif
435        responder = create_listen_socket(port, net_socket::SOCKET_FAST);
436        if(responder)
437        {
438            responder->read_selectable();
439            responder->write_unselectable();
440            bcast = (ip_address *)get_local_address();
441            bcast->set_port(port);
442   
443//#ifdef TCPIP_DEBUG
444            *((unsigned char *)(&bcast->addr.sin_addr)+3) = 255;
445            bcast->store_string(s,256);
446            fprintf(stderr,"Simulating broadcast to [%s]\n",s);
447//#endif
448
449            *((unsigned char *)(&bcast->addr.sin_addr)+3) = 0;         
450        }
451    }
452
453  if (responder)
454  {
455    int i;
456   
457    for (i=0; i<5; i++)
458    {
459#ifdef TCPIP_DEBUG
460                        bcast->store_string(s,256);
461                        fprintf(stderr,"\r[%s]",s);
462#endif
463            int found = 0;
464           
465            for (p_request p = servers.begin(); !found && p!=servers.end(); ++p)
466                if ( *((*p)->addr) == *bcast )
467                        found = 1;
468            for (p_request q = returned.begin(); !found && q!=returned.end(); ++q)
469                if ( *((*q)->addr) == *bcast )
470                        found = 1;
471                       
472                        if (!found) {
473                                responder->write((void*)notify_signature,
474                                                                                                 strlen(notify_signature),bcast);
475                                select(0);
476                        }
477            *((unsigned char *)(&bcast->addr.sin_addr)+3) += 1;
478       
479            select(0);
480           
481            if (!servers.empty())
482                break;
483                }
484  }
485 
486  if (servers.empty())
487    return 0;
488
489  servers.move_next(servers.begin_prev(), returned.begin_prev());
490        ip_address *ret = (ip_address*)(*returned.begin())->addr->copy();
491        strcpy(name,(*returned.begin())->name);
492
493#ifdef TCPIP_DEBUG
494        ret->store_string(s,256);
495        fprintf(stderr,"Found [%s]\n",s);
496#endif
497
498  return ret;
499}
500//}}}///////////////////////////////////
501
502void tcpip_protocol::reset_find_list()
503//{{{
504{
505        p_request p;
506       
507        for (p=servers.begin(); p!=servers.end(); ++p)
508                delete (*p)->addr;
509        for (p=returned.begin(); p!=returned.end(); ++p)
510                delete (*p)->addr;
511               
512  servers.erase_all();
513  returned.erase_all();
514}
515//}}}///////////////////////////////////
516
517int tcpip_protocol::handle_responder()
518//{{{
519{
520  if (!responder)
521    return 0;
522   
523  if (responder->ready_to_read())
524  {
525    char buf[513];
526    int len;
527    // got a notification response
528    ip_address *addr;
529    net_address *tmp;
530
531#ifdef TCPIP_DEBUG
532                fprintf(stderr,"Responder: ");
533#endif
534
535    len = responder->read(buf, 512, &tmp);
536    addr = (ip_address *)tmp;
537
538#ifdef TCPIP_DEBUG
539                if (len>0) {
540                        buf[len] = 0;
541                        fprintf(stderr,"[%s] ",buf);
542                }
543#endif
544    if (addr && len>0)
545    {
546        buf[len] = 0;
547      buf[4] = 0;                                                                                               // ack! hard coded numbers for now
548      if (strcmp(buf,notify_response)==0)
549      {
550        int found=0;
551        for (p_request p = servers.begin(); !found && p!=servers.end(); ++p)
552                if ( *((*p)->addr) == *addr)
553                        found = 1;
554                    for (p_request q = returned.begin(); !found && q!=returned.end(); ++q)
555                        if ( *((*q)->addr) == *addr )
556                                found = 1;
557                       
558        if (!found)
559        {
560#ifdef TCPIP_DEBUG
561                                        char s[256];
562#endif
563                                        RequestItem *r = new RequestItem;
564                                        r->addr = addr;
565                                        strcpy(r->name,buf+5);                                  // ack hard coded numbers for now
566              servers.insert(r);
567#ifdef TCPIP_DEBUG
568                                        addr->store_string(s,256);
569                                        fprintf(stderr,"accepted %s",s);
570#endif
571                                }
572                        }
573      else {
574        delete addr;
575                        }
576    }
577#ifdef TCPIP_DEBUG
578    fprintf(stderr,"\n");
579#endif
580
581    return 1;
582  }
583  if (responder->error())
584  {
585    fprintf(stderr,"Error on responder socket!\n");
586    return 1;
587  }
588
589  return 0;
590}
591//}}}///////////////////////////////////
592
593tcpip_protocol::tcpip_protocol()
594//{{{
595  : notifier(0), notify_len(0), responder(0)
596{
597#if (defined(__APPLE__) && !defined(__MACH__))
598  GUSISetup(GUSIwithSIOUXSockets);
599  GUSISetup(GUSIwithPPCSockets);
600#endif 
601  FD_ZERO(&master_set); 
602  FD_ZERO(&master_write_set); 
603  FD_ZERO(&read_set);
604  FD_ZERO(&exception_set);
605  FD_ZERO(&write_set);
606}
607//}}}///////////////////////////////////
608
609int tcpip_protocol::select(int block)
610//{{{
611{
612  int ret;
613 
614  memcpy(&read_set,&master_set,sizeof(master_set));
615  memcpy(&exception_set,&master_set,sizeof(master_set));
616  memcpy(&write_set,&master_write_set,sizeof(master_set));
617  if (block)
618  {
619    ret = 0;
620    while (ret == 0) {
621      // get number of sockets ready from system call
622      ret = ::select(FD_SETSIZE,&read_set,&write_set,&exception_set,NULL);
623
624      // remove notifier & responder events from the count of sockets selected
625      if (handle_notification())
626        ret--;
627      if (handle_responder())
628        ret--;
629    }
630  }
631  else
632  {
633    timeval tv={0,0};
634    // get number of sockets ready from system call
635    ret = ::select(FD_SETSIZE,&read_set,&write_set,&exception_set,&tv);
636
637    // remove notifier & responder events from the count of sockets selected
638    if (handle_notification())
639      ret--;
640    if (handle_responder())
641      ret--;
642  }
643  return ret;
644}
645//}}}///////////////////////////////////
646
647void tcpip_protocol::cleanup()
648//{{{
649{
650        if (notifier)
651                end_notify();
652               
653        reset_find_list();
654               
655        if (responder) {
656                delete responder;
657                delete bcast;
658                responder = 0;
659        }
660}
661//}}}///////////////////////////////////
662
663//{{{ Revision Log
664/*//////////////////////////////////////////////////////////////////////
665$Log$
666//////////////////////////////////////////////////////////////////////
667*/
668//}}}
669
670//{{{ Emacs Locals
671// Local Variables:
672// folded-file: t
673// End:
674//}}}
675
Note: See TracBrowser for help on using the repository browser.