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