2 * $Source: /cvs/cvsroot/d2x/main/ip_base.cpp,v $
5 * $Date: 2002-02-15 06:41:42 $
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.3 2002/02/14 09:24:19 bradleyb
14 * Revision 1.2 2002/02/13 10:39:21 bradleyb
15 * Lotsa networking stuff from d1x
17 * Revision 1.1 2002/02/06 09:22:41 bradleyb
18 * Adding d1x network code
37 int baseport=UDP_BASEPORT;
39 ip_addr_list ip_my_addrs;
40 ip_peer_list peer_list;
42 int ip_handshake_base::fillbuf(ubyte *buf){
48 // memcpy(buf+pos,id,6);pos+=6;
49 pos+=id.fillbuf(buf+pos);
51 memcpy(buf+pos,&tmp16,2);pos+=2;
53 memcpy(buf+pos,&tmp32,4);pos+=4;
56 int ip_handshake_base::readbuf(ubyte *buf){
61 // memcpy(id,buf+pos,6);pos+=6;
62 pos+=id.readbuf(buf+pos);
63 memcpy(&iver,buf+pos,2);pos+=2;
65 memcpy(&tryid,buf+pos,4);pos+=4;
69 void ip_handshake_base::setstate(int newstate){
71 if (state&STATE_NEED_RESEND){
72 if (!(newstate&STATE_NEED_RESEND))
73 peer_list.pendinghandshakes--;
75 if (newstate&STATE_NEED_RESEND)
76 peer_list.pendinghandshakes++;
78 mprintf((0,"peer_list.pendinghandshakes=%i\n",peer_list.pendinghandshakes));
80 state=newstate;attempts=0;nextsend=0;
82 int ip_handshake_base::addstate(int newstate){
83 if (state & STATE_ERR){
84 setstate((state | newstate) & ~STATE_ERR);
87 if ((state | newstate) != state){
88 setstate(state | newstate);
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;
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;
107 int ip_handshake_relay::fillbuf(ubyte *buf){
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);
115 memcpy(buf+pos,&tmp16,2);pos+=2;
116 pos+=r_addr.fillbuf(buf+pos);
117 // pos+=r_addr[1].fillbuf(buf+pos);
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);
132 ip_handshake_relay::ip_handshake_relay(ip_peer *torelay):ip_handshake_base(1){
135 r_iver=torelay->iver;
136 r_addr=torelay->addr;
137 // r_addr[1]=torelay->addr[1];
138 setstate(STATE_INEEDINFO);
141 /*void ip_peer::set_good_addr(ubyte *fraddr){
143 for (i=0;i<numaddr;i++)
144 if (addr[i]==fraddr){
153 void ip_peer::send_handshake(ip_handshake_base*hsb){
156 memcpy(buf+s,D2Xcfgid,4);s+=4;
157 s+=hsb->fillbuf(buf+s);
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);
164 // for (i=0;i<addr.naddr;i++)
165 // ip_sendtoca(addr[i],buf,s);
167 //ip_sendtoca(addr[goodaddr],buf,s);
168 ip_sendtoca(*addr.goodaddr,buf,s);
169 hsb->nextsend=timer_get_approx_seconds()+IP_HS_RETRYTIME;
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++){
177 con_printf(CON_DEBUG, ", ");
178 dumpraddr(addr[hj].addr);
180 con_printf(CON_DEBUG, " v%i\n",iver);
184 bool ip_peer::verify_addr(ip_addr_list &fraddrs){
185 int a1=addr.add(fraddrs);
188 /* a1=(addr[0]!=fraddr0 && addr[1]!=fraddr0);
189 a2=(addr[0]!=fraddr1 && addr[1]!=fraddr1);
190 if (a1 || a2 || (numaddr<2 && fraddr0!=fraddr1))
192 mprintf((0,"verify_peer_addr_hsi %i %i\n",a1,a2));
201 ip_peer * ip_peer_list::add_1(ip_addr addr/*,ip_id id*/){
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);
221 mprintf((0,"addfull %i addrs\n",n->addr.naddr));
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);
234 peers.insert(peer_map::value_type(p->id,p));
236 ip_peer * ip_peer_list::find_byid(ip_id id){
237 peer_map::iterator i=peers.find(id);
242 struct do_find_by_addr : public unary_function<ip_peer*,bool> {
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])
250 if (p->addr.hasaddr(addr))
255 template <class ret,class p1,class p2, class fo>
258 ret operator()(pair<p1,p2> &aoeuaoeu) {
259 return (*o)(aoeuaoeu.second);
261 pairkiller(fo *no):o(no){}
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);
269 ip_peer * ip_peer_list::find_by_addr(ip_addr addr){
271 // pairkiller<const ip_id,ip_peer*,do_find_by_addr> fbap(&fba);
273 peer_map::iterator i=find_if(peers.begin(),peers.end(),pairkill<const ip_id>(&fba));
276 list<ip_peer*>::iterator j=find_if(unknown_peers.begin(),unknown_peers.end(),fba);
277 if (j!=unknown_peers.end())
281 ip_peer * ip_peer_list::find_unk_by_addr(ip_addr addr){
284 list<ip_peer*>::iterator j=find_if(unknown_peers.begin(),unknown_peers.end(),fba);
285 if (j!=unknown_peers.end())
289 struct do_peer_handshake : public unary_function<ip_peer *, void>{
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){
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){
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++){
304 con_printf(CON_DEBUG, ", ");
305 dumpraddr(peer->addr[hj].addr);
307 con_printf(CON_DEBUG, " v%i\n",peer->iver);
309 hsb->setstate(STATE_ERR);
311 // handshake_buf.state=handshakers[i].state;
312 peer->send_handshake(hsb);
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);
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);
336 struct do_peer_delete : public unary_function<ip_peer *, void>{
337 void operator() (ip_peer* peer) {
341 void ip_peer_list::clear(void){
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());
348 ip_peer_list::~ip_peer_list(){
356 static void dumpid(unsigned char *a)
358 con_printf(CON_DEBUG, "<%u.%u.%u.%u.%u.%u>",a[0],a[1],a[2],a[3],a[4],a[5]);
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){
367 con_printf(CON_DEBUG, MSGHDR"send to invalid id(");
369 con_printf(CON_DEBUG, ") %p.",p);
373 return ip_sendtoca(*p->addr.goodaddr,buf,len);
376 void ip_receive_cfg(ubyte *buf,int buflen,ip_addr fromaddr){
382 con_printf(CON_DEBUG, "ip_receive_cfg: %i %i ",buf[0],buf[1]);
384 con_printf(CON_DEBUG, " v%i tryid%u\n",ntohs(*(unsigned short*)(buf+8)),(unsigned int)ntohl(*(u_int32_t*)(buf+10)));
388 case IP_CFG_HANDSHAKE:
390 con_printf(CON_DEBUG, "ip_receive_cfg: %i %i ",buf[0],buf[1]);
392 con_printf(CON_DEBUG, " v%i tryid%u\n",ntohs(*(unsigned short*)(buf+8)),(unsigned int)ntohl(*(u_int32_t*)(buf+10)));
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);
400 con_printf(CON_DEBUG, "hsi %i %i id=",hsi->type,hsi->state);
402 con_printf(CON_DEBUG, " ver=%i tryid=%u\n",hsi->iver,hsi->tryid);
403 mprintf((0,"peer_list.find_byid=%p\n",p));
406 p=peer_list.find_unk_by_addr(fromaddr);
407 // mprintf((0,"peer_list.find_by_addr=%p\n",p));
409 peer_list.make_full(p,hsi->id,hsi->iver,hsi->addr);
413 p->verify_addr(hsi->addr);
415 p=peer_list.add_hsi(hsi);
416 // mprintf((0,"peer_list.add_hsi=%p\n",p));
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;
424 if (hsi->state&STATE_INEEDINFO)
425 lhsi->setstate(STATE_SENDINGINFO);
426 //lhsi->state&=STATE_SENDINGINFO;
430 // mprintf((0,"lhsi->state=%i\n",lhsi->state));
431 // mprintf((0,"hsi->state=%i\n",hsi->state));
433 p->send_handshake(lhsi);
440 ip_handshake_relay hsr(buf);
442 con_printf(CON_DEBUG, "ip_receive_cfg: %i %i ",buf[0],buf[1]);
444 con_printf(CON_DEBUG, " v%i r_id ",ntohs(*(unsigned short*)(buf+8)));
446 con_printf(CON_DEBUG, " r_iv%i\n",hsr.r_iver);
448 p=peer_list.find_byid(hsr.id);
450 mprintf((0,"relay from unknown peer\n"));
453 rp=peer_list.find_byid(hsr.r_id);
454 if (hsr.state&STATE_RELAYREPLY){
456 mprintf((0,"relay reply for unknown peer\n"));
459 ip_handshake_relay *rhsr=p->find_relay(rp->id);
464 con_printf(CON_DEBUG, "**** ");
466 con_printf(CON_DEBUG, " is ok with ");
468 con_printf(CON_DEBUG, "\n");
472 rp=peer_list.add_full(hsr.r_id,hsr.r_iver,hsr.r_addr);
474 rp->verify_addr(hsr.r_addr);
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);
484 mprintf((0,"sending relayed reply\n"));
486 ip_handshake_relay rhsr(rp);
487 rhsr.setstate(STATE_RELAYREPLY);
488 p->send_handshake(&rhsr);
497 int ipx_ip_GetMyAddress(void) {
500 u_int32_t myhandshakeid;
502 d_srand( timer_get_approx_seconds() );
503 // con_printf(CON_DEBUG, "set my id to %u\n",myhandshakeid);
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;
511 if ((i=FindArg("-ip_myaddr"))){
513 if (!ip.dns(Args[i+1],myport)){
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];
526 ipx_MyAddress[4]=d_rand()%255;
527 ipx_MyAddress[5]=d_rand()%255;
529 //memcpy(ipx_MyAddress+6,&handshake_buf.id,4);
530 memcpy(ipx_MyAddress+6,&myhandshakeid,4);
533 con_printf(CON_DEBUG, MSGHDR "Using TCP/IP id ");
534 dumprid(ipx_MyAddress+4);
535 con_printf(CON_DEBUG, "\n");
539 /* Parse PORTSHIFT numeric parameter
542 unsigned short ip_portshift(unsigned short baseport, const char *cs)
545 unsigned short ports=htons(baseport);
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);
552 ports=htons(port+baseport);
554 ports=htons(port);//absolute port
556 // memcpy(qhbuf+4,&ports,2);