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