2 * $Source: /cvs/cvsroot/d2x/main/ip_base.h,v $
5 * $Date: 2002-02-15 06:41:42 $
7 * ip_base.h - 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:45:49 bradleyb
15 * Lotsa networking stuff from d1x
17 * Revision 1.1 2002/02/06 09:22:41 bradleyb
18 * Adding d1x network code
42 class ip_addr;//prototype for arch_ip_queryhost
48 //inline u_int32_t d_rand32(void) { return d_rand() + (d_rand()<<16);}
49 inline u_int32_t d_rand32(void) { return d_rand() + (d_rand()<<15) + (d_rand()<<30);}//d_rand() only returns 15 bits
52 void ip_receive_cfg(ubyte *buf,int buflen,ip_addr fromaddr);
54 extern unsigned char ipx_MyAddress[10];
56 unsigned short ip_portshift(unsigned short baseport, const char *cs);
58 #define UDP_BASEPORT 31017
59 #define UDP_SERV_BASEPORT 30817
60 #define PORTSHIFT_TOLERANCE 0x100
61 #define MAX_PACKETSIZE 8192
63 // Length HAS TO BE 2!
65 // Length HAS TO BE 4!
66 #define D2Xcfgid "\xcfg\xd2x"
71 #define IP_CFG_HANDSHAKE 1
72 #define IP_CFG_RELAY 2
73 //someone giving us an error (ie, outdated version, etc.) ... not handled yet.
74 #define IP_CFG_SORRY 3
77 #define STATE_INEEDINFO 1<<0
78 #define STATE_SENDINGINFO 1<<1
79 //#define STATE_NEED_RESEND (STATE_INEEDINFO | STATE_SENDINGINFO)
80 #define STATE_NEED_RESEND (STATE_INEEDINFO)
81 #define STATE_VALID_STATES (STATE_INEEDINFO | STATE_SENDINGINFO)
82 #define STATE_RELAYREPLY 1<<6
83 #define STATE_ERR 1<<7
84 /* Dump raw form of IP address/port by fancy output to user
90 inline char *ip_hs_statetoa(int state){
95 if ((state&(STATE_INEEDINFO|STATE_SENDINGINFO))==(STATE_INEEDINFO|STATE_SENDINGINFO))
97 if (state&STATE_INEEDINFO)
99 if (state&STATE_SENDINGINFO)
103 inline void dumprid(const unsigned char *a)
105 con_printf(CON_DEBUG, "<%u.%u.%u.%u.%u.%u>",a[0],a[1],a[2],a[3],a[4],a[5]);
107 inline void dumpraddr(const unsigned char *addr)
110 con_printf(CON_DEBUG, "[%u.%u.%u.%u]",addr[0],addr[1],addr[2],addr[3]);
111 port=(unsigned short)ntohs(*(unsigned short *)(addr+4));
112 con_printf(CON_DEBUG, ":%d",port);
121 int fillbuf(ubyte *buf)const {memcpy(buf,id,6);return 6;};
122 int readbuf(const ubyte *buf){memcpy(id,buf,6);return 6;};
123 bool operator < (const ip_id &a_id)const {return memcmp(id,a_id.id,6)<0;}
124 bool operator == (const ip_id &a_id)const {return memcmp(id,a_id.id,6)==0;}
125 bool operator > (const ip_id &a_id)const {return memcmp(id,a_id.id,6)>0;}
126 ip_id& operator = (const ip_id &a_id){readbuf(a_id.id);return *this;}
128 void dump(void){dumprid(id);}
130 ip_id(ubyte*nid){readbuf(nid);}
136 ubyte alen;//alen stuff is to maybe make ipv6 support easier (if the transition ever actually happens)
140 int fillbuf(ubyte *buf)const {buf[0]=alen;memcpy(buf+1,addr,alen);return alen+1;};
141 int readbuf(const ubyte *buf){
144 memcpy(addr,buf+1,6);alen=l;
146 mprintf((0,"ip_addr readbuf bad len %i\n",l));
147 memset(addr,0,6);alen=0;
151 bool operator < (const ip_addr &a_addr)const {
152 if (alen!=a_addr.alen) return alen<a_addr.alen;
153 return memcmp(addr,a_addr.addr,alen)<0;
155 bool operator == (const ip_addr &a_addr)const {return ((alen==a_addr.alen) && (memcmp(addr,a_addr.addr,alen)==0));}
156 bool operator > (const ip_addr &a_addr)const {
157 if (alen!=a_addr.alen) return alen>a_addr.alen;
158 return memcmp(addr,a_addr.addr,alen)>0;
160 ip_addr& operator = (const ip_addr &a_addr){alen=a_addr.alen;memcpy(addr,a_addr.addr,6);return *this;}
162 void dump(void)const{dumpraddr(addr);}
164 void set(int addrsize,ubyte *naddr,ushort port){
165 if (addrsize!=4)return;//not handled yet.
167 memcpy(addr,naddr,addrsize);
169 memcpy(addr+addrsize,&port,2);
171 int dns(char *address,ushort baseport){
172 return arch_ip_queryhost(this,address,baseport);
174 bool ok(void)const{return alen>0;}
175 int addrlen(void)const{return alen-2;}
176 // ip_addr(ubyte*naddr){readbuf(naddr);}
177 ip_addr(void){alen=0;};
184 typedef list<ip_addr>::iterator iterator;
185 typedef list<ip_addr>::const_iterator const_iterator;
189 iterator begin(void){return addrs.begin();}
190 iterator end(void){return addrs.end();}
191 const_iterator begin(void)const{return addrs.begin();}
192 const_iterator end(void)const{return addrs.end();}
193 bool hasaddr(ip_addr addr){
194 iterator i=find(begin(),end(),addr);
195 return (i!=addrs.end());
197 int add(ip_addr addr){
200 addrs.push_back(addr);
204 int add(const ip_addr_list &na){
206 const_iterator i=na.begin();
207 for (;i!=na.end();++i)
211 void setgoodaddr(ip_addr addr){
212 iterator i=find(begin(),end(),addr);
217 addrs.push_back(addr);
218 goodaddr=&(*addrs.end());
220 int fillbuf(ubyte *buf)const {
224 for (i=begin();i!=end();++i)
225 s+=(*i).fillbuf(buf+s);
228 int readbuf(const ubyte *buf){
231 for (n=buf[0];n;--n){
233 // addrs.push_back(a);
242 addrs.erase(begin(),end());
245 ip_addr_list(const ip_addr_list &nl):addrs(nl.addrs),naddr(nl.naddr){setgoodaddr(*nl.goodaddr);}
246 ip_addr_list(void):naddr(0),goodaddr(NULL){}
247 // ip_addr_list(const ubyte * buf):naddr(0),goodaddr(NULL){readbuf(buf);}
250 extern ip_addr_list ip_my_addrs;
252 extern int ip_sendtoca(ip_addr addr,const void *buf,int len);
254 class ip_handshake_base {
266 virtual int fillbuf(ubyte *buf);
267 virtual int readbuf(ubyte *buf);
268 void setrandid(void){tryid=d_rand32() ^ timer_get_approx_seconds();}
269 void setstate(int newstate);
270 int addstate(int newstate);
272 // ip_handshake_base(void):type(IP_CFG_BASE){setstate(IPNOSTATE);}
273 ip_handshake_base(bool initme=0):type(IP_CFG_BASE){
284 virtual ~ip_handshake_base(){setstate(0);}//decrement pendinghandshakes if needed.
286 class ip_handshake_info : public ip_handshake_base {
290 virtual int fillbuf(ubyte *buf);
291 virtual int readbuf(ubyte *buf);
293 ip_handshake_info(ubyte *buf){
296 ip_handshake_info(void):ip_handshake_base(1){
297 type=IP_CFG_HANDSHAKE;
299 // setstate(STATE_INEEDINFO);
303 class ip_handshake_relay : public ip_handshake_base {
309 virtual int fillbuf(ubyte *buf);
310 virtual int readbuf(ubyte *buf);
312 ip_handshake_relay(ubyte *buf){
315 ip_handshake_relay(ip_peer *torelay);
318 //max number of times to try to handshake a host
319 #define IP_MAX_HS_ATTEMPTS 10
320 //how often to resend a hand-shake (3 seconds)
321 #define IP_HS_RETRYTIME (F1_0*3)
322 //how often (max) to search through the resend loop (1 second)
323 #define IP_HS_FRAME_RETRYTIME (F1_0)
331 // ip_hs_state query;
332 // ip_hs_state reply;
333 list<ip_handshake_base*> handshakes;
335 // void set_good_addr(ubyte *fraddr);
336 void add_hs(ip_handshake_base* hs){
337 // mprintf((0,"########## add_hs %p: adding a hs %p %i %i\n",this,hs,hs->type,hs->state));
338 handshakes.push_back(hs);
340 ip_handshake_relay* find_relay(ip_id r_id){
341 list<ip_handshake_base*>::iterator i;
342 ip_handshake_base* hsb;
343 ip_handshake_relay* hsr;
344 for (i=handshakes.begin();i!=handshakes.end();++i){
346 if (hsb->type==IP_CFG_RELAY){
347 hsr=(ip_handshake_relay*)hsb;
354 ip_handshake_info* find_handshake(void){
355 list<ip_handshake_base*>::iterator i;
356 ip_handshake_base* hsb;
357 for (i=handshakes.begin();i!=handshakes.end();++i){
359 if (hsb->type==IP_CFG_HANDSHAKE)
360 return (ip_handshake_info*) hsb;
362 ip_handshake_info *ni=new ip_handshake_info();
363 // handshakes.push_back(ni);
367 /* ip_handshake_base* find_hs(u_int32_t tryid, ubyte type){
368 list<ip_handshake_base*>::iterator i;
369 ip_handshake_base* hsb;
370 for (i=handshakes.begin();i!=handshakes.end();++i){
372 if (hsb->tryid==tryid && hsb->type==type)
377 void send_handshake(ip_handshake_base*hsb);
378 bool verify_addr(ip_addr_list &fraddrs);
379 ip_peer(void){iver=0;}
381 list<ip_handshake_base*>::iterator i;
382 for (i=handshakes.begin();i!=handshakes.end();++i){
383 /* mprintf((0,"###### ~ip_peer %p: deleting a hs %p %i %i\n",this,(*i),(*i)->type,(*i)->state));
385 mprintf((0,"~ip_peer null hs?\n"));
395 typedef map<ip_id,ip_peer *,less<ip_id> > peer_map;
397 list<ip_peer*> unknown_peers;
398 int pendinghandshakes;
399 fix pendinghandshake_lasttime;
401 ip_peer * add_id(ip_id id){
402 ip_peer*n=new ip_peer();
404 peers.insert(peer_map::value_type(n->id,n));
407 ip_peer * add_unk(void){
408 ip_peer*n=new ip_peer();
409 unknown_peers.push_back(n);
412 //ip_peer * add_1(ubyte *addr,ip_id id);
413 ip_peer * add_1(ip_addr addr);
414 ip_peer * add_full(ip_id id, u_int16_t iver, ip_addr_list &addrs);
415 void make_full(ip_peer*p,ip_id id, u_int16_t iver, ip_addr_list &addrs);
416 ip_peer * add_hsi(ip_handshake_info *hsi){return add_full(hsi->id,hsi->iver,hsi->addr);}
417 ip_peer * find_byid(ip_id id);
418 ip_peer * find_by_addr(ip_addr addr);
419 ip_peer * find_unk_by_addr(ip_addr addr);
420 void handshake_frame(void);
424 pendinghandshake_lasttime=0;
428 extern ip_peer_list peer_list;