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

Last change on this file since 56 was 56, checked in by Sam Hocevar, 14 years ago
  • Add licensing terms to most C / C++ files (Ref #5).
File size: 14.6 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//#ifdef TCPIP_DEBUG
432                fprintf(stderr,"Creating responder on port %d\n",port);
433//#endif
434    responder = create_listen_socket(port, net_socket::SOCKET_FAST);
435                responder->read_selectable();
436                responder->write_unselectable();
437    bcast = (ip_address *)get_local_address();
438    bcast->set_port(port);
439   
440//#ifdef TCPIP_DEBUG
441                *((unsigned char *)(&bcast->addr.sin_addr)+3) = 255;
442                bcast->store_string(s,256);
443                fprintf(stderr,"Simulating broadcast to [%s]\n",s);
444//#endif
445
446                *((unsigned char *)(&bcast->addr.sin_addr)+3) = 0;             
447        }
448
449  if (responder)
450  {
451    int i;
452   
453    for (i=0; i<5; i++)
454    {
455#ifdef TCPIP_DEBUG
456                        bcast->store_string(s,256);
457                        fprintf(stderr,"\r[%s]",s);
458#endif
459            int found = 0;
460           
461            for (p_request p = servers.begin(); !found && p!=servers.end(); ++p)
462                if ( *((*p)->addr) == *bcast )
463                        found = 1;
464            for (p_request q = returned.begin(); !found && q!=returned.end(); ++q)
465                if ( *((*q)->addr) == *bcast )
466                        found = 1;
467                       
468                        if (!found) {
469                                responder->write((void*)notify_signature,
470                                                                                                 strlen(notify_signature),bcast);
471                                select(0);
472                        }
473            *((unsigned char *)(&bcast->addr.sin_addr)+3) += 1;
474       
475            select(0);
476           
477            if (!servers.empty())
478                break;
479                }
480  }
481 
482  if (servers.empty())
483    return 0;
484
485  servers.move_next(servers.begin_prev(), returned.begin_prev());
486        ip_address *ret = (ip_address*)(*returned.begin())->addr->copy();
487        strcpy(name,(*returned.begin())->name);
488
489#ifdef TCPIP_DEBUG
490        ret->store_string(s,256);
491        fprintf(stderr,"Found [%s]\n",s);
492#endif
493
494  return ret;
495}
496//}}}///////////////////////////////////
497
498void tcpip_protocol::reset_find_list()
499//{{{
500{
501        p_request p;
502       
503        for (p=servers.begin(); p!=servers.end(); ++p)
504                delete (*p)->addr;
505        for (p=returned.begin(); p!=returned.end(); ++p)
506                delete (*p)->addr;
507               
508  servers.erase_all();
509  returned.erase_all();
510}
511//}}}///////////////////////////////////
512
513int tcpip_protocol::handle_responder()
514//{{{
515{
516  if (!responder)
517    return 0;
518   
519  if (responder->ready_to_read())
520  {
521    char buf[513];
522    int len;
523    // got a notification response
524    ip_address *addr;
525    net_address *tmp;
526
527#ifdef TCPIP_DEBUG
528                fprintf(stderr,"Responder: ");
529#endif
530
531    len = responder->read(buf, 512, &tmp);
532    addr = (ip_address *)tmp;
533
534#ifdef TCPIP_DEBUG
535                if (len>0) {
536                        buf[len] = 0;
537                        fprintf(stderr,"[%s] ",buf);
538                }
539#endif
540    if (addr && len>0)
541    {
542        buf[len] = 0;
543      buf[4] = 0;                                                                                               // ack! hard coded numbers for now
544      if (strcmp(buf,notify_response)==0)
545      {
546        int found=0;
547        for (p_request p = servers.begin(); !found && p!=servers.end(); ++p)
548                if ( *((*p)->addr) == *addr)
549                        found = 1;
550                    for (p_request q = returned.begin(); !found && q!=returned.end(); ++q)
551                        if ( *((*q)->addr) == *addr )
552                                found = 1;
553                       
554        if (!found)
555        {
556#ifdef TCPIP_DEBUG
557                                        char s[256];
558#endif
559                                        RequestItem *r = new RequestItem;
560                                        r->addr = addr;
561                                        strcpy(r->name,buf+5);                                  // ack hard coded numbers for now
562              servers.insert(r);
563#ifdef TCPIP_DEBUG
564                                        addr->store_string(s,256);
565                                        fprintf(stderr,"accepted %s",s);
566#endif
567                                }
568                        }
569      else {
570        delete addr;
571                        }
572    }
573#ifdef TCPIP_DEBUG
574    fprintf(stderr,"\n");
575#endif
576
577    return 1;
578  }
579  if (responder->error())
580  {
581    fprintf(stderr,"Error on responder socket!\n");
582    return 1;
583  }
584
585  return 0;
586}
587//}}}///////////////////////////////////
588
589tcpip_protocol::tcpip_protocol()
590//{{{
591  : notifier(0), notify_len(0), responder(0)
592{
593#if (defined(__APPLE__) && !defined(__MACH__))
594  GUSISetup(GUSIwithSIOUXSockets);
595  GUSISetup(GUSIwithPPCSockets);
596#endif 
597  FD_ZERO(&master_set); 
598  FD_ZERO(&master_write_set); 
599  FD_ZERO(&read_set);
600  FD_ZERO(&exception_set);
601  FD_ZERO(&write_set);
602}
603//}}}///////////////////////////////////
604
605int tcpip_protocol::select(int block)
606//{{{
607{
608  int ret;
609 
610  memcpy(&read_set,&master_set,sizeof(master_set));
611  memcpy(&exception_set,&master_set,sizeof(master_set));
612  memcpy(&write_set,&master_write_set,sizeof(master_set));
613  if (block)
614  {
615    ret = 0;
616    while (ret == 0) {
617      // get number of sockets ready from system call
618      ret = ::select(FD_SETSIZE,&read_set,&write_set,&exception_set,NULL);
619
620      // remove notifier & responder events from the count of sockets selected
621      if (handle_notification())
622        ret--;
623      if (handle_responder())
624        ret--;
625    }
626  }
627  else
628  {
629    timeval tv={0,0};
630    // get number of sockets ready from system call
631    ret = ::select(FD_SETSIZE,&read_set,&write_set,&exception_set,&tv);
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  return ret;
640}
641//}}}///////////////////////////////////
642
643void tcpip_protocol::cleanup()
644//{{{
645{
646        if (notifier)
647                end_notify();
648               
649        reset_find_list();
650               
651        if (responder) {
652                delete responder;
653                delete bcast;
654                responder = 0;
655        }
656}
657//}}}///////////////////////////////////
658
659//{{{ Revision Log
660/*//////////////////////////////////////////////////////////////////////
661$Log$
662//////////////////////////////////////////////////////////////////////
663*/
664//}}}
665
666//{{{ Emacs Locals
667// Local Variables:
668// folded-file: t
669// End:
670//}}}
671
Note: See TracBrowser for help on using the repository browser.