2 * $Source: /cvs/cvsroot/d2x/main/ip_base.cpp,v $
5 * $Date: 2002-02-14 09:24:19 $
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.2 2002/02/13 10:39:21 bradleyb
12 * Lotsa networking stuff from d1x
14 * Revision 1.1 2002/02/06 09:22:41 bradleyb
15 * Adding d1x network code
34 int baseport=UDP_BASEPORT;
36 ip_addr_list ip_my_addrs;
37 ip_peer_list peer_list;
39 int ip_handshake_base::fillbuf(ubyte *buf){
45 // memcpy(buf+pos,id,6);pos+=6;
46 pos+=id.fillbuf(buf+pos);
48 memcpy(buf+pos,&tmp16,2);pos+=2;
50 memcpy(buf+pos,&tmp32,4);pos+=4;
53 int ip_handshake_base::readbuf(ubyte *buf){
58 // memcpy(id,buf+pos,6);pos+=6;
59 pos+=id.readbuf(buf+pos);
60 memcpy(&iver,buf+pos,2);pos+=2;
62 memcpy(&tryid,buf+pos,4);pos+=4;
66 void ip_handshake_base::setstate(int newstate){
68 if (state&STATE_NEED_RESEND){
69 if (!(newstate&STATE_NEED_RESEND))
70 peer_list.pendinghandshakes--;
72 if (newstate&STATE_NEED_RESEND)
73 peer_list.pendinghandshakes++;
75 mprintf((0,"peer_list.pendinghandshakes=%i\n",peer_list.pendinghandshakes));
77 state=newstate;attempts=0;nextsend=0;
79 int ip_handshake_base::addstate(int newstate){
80 if (state & STATE_ERR){
81 setstate((state | newstate) & ~STATE_ERR);
84 if ((state | newstate) != state){
85 setstate(state | newstate);
91 int ip_handshake_info::fillbuf(ubyte *buf){
92 int pos=ip_handshake_base::fillbuf(buf);
93 pos+=addr.fillbuf(buf+pos);
94 // memcpy(buf+pos,addr,6);pos+=6;
97 int ip_handshake_info::readbuf(ubyte *buf){
98 int pos=ip_handshake_base::readbuf(buf);
99 pos+=addr.readbuf(buf+pos);
100 // memcpy(addr,buf+pos,6);pos+=6;
104 int ip_handshake_relay::fillbuf(ubyte *buf){
106 int pos=ip_handshake_base::fillbuf(buf);
107 // memcpy(buf+pos,r_addr[0],6);pos+=6;
108 // memcpy(buf+pos,r_addr[1],6);pos+=6;
109 // memcpy(buf+pos,r_id,6);pos+=6;
110 pos+=r_id.fillbuf(buf+pos);
112 memcpy(buf+pos,&tmp16,2);pos+=2;
113 pos+=r_addr.fillbuf(buf+pos);
114 // pos+=r_addr[1].fillbuf(buf+pos);
117 int ip_handshake_relay::readbuf(ubyte *buf){
118 int pos=ip_handshake_base::readbuf(buf);
119 // memcpy(r_addr[0],buf+pos,6);pos+=6;
120 // memcpy(r_addr[1],buf+pos,6);pos+=6;
121 // memcpy(r_id,buf+pos,6);pos+=6;
122 pos+=r_id.readbuf(buf+pos);
123 memcpy(&r_iver,buf+pos,2);pos+=2;
124 r_iver=htons(r_iver);
125 pos+=r_addr.readbuf(buf+pos);
126 // pos+=r_addr[1].readbuf(buf+pos);
129 ip_handshake_relay::ip_handshake_relay(ip_peer *torelay):ip_handshake_base(1){
132 r_iver=torelay->iver;
133 r_addr=torelay->addr;
134 // r_addr[1]=torelay->addr[1];
135 setstate(STATE_INEEDINFO);
138 /*void ip_peer::set_good_addr(ubyte *fraddr){
140 for (i=0;i<numaddr;i++)
141 if (addr[i]==fraddr){
150 void ip_peer::send_handshake(ip_handshake_base*hsb){
153 memcpy(buf+s,D2Xcfgid,4);s+=4;
154 s+=hsb->fillbuf(buf+s);
156 if (addr.goodaddr==NULL){
157 ip_addr_list::iterator i;
158 for (i=addr.begin();i!=addr.end();i++)
159 ip_sendtoca(*i,buf,s);
161 // for (i=0;i<addr.naddr;i++)
162 // ip_sendtoca(addr[i],buf,s);
164 //ip_sendtoca(addr[goodaddr],buf,s);
165 ip_sendtoca(*addr.goodaddr,buf,s);
166 hsb->nextsend=timer_get_approx_seconds()+IP_HS_RETRYTIME;
171 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);
172 for (hj=0;hj<numaddr;hj++){
175 dumpraddr(addr[hj].addr);
177 printf(" v%i\n",iver);
181 bool ip_peer::verify_addr(ip_addr_list &fraddrs){
182 int a1=addr.add(fraddrs);
185 /* a1=(addr[0]!=fraddr0 && addr[1]!=fraddr0);
186 a2=(addr[0]!=fraddr1 && addr[1]!=fraddr1);
187 if (a1 || a2 || (numaddr<2 && fraddr0!=fraddr1))
189 mprintf((0,"verify_peer_addr_hsi %i %i\n",a1,a2));
198 ip_peer * ip_peer_list::add_1(ip_addr addr/*,ip_id id*/){
206 ip_peer * ip_peer_list::add_full(ip_id id, u_int16_t iver,ip_addr_list &addrs){
207 ip_peer*n=add_id(id);
218 mprintf((0,"addfull %i addrs\n",n->addr.naddr));
222 void ip_peer_list::make_full(ip_peer*p,ip_id id, u_int16_t iver, ip_addr_list &addrs){
223 list<ip_peer*>::iterator unki=find(unknown_peers.begin(),unknown_peers.end(),p);
224 if (unki!=unknown_peers.end())
225 unknown_peers.erase(unki);
231 peers.insert(peer_map::value_type(p->id,p));
233 ip_peer * ip_peer_list::find_byid(ip_id id){
234 peer_map::iterator i=peers.find(id);
239 struct do_find_by_addr : public unary_function<ip_peer*,bool> {
242 bool operator()(ip_peer * p) {
243 //// bool operator()(pair<const ip_id,ip_peer *> &) {
244 // for(j=0;j<p->numaddr;j++)
245 // if (addr==p->addr[j])
247 if (p->addr.hasaddr(addr))
252 template <class ret,class p1,class p2, class fo>
255 ret operator()(pair<p1,p2> &aoeuaoeu) {
256 return (*o)(aoeuaoeu.second);
258 pairkiller(fo *no):o(no){}
260 //template <class ret,class p1,class p2, class fo>
261 template <class p1, class fo>
262 pairkiller<typename fo::result_type,p1,typename fo::argument_type,fo> pairkill(fo * no){
263 return pairkiller<typename fo::result_type,p1,typename fo::argument_type,fo>(no);
266 ip_peer * ip_peer_list::find_by_addr(ip_addr addr){
268 // pairkiller<const ip_id,ip_peer*,do_find_by_addr> fbap(&fba);
270 peer_map::iterator i=find_if(peers.begin(),peers.end(),pairkill<const ip_id>(&fba));
273 list<ip_peer*>::iterator j=find_if(unknown_peers.begin(),unknown_peers.end(),fba);
274 if (j!=unknown_peers.end())
278 ip_peer * ip_peer_list::find_unk_by_addr(ip_addr addr){
281 list<ip_peer*>::iterator j=find_if(unknown_peers.begin(),unknown_peers.end(),fba);
282 if (j!=unknown_peers.end())
286 struct do_peer_handshake : public unary_function<ip_peer *, void>{
288 list<ip_handshake_base*>::iterator i;
289 ip_handshake_base *hsb;
290 void operator() (ip_peer* peer) {
291 for(i=peer->handshakes.begin();i!=peer->handshakes.end();++i){
293 //if (hsb->state<IPNOSTATE && hsb->nextsend<mintime){
294 if ((hsb->state & STATE_NEED_RESEND) && hsb->nextsend<mintime){
295 if(hsb->attempts>IP_MAX_HS_ATTEMPTS){
298 printf(MSGHDR"handshake timeout (state %i(%s)) for (%i)",hsb->state,ip_hs_statetoa(hsb->state),peer->goodaddr);
299 for (hj=0;hj<peer->numaddr;hj++){
302 dumpraddr(peer->addr[hj].addr);
304 printf(" v%i\n",peer->iver);
306 hsb->setstate(STATE_ERR);
308 // handshake_buf.state=handshakers[i].state;
309 peer->send_handshake(hsb);
315 void ip_peer_list::handshake_frame(void){
316 if(pendinghandshakes){
317 fix mintime=timer_get_approx_seconds();//try every X seconds
318 if (pendinghandshake_lasttime<mintime-IP_HS_FRAME_RETRYTIME){
319 do_peer_handshake doph;
320 // pairkiller<const ip_id,ip_peer*,do_peer_handshake> dophp(&doph);
321 doph.mintime=mintime;
322 for_each(peers.begin(),peers.end(),pairkill<const ip_id>(&doph));
323 for_each(unknown_peers.begin(),unknown_peers.end(),doph);
325 // mintime-=IP_HS_RETRYTIME;//try every X seconds
326 /* for (i=0;i<numpeers;i++){
327 ip_handshake_do_hs(&peers[i],&peers[i].query,mintime);
328 ip_handshake_do_hs(&peers[i],&peers[i].reply,mintime);
333 struct do_peer_delete : public unary_function<ip_peer *, void>{
334 void operator() (ip_peer* peer) {
338 void ip_peer_list::clear(void){
340 for_each(peers.begin(),peers.end(),pairkill<const ip_id>(&dopd));
341 peers.erase(peers.begin(),peers.end());
342 for_each(unknown_peers.begin(),unknown_peers.end(),dopd);
343 unknown_peers.erase(unknown_peers.begin(),unknown_peers.end());
345 ip_peer_list::~ip_peer_list(){
353 static void dumpid(unsigned char *a)
355 printf("<%u.%u.%u.%u.%u.%u>",a[0],a[1],a[2],a[3],a[4],a[5]);
359 int ip_sendtoid(ubyte *id,const void *buf,int len){
360 // ip_handshaker *hsr=find_handshaker_by_id(id);
361 ip_peer *p=peer_list.find_byid(id);
362 if (!p || p->addr.goodaddr==NULL){
364 printf(MSGHDR"send to invalid id(");
370 return ip_sendtoca(*p->addr.goodaddr,buf,len);
373 void ip_receive_cfg(ubyte *buf,int buflen,ip_addr fromaddr){
379 printf("ip_receive_cfg: %i %i ",buf[0],buf[1]);
381 printf(" v%i tryid%u\n",ntohs(*(unsigned short*)(buf+8)),(unsigned int)ntohl(*(u_int32_t*)(buf+10)));
385 case IP_CFG_HANDSHAKE:
387 printf("ip_receive_cfg: %i %i ",buf[0],buf[1]);
389 printf(" v%i tryid%u\n",ntohs(*(unsigned short*)(buf+8)),(unsigned int)ntohl(*(u_int32_t*)(buf+10)));
392 ip_handshake_info *hsi=new ip_handshake_info(buf);
393 hsi->addr.add(fromaddr);
394 ip_handshake_info *lhsi=NULL;
395 p=peer_list.find_byid(hsi->id);
397 printf("hsi %i %i id=",hsi->type,hsi->state);
399 printf(" ver=%i tryid=%u\n",hsi->iver,hsi->tryid);
400 mprintf((0,"peer_list.find_byid=%p\n",p));
403 p=peer_list.find_unk_by_addr(fromaddr);
404 // mprintf((0,"peer_list.find_by_addr=%p\n",p));
406 peer_list.make_full(p,hsi->id,hsi->iver,hsi->addr);
410 p->verify_addr(hsi->addr);
412 p=peer_list.add_hsi(hsi);
413 // mprintf((0,"peer_list.add_hsi=%p\n",p));
415 lhsi=p->find_handshake();
416 lhsi->tryid=hsi->tryid;
417 if (p->addr.goodaddr==NULL){
418 p->addr.setgoodaddr(fromaddr);
419 // lhsi->state&=STATE_INEEDINFO;
421 if (hsi->state&STATE_INEEDINFO)
422 lhsi->setstate(STATE_SENDINGINFO);
423 //lhsi->state&=STATE_SENDINGINFO;
427 // mprintf((0,"lhsi->state=%i\n",lhsi->state));
428 // mprintf((0,"hsi->state=%i\n",hsi->state));
430 p->send_handshake(lhsi);
437 ip_handshake_relay hsr(buf);
439 printf("ip_receive_cfg: %i %i ",buf[0],buf[1]);
441 printf(" v%i r_id ",ntohs(*(unsigned short*)(buf+8)));
443 printf(" r_iv%i\n",hsr.r_iver);
445 p=peer_list.find_byid(hsr.id);
447 mprintf((0,"relay from unknown peer\n"));
450 rp=peer_list.find_byid(hsr.r_id);
451 if (hsr.state&STATE_RELAYREPLY){
453 mprintf((0,"relay reply for unknown peer\n"));
456 ip_handshake_relay *rhsr=p->find_relay(rp->id);
463 printf(" is ok with ");
469 rp=peer_list.add_full(hsr.r_id,hsr.r_iver,hsr.r_addr);
471 rp->verify_addr(hsr.r_addr);
473 if (rp->addr.goodaddr==NULL){
474 mprintf((0,"sending relayed handshake\n"));
475 //handshake with relayed peer
476 ip_handshake_info *lhsi=rp->find_handshake();
477 // lhsi->setstate(STATE_INEEDINFO);
478 if (lhsi->addstate(STATE_INEEDINFO));
479 rp->send_handshake(lhsi);
481 mprintf((0,"sending relayed reply\n"));
483 ip_handshake_relay rhsr(rp);
484 rhsr.setstate(STATE_RELAYREPLY);
485 p->send_handshake(&rhsr);
494 int ipx_ip_GetMyAddress(void) {
497 u_int32_t myhandshakeid;
499 d_srand( timer_get_approx_seconds() );
500 // printf("set my id to %u\n",myhandshakeid);
504 if (!FindArg("-ip_nogetmyaddr"))
505 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.
506 // if (arch_ip_get_my_addr(myport)) return -1;
508 if ((i=FindArg("-ip_myaddr"))){
510 if (!ip.dns(Args[i+1],myport)){
515 myhandshakeid=htonl(d_rand32());
516 //ipx_MyAddress[4]=qhbuf[2];
517 //ipx_MyAddress[5]=qhbuf[3];
518 if (ip_my_addrs.naddr){
519 ip_addr ip=*ip_my_addrs.begin();
520 ipx_MyAddress[4]=ip.addr[2];
521 ipx_MyAddress[5]=ip.addr[3];
523 ipx_MyAddress[4]=d_rand()%255;
524 ipx_MyAddress[5]=d_rand()%255;
526 //memcpy(ipx_MyAddress+6,&handshake_buf.id,4);
527 memcpy(ipx_MyAddress+6,&myhandshakeid,4);
530 printf(MSGHDR "Using TCP/IP id ");
531 dumprid(ipx_MyAddress+4);
536 /* Parse PORTSHIFT numeric parameter
539 unsigned short ip_portshift(unsigned short baseport, const char *cs)
542 unsigned short ports=htons(baseport);
545 if (cs[0]=='-' || cs[0]=='+')//relative port
546 // if (port<-PORTSHIFT_TOLERANCE || port>+PORTSHIFT_TOLERANCE)
547 // msg("Invalid portshift in \"%s\", tolerance is +/-%d",cs,PORTSHIFT_TOLERANCE);
549 ports=htons(port+baseport);
551 ports=htons(port);//absolute port
553 // memcpy(qhbuf+4,&ports,2);