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