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

Last change on this file since 555 was 555, checked in by Sam Hocevar, 10 years ago

ps3: make everything compile on the PS3. Of course, nothing links yet
because so much support is missing.

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