d1x->d2x
[btb/d2x.git] / main / ipclient.cpp
1 /*
2  * $Source: /cvs/cvsroot/d2x/main/ipclient.cpp,v $
3  * $Revision: 1.2 $
4  * $Author: bradleyb $
5  * $Date: 2002-02-14 09:27:09 $
6  *
7  * ipclient.cpp - udp/ip client code
8  * added 2000/02/07 Matt Mueller
9  *
10  * $Log: not supported by cvs2svn $
11  * Revision 1.1  2002/02/06 09:22:42  bradleyb
12  * Adding d1x network code
13  *
14  *
15  */
16
17 #ifdef HAVE_CONFIG_H
18 #include <conf.h>
19 #endif
20
21 extern "C"{
22 #include "mono.h"
23 #include "key.h"
24 #include "text.h"
25 #include "newmenu.h"
26 #include "args.h"
27 void network_init(void);
28 int get_and_show_netgame_info(ubyte *server, ubyte *node, ubyte *net_address);
29 }
30
31 #include "ip_base.h"
32 #include "ipclient.h"
33
34
35 extern int Player_num;
36 extern int Network_send_objects;
37
38 extern int N_players;
39
40 int ip_connect_manual(char *textaddr) {
41 //  ip_handshake_info handshake;
42 //  ip_init_handshake_info(&handshake,0);
43     int r;
44     ubyte buf[1500];
45     ip_peer *p;
46         ip_addr addr;
47
48     if (addr.dns(textaddr,UDP_BASEPORT)) {
49                 nm_messagebox(TXT_ERROR,1,TXT_OK,"Could not resolve address");
50                 return -1;
51         }
52 #ifdef UDPDEBUG
53     printf("connecting to ");
54     addr.dump();
55     printf("\n");
56 #endif
57
58     network_init();
59     N_players = 0;
60
61     if (!(p=peer_list.find_by_addr(addr))){
62         p=peer_list.add_1(addr);
63     }
64     ip_handshake_info *hsi=p->find_handshake();
65         hsi->setstate(STATE_INEEDINFO);
66    // p->newhandshake(hsi);
67 //      p->handshakes.push_back(hsi);
68 //  set_hs_state(&hsr->reply,IPHELLO);
69 //  ip_send_handshake(hsr,&hsr->reply);
70     while(hsi->state&STATE_VALID_STATES){
71         r=ipx_get_packet_data(buf);
72         if (r>0)
73             mprintf((0,MSGHDR "ip_connect_manual: weird, someone sent us normal data\n"));
74         if (key_inkey()==KEY_ESC)
75             return 0;
76     }
77     if (hsi->state&STATE_ERR) {
78                 nm_messagebox(TXT_ERROR,1,TXT_OK,"handshake timeout");
79                 return -1;
80         }
81
82 //  join the Netgame.
83
84     return get_and_show_netgame_info(null_addr,p->id.id,NULL);
85 }
86
87
88 static int ipx_ip_OpenSocket(int oport) {
89         int i;
90         if ((i=FindArg("-ip_baseport"))){
91                 baseport=UDP_BASEPORT+atoi(Args[i+1]);
92         }
93
94         myport=baseport+(oport - IPX_DEFAULT_SOCKET);
95         if (arch_ip_open_socket(myport)) return -1;
96
97         if (ipx_ip_GetMyAddress() < 0) FAIL("Error getting my address");
98
99         //      if (!port)
100         //              port = dynamic_socket++;
101 #ifdef UDPDEBUG
102         msg("OpenSocket on D1X socket port %d (%d : %+d) : %+d",myport,oport,oport-IPX_DEFAULT_SOCKET,baseport-UDP_BASEPORT);
103 #endif
104         //sk->socket = UDP_BASEPORT+(oport - IPX_DEFAULT_SOCKET);
105 //      sk->socket = port;
106         return 0;
107 }
108 static void ipx_ip_CloseSocket(void) {
109 #ifdef UDPDEBUG
110         msg("CloseSocket on D1X socket port %d",myport);
111 #endif
112         arch_ip_close_socket();
113         peer_list.clear();
114 }
115
116
117
118 /* Here we'll send the packet to our host. If it is unicast packet, send
119  * it to IP address/port as retrieved from IPX address. Otherwise (broadcast)
120  * we'll repeat the same data to each host in our broadcasting list.
121  */
122
123 static int ipx_ip_SendPacket(IPXPacket_t *IPXHeader,
124                 ubyte *data, int dataLen) {
125 //      struct sockaddr_in toaddr;
126         int i=dataLen;
127         //int bcast;
128         char *buf;
129
130         if (dataLen<0 || dataLen>MAX_PACKETSIZE) {
131 #ifdef UDPDEBUG
132                 msg("SendPacket enter, dataLen=%d out of range",dataLen);
133 #endif
134                 return -1;
135         }
136         chk(buf=(char*)alloca(2+dataLen));
137         memcpy(buf+0,D2Xid ,2);
138         memcpy(buf+2,data,dataLen);
139
140 #ifdef UDPDEBUG
141         printf(MSGHDR "sendto((%d),Node=[4] %02X %02X,Socket=%02X %02X,s_port=%u,",
142                         dataLen,
143                         IPXHeader->Destination.Node [4],IPXHeader->Destination.Node  [5],
144                         IPXHeader->Destination.Socket[0],IPXHeader->Destination.Socket[1],
145                         ntohs(*(unsigned short *)(IPXHeader->Destination.Socket)));
146         dumprid(IPXHeader->Destination.Node);
147         puts(").");
148 #endif
149
150         //toaddr.sin_family=AF_INET;
151         if (memcmp(broadcast_addr,IPXHeader->Destination.Node,6)==0){
152 //              ubyte brbuf[6];
153                 ip_addr brbuf;
154 //              ushort port=htons(myport);
155 //              //int j;
156 //              memcpy(brbuf+0,IPXHeader->Destination.Node+0,4);
157 //              //memcpy(brbuf+4,IPXHeader->Destination.Socket,2);
158 //              memcpy(brbuf+4,&port,2);
159                 brbuf.set(4,IPXHeader->Destination.Node,htons(myport));
160                 i=ip_sendtoca(brbuf,buf,2+dataLen);
161 //              memcpy(&toaddr.sin_addr,IPXHeader->Destination.Node+0,4);
162 //              toaddr.sin_port=*(unsigned short *)(IPXHeader->Destination.Socket);
163                 ip_sendtoall(buf,2+dataLen);
164         }else {
165                 i=ip_sendtoid(IPXHeader->Destination.Node,buf,2+dataLen);
166 //              memcpy(&toaddr.sin_addr,hsr->addr[hsr->goodaddr],4);
167 //              toaddr.sin_port=*(unsigned short *)(hsr->addr[hsr->goodaddr]+4);
168 ////            toaddr.sin_port=*(unsigned short *)(IPXHeader->Destination.Node+4);
169         }
170                 //toaddr.sin_port=htons(((short)ntohs(*(unsigned short *)(IPXHeader->Destination.Node+4)))+UDP_BASEPORT);
171 //      toaddr.sin_port=*(unsigned short *)(IPXHeader->Destination.Socket);
172
173 //      i=sendto(mysock->fd,buf,2+dataLen,
174 //                      0,(struct sockaddr *)&toaddr,sizeof(toaddr));
175         return(i<1?-1:i-1);
176 }
177
178 /* Here we will receive new packet to the given buffer. Both formats of packets
179  * are supported, we fallback to old format when first obsolete packet is seen.
180  * If the (valid) packet is received from unknown host, we will add it to our
181  * broadcasting list. FIXME: For now such autoconfigured hosts are NEVER removed.
182  */
183
184 static int ipx_ip_ReceivePacket(char *outbuf, int outbufsize, 
185  struct ipx_recv_data *rd) {
186         int size;
187         size_t offs;
188         ip_addr *fromaddr;
189         //int i;
190
191         if ((size=arch_ip_recvfrom(outbuf,outbufsize,rd))<0)
192                 return -1;
193
194         if (size<2) return -1;
195
196         memcpy(&fromaddr,rd->src_node,sizeof(ip_addr*));
197
198         if (memcmp(outbuf+0,D2Xid,2)) {
199                 if (memcmp(outbuf+0,D2Xcfgid,4)) {
200                         mprintf((0,MSGHDR"no valid header\n"));
201                         return -1;
202                 }
203                 {
204 /*                      ubyte buf[6];
205                         memcpy(buf,&fromaddr.sin_addr,4);
206                         *(unsigned short *)(buf+4)=fromaddr.sin_port;*/
207                         //do stuff.
208 //                      fromaddr.set(4,rd->src_node,*(unsigned short*)(rd->src_node+4));
209                         ip_receive_cfg((ubyte*)outbuf+4,size-4,*fromaddr);
210                 }
211                 return 0;
212         }
213         else offs=2;
214
215         /* Lace: (dst_socket & src_socket) should be network-byte-order by comment in include/ipx_drv.h */
216         /*       This behaviour presented here is broken. It is not used anywhere, so why bother? */
217 /*      rd->src_socket = ntohs(*(unsigned short *)(outbuf+offs));
218         if (rd->src_socket != s->socket) {
219 #ifdef UDPDEBUG
220                 msg(" - pkt was dropped (dst=%d,my=%d)",rd->src_socket,s->socket);
221 #endif
222                 return -1;
223                 }*/
224 //      rd->src_socket = s->socket;
225 //      rd->dst_socket = s->socket;
226
227         memmove(outbuf,outbuf+offs,size-(offs));
228         size-=offs;
229
230         rd->src_socket = myport;
231     rd->dst_socket = myport;
232
233         rd->pkt_type = 0;
234 #ifdef UDPDEBUG
235         printf(MSGHDR "ReceivePacket: size=%d,from=",size);
236 //      dumpraddr(rd->src_node);
237         fromaddr->dump();
238         putchar('\n');
239 #endif
240 /*      ip_peer *p=peer_list.find_by_addr(*fromaddr);
241         if(p)
242                 p->id.fillbuf(rd->src_node);
243         else
244                 memset(rd->src_node,0,6);*/
245         if (ip_my_addrs.hasaddr(*fromaddr))
246                 memcpy(rd->src_node,ipx_MyAddress+4,6);
247         else
248                 memset(rd->src_node,0,6);
249
250         return size;
251 }
252
253 static int ipx_ip_general_PacketReady(void) {
254         //ip_handshake_frame();//handle handshake resending
255         peer_list.handshake_frame();
256         return arch_ip_PacketReady();
257 }
258
259 static int ipx_ip_CheckReadyToJoin(ubyte *server, ubyte *node){
260         if (Network_send_objects) return 0;//if we are currently letting someone else join, we don't know if this person can join ok.
261
262         ip_peer *p=peer_list.find_byid(node);
263         if (!p || p->addr.goodaddr==NULL)
264                 return 0;
265         ip_peer *np;
266         ip_handshake_relay *hsr;
267         int j;
268         int ok,nope=0;
269
270         for (j=0;j<get_MAX_PLAYERS();j++){
271                 if (get_Netgame_player_connected(j) && j!=Player_num){
272                         np=peer_list.find_byid(get_Netgame_player_node(j));
273                         if (!np)continue;//huh??
274                         if (np->id==node)continue;//don't tell them to talk to themselves.
275
276                         ok=0;
277
278                         hsr=p->find_relay(np->id);
279                         if (!hsr){
280                                 hsr=new ip_handshake_relay(np);
281                                 p->add_hs(hsr);
282                         }
283                         if (hsr->state==0)
284                                 ok++;
285
286                         hsr=np->find_relay(p->id);
287                         if (!hsr){
288                                 hsr=new ip_handshake_relay(p);
289                                 np->add_hs(hsr);
290                         }
291                         if (hsr->state==0)
292                                 ok++;
293                         if (ok!=2)
294                                 nope++;
295                 }
296         }
297         if (nope)
298                 return 0;
299
300         return 1;
301 }
302
303 struct ipx_driver ipx_ip = {
304 //      ipx_ip_GetMyAddress,
305         ipx_ip_OpenSocket,
306         ipx_ip_CloseSocket,
307         ipx_ip_SendPacket,
308         ipx_ip_ReceivePacket,
309         ipx_ip_general_PacketReady,
310         ipx_ip_CheckReadyToJoin,
311         0, //save 4 bytes.  udp/ip is completely inaccessable by the other methods, so we don't need to worry about compatibility.
312         NULL, //use the easier ones
313         NULL, //use the easier ones
314         NULL  //use the easier ones
315 };