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