2 * $Source: /cvs/cvsroot/d2x/main/ip_base.cpp,v $
5 * $Date: 2002-02-13 10:39:21 $
7 * ip_base.cpp - base for NAT-compatible udp/ip code.
8 * added 2000/02/07 Matt Mueller
10 * $Log: not supported by cvs2svn $
11 * Revision 1.1 2002/02/06 09:22:41 bradleyb
12 * Adding d1x network code
31 int baseport=UDP_BASEPORT;
33 ip_addr_list ip_my_addrs;
34 ip_peer_list peer_list;
36 int ip_handshake_base::fillbuf(ubyte *buf){
42 // memcpy(buf+pos,id,6);pos+=6;
43 pos+=id.fillbuf(buf+pos);
45 memcpy(buf+pos,&tmp16,2);pos+=2;
47 memcpy(buf+pos,&tmp32,4);pos+=4;
50 int ip_handshake_base::readbuf(ubyte *buf){
55 // memcpy(id,buf+pos,6);pos+=6;
56 pos+=id.readbuf(buf+pos);
57 memcpy(&iver,buf+pos,2);pos+=2;
59 memcpy(&tryid,buf+pos,4);pos+=4;
63 void ip_handshake_base::setstate(int newstate){
65 if (state&STATE_NEED_RESEND){
66 if (!(newstate&STATE_NEED_RESEND))
67 peer_list.pendinghandshakes--;
69 if (newstate&STATE_NEED_RESEND)
70 peer_list.pendinghandshakes++;
72 mprintf((0,"peer_list.pendinghandshakes=%i\n",peer_list.pendinghandshakes));
74 state=newstate;attempts=0;nextsend=0;
76 int ip_handshake_base::addstate(int newstate){
77 if (state & STATE_ERR){
78 setstate((state | newstate) & ~STATE_ERR);
81 if ((state | newstate) != state){
82 setstate(state | newstate);
88 int ip_handshake_info::fillbuf(ubyte *buf){
89 int pos=ip_handshake_base::fillbuf(buf);
90 pos+=addr.fillbuf(buf+pos);
91 // memcpy(buf+pos,addr,6);pos+=6;
94 int ip_handshake_info::readbuf(ubyte *buf){
95 int pos=ip_handshake_base::readbuf(buf);
96 pos+=addr.readbuf(buf+pos);
97 // memcpy(addr,buf+pos,6);pos+=6;
101 int ip_handshake_relay::fillbuf(ubyte *buf){
103 int pos=ip_handshake_base::fillbuf(buf);
104 // memcpy(buf+pos,r_addr[0],6);pos+=6;
105 // memcpy(buf+pos,r_addr[1],6);pos+=6;
106 // memcpy(buf+pos,r_id,6);pos+=6;
107 pos+=r_id.fillbuf(buf+pos);
109 memcpy(buf+pos,&tmp16,2);pos+=2;
110 pos+=r_addr.fillbuf(buf+pos);
111 // pos+=r_addr[1].fillbuf(buf+pos);
114 int ip_handshake_relay::readbuf(ubyte *buf){
115 int pos=ip_handshake_base::readbuf(buf);
116 // memcpy(r_addr[0],buf+pos,6);pos+=6;
117 // memcpy(r_addr[1],buf+pos,6);pos+=6;
118 // memcpy(r_id,buf+pos,6);pos+=6;
119 pos+=r_id.readbuf(buf+pos);
120 memcpy(&r_iver,buf+pos,2);pos+=2;
121 r_iver=htons(r_iver);
122 pos+=r_addr.readbuf(buf+pos);
123 // pos+=r_addr[1].readbuf(buf+pos);
126 ip_handshake_relay::ip_handshake_relay(ip_peer *torelay):ip_handshake_base(1){
129 r_iver=torelay->iver;
130 r_addr=torelay->addr;
131 // r_addr[1]=torelay->addr[1];
132 setstate(STATE_INEEDINFO);
135 /*void ip_peer::set_good_addr(ubyte *fraddr){
137 for (i=0;i<numaddr;i++)
138 if (addr[i]==fraddr){
147 void ip_peer::send_handshake(ip_handshake_base*hsb){
150 memcpy(buf+s,DXXcfgid,4);s+=4;
151 s+=hsb->fillbuf(buf+s);
153 if (addr.goodaddr==NULL){
154 ip_addr_list::iterator i;
155 for (i=addr.begin();i!=addr.end();i++)
156 ip_sendtoca(*i,buf,s);
158 // for (i=0;i<addr.naddr;i++)
159 // ip_sendtoca(addr[i],buf,s);
161 //ip_sendtoca(addr[goodaddr],buf,s);
162 ip_sendtoca(*addr.goodaddr,buf,s);
163 hsb->nextsend=timer_get_approx_seconds()+IP_HS_RETRYTIME;
168 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);
169 for (hj=0;hj<numaddr;hj++){
172 dumpraddr(addr[hj].addr);
174 printf(" v%i\n",iver);
178 bool ip_peer::verify_addr(ip_addr_list &fraddrs){
179 int a1=addr.add(fraddrs);
182 /* a1=(addr[0]!=fraddr0 && addr[1]!=fraddr0);
183 a2=(addr[0]!=fraddr1 && addr[1]!=fraddr1);
184 if (a1 || a2 || (numaddr<2 && fraddr0!=fraddr1))
186 mprintf((0,"verify_peer_addr_hsi %i %i\n",a1,a2));
195 ip_peer * ip_peer_list::add_1(ip_addr addr/*,ip_id id*/){
203 ip_peer * ip_peer_list::add_full(ip_id id, u_int16_t iver,ip_addr_list &addrs){
204 ip_peer*n=add_id(id);
215 mprintf((0,"addfull %i addrs\n",n->addr.naddr));
219 void ip_peer_list::make_full(ip_peer*p,ip_id id, u_int16_t iver, ip_addr_list &addrs){
220 list<ip_peer*>::iterator unki=find(unknown_peers.begin(),unknown_peers.end(),p);
221 if (unki!=unknown_peers.end())
222 unknown_peers.erase(unki);
228 peers.insert(peer_map::value_type(p->id,p));
230 ip_peer * ip_peer_list::find_byid(ip_id id){
231 peer_map::iterator i=peers.find(id);
236 struct do_find_by_addr : public unary_function<ip_peer*,bool> {
239 bool operator()(ip_peer * p) {
240 //// bool operator()(pair<const ip_id,ip_peer *> &) {
241 // for(j=0;j<p->numaddr;j++)
242 // if (addr==p->addr[j])
244 if (p->addr.hasaddr(addr))
249 template <class ret,class p1,class p2, class fo>
252 ret operator()(pair<p1,p2> &aoeuaoeu) {
253 return (*o)(aoeuaoeu.second);
255 pairkiller(fo *no):o(no){}
257 //template <class ret,class p1,class p2, class fo>
258 template <class p1, class fo>
259 pairkiller<typename fo::result_type,p1,typename fo::argument_type,fo> pairkill(fo * no){
260 return pairkiller<typename fo::result_type,p1,typename fo::argument_type,fo>(no);
263 ip_peer * ip_peer_list::find_by_addr(ip_addr addr){
265 // pairkiller<const ip_id,ip_peer*,do_find_by_addr> fbap(&fba);
267 peer_map::iterator i=find_if(peers.begin(),peers.end(),pairkill<const ip_id>(&fba));
270 list<ip_peer*>::iterator j=find_if(unknown_peers.begin(),unknown_peers.end(),fba);
271 if (j!=unknown_peers.end())
275 ip_peer * ip_peer_list::find_unk_by_addr(ip_addr addr){
278 list<ip_peer*>::iterator j=find_if(unknown_peers.begin(),unknown_peers.end(),fba);
279 if (j!=unknown_peers.end())
283 struct do_peer_handshake : public unary_function<ip_peer *, void>{
285 list<ip_handshake_base*>::iterator i;
286 ip_handshake_base *hsb;
287 void operator() (ip_peer* peer) {
288 for(i=peer->handshakes.begin();i!=peer->handshakes.end();++i){
290 //if (hsb->state<IPNOSTATE && hsb->nextsend<mintime){
291 if ((hsb->state & STATE_NEED_RESEND) && hsb->nextsend<mintime){
292 if(hsb->attempts>IP_MAX_HS_ATTEMPTS){
295 printf(MSGHDR"handshake timeout (state %i(%s)) for (%i)",hsb->state,ip_hs_statetoa(hsb->state),peer->goodaddr);
296 for (hj=0;hj<peer->numaddr;hj++){
299 dumpraddr(peer->addr[hj].addr);
301 printf(" v%i\n",peer->iver);
303 hsb->setstate(STATE_ERR);
305 // handshake_buf.state=handshakers[i].state;
306 peer->send_handshake(hsb);
312 void ip_peer_list::handshake_frame(void){
313 if(pendinghandshakes){
314 fix mintime=timer_get_approx_seconds();//try every X seconds
315 if (pendinghandshake_lasttime<mintime-IP_HS_FRAME_RETRYTIME){
316 do_peer_handshake doph;
317 // pairkiller<const ip_id,ip_peer*,do_peer_handshake> dophp(&doph);
318 doph.mintime=mintime;
319 for_each(peers.begin(),peers.end(),pairkill<const ip_id>(&doph));
320 for_each(unknown_peers.begin(),unknown_peers.end(),doph);
322 // mintime-=IP_HS_RETRYTIME;//try every X seconds
323 /* for (i=0;i<numpeers;i++){
324 ip_handshake_do_hs(&peers[i],&peers[i].query,mintime);
325 ip_handshake_do_hs(&peers[i],&peers[i].reply,mintime);
330 struct do_peer_delete : public unary_function<ip_peer *, void>{
331 void operator() (ip_peer* peer) {
335 void ip_peer_list::clear(void){
337 for_each(peers.begin(),peers.end(),pairkill<const ip_id>(&dopd));
338 peers.erase(peers.begin(),peers.end());
339 for_each(unknown_peers.begin(),unknown_peers.end(),dopd);
340 unknown_peers.erase(unknown_peers.begin(),unknown_peers.end());
342 ip_peer_list::~ip_peer_list(){
350 static void dumpid(unsigned char *a)
352 printf("<%u.%u.%u.%u.%u.%u>",a[0],a[1],a[2],a[3],a[4],a[5]);
356 int ip_sendtoid(ubyte *id,const void *buf,int len){
357 // ip_handshaker *hsr=find_handshaker_by_id(id);
358 ip_peer *p=peer_list.find_byid(id);
359 if (!p || p->addr.goodaddr==NULL){
361 printf(MSGHDR"send to invalid id(");
367 return ip_sendtoca(*p->addr.goodaddr,buf,len);
370 void ip_receive_cfg(ubyte *buf,int buflen,ip_addr fromaddr){
376 printf("ip_receive_cfg: %i %i ",buf[0],buf[1]);
378 printf(" v%i tryid%u\n",ntohs(*(unsigned short*)(buf+8)),(unsigned int)ntohl(*(u_int32_t*)(buf+10)));
382 case IP_CFG_HANDSHAKE:
384 printf("ip_receive_cfg: %i %i ",buf[0],buf[1]);
386 printf(" v%i tryid%u\n",ntohs(*(unsigned short*)(buf+8)),(unsigned int)ntohl(*(u_int32_t*)(buf+10)));
389 ip_handshake_info *hsi=new ip_handshake_info(buf);
390 hsi->addr.add(fromaddr);
391 ip_handshake_info *lhsi=NULL;
392 p=peer_list.find_byid(hsi->id);
394 printf("hsi %i %i id=",hsi->type,hsi->state);
396 printf(" ver=%i tryid=%u\n",hsi->iver,hsi->tryid);
397 mprintf((0,"peer_list.find_byid=%p\n",p));
400 p=peer_list.find_unk_by_addr(fromaddr);
401 // mprintf((0,"peer_list.find_by_addr=%p\n",p));
403 peer_list.make_full(p,hsi->id,hsi->iver,hsi->addr);
407 p->verify_addr(hsi->addr);
409 p=peer_list.add_hsi(hsi);
410 // mprintf((0,"peer_list.add_hsi=%p\n",p));
412 lhsi=p->find_handshake();
413 lhsi->tryid=hsi->tryid;
414 if (p->addr.goodaddr==NULL){
415 p->addr.setgoodaddr(fromaddr);
416 // lhsi->state&=STATE_INEEDINFO;
418 if (hsi->state&STATE_INEEDINFO)
419 lhsi->setstate(STATE_SENDINGINFO);
420 //lhsi->state&=STATE_SENDINGINFO;
424 // mprintf((0,"lhsi->state=%i\n",lhsi->state));
425 // mprintf((0,"hsi->state=%i\n",hsi->state));
427 p->send_handshake(lhsi);
434 ip_handshake_relay hsr(buf);
436 printf("ip_receive_cfg: %i %i ",buf[0],buf[1]);
438 printf(" v%i r_id ",ntohs(*(unsigned short*)(buf+8)));
440 printf(" r_iv%i\n",hsr.r_iver);
442 p=peer_list.find_byid(hsr.id);
444 mprintf((0,"relay from unknown peer\n"));
447 rp=peer_list.find_byid(hsr.r_id);
448 if (hsr.state&STATE_RELAYREPLY){
450 mprintf((0,"relay reply for unknown peer\n"));
453 ip_handshake_relay *rhsr=p->find_relay(rp->id);
460 printf(" is ok with ");
466 rp=peer_list.add_full(hsr.r_id,hsr.r_iver,hsr.r_addr);
468 rp->verify_addr(hsr.r_addr);
470 if (rp->addr.goodaddr==NULL){
471 mprintf((0,"sending relayed handshake\n"));
472 //handshake with relayed peer
473 ip_handshake_info *lhsi=rp->find_handshake();
474 // lhsi->setstate(STATE_INEEDINFO);
475 if (lhsi->addstate(STATE_INEEDINFO));
476 rp->send_handshake(lhsi);
478 mprintf((0,"sending relayed reply\n"));
480 ip_handshake_relay rhsr(rp);
481 rhsr.setstate(STATE_RELAYREPLY);
482 p->send_handshake(&rhsr);
491 int ipx_ip_GetMyAddress(void) {
494 u_int32_t myhandshakeid;
496 d_srand( timer_get_approx_seconds() );
497 // printf("set my id to %u\n",myhandshakeid);
501 if (!FindArg("-ip_nogetmyaddr"))
502 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.
503 // if (arch_ip_get_my_addr(myport)) return -1;
505 if ((i=FindArg("-ip_myaddr"))){
507 if (!ip.dns(Args[i+1],myport)){
512 myhandshakeid=htonl(d_rand32());
513 //ipx_MyAddress[4]=qhbuf[2];
514 //ipx_MyAddress[5]=qhbuf[3];
515 if (ip_my_addrs.naddr){
516 ip_addr ip=*ip_my_addrs.begin();
517 ipx_MyAddress[4]=ip.addr[2];
518 ipx_MyAddress[5]=ip.addr[3];
520 ipx_MyAddress[4]=d_rand()%255;
521 ipx_MyAddress[5]=d_rand()%255;
523 //memcpy(ipx_MyAddress+6,&handshake_buf.id,4);
524 memcpy(ipx_MyAddress+6,&myhandshakeid,4);
527 printf(MSGHDR "Using TCP/IP id ");
528 dumprid(ipx_MyAddress+4);
533 /* Parse PORTSHIFT numeric parameter
536 unsigned short ip_portshift(unsigned short baseport, const char *cs)
539 unsigned short ports=htons(baseport);
542 if (cs[0]=='-' || cs[0]=='+')//relative port
543 // if (port<-PORTSHIFT_TOLERANCE || port>+PORTSHIFT_TOLERANCE)
544 // msg("Invalid portshift in \"%s\", tolerance is +/-%d",cs,PORTSHIFT_TOLERANCE);
546 ports=htons(port+baseport);
548 ports=htons(port);//absolute port
550 // memcpy(qhbuf+4,&ports,2);