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

Last change on this file since 494 was 494, checked in by Sam Hocevar, 11 years ago

style: remove trailing spaces, fix copyright statements.

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