]> icculus.org git repositories - taylor/freespace2.git/blob - src/network/gtrack.cpp
first pass at PXO reintegration
[taylor/freespace2.git] / src / network / gtrack.cpp
1 /*
2  * Copyright (C) Volition, Inc. 2005.  All rights reserved.
3  * 
4  * All source code herein is the property of Volition, Inc. You may not sell 
5  * or otherwise commercially exploit the source or things you created based on the 
6  * source.
7  *
8 */
9
10
11 //Game Tracker client code
12 /*
13
14   InitGameTracker(int game_type); //D3 or Freespace
15          
16   //Call periodically so we can send our update, and make sure it is received
17   IdleGameTracker();
18   
19   StartTrackerGame(void *buffer)  //Call with a freespace_net_game_data or d3_net_game_data structure
20   //Call with a freespace_net_game_data or d3_net_game_data structure
21   //Updates our memory so when it is time, we send the latest game data
22   UpdateGameData(gamedata);
23
24
25   //Call to signify end of game
26
27   RequestGameList();//Sends a GNT_GAMELIST_REQ packet to the server.
28
29   game_list * GetGameList();//returns a pointer to a game_list struct
30
31 */
32
33
34 #ifdef PLAT_UNIX
35 #include <arpa/inet.h>
36 #include <netinet/in.h>
37 #include <errno.h>
38 #include <netdb.h>
39 #endif
40
41 #include "pstypes.h"
42 #include "timer.h"
43 #include "multi.h"
44 #include "multi_pxo.h"
45 #include "gtrack.h"
46
47
48 //Variables
49 // SOCKET gamesock;
50 SOCKADDR_IN     gtrackaddr;
51
52 game_list GameBuffer[MAX_GAME_BUFFERS];
53 int GameType;//d3 or fs
54
55 unsigned int LastTrackerUpdate;
56 unsigned int LastSentToTracker;
57 unsigned int TrackerAckdUs;
58 unsigned int TrackerGameIsRunning;
59
60 game_packet_header TrackerGameData;
61 game_packet_header GameListReq;
62 game_packet_header TrackAckPacket;
63 game_packet_header GameOverPacket;
64
65 #ifdef MAKE_FS1
66 freespace_net_game_data         *FreeSpaceTrackerGameData;
67 #else
68 freespace2_net_game_data        *FreeSpace2TrackerGameData;
69 #endif
70
71 //Start New 7-9-98
72 unsigned int LastGameOverPacket;
73 unsigned int FirstGameOverPacket;
74
75 int SendingGameOver;
76 //End New 7-9-98
77
78
79 int InitGameTrackerClient(int gametype)
80 {
81         SOCKADDR_IN sockaddr;
82         unsigned int iaddr;
83
84         GameType = gametype;
85         LastTrackerUpdate = 0;
86         switch(gametype)
87         {
88         case GT_FREESPACE:
89 #ifndef MAKE_FS1
90                 Int3();
91                 return 0;
92 #else
93                 TrackerGameData.len = GAME_HEADER_ONLY_SIZE+sizeof(freespace_net_game_data);
94 #endif
95                 break;
96
97         case GT_FREESPACE2:
98 #ifdef MAKE_FS1
99                 Int3();
100                 return 0;
101 #else
102                 TrackerGameData.len = GAME_HEADER_ONLY_SIZE+sizeof(freespace2_net_game_data);
103 #endif
104                 break;
105
106         default:
107                 Int3();
108                 return 0;
109         }
110         TrackerGameData.game_type = (unsigned char)gametype;    //1==freespace (GT_FREESPACE), 2==D3, 3==tuberacer, etc.
111         TrackerGameData.type = GNT_GAMEUPDATE;  //Used to specify what to do ie. Add a new net game (GNT_GAMESTARTED), remove a net game (game over), etc.
112
113 #ifdef MAKE_FS1
114         FreeSpaceTrackerGameData = (freespace_net_game_data *)&TrackerGameData.data;
115 #else
116         FreeSpace2TrackerGameData = (freespace2_net_game_data *)&TrackerGameData.data;
117 #endif
118         
119         GameListReq.game_type = (unsigned char)gametype;
120         GameListReq.type = GNT_GAMELIST_REQ;
121         GameListReq.len = GAME_HEADER_ONLY_SIZE;
122
123         TrackAckPacket.game_type = (unsigned char)gametype;
124         TrackAckPacket.len = GAME_HEADER_ONLY_SIZE;
125         TrackAckPacket.type = GNT_CLIENT_ACK;
126
127         GameOverPacket.game_type = (unsigned char)gametype;
128         GameOverPacket.len = GAME_HEADER_ONLY_SIZE;
129         GameOverPacket.type = GNT_GAMEOVER;
130
131         // gamesock = socket(AF_INET,SOCK_DGRAM,0);
132         
133         /*
134         if ( gamesock == INVALID_SOCKET )
135         {
136                 printf("Unable to open a socket.\n");
137                 return 0;
138         }
139         */
140         
141         memset( &sockaddr, 0, sizeof(SOCKADDR_IN) );
142         sockaddr.sin_family = AF_INET; 
143         sockaddr.sin_addr.s_addr = INADDR_ANY; 
144         sockaddr.sin_port = 0;//htons(GAMEPORT);
145         
146         /*
147         if (SOCKET_ERROR==bind(gamesock, (SOCKADDR*)&sockaddr, sizeof (sockaddr))) 
148         {       
149                 printf("Unable to bind a socket.\n");
150                 printf("WSAGetLastError() returned %d.\n",WSAGetLastError());
151                 return 0;
152         }
153         */
154                 
155         iaddr = inet_addr ( Multi_options_g.game_tracker_ip ); 
156         if ( iaddr == INADDR_NONE ) {
157                 // first try and resolve by name
158                 HOSTENT *he;
159                 he = gethostbyname( Multi_options_g.game_tracker_ip );
160                 if(!he)
161                 {               
162                         return 0;
163                         /*
164                         // try and resolve by address           
165                         unsigned int n_order = inet_addr(Multi_game_tracker_ip_address);
166                         he = gethostbyaddr((char*)&n_order,4,PF_INET);          
167
168                         if(!he){
169                                 return 0;
170                         }
171                         */
172                 }
173                 memcpy(&iaddr, he->h_addr_list[0],4);
174         }
175
176         // This would be a good place to resolve the IP based on a domain name
177         memcpy(&gtrackaddr.sin_addr.s_addr, &iaddr, 4);
178         gtrackaddr.sin_family = AF_INET; 
179         gtrackaddr.sin_port = htons( GAMEPORT );
180
181         //Start New 7-9-98
182         SendingGameOver = 0;
183         //End New 7-9-98
184
185         return 1;
186 }
187
188 void IdleGameTracker()
189 {
190         fd_set read_fds;                   
191         TIMEVAL timeout;
192
193         PSNET_TOP_LAYER_PROCESS();
194         
195         timeout.tv_sec=0;            
196         timeout.tv_usec=0;
197         if((TrackerGameIsRunning) && ((timer_get_seconds()-LastTrackerUpdate)>TRACKER_UPDATE_INTERVAL) && !SendingGameOver)
198         {
199                 //Time to update the tracker again
200                 SENDTO(Unreliable_socket, (char *)&TrackerGameData,TrackerGameData.len,0,(SOCKADDR *)&gtrackaddr,sizeof(SOCKADDR_IN), PSNET_TYPE_GAME_TRACKER);
201                 TrackerAckdUs = 0;
202                 LastTrackerUpdate = timer_get_seconds();
203         }
204         else if((TrackerGameIsRunning)&&(!TrackerAckdUs)&&((timer_get_milliseconds()-LastSentToTracker)>TRACKER_RESEND_TIME))
205         {
206                 //We still haven't been acked by the last packet and it's time to resend.
207                 SENDTO(Unreliable_socket, (char *)&TrackerGameData,TrackerGameData.len,0,(SOCKADDR *)&gtrackaddr,sizeof(SOCKADDR_IN), PSNET_TYPE_GAME_TRACKER);
208                 TrackerAckdUs = 0;
209                 LastTrackerUpdate = timer_get_seconds();
210                 LastSentToTracker = timer_get_milliseconds();
211         }
212
213         //Start New 7-9-98
214         if(SendingGameOver){
215                 if((timer_get_milliseconds()-LastGameOverPacket)>TRACKER_RESEND_TIME){
216                         //resend
217                         LastGameOverPacket = timer_get_milliseconds();
218                         SENDTO(Unreliable_socket, (char *)&GameOverPacket,GameOverPacket.len,0,(SOCKADDR *)&gtrackaddr,sizeof(SOCKADDR_IN), PSNET_TYPE_GAME_TRACKER);
219                 } 
220                 /*
221                 else if((timer_get_milliseconds()-FirstGameOverPacket)>NET_ACK_TIMEOUT) {
222                         //Giving up, it timed out.
223                         SendingGameOver = 2;
224                 }
225                 */
226         }
227         //End New 7-9-98
228
229         //Check for incoming
230                 
231         FD_ZERO(&read_fds);
232         FD_SET(Unreliable_socket, &read_fds);    
233
234 #ifndef PLAT_UNIX
235         if(SELECT(0,&read_fds,NULL,NULL,&timeout, PSNET_TYPE_GAME_TRACKER))
236 #else
237         if(SELECT(Unreliable_socket+1,&read_fds,NULL,NULL,&timeout, PSNET_TYPE_GAME_TRACKER))
238 #endif
239         {
240                 unsigned int bytesin;
241                 int addrsize;
242                 SOCKADDR_IN fromaddr;
243
244                 game_packet_header inpacket;
245                 addrsize = sizeof(SOCKADDR_IN);
246
247                 bytesin = RECVFROM(Unreliable_socket, (char *)&inpacket,sizeof(game_packet_header),0,(SOCKADDR *)&fromaddr,&addrsize, PSNET_TYPE_GAME_TRACKER);
248                 if((int)bytesin==-1)
249                 {
250                         int wserr=WSAGetLastError();
251                         printf("RECVFROM() failure. WSAGetLastError() returned %d\n",wserr);
252                         
253                 }
254
255                 // subtract one from the header
256                 inpacket.len--;
257
258                 //Check to make sure the packets ok
259                 if(bytesin==inpacket.len)
260                 {
261                         switch(inpacket.type)
262                         {
263                         case GNT_SERVER_ACK:
264                                 //The server got our packet so we can stop sending now
265                                 TrackerAckdUs = 1;                              
266                                 
267                                 // 7/13/98 -- because of the FreeSpace iterative frame process -- set this value to 0, instead
268                                 // of to 2 (as it originally was) since we call SendGameOver() only once.  Once we get the ack
269                                 // from the server, we can assume that we are done.
270                                 // need to mark this as 0
271                                 SendingGameOver = 0;                                                    
272                                 break;
273                         case GNT_GAMELIST_DATA:
274                                 int i;
275                                 //Woohoo! Game data! put it in the buffer (if one's free)
276                                 for(i=0;i<MAX_GAME_BUFFERS;i++)
277                                 {
278                                         if(GameBuffer[i].game_type==GT_UNUSED)
279                                         {
280                                                 memcpy(&GameBuffer[i],&inpacket.data,sizeof(game_list));
281                                                 i=MAX_GAME_BUFFERS+1;
282                                         }
283                                 }
284                                 break;
285
286                         case GNT_GAME_COUNT_DATA:
287                                 //Here, inpacket.data contains the following structure
288                                 //struct {
289                                 //      int numusers;
290                                 //      char channel[];//Null terminated
291                                 //      }
292                                 //You can add whatever code, or callback, etc. you need to deal with this data
293
294                                 // let the PXO screen know about this data
295                                 int num_servers;
296                                 char channel[512];
297
298                                 // get the user count
299                                 memcpy(&num_servers,inpacket.data,sizeof(int));
300
301                                 // copy the channel name
302                                 memset(channel,0,512);
303                                 strcpy(channel,inpacket.data+4);
304
305                                 // send it to the PXO screen                            
306                                 multi_pxo_channel_count_update(channel,num_servers);
307                                 break;
308                         }
309                         AckPacket(inpacket.sig);                        
310                 }
311         }
312 }
313
314 void UpdateGameData(void *buffer)
315 {
316         SendingGameOver = 0;
317
318         switch(GameType){
319         case GT_FREESPACE:
320 #ifndef MAKE_FS1
321                 Int3();
322 #else
323                 memcpy(FreeSpaceTrackerGameData,buffer,sizeof(freespace_net_game_data));
324 #endif
325                 break;
326
327         case GT_FREESPACE2:
328 #ifdef MAKE_FS1
329                 Int3();
330 #else
331                 memcpy(FreeSpace2TrackerGameData,buffer,sizeof(freespace2_net_game_data));
332 #endif
333                 break;
334
335         default:
336                 Int3();
337                 break;
338         }
339 }
340
341 game_list * GetGameList()
342 {
343         static game_list gl;
344         for(int i=0;i<MAX_GAME_BUFFERS;i++)
345         {
346                 if(GameBuffer[i].game_type!=GT_UNUSED)
347                 {
348                         memcpy(&gl,&GameBuffer[i],sizeof(game_list));
349                         GameBuffer[i].game_type = GT_UNUSED;
350                         return &gl;
351                 }
352         }
353         return NULL;
354 }
355
356 void RequestGameList()
357 {
358         GameListReq.len = GAME_HEADER_ONLY_SIZE;
359         SENDTO(Unreliable_socket, (char *)&GameListReq,GameListReq.len,0,(SOCKADDR *)&gtrackaddr,sizeof(SOCKADDR_IN), PSNET_TYPE_GAME_TRACKER);
360 }
361
362 void RequestGameListWithFilter(void *filter)
363 {
364         memcpy(&GameListReq.data,filter,sizeof(filter_game_list_struct));
365         GameListReq.len = GAME_HEADER_ONLY_SIZE+sizeof(filter_game_list_struct);
366         SENDTO(Unreliable_socket, (char *)&GameListReq,GameListReq.len,0,(SOCKADDR *)&gtrackaddr,sizeof(SOCKADDR_IN), PSNET_TYPE_GAME_TRACKER);
367 }
368
369
370 /* REPLACED BELOW
371 void SendGameOver()
372 {
373         TrackerGameIsRunning = 0;
374         sendto(gamesock,(const char *)&GameOverPacket,GameOverPacket.len,0,(SOCKADDR *)&gtrackaddr,sizeof(SOCKADDR_IN));
375 }
376 */
377
378 //Start New 7-9-98
379 int SendGameOver()
380 {
381         if(SendingGameOver==2) 
382         {
383                 SendingGameOver = 0;    
384                 return 1;
385         }
386         if(SendingGameOver==1) 
387         {
388                 //Wait until it's sent.
389                 IdleGameTracker();
390                 return 0;
391         }
392         if(SendingGameOver==0)
393         {
394                 LastGameOverPacket = timer_get_milliseconds();
395                 FirstGameOverPacket = timer_get_milliseconds();
396                 SendingGameOver = 1;
397                 TrackerGameIsRunning = 0;
398                 SENDTO(Unreliable_socket, (char *)&GameOverPacket,GameOverPacket.len,0,(SOCKADDR *)&gtrackaddr,sizeof(SOCKADDR_IN), PSNET_TYPE_GAME_TRACKER);
399                 return 0;
400         }
401         return 0;
402 }
403 //End New 7-9-98
404
405 void AckPacket(int sig)
406 {
407         TrackAckPacket.sig = sig;
408         SENDTO(Unreliable_socket, (char *)&TrackAckPacket,TrackAckPacket.len,0,(SOCKADDR *)&gtrackaddr,sizeof(SOCKADDR_IN), PSNET_TYPE_GAME_TRACKER);
409 }
410
411 void StartTrackerGame(void *buffer)
412 {
413         SendingGameOver = 0;
414
415         switch(GameType){
416         case GT_FREESPACE:
417 #ifndef MAKE_FS1
418                 Int3();
419 #else
420                 memcpy(FreeSpaceTrackerGameData,buffer,sizeof(freespace_net_game_data));
421 #endif
422                 break;
423
424         case GT_FREESPACE2:
425 #ifdef MAKE_FS1
426                 Int3();
427 #else
428                 memcpy(FreeSpace2TrackerGameData,buffer,sizeof(freespace2_net_game_data));
429 #endif
430                 break;
431
432         default:
433                 Int3();
434                 break;
435         }
436         TrackerGameIsRunning = 1;
437         LastTrackerUpdate = 0;  
438 }
439
440 //A new function
441 void RequestGameCountWithFilter(void *filter) 
442 {
443         game_packet_header GameCountReq;
444
445 #ifdef MAKE_FS1
446         GameCountReq.game_type = GT_FREESPACE;
447 #else
448         GameCountReq.game_type = GT_FREESPACE2;
449 #endif
450         GameCountReq.type = GNT_GAME_COUNT_REQ;
451         GameCountReq.len = GAME_HEADER_ONLY_SIZE+sizeof(filter_game_list_struct);       
452         memcpy(&GameCountReq.data, ((filter_game_list_struct*)filter)->channel, sizeof(filter_game_list_struct) - 4);
453         SENDTO(Unreliable_socket, (char *)&GameCountReq, GameCountReq.len, 0, (SOCKADDR *)&gtrackaddr, sizeof(SOCKADDR_IN), PSNET_TYPE_GAME_TRACKER);
454 }