Adding d1x network code
[btb/d2x.git] / main / ip_base.cpp
1 /*
2  * $Source: /cvs/cvsroot/d2x/main/ip_base.cpp,v $
3  * $Revision: 1.1 $
4  * $Author: bradleyb $
5  * $Date: 2002-02-06 09:22:41 $
6  *
7  * ip_base.cpp - base for NAT-compatible udp/ip code.
8  * added 2000/02/07 Matt Mueller
9  *
10  * $Log: not supported by cvs2svn $
11  *
12  */
13
14 #ifdef HAVE_CONFIG_H
15 #include <conf.h>
16 #endif
17
18 extern "C" {
19 #include "timer.h"
20 #include "mono.h"
21 #include "args.h"
22 }
23 #include <string.h>
24 #include "ip_base.h"
25
26 int myport=-1;
27
28 int baseport=UDP_BASEPORT;
29
30 ip_addr_list ip_my_addrs;
31 ip_peer_list peer_list;
32
33 int ip_handshake_base::fillbuf(ubyte *buf){
34         u_int32_t tmp32;
35         u_int16_t tmp16;
36         int pos=0;
37         buf[pos++]=type;
38         buf[pos++]=state;
39 //      memcpy(buf+pos,id,6);pos+=6;
40         pos+=id.fillbuf(buf+pos);
41         tmp16=htons(iver);
42         memcpy(buf+pos,&tmp16,2);pos+=2;
43         tmp32=htonl(tryid);
44         memcpy(buf+pos,&tmp32,4);pos+=4;
45         return pos;
46 }
47 int ip_handshake_base::readbuf(ubyte *buf){
48         int pos=0;
49         nopend=1;
50         type=buf[pos++];
51         state=buf[pos++];
52 //      memcpy(id,buf+pos,6);pos+=6;
53         pos+=id.readbuf(buf+pos);
54         memcpy(&iver,buf+pos,2);pos+=2;
55         iver=htons(iver);
56         memcpy(&tryid,buf+pos,4);pos+=4;
57         tryid=htonl(tryid);
58         return pos;
59 }
60 void ip_handshake_base::setstate(int newstate){
61         if (!nopend){
62                 if (state&STATE_NEED_RESEND){
63                         if (!(newstate&STATE_NEED_RESEND))
64                                 peer_list.pendinghandshakes--;
65                 }else{
66                         if (newstate&STATE_NEED_RESEND)
67                                 peer_list.pendinghandshakes++;
68                 }
69                 mprintf((0,"peer_list.pendinghandshakes=%i\n",peer_list.pendinghandshakes));
70         }
71         state=newstate;attempts=0;nextsend=0;
72 }
73 int ip_handshake_base::addstate(int newstate){
74         if (state & STATE_ERR){
75                 setstate((state | newstate) & ~STATE_ERR);
76                 return 2;
77         }
78         if ((state | newstate) != state){
79                 setstate(state | newstate);
80                 return 1;
81         }
82         return 0;
83 }
84
85 int ip_handshake_info::fillbuf(ubyte *buf){
86         int pos=ip_handshake_base::fillbuf(buf);
87         pos+=addr.fillbuf(buf+pos);
88 //      memcpy(buf+pos,addr,6);pos+=6;
89         return pos;
90 }
91 int ip_handshake_info::readbuf(ubyte *buf){
92         int pos=ip_handshake_base::readbuf(buf);
93         pos+=addr.readbuf(buf+pos);
94 //      memcpy(addr,buf+pos,6);pos+=6;
95         return pos;
96 }
97
98 int ip_handshake_relay::fillbuf(ubyte *buf){
99         u_int16_t tmp16;
100         int pos=ip_handshake_base::fillbuf(buf);
101 //      memcpy(buf+pos,r_addr[0],6);pos+=6;
102 //      memcpy(buf+pos,r_addr[1],6);pos+=6;
103 //      memcpy(buf+pos,r_id,6);pos+=6;
104         pos+=r_id.fillbuf(buf+pos);
105         tmp16=htons(r_iver);
106         memcpy(buf+pos,&tmp16,2);pos+=2;
107         pos+=r_addr.fillbuf(buf+pos);
108 //      pos+=r_addr[1].fillbuf(buf+pos);
109         return pos;
110 }
111 int ip_handshake_relay::readbuf(ubyte *buf){
112         int pos=ip_handshake_base::readbuf(buf);
113 //      memcpy(r_addr[0],buf+pos,6);pos+=6;
114 //      memcpy(r_addr[1],buf+pos,6);pos+=6;
115 //      memcpy(r_id,buf+pos,6);pos+=6;
116         pos+=r_id.readbuf(buf+pos);
117         memcpy(&r_iver,buf+pos,2);pos+=2;
118         r_iver=htons(r_iver);
119         pos+=r_addr.readbuf(buf+pos);
120 //      pos+=r_addr[1].readbuf(buf+pos);
121         return pos;
122 }
123 ip_handshake_relay::ip_handshake_relay(ip_peer *torelay):ip_handshake_base(1){
124         type=IP_CFG_RELAY;
125         r_id=torelay->id;
126         r_iver=torelay->iver;
127         r_addr=torelay->addr;
128 //      r_addr[1]=torelay->addr[1];
129         setstate(STATE_INEEDINFO);
130 }
131
132 /*void ip_peer::set_good_addr(ubyte *fraddr){
133         int i;
134         for (i=0;i<numaddr;i++)
135                 if (addr[i]==fraddr){
136                         goodaddr=i;
137                         return;
138                 }
139         //######hrm.
140         addr[1]=fraddr;
141         numaddr=2;
142         goodaddr=1;
143 }*/
144 void ip_peer::send_handshake(ip_handshake_base*hsb){
145         ubyte buf[256];
146         int s=0;
147         memcpy(buf+s,D1Xcfgid,4);s+=4;
148         s+=hsb->fillbuf(buf+s);
149         assert(s<256);
150         if (addr.goodaddr==NULL){
151                 ip_addr_list::iterator i;
152                 for (i=addr.begin();i!=addr.end();i++)
153                         ip_sendtoca(*i,buf,s);
154 //              int i;
155 //              for (i=0;i<addr.naddr;i++)
156 //                      ip_sendtoca(addr[i],buf,s);
157         }else
158                 //ip_sendtoca(addr[goodaddr],buf,s);
159                 ip_sendtoca(*addr.goodaddr,buf,s);
160         hsb->nextsend=timer_get_approx_seconds()+IP_HS_RETRYTIME;
161         hsb->attempts++;
162 /*#ifdef UDPDEBUG
163         {
164                 int hj;
165                 printf(MSGHDR"sending handshake %i (t%i state %i(%s)) for (%i)",hsb->attempts,hsb->type,hsb->state,ip_hs_statetoa(hsb->state),addr.goodaddr);
166                 for (hj=0;hj<numaddr;hj++){
167                         if (hj>0)
168                                 printf(", ");
169                         dumpraddr(addr[hj].addr);
170                 }
171                 printf(" v%i\n",iver);
172         }
173 #endif*/
174 }
175 bool ip_peer::verify_addr(ip_addr_list &fraddrs){
176         int a1=addr.add(fraddrs);
177         if (a1)
178                 addr.goodaddr=NULL;
179 /*      a1=(addr[0]!=fraddr0 && addr[1]!=fraddr0);
180         a2=(addr[0]!=fraddr1 && addr[1]!=fraddr1);
181         if (a1 || a2 || (numaddr<2 && fraddr0!=fraddr1))
182         {
183                 mprintf((0,"verify_peer_addr_hsi %i %i\n",a1,a2));
184                 addr[0]=fraddr1;
185                 addr[1]=fraddr0;
186                 goodaddr=-1;
187                 numaddr=2;
188                 return 1;
189         }*/
190         return a1>0;
191 }
192 ip_peer * ip_peer_list::add_1(ip_addr addr/*,ip_id id*/){
193         ip_peer*n=add_unk();
194         n->addr.add(addr);
195 //      n->goodaddr=-1;
196 //      n->numaddr=1;
197 //      n->id=id;
198         return n;
199 }
200 ip_peer * ip_peer_list::add_full(ip_id id, u_int16_t iver,ip_addr_list &addrs){
201         ip_peer*n=add_id(id);
202 /*      n->addr[0]=addr0;
203         n->addr[1]=addr1;
204         n->goodaddr=-1;
205         if (addr0==addr1){
206                 n->numaddr=1;
207         }else{
208                 n->numaddr=2;
209         }*/
210         n->addr.add(addrs);
211         n->iver=iver;
212         mprintf((0,"addfull %i addrs\n",n->addr.naddr));
213 //      n->id=id;
214         return n;
215 }
216 void ip_peer_list::make_full(ip_peer*p,ip_id id, u_int16_t iver, ip_addr_list &addrs){
217         list<ip_peer*>::iterator unki=find(unknown_peers.begin(),unknown_peers.end(),p);
218         if (unki!=unknown_peers.end())
219                 unknown_peers.erase(unki);
220         p->id=id;
221         p->iver=iver;
222 //      p->addr[0]=addr0;
223 //      p->addr[1]=addr1;
224         p->addr.add(addrs);
225         peers.insert(peer_map::value_type(p->id,p));
226 }
227 ip_peer * ip_peer_list::find_byid(ip_id id){
228         peer_map::iterator i=peers.find(id);
229         if (i!=peers.end())
230                 return (*i).second;
231         return NULL;
232 }
233 struct do_find_by_addr : public unary_function<ip_peer*,bool> {
234         int j;
235         ip_addr addr;
236         bool operator()(ip_peer * p) {
237 ////    bool operator()(pair<const ip_id,ip_peer *> &) {
238 //              for(j=0;j<p->numaddr;j++)
239 //                      if (addr==p->addr[j])
240 //                              return 1;
241                 if (p->addr.hasaddr(addr))
242                         return 1;
243                 return 0;
244         }
245 };
246 template <class ret,class p1,class p2, class fo>
247 struct pairkiller {
248         fo *o;
249         ret operator()(pair<p1,p2> &aoeuaoeu) {
250                 return (*o)(aoeuaoeu.second);
251         }
252         pairkiller(fo *no):o(no){}
253 };
254 //template <class ret,class p1,class p2, class fo>
255 template <class p1, class fo>
256 pairkiller<typename fo::result_type,p1,typename fo::argument_type,fo> pairkill(fo * no){
257         return pairkiller<typename fo::result_type,p1,typename fo::argument_type,fo>(no);
258 }
259
260 ip_peer * ip_peer_list::find_by_addr(ip_addr addr){
261         do_find_by_addr fba;
262 //      pairkiller<const ip_id,ip_peer*,do_find_by_addr> fbap(&fba);
263         fba.addr=addr;
264         peer_map::iterator i=find_if(peers.begin(),peers.end(),pairkill<const ip_id>(&fba));
265         if (i!=peers.end())
266                 return (*i).second;
267         list<ip_peer*>::iterator j=find_if(unknown_peers.begin(),unknown_peers.end(),fba);
268         if (j!=unknown_peers.end())
269                 return (*j);
270         return NULL;
271 }
272 ip_peer * ip_peer_list::find_unk_by_addr(ip_addr addr){
273         do_find_by_addr fba;
274         fba.addr=addr;
275         list<ip_peer*>::iterator j=find_if(unknown_peers.begin(),unknown_peers.end(),fba);
276         if (j!=unknown_peers.end())
277                 return (*j);
278         return NULL;
279 }
280 struct do_peer_handshake : public unary_function<ip_peer *, void>{
281         fix mintime;
282         list<ip_handshake_base*>::iterator i;
283         ip_handshake_base *hsb;
284         void operator() (ip_peer* peer) {
285                 for(i=peer->handshakes.begin();i!=peer->handshakes.end();++i){
286                         hsb=(*i);
287                         //if (hsb->state<IPNOSTATE && hsb->nextsend<mintime){
288                         if ((hsb->state & STATE_NEED_RESEND) && hsb->nextsend<mintime){
289                                 if(hsb->attempts>IP_MAX_HS_ATTEMPTS){
290 /*#ifdef UDPDEBUG
291                                         int hj;
292                                         printf(MSGHDR"handshake timeout (state %i(%s)) for (%i)",hsb->state,ip_hs_statetoa(hsb->state),peer->goodaddr);
293                                         for (hj=0;hj<peer->numaddr;hj++){
294                                                 if (hj>0)
295                                                         printf(", ");
296                                                 dumpraddr(peer->addr[hj].addr);
297                                         }
298                                         printf(" v%i\n",peer->iver);
299 #endif*/
300                                         hsb->setstate(STATE_ERR);
301                                 }else{
302                         //                                      handshake_buf.state=handshakers[i].state;
303                                         peer->send_handshake(hsb);
304                                 }
305                         }
306                 }
307         }
308 };
309 void ip_peer_list::handshake_frame(void){
310         if(pendinghandshakes){
311                 fix mintime=timer_get_approx_seconds();//try every X seconds
312                 if (pendinghandshake_lasttime<mintime-IP_HS_FRAME_RETRYTIME){
313                         do_peer_handshake doph;
314 //                      pairkiller<const ip_id,ip_peer*,do_peer_handshake> dophp(&doph);
315                         doph.mintime=mintime;
316                         for_each(peers.begin(),peers.end(),pairkill<const ip_id>(&doph));
317                         for_each(unknown_peers.begin(),unknown_peers.end(),doph);
318 //                      int i;
319 //                      mintime-=IP_HS_RETRYTIME;//try every X seconds
320 /*                      for (i=0;i<numpeers;i++){
321                                 ip_handshake_do_hs(&peers[i],&peers[i].query,mintime);
322                                 ip_handshake_do_hs(&peers[i],&peers[i].reply,mintime);
323                         }*/
324                 }
325         }
326 }
327 struct do_peer_delete : public unary_function<ip_peer *, void>{
328         void operator() (ip_peer* peer) {
329                 delete peer;
330         }
331 };
332 void ip_peer_list::clear(void){
333         do_peer_delete dopd;
334         for_each(peers.begin(),peers.end(),pairkill<const ip_id>(&dopd));
335         peers.erase(peers.begin(),peers.end());
336         for_each(unknown_peers.begin(),unknown_peers.end(),dopd);
337         unknown_peers.erase(unknown_peers.begin(),unknown_peers.end());
338 }
339 ip_peer_list::~ip_peer_list(){
340         clear();
341 }
342
343
344 #ifdef UDPDEBUG
345 //000a0oeuaoeu
346
347 static void dumpid(unsigned char *a)
348 {
349         printf("<%u.%u.%u.%u.%u.%u>",a[0],a[1],a[2],a[3],a[4],a[5]);
350 }
351 #endif
352
353 int ip_sendtoid(ubyte *id,const void *buf,int len){
354 //      ip_handshaker *hsr=find_handshaker_by_id(id);
355         ip_peer *p=peer_list.find_byid(id);
356         if (!p || p->addr.goodaddr==NULL){
357 #ifdef UDPDEBUG
358                 printf(MSGHDR"send to invalid id(");
359                 dumpid(id);
360                 printf(") %p.",p);
361 #endif
362                 return -1;
363         }
364         return ip_sendtoca(*p->addr.goodaddr,buf,len);
365 }
366
367 void ip_receive_cfg(ubyte *buf,int buflen,ip_addr fromaddr){
368         ip_peer *p;
369         switch(buf[0]){
370                 case IP_CFG_SORRY:
371                         {
372 #ifdef UDPDEBUG
373         printf("ip_receive_cfg: %i %i ",buf[0],buf[1]);
374         dumprid(buf+2);
375         printf(" v%i tryid%u\n",ntohs(*(unsigned short*)(buf+8)),(unsigned int)ntohl(*(u_int32_t*)(buf+10)));
376 #endif
377
378                         }break;
379                 case IP_CFG_HANDSHAKE:
380 #ifdef UDPDEBUG
381         printf("ip_receive_cfg: %i %i ",buf[0],buf[1]);
382         dumprid(buf+2);
383         printf(" v%i tryid%u\n",ntohs(*(unsigned short*)(buf+8)),(unsigned int)ntohl(*(u_int32_t*)(buf+10)));
384 #endif
385                         {
386                                 ip_handshake_info *hsi=new ip_handshake_info(buf);
387                                 hsi->addr.add(fromaddr);
388                                 ip_handshake_info *lhsi=NULL;
389                                 p=peer_list.find_byid(hsi->id);
390 /*#ifdef UDPDEBUG
391                                 printf("hsi %i %i id=",hsi->type,hsi->state);
392                                 hsi->id.dump();
393                                 printf(" ver=%i tryid=%u\n",hsi->iver,hsi->tryid);
394                                 mprintf((0,"peer_list.find_byid=%p\n",p));
395 #endif*/
396                                 if (!p){
397                                         p=peer_list.find_unk_by_addr(fromaddr);
398 //                                      mprintf((0,"peer_list.find_by_addr=%p\n",p));
399                                         if (p){
400                                                 peer_list.make_full(p,hsi->id,hsi->iver,hsi->addr);
401                                         }
402                                 }
403                                 else
404                                         p->verify_addr(hsi->addr);
405                                 if (!p){
406                                         p=peer_list.add_hsi(hsi);
407 //                                      mprintf((0,"peer_list.add_hsi=%p\n",p));
408                                 }
409                                 lhsi=p->find_handshake();
410                                 lhsi->tryid=hsi->tryid;
411                                 if (p->addr.goodaddr==NULL){
412                                         p->addr.setgoodaddr(fromaddr);
413 //                                      lhsi->state&=STATE_INEEDINFO;
414                                 }
415                                 if (hsi->state&STATE_INEEDINFO)
416                                         lhsi->setstate(STATE_SENDINGINFO);
417                                         //lhsi->state&=STATE_SENDINGINFO;
418                                 else
419                                         lhsi->setstate(0);
420
421 //                              mprintf((0,"lhsi->state=%i\n",lhsi->state));
422 //                              mprintf((0,"hsi->state=%i\n",hsi->state));
423                                 if (lhsi->state)
424                                         p->send_handshake(lhsi);
425
426                                 delete hsi;
427                         }break;
428                 case IP_CFG_RELAY:
429                         {
430                                 ip_peer *rp;
431                                 ip_handshake_relay hsr(buf);
432 #ifdef UDPDEBUG
433                                 printf("ip_receive_cfg: %i %i ",buf[0],buf[1]);
434                                 dumprid(buf+2);
435                                 printf(" v%i r_id ",ntohs(*(unsigned short*)(buf+8)));
436                                 hsr.r_id.dump();
437                                 printf(" r_iv%i\n",hsr.r_iver);
438 #endif
439                                 p=peer_list.find_byid(hsr.id);
440                                 if (!p) {
441                                         mprintf((0,"relay from unknown peer\n"));
442                                         break;//hrm.
443                                 }
444                                 rp=peer_list.find_byid(hsr.r_id);
445                                 if (hsr.state&STATE_RELAYREPLY){
446                                         if (!rp) {
447                                                 mprintf((0,"relay reply for unknown peer\n"));
448                                                 break;//hrm.
449                                         }
450                                         ip_handshake_relay *rhsr=p->find_relay(rp->id);
451                                         if (!rhsr)
452                                                 break;
453                                         rhsr->setstate(0);
454 #ifdef UDPDEBUG
455                                         printf("**** ");
456                                         p->id.dump();
457                                         printf(" is ok with ");
458                                         rp->id.dump();
459                                         printf("\n");
460 #endif
461                                 }else{
462                                         if (!rp)
463                                                 rp=peer_list.add_full(hsr.r_id,hsr.r_iver,hsr.r_addr);
464                                         else
465                                                 rp->verify_addr(hsr.r_addr);
466
467                                         if (rp->addr.goodaddr==NULL){
468                                                 mprintf((0,"sending relayed handshake\n"));
469                                                 //handshake with relayed peer
470                                                 ip_handshake_info *lhsi=rp->find_handshake();
471 //                                              lhsi->setstate(STATE_INEEDINFO);
472                                                 if (lhsi->addstate(STATE_INEEDINFO));
473                                                         rp->send_handshake(lhsi);
474                                         }else{
475                                                 mprintf((0,"sending relayed reply\n"));
476                                                 //reply to relayer
477                                                 ip_handshake_relay rhsr(rp);
478                                                 rhsr.setstate(STATE_RELAYREPLY);
479                                                 p->send_handshake(&rhsr);
480                                         }
481                                 }
482                         }break;
483         }
484 }
485
486
487
488 int ipx_ip_GetMyAddress(void) {
489
490         int i;
491         u_int32_t myhandshakeid;
492
493         d_srand( timer_get_approx_seconds() );
494 //      printf("set my id to %u\n",myhandshakeid);
495
496         ip_my_addrs.clear();
497
498         if (!FindArg("-ip_nogetmyaddr"))
499                 arch_ip_get_my_addr(myport);//if we can't get an addr, then we can still probably play, just some NAT configs might not work.
500 //              if (arch_ip_get_my_addr(myport)) return -1;
501
502         if ((i=FindArg("-ip_myaddr"))){
503                 ip_addr ip;
504                 if (!ip.dns(Args[i+1],myport)){
505                         ip_my_addrs.add(ip);
506                 }
507         }
508
509         myhandshakeid=htonl(d_rand32());
510         //ipx_MyAddress[4]=qhbuf[2];
511         //ipx_MyAddress[5]=qhbuf[3];
512         if (ip_my_addrs.naddr){
513                 ip_addr ip=*ip_my_addrs.begin();
514                 ipx_MyAddress[4]=ip.addr[2];
515                 ipx_MyAddress[5]=ip.addr[3];
516         }else{
517                 ipx_MyAddress[4]=d_rand()%255;
518                 ipx_MyAddress[5]=d_rand()%255;
519         }
520         //memcpy(ipx_MyAddress+6,&handshake_buf.id,4);
521         memcpy(ipx_MyAddress+6,&myhandshakeid,4);
522
523 #ifdef UDPDEBUG
524         printf(MSGHDR "Using TCP/IP id ");
525         dumprid(ipx_MyAddress+4);
526         putchar('\n');
527 #endif
528         return 0;
529 }
530 /* Parse PORTSHIFT numeric parameter
531  */
532
533 unsigned short ip_portshift(unsigned short baseport, const char *cs)
534 {
535         long port;
536         unsigned short ports=htons(baseport);
537         if (cs){
538                 port=atol(cs);
539                 if (cs[0]=='-' || cs[0]=='+')//relative port
540 //              if (port<-PORTSHIFT_TOLERANCE || port>+PORTSHIFT_TOLERANCE)
541 //                      msg("Invalid portshift in \"%s\", tolerance is +/-%d",cs,PORTSHIFT_TOLERANCE);
542 //              else
543                         ports=htons(port+baseport);
544                 else
545                         ports=htons(port);//absolute port
546         }
547 //      memcpy(qhbuf+4,&ports,2);
548         return ports;
549 }
550