d1x->d2x
[btb/d2x.git] / main / ip_base.h
1 /*
2  * $Source: /cvs/cvsroot/d2x/main/ip_base.h,v $
3  * $Revision: 1.3 $
4  * $Author: bradleyb $
5  * $Date: 2002-02-14 09:24:19 $
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.2  2002/02/13 10:45:49  bradleyb
12  * Lotsa networking stuff from d1x
13  *
14  * Revision 1.1  2002/02/06 09:22:41  bradleyb
15  * Adding d1x network code
16  *
17  *
18  */
19
20 #ifndef ___IP_BASE_H
21 #define ___IP_BASE_H
22
23 #include <map.h>
24 #include <list.h>
25 #include <algo.h>
26 extern "C" {
27 #include "ip_basec.h"
28 #include "fix.h"
29 #include "mono.h"
30 #include "vers_id.h"
31 //#include "inetc.h"
32 #include "timer.h"
33 }
34
35 class ip_addr;//prototype for arch_ip_queryhost
36
37 #include "ipclient.h"
38 #include <stdio.h>
39
40
41 //inline u_int32_t d_rand32(void) { return d_rand() + (d_rand()<<16);}
42 inline u_int32_t d_rand32(void) { return d_rand() + (d_rand()<<15) + (d_rand()<<30);}//d_rand() only returns 15 bits
43
44
45 void ip_receive_cfg(ubyte *buf,int buflen,ip_addr fromaddr);
46
47 extern unsigned char ipx_MyAddress[10];
48
49 unsigned short ip_portshift(unsigned short baseport, const char *cs);
50
51 #define UDP_BASEPORT 31017
52 #define UDP_SERV_BASEPORT 30817
53 #define PORTSHIFT_TOLERANCE 0x100
54 #define MAX_PACKETSIZE 8192
55
56 // Length HAS TO BE 2!
57 #define D2Xid "\xd2x"
58 // Length HAS TO BE 4!
59 #define D2Xcfgid "\xcfg\xd2x"
60
61
62 //cfg packet types
63 #define IP_CFG_BASE 0
64 #define IP_CFG_HANDSHAKE 1
65 #define IP_CFG_RELAY 2
66 //someone giving us an error (ie, outdated version, etc.) ... not handled yet.
67 #define IP_CFG_SORRY 3
68
69
70 #define STATE_INEEDINFO         1<<0
71 #define STATE_SENDINGINFO       1<<1
72 //#define STATE_NEED_RESEND     (STATE_INEEDINFO | STATE_SENDINGINFO)
73 #define STATE_NEED_RESEND       (STATE_INEEDINFO)
74 #define STATE_VALID_STATES      (STATE_INEEDINFO | STATE_SENDINGINFO)
75 #define STATE_RELAYREPLY        1<<6
76 #define STATE_ERR                       1<<7
77 /* Dump raw form of IP address/port by fancy output to user
78  */
79
80 #ifdef UDPDEBUG
81 #include <stdio.h>
82 inline char *ip_hs_statetoa(int state){
83         if (!state)
84                 return "NOSTATE";
85         if (state&STATE_ERR)
86                 return "ERR";
87         if ((state&(STATE_INEEDINFO|STATE_SENDINGINFO))==(STATE_INEEDINFO|STATE_SENDINGINFO))
88                 return "NEED+SEND";
89         if (state&STATE_INEEDINFO)
90                 return "NEED";
91         if (state&STATE_SENDINGINFO)
92                 return "SEND";
93         return "huh?";
94 }
95 inline void dumprid(const unsigned char *a)
96 {
97     printf("<%u.%u.%u.%u.%u.%u>",a[0],a[1],a[2],a[3],a[4],a[5]);
98 }
99 inline void dumpraddr(const unsigned char *addr)
100 {
101         ushort port;
102         printf("[%u.%u.%u.%u]",addr[0],addr[1],addr[2],addr[3]);
103         port=(unsigned short)ntohs(*(unsigned short *)(addr+4));
104         printf(":%d",port);
105 }
106 #endif
107
108
109 class ip_id {
110         public:
111                 ubyte id[6];
112
113                 int fillbuf(ubyte *buf)const {memcpy(buf,id,6);return 6;};
114                 int readbuf(const ubyte *buf){memcpy(id,buf,6);return 6;};
115                 bool operator < (const ip_id &a_id)const {return memcmp(id,a_id.id,6)<0;}
116                 bool operator == (const ip_id &a_id)const {return memcmp(id,a_id.id,6)==0;}
117                 bool operator > (const ip_id &a_id)const {return memcmp(id,a_id.id,6)>0;}
118                 ip_id& operator = (const ip_id &a_id){readbuf(a_id.id);return *this;}
119 #ifdef UDPDEBUG
120                 void dump(void){dumprid(id);}
121 #endif
122                 ip_id(ubyte*nid){readbuf(nid);}
123                 ip_id(void){};
124 };
125
126 class ip_addr {
127         protected:
128                 ubyte alen;//alen stuff is to maybe make ipv6 support easier (if the transition ever actually happens)
129         public:
130                 ubyte addr[6];
131
132                 int fillbuf(ubyte *buf)const {buf[0]=alen;memcpy(buf+1,addr,alen);return alen+1;};
133                 int readbuf(const ubyte *buf){
134                         int l=buf[0];
135                         if (l==6){
136                                 memcpy(addr,buf+1,6);alen=l;
137                         }else{
138                                 mprintf((0,"ip_addr readbuf bad len %i\n",l));
139                                 memset(addr,0,6);alen=0;
140                         }
141                         return l+1;
142                 };
143                 bool operator < (const ip_addr &a_addr)const {
144                         if (alen!=a_addr.alen) return alen<a_addr.alen;
145                         return memcmp(addr,a_addr.addr,alen)<0;
146                 }
147                 bool operator == (const ip_addr &a_addr)const {return ((alen==a_addr.alen) && (memcmp(addr,a_addr.addr,alen)==0));}
148                 bool operator > (const ip_addr &a_addr)const {
149                         if (alen!=a_addr.alen) return alen>a_addr.alen;
150                         return memcmp(addr,a_addr.addr,alen)>0;
151                 }
152                 ip_addr& operator = (const ip_addr &a_addr){alen=a_addr.alen;memcpy(addr,a_addr.addr,6);return *this;}
153 #ifdef UDPDEBUG
154                 void dump(void)const{dumpraddr(addr);}
155 #endif
156                 void set(int addrsize,ubyte *naddr,ushort port){
157                         if (addrsize!=4)return;//not handled yet.
158                         alen=addrsize+2;
159                         memcpy(addr,naddr,addrsize);
160 //                      port=htons(port);
161                         memcpy(addr+addrsize,&port,2);
162                 }
163                 int dns(char *address,ushort baseport){
164                         return arch_ip_queryhost(this,address,baseport);
165                 }
166                 bool ok(void)const{return alen>0;}
167                 int addrlen(void)const{return alen-2;}
168 //              ip_addr(ubyte*naddr){readbuf(naddr);}
169                 ip_addr(void){alen=0;};
170 };
171
172 class ip_addr_list {
173         protected:
174                 list<ip_addr> addrs;
175         public:
176                 typedef list<ip_addr>::iterator iterator;
177                 typedef list<ip_addr>::const_iterator const_iterator;
178                 int naddr;
179                 ip_addr *goodaddr;
180
181                 iterator begin(void){return addrs.begin();}
182                 iterator end(void){return addrs.end();}
183                 const_iterator begin(void)const{return addrs.begin();}
184                 const_iterator end(void)const{return addrs.end();}
185                 bool hasaddr(ip_addr addr){
186                         iterator i=find(begin(),end(),addr);
187                         return (i!=addrs.end());
188                 }
189                 int add(ip_addr addr){
190                         if (hasaddr(addr))
191                                 return 0;
192                         addrs.push_back(addr);
193                         naddr++;
194                         return 1;
195                 }
196                 int add(const ip_addr_list &na){
197                         int j=0;
198                         const_iterator i=na.begin();
199                         for (;i!=na.end();++i)
200                                 j+=add(*i);
201                         return j;
202                 }
203                 void setgoodaddr(ip_addr addr){
204                         iterator i=find(begin(),end(),addr);
205                         if (i!=end()){
206                                 goodaddr=&(*i);
207                                 return;
208                         }
209                         addrs.push_back(addr);
210                         goodaddr=&(*addrs.end());
211                 }
212                 int fillbuf(ubyte *buf)const {
213                         int s=0;
214                         const_iterator i;
215                         buf[s++]=naddr;
216                         for (i=begin();i!=end();++i)
217                                 s+=(*i).fillbuf(buf+s);
218                         return s;
219                 }
220                 int readbuf(const ubyte *buf){
221                         int s=1,n;
222                         ip_addr a;
223                         for (n=buf[0];n;--n){
224                                 s+=a.readbuf(buf+s);
225 //                              addrs.push_back(a);
226                                 if (a.ok())
227                                         add(a);
228                         }
229                         return s;
230                 }
231                 void clear(void){
232                         naddr=0;
233                         goodaddr=NULL;
234                         addrs.erase(begin(),end());
235                 }
236
237                 ip_addr_list(const ip_addr_list &nl):addrs(nl.addrs),naddr(nl.naddr){setgoodaddr(*nl.goodaddr);}
238                 ip_addr_list(void):naddr(0),goodaddr(NULL){}
239 //              ip_addr_list(const ubyte * buf):naddr(0),goodaddr(NULL){readbuf(buf);}
240 };
241
242 extern ip_addr_list ip_my_addrs;
243
244 extern int ip_sendtoca(ip_addr addr,const void *buf,int len);
245
246 class ip_handshake_base {
247         public:
248                 ubyte type;
249                 ubyte state;
250                 ip_id id;
251                 u_int16_t iver;
252                 u_int32_t tryid;
253
254                 fix nextsend;
255                 int attempts;
256                 int nopend;
257
258                 virtual int fillbuf(ubyte *buf);
259                 virtual int readbuf(ubyte *buf);
260                 void setrandid(void){tryid=d_rand32() ^ timer_get_approx_seconds();}
261                 void setstate(int newstate);
262                 int addstate(int newstate);
263
264 //              ip_handshake_base(void):type(IP_CFG_BASE){setstate(IPNOSTATE);}
265                 ip_handshake_base(bool initme=0):type(IP_CFG_BASE){
266                         nopend=0;
267                         state=0;
268                         setstate(0);
269                         if(initme){
270                 //              id=ip_my_id;
271                                 id=ipx_MyAddress+4;
272                                 iver=D2X_IVER;
273                                 setrandid();
274                         }
275                 }
276                 virtual ~ip_handshake_base(){setstate(0);}//decrement pendinghandshakes if needed.
277 };
278 class ip_handshake_info : public ip_handshake_base {
279         public:
280                 ip_addr_list addr;
281
282                 virtual int fillbuf(ubyte *buf);
283                 virtual int readbuf(ubyte *buf);
284
285                 ip_handshake_info(ubyte *buf){
286                         readbuf(buf);
287                 }
288                 ip_handshake_info(void):ip_handshake_base(1){
289                         type=IP_CFG_HANDSHAKE;
290                         addr=ip_my_addrs;
291 //                      setstate(STATE_INEEDINFO);
292                 }
293 };
294 class ip_peer;
295 class ip_handshake_relay : public ip_handshake_base {
296         public:
297                 ip_id r_id;
298                 u_int16_t r_iver;
299                 ip_addr_list r_addr;
300
301                 virtual int fillbuf(ubyte *buf);
302                 virtual int readbuf(ubyte *buf);
303
304                 ip_handshake_relay(ubyte *buf){
305                         readbuf(buf);
306                 }
307                 ip_handshake_relay(ip_peer *torelay);
308 };
309
310 //max number of times to try to handshake a host
311 #define IP_MAX_HS_ATTEMPTS 10
312 //how often to resend a hand-shake (3 seconds)
313 #define IP_HS_RETRYTIME (F1_0*3)
314 //how often (max) to search through the resend loop (1 second)
315 #define IP_HS_FRAME_RETRYTIME (F1_0)
316
317 class ip_peer {
318         public:
319                 ip_addr_list addr;
320 //              int goodaddr;
321                 ip_id id;
322                 int iver;
323 //              ip_hs_state query;
324 //              ip_hs_state reply;
325                 list<ip_handshake_base*> handshakes;
326
327 //              void set_good_addr(ubyte *fraddr);
328                 void add_hs(ip_handshake_base* hs){
329 //                      mprintf((0,"########## add_hs %p: adding a hs %p %i %i\n",this,hs,hs->type,hs->state));
330                         handshakes.push_back(hs);
331                 }
332                 ip_handshake_relay* find_relay(ip_id r_id){
333                         list<ip_handshake_base*>::iterator i;
334                         ip_handshake_base* hsb;
335                         ip_handshake_relay* hsr;
336                         for (i=handshakes.begin();i!=handshakes.end();++i){
337                                 hsb=(*i);
338                                 if (hsb->type==IP_CFG_RELAY){
339                                         hsr=(ip_handshake_relay*)hsb;
340                                         if (hsr->r_id==r_id)
341                                                 return hsr;
342                                 }
343                         }
344                         return NULL;
345                 }
346                 ip_handshake_info* find_handshake(void){
347                         list<ip_handshake_base*>::iterator i;
348                         ip_handshake_base* hsb;
349                         for (i=handshakes.begin();i!=handshakes.end();++i){
350                                 hsb=(*i);
351                                 if (hsb->type==IP_CFG_HANDSHAKE)
352                                         return (ip_handshake_info*) hsb;
353                         }
354                         ip_handshake_info *ni=new ip_handshake_info();
355 //                      handshakes.push_back(ni);
356                         add_hs(ni);
357                         return ni;
358                 }
359 /*              ip_handshake_base* find_hs(u_int32_t tryid, ubyte type){
360                         list<ip_handshake_base*>::iterator i;
361                         ip_handshake_base* hsb;
362                         for (i=handshakes.begin();i!=handshakes.end();++i){
363                                 hsb=(*i);
364                                 if (hsb->tryid==tryid && hsb->type==type)
365                                         return hsb;
366                         }
367                         return NULL;
368                 }*/
369                 void send_handshake(ip_handshake_base*hsb);
370                 bool verify_addr(ip_addr_list &fraddrs);
371                 ip_peer(void){iver=0;}
372                 ~ip_peer(){
373                         list<ip_handshake_base*>::iterator i;
374                         for (i=handshakes.begin();i!=handshakes.end();++i){
375 /*                              mprintf((0,"###### ~ip_peer %p: deleting a hs %p %i %i\n",this,(*i),(*i)->type,(*i)->state));
376                                 if (!(*i))
377                                         mprintf((0,"~ip_peer null hs?\n"));
378                                 else*/
379                                         delete (*i);
380                         }
381                 }
382 };
383
384
385 class ip_peer_list {
386         public:
387                 typedef map<ip_id,ip_peer *,less<ip_id> > peer_map;
388                 peer_map peers;
389                 list<ip_peer*> unknown_peers;
390                 int pendinghandshakes;
391                 fix pendinghandshake_lasttime;
392
393                 ip_peer * add_id(ip_id id){
394                         ip_peer*n=new ip_peer();
395                         n->id=id;
396                         peers.insert(peer_map::value_type(n->id,n));
397                         return n;
398                 }
399                 ip_peer * add_unk(void){
400                         ip_peer*n=new ip_peer();
401                         unknown_peers.push_back(n);
402                         return n;
403                 }
404                 //ip_peer * add_1(ubyte *addr,ip_id id);
405                 ip_peer * add_1(ip_addr addr);
406                 ip_peer * add_full(ip_id id, u_int16_t iver, ip_addr_list &addrs);
407                 void make_full(ip_peer*p,ip_id id, u_int16_t iver, ip_addr_list &addrs);
408                 ip_peer * add_hsi(ip_handshake_info *hsi){return add_full(hsi->id,hsi->iver,hsi->addr);}
409                 ip_peer * find_byid(ip_id id);
410                 ip_peer * find_by_addr(ip_addr addr);
411                 ip_peer * find_unk_by_addr(ip_addr addr);
412                 void handshake_frame(void);
413                 void clear(void);
414                 ip_peer_list(){
415                         pendinghandshakes=0;
416                         pendinghandshake_lasttime=0;
417                 }
418                 ~ip_peer_list();
419 };
420 extern ip_peer_list peer_list;
421
422 #endif