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

Last change on this file since 162 was 162, checked in by Sam Hocevar, 13 years ago

Fix numerous compiler warnings.

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