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

Last change on this file since 651 was 651, checked in by Sam Hocevar, 12 years ago

build: add a --disable-network compilation flag and get rid of most of
the CELLOS_LV2 ifdefs.

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