2 * $Source: /cvs/cvsroot/d2x/main/ip_base.cpp,v $
5 * $Date: 2002-02-06 09:22:41 $
7 * ip_base.cpp - base for NAT-compatible udp/ip code.
8 * added 2000/02/07 Matt Mueller
10 * $Log: not supported by cvs2svn $
28 int baseport=UDP_BASEPORT;
30 ip_addr_list ip_my_addrs;
31 ip_peer_list peer_list;
33 int ip_handshake_base::fillbuf(ubyte *buf){
39 // memcpy(buf+pos,id,6);pos+=6;
40 pos+=id.fillbuf(buf+pos);
42 memcpy(buf+pos,&tmp16,2);pos+=2;
44 memcpy(buf+pos,&tmp32,4);pos+=4;
47 int ip_handshake_base::readbuf(ubyte *buf){
52 // memcpy(id,buf+pos,6);pos+=6;
53 pos+=id.readbuf(buf+pos);
54 memcpy(&iver,buf+pos,2);pos+=2;
56 memcpy(&tryid,buf+pos,4);pos+=4;
60 void ip_handshake_base::setstate(int newstate){
62 if (state&STATE_NEED_RESEND){
63 if (!(newstate&STATE_NEED_RESEND))
64 peer_list.pendinghandshakes--;
66 if (newstate&STATE_NEED_RESEND)
67 peer_list.pendinghandshakes++;
69 mprintf((0,"peer_list.pendinghandshakes=%i\n",peer_list.pendinghandshakes));
71 state=newstate;attempts=0;nextsend=0;
73 int ip_handshake_base::addstate(int newstate){
74 if (state & STATE_ERR){
75 setstate((state | newstate) & ~STATE_ERR);
78 if ((state | newstate) != state){
79 setstate(state | newstate);
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;
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;
98 int ip_handshake_relay::fillbuf(ubyte *buf){
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);
106 memcpy(buf+pos,&tmp16,2);pos+=2;
107 pos+=r_addr.fillbuf(buf+pos);
108 // pos+=r_addr[1].fillbuf(buf+pos);
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);
123 ip_handshake_relay::ip_handshake_relay(ip_peer *torelay):ip_handshake_base(1){
126 r_iver=torelay->iver;
127 r_addr=torelay->addr;
128 // r_addr[1]=torelay->addr[1];
129 setstate(STATE_INEEDINFO);
132 /*void ip_peer::set_good_addr(ubyte *fraddr){
134 for (i=0;i<numaddr;i++)
135 if (addr[i]==fraddr){
144 void ip_peer::send_handshake(ip_handshake_base*hsb){
147 memcpy(buf+s,D1Xcfgid,4);s+=4;
148 s+=hsb->fillbuf(buf+s);
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);
155 // for (i=0;i<addr.naddr;i++)
156 // ip_sendtoca(addr[i],buf,s);
158 //ip_sendtoca(addr[goodaddr],buf,s);
159 ip_sendtoca(*addr.goodaddr,buf,s);
160 hsb->nextsend=timer_get_approx_seconds()+IP_HS_RETRYTIME;
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++){
169 dumpraddr(addr[hj].addr);
171 printf(" v%i\n",iver);
175 bool ip_peer::verify_addr(ip_addr_list &fraddrs){
176 int a1=addr.add(fraddrs);
179 /* a1=(addr[0]!=fraddr0 && addr[1]!=fraddr0);
180 a2=(addr[0]!=fraddr1 && addr[1]!=fraddr1);
181 if (a1 || a2 || (numaddr<2 && fraddr0!=fraddr1))
183 mprintf((0,"verify_peer_addr_hsi %i %i\n",a1,a2));
192 ip_peer * ip_peer_list::add_1(ip_addr addr/*,ip_id id*/){
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);
212 mprintf((0,"addfull %i addrs\n",n->addr.naddr));
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);
225 peers.insert(peer_map::value_type(p->id,p));
227 ip_peer * ip_peer_list::find_byid(ip_id id){
228 peer_map::iterator i=peers.find(id);
233 struct do_find_by_addr : public unary_function<ip_peer*,bool> {
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])
241 if (p->addr.hasaddr(addr))
246 template <class ret,class p1,class p2, class fo>
249 ret operator()(pair<p1,p2> &aoeuaoeu) {
250 return (*o)(aoeuaoeu.second);
252 pairkiller(fo *no):o(no){}
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);
260 ip_peer * ip_peer_list::find_by_addr(ip_addr addr){
262 // pairkiller<const ip_id,ip_peer*,do_find_by_addr> fbap(&fba);
264 peer_map::iterator i=find_if(peers.begin(),peers.end(),pairkill<const ip_id>(&fba));
267 list<ip_peer*>::iterator j=find_if(unknown_peers.begin(),unknown_peers.end(),fba);
268 if (j!=unknown_peers.end())
272 ip_peer * ip_peer_list::find_unk_by_addr(ip_addr addr){
275 list<ip_peer*>::iterator j=find_if(unknown_peers.begin(),unknown_peers.end(),fba);
276 if (j!=unknown_peers.end())
280 struct do_peer_handshake : public unary_function<ip_peer *, void>{
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){
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){
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++){
296 dumpraddr(peer->addr[hj].addr);
298 printf(" v%i\n",peer->iver);
300 hsb->setstate(STATE_ERR);
302 // handshake_buf.state=handshakers[i].state;
303 peer->send_handshake(hsb);
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);
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);
327 struct do_peer_delete : public unary_function<ip_peer *, void>{
328 void operator() (ip_peer* peer) {
332 void ip_peer_list::clear(void){
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());
339 ip_peer_list::~ip_peer_list(){
347 static void dumpid(unsigned char *a)
349 printf("<%u.%u.%u.%u.%u.%u>",a[0],a[1],a[2],a[3],a[4],a[5]);
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){
358 printf(MSGHDR"send to invalid id(");
364 return ip_sendtoca(*p->addr.goodaddr,buf,len);
367 void ip_receive_cfg(ubyte *buf,int buflen,ip_addr fromaddr){
373 printf("ip_receive_cfg: %i %i ",buf[0],buf[1]);
375 printf(" v%i tryid%u\n",ntohs(*(unsigned short*)(buf+8)),(unsigned int)ntohl(*(u_int32_t*)(buf+10)));
379 case IP_CFG_HANDSHAKE:
381 printf("ip_receive_cfg: %i %i ",buf[0],buf[1]);
383 printf(" v%i tryid%u\n",ntohs(*(unsigned short*)(buf+8)),(unsigned int)ntohl(*(u_int32_t*)(buf+10)));
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);
391 printf("hsi %i %i id=",hsi->type,hsi->state);
393 printf(" ver=%i tryid=%u\n",hsi->iver,hsi->tryid);
394 mprintf((0,"peer_list.find_byid=%p\n",p));
397 p=peer_list.find_unk_by_addr(fromaddr);
398 // mprintf((0,"peer_list.find_by_addr=%p\n",p));
400 peer_list.make_full(p,hsi->id,hsi->iver,hsi->addr);
404 p->verify_addr(hsi->addr);
406 p=peer_list.add_hsi(hsi);
407 // mprintf((0,"peer_list.add_hsi=%p\n",p));
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;
415 if (hsi->state&STATE_INEEDINFO)
416 lhsi->setstate(STATE_SENDINGINFO);
417 //lhsi->state&=STATE_SENDINGINFO;
421 // mprintf((0,"lhsi->state=%i\n",lhsi->state));
422 // mprintf((0,"hsi->state=%i\n",hsi->state));
424 p->send_handshake(lhsi);
431 ip_handshake_relay hsr(buf);
433 printf("ip_receive_cfg: %i %i ",buf[0],buf[1]);
435 printf(" v%i r_id ",ntohs(*(unsigned short*)(buf+8)));
437 printf(" r_iv%i\n",hsr.r_iver);
439 p=peer_list.find_byid(hsr.id);
441 mprintf((0,"relay from unknown peer\n"));
444 rp=peer_list.find_byid(hsr.r_id);
445 if (hsr.state&STATE_RELAYREPLY){
447 mprintf((0,"relay reply for unknown peer\n"));
450 ip_handshake_relay *rhsr=p->find_relay(rp->id);
457 printf(" is ok with ");
463 rp=peer_list.add_full(hsr.r_id,hsr.r_iver,hsr.r_addr);
465 rp->verify_addr(hsr.r_addr);
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);
475 mprintf((0,"sending relayed reply\n"));
477 ip_handshake_relay rhsr(rp);
478 rhsr.setstate(STATE_RELAYREPLY);
479 p->send_handshake(&rhsr);
488 int ipx_ip_GetMyAddress(void) {
491 u_int32_t myhandshakeid;
493 d_srand( timer_get_approx_seconds() );
494 // printf("set my id to %u\n",myhandshakeid);
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;
502 if ((i=FindArg("-ip_myaddr"))){
504 if (!ip.dns(Args[i+1],myport)){
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];
517 ipx_MyAddress[4]=d_rand()%255;
518 ipx_MyAddress[5]=d_rand()%255;
520 //memcpy(ipx_MyAddress+6,&handshake_buf.id,4);
521 memcpy(ipx_MyAddress+6,&myhandshakeid,4);
524 printf(MSGHDR "Using TCP/IP id ");
525 dumprid(ipx_MyAddress+4);
530 /* Parse PORTSHIFT numeric parameter
533 unsigned short ip_portshift(unsigned short baseport, const char *cs)
536 unsigned short ports=htons(baseport);
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);
543 ports=htons(port+baseport);
545 ports=htons(port);//absolute port
547 // memcpy(qhbuf+4,&ports,2);