]> icculus.org git repositories - btb/d2x.git/blob - main/ip_base.h
more d1 level loading stuff
[btb/d2x.git] / main / ip_base.h
1 /*
2  * $Source: /cvs/cvsroot/d2x/main/ip_base.h,v $
3  * $Revision: 1.4 $
4  * $Author: bradleyb $
5  * $Date: 2002-02-15 06:41:42 $
6  *
7  * ip_base.h - base for NAT-compatible udp/ip code.
8  * added 2000/02/07 Matt Mueller
9  *
10  * $Log: not supported by cvs2svn $
11  * Revision 1.3  2002/02/14 09:24:19  bradleyb
12  * d1x->d2x
13  *
14  * Revision 1.2  2002/02/13 10:45:49  bradleyb
15  * Lotsa networking stuff from d1x
16  *
17  * Revision 1.1  2002/02/06 09:22:41  bradleyb
18  * Adding d1x network code
19  *
20  *
21  */
22
23 #ifndef ___IP_BASE_H
24 #define ___IP_BASE_H
25
26 #ifndef NDEBUG
27 #define UDPDEBUG
28 #endif
29
30 #include <map.h>
31 #include <list.h>
32 #include <algo.h>
33 extern "C" {
34 #include "ip_basec.h"
35 #include "fix.h"
36 #include "mono.h"
37 #include "vers_id.h"
38 //#include "inetc.h"
39 #include "timer.h"
40 }
41
42 class ip_addr;//prototype for arch_ip_queryhost
43
44 #include "ipclient.h"
45 #include <stdio.h>
46
47
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
50
51
52 void ip_receive_cfg(ubyte *buf,int buflen,ip_addr fromaddr);
53
54 extern unsigned char ipx_MyAddress[10];
55
56 unsigned short ip_portshift(unsigned short baseport, const char *cs);
57
58 #define UDP_BASEPORT 31017
59 #define UDP_SERV_BASEPORT 30817
60 #define PORTSHIFT_TOLERANCE 0x100
61 #define MAX_PACKETSIZE 8192
62
63 // Length HAS TO BE 2!
64 #define D2Xid "\xd2x"
65 // Length HAS TO BE 4!
66 #define D2Xcfgid "\xcfg\xd2x"
67
68
69 //cfg packet types
70 #define IP_CFG_BASE 0
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
75
76
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
85  */
86
87 #ifdef UDPDEBUG
88 #include "console.h"
89
90 inline char *ip_hs_statetoa(int state){
91         if (!state)
92                 return "NOSTATE";
93         if (state&STATE_ERR)
94                 return "ERR";
95         if ((state&(STATE_INEEDINFO|STATE_SENDINGINFO))==(STATE_INEEDINFO|STATE_SENDINGINFO))
96                 return "NEED+SEND";
97         if (state&STATE_INEEDINFO)
98                 return "NEED";
99         if (state&STATE_SENDINGINFO)
100                 return "SEND";
101         return "huh?";
102 }
103 inline void dumprid(const unsigned char *a)
104 {
105     con_printf(CON_DEBUG, "<%u.%u.%u.%u.%u.%u>",a[0],a[1],a[2],a[3],a[4],a[5]);
106 }
107 inline void dumpraddr(const unsigned char *addr)
108 {
109         ushort port;
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);
113 }
114 #endif
115
116
117 class ip_id {
118         public:
119                 ubyte id[6];
120
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;}
127 #ifdef UDPDEBUG
128                 void dump(void){dumprid(id);}
129 #endif
130                 ip_id(ubyte*nid){readbuf(nid);}
131                 ip_id(void){};
132 };
133
134 class ip_addr {
135         protected:
136                 ubyte alen;//alen stuff is to maybe make ipv6 support easier (if the transition ever actually happens)
137         public:
138                 ubyte addr[6];
139
140                 int fillbuf(ubyte *buf)const {buf[0]=alen;memcpy(buf+1,addr,alen);return alen+1;};
141                 int readbuf(const ubyte *buf){
142                         int l=buf[0];
143                         if (l==6){
144                                 memcpy(addr,buf+1,6);alen=l;
145                         }else{
146                                 mprintf((0,"ip_addr readbuf bad len %i\n",l));
147                                 memset(addr,0,6);alen=0;
148                         }
149                         return l+1;
150                 };
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;
154                 }
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;
159                 }
160                 ip_addr& operator = (const ip_addr &a_addr){alen=a_addr.alen;memcpy(addr,a_addr.addr,6);return *this;}
161 #ifdef UDPDEBUG
162                 void dump(void)const{dumpraddr(addr);}
163 #endif
164                 void set(int addrsize,ubyte *naddr,ushort port){
165                         if (addrsize!=4)return;//not handled yet.
166                         alen=addrsize+2;
167                         memcpy(addr,naddr,addrsize);
168 //                      port=htons(port);
169                         memcpy(addr+addrsize,&port,2);
170                 }
171                 int dns(char *address,ushort baseport){
172                         return arch_ip_queryhost(this,address,baseport);
173                 }
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;};
178 };
179
180 class ip_addr_list {
181         protected:
182                 list<ip_addr> addrs;
183         public:
184                 typedef list<ip_addr>::iterator iterator;
185                 typedef list<ip_addr>::const_iterator const_iterator;
186                 int naddr;
187                 ip_addr *goodaddr;
188
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());
196                 }
197                 int add(ip_addr addr){
198                         if (hasaddr(addr))
199                                 return 0;
200                         addrs.push_back(addr);
201                         naddr++;
202                         return 1;
203                 }
204                 int add(const ip_addr_list &na){
205                         int j=0;
206                         const_iterator i=na.begin();
207                         for (;i!=na.end();++i)
208                                 j+=add(*i);
209                         return j;
210                 }
211                 void setgoodaddr(ip_addr addr){
212                         iterator i=find(begin(),end(),addr);
213                         if (i!=end()){
214                                 goodaddr=&(*i);
215                                 return;
216                         }
217                         addrs.push_back(addr);
218                         goodaddr=&(*addrs.end());
219                 }
220                 int fillbuf(ubyte *buf)const {
221                         int s=0;
222                         const_iterator i;
223                         buf[s++]=naddr;
224                         for (i=begin();i!=end();++i)
225                                 s+=(*i).fillbuf(buf+s);
226                         return s;
227                 }
228                 int readbuf(const ubyte *buf){
229                         int s=1,n;
230                         ip_addr a;
231                         for (n=buf[0];n;--n){
232                                 s+=a.readbuf(buf+s);
233 //                              addrs.push_back(a);
234                                 if (a.ok())
235                                         add(a);
236                         }
237                         return s;
238                 }
239                 void clear(void){
240                         naddr=0;
241                         goodaddr=NULL;
242                         addrs.erase(begin(),end());
243                 }
244
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);}
248 };
249
250 extern ip_addr_list ip_my_addrs;
251
252 extern int ip_sendtoca(ip_addr addr,const void *buf,int len);
253
254 class ip_handshake_base {
255         public:
256                 ubyte type;
257                 ubyte state;
258                 ip_id id;
259                 u_int16_t iver;
260                 u_int32_t tryid;
261
262                 fix nextsend;
263                 int attempts;
264                 int nopend;
265
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);
271
272 //              ip_handshake_base(void):type(IP_CFG_BASE){setstate(IPNOSTATE);}
273                 ip_handshake_base(bool initme=0):type(IP_CFG_BASE){
274                         nopend=0;
275                         state=0;
276                         setstate(0);
277                         if(initme){
278                 //              id=ip_my_id;
279                                 id=ipx_MyAddress+4;
280                                 iver=D2X_IVER;
281                                 setrandid();
282                         }
283                 }
284                 virtual ~ip_handshake_base(){setstate(0);}//decrement pendinghandshakes if needed.
285 };
286 class ip_handshake_info : public ip_handshake_base {
287         public:
288                 ip_addr_list addr;
289
290                 virtual int fillbuf(ubyte *buf);
291                 virtual int readbuf(ubyte *buf);
292
293                 ip_handshake_info(ubyte *buf){
294                         readbuf(buf);
295                 }
296                 ip_handshake_info(void):ip_handshake_base(1){
297                         type=IP_CFG_HANDSHAKE;
298                         addr=ip_my_addrs;
299 //                      setstate(STATE_INEEDINFO);
300                 }
301 };
302 class ip_peer;
303 class ip_handshake_relay : public ip_handshake_base {
304         public:
305                 ip_id r_id;
306                 u_int16_t r_iver;
307                 ip_addr_list r_addr;
308
309                 virtual int fillbuf(ubyte *buf);
310                 virtual int readbuf(ubyte *buf);
311
312                 ip_handshake_relay(ubyte *buf){
313                         readbuf(buf);
314                 }
315                 ip_handshake_relay(ip_peer *torelay);
316 };
317
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)
324
325 class ip_peer {
326         public:
327                 ip_addr_list addr;
328 //              int goodaddr;
329                 ip_id id;
330                 int iver;
331 //              ip_hs_state query;
332 //              ip_hs_state reply;
333                 list<ip_handshake_base*> handshakes;
334
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);
339                 }
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){
345                                 hsb=(*i);
346                                 if (hsb->type==IP_CFG_RELAY){
347                                         hsr=(ip_handshake_relay*)hsb;
348                                         if (hsr->r_id==r_id)
349                                                 return hsr;
350                                 }
351                         }
352                         return NULL;
353                 }
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){
358                                 hsb=(*i);
359                                 if (hsb->type==IP_CFG_HANDSHAKE)
360                                         return (ip_handshake_info*) hsb;
361                         }
362                         ip_handshake_info *ni=new ip_handshake_info();
363 //                      handshakes.push_back(ni);
364                         add_hs(ni);
365                         return ni;
366                 }
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){
371                                 hsb=(*i);
372                                 if (hsb->tryid==tryid && hsb->type==type)
373                                         return hsb;
374                         }
375                         return NULL;
376                 }*/
377                 void send_handshake(ip_handshake_base*hsb);
378                 bool verify_addr(ip_addr_list &fraddrs);
379                 ip_peer(void){iver=0;}
380                 ~ip_peer(){
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));
384                                 if (!(*i))
385                                         mprintf((0,"~ip_peer null hs?\n"));
386                                 else*/
387                                         delete (*i);
388                         }
389                 }
390 };
391
392
393 class ip_peer_list {
394         public:
395                 typedef map<ip_id,ip_peer *,less<ip_id> > peer_map;
396                 peer_map peers;
397                 list<ip_peer*> unknown_peers;
398                 int pendinghandshakes;
399                 fix pendinghandshake_lasttime;
400
401                 ip_peer * add_id(ip_id id){
402                         ip_peer*n=new ip_peer();
403                         n->id=id;
404                         peers.insert(peer_map::value_type(n->id,n));
405                         return n;
406                 }
407                 ip_peer * add_unk(void){
408                         ip_peer*n=new ip_peer();
409                         unknown_peers.push_back(n);
410                         return n;
411                 }
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);
421                 void clear(void);
422                 ip_peer_list(){
423                         pendinghandshakes=0;
424                         pendinghandshake_lasttime=0;
425                 }
426                 ~ip_peer_list();
427 };
428 extern ip_peer_list peer_list;
429
430 #endif