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

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