]> icculus.org git repositories - taylor/freespace2.git/blob - src/network/valid.cpp
make websocket connection work over both http and https
[taylor/freespace2.git] / src / network / valid.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 //Validate tracker user class
12
13
14 #ifdef PLAT_UNIX
15 #include <arpa/inet.h>
16 #include <netinet/in.h>
17 #include <errno.h>
18 #include <netdb.h>
19 #endif
20
21 #include "multi.h"
22 #include "ptrack.h"
23 #include "valid.h"
24 #include "psnet.h"
25 #include "timer.h"
26
27
28 // check structs for size compatibility
29 SDL_COMPILE_TIME_ASSERT(vmt_validate_mission_req_struct, sizeof(vmt_validate_mission_req_struct) == 104);
30
31
32 // Variables
33 udp_packet_header PacketHeader;
34 validate_id_request *ValidIDReq;
35
36 int ValidState;
37
38 #ifdef MAKE_FS1
39 SOCKET validsock;
40 #define VALIDSOCKET validsock
41 #else
42 #define VALIDSOCKET Unreliable_socket
43 #endif
44 struct sockaddr_in      rtrackaddr;
45
46 int ValidFirstSent;
47 int ValidLastSent;
48
49 char *Psztracker_id;
50
51 // mission validation
52 int MissionValidState;
53 int MissionValidFirstSent;
54 int MissionValidLastSent;
55
56 // squad war validation
57 int SquadWarValidState;
58 int SquadWarFirstSent;
59 int SquadWarLastSent;
60
61 // squad war response
62 squad_war_response SquadWarValidateResponse;
63
64
65 static int SerializeValidatePacket(const udp_packet_header *uph, ubyte *data)
66 {
67         int packet_size = 0;
68         int i;
69 #ifdef MAKE_FS1
70         char h_pad = 0;
71 #endif
72
73         PXO_ADD_DATA(uph->type);
74 #ifdef MAKE_FS1
75         PXO_ADD_DATA(h_pad);
76 #endif
77         PXO_ADD_USHORT(uph->len);
78         PXO_ADD_UINT(uph->code);
79         PXO_ADD_USHORT(uph->xcode);
80 #ifdef MAKE_FS1
81         PXO_ADD_DATA(h_pad);
82         PXO_ADD_DATA(h_pad);
83 #endif
84         PXO_ADD_UINT(uph->sig);
85         PXO_ADD_UINT(uph->security);
86
87         switch (uph->type) {
88                 // no extra data for this
89                 case UNT_CONTROL:
90                         break;
91
92                 case UNT_LOGIN_AUTH_REQUEST: {
93                         validate_id_request *id_req = (validate_id_request *)&uph->data;
94
95                         PXO_ADD_DATA(id_req->login);
96                         PXO_ADD_DATA(id_req->password);
97                         PXO_ADD_DATA(id_req->tracker_id);       // junk here, just for size
98
99                         break;
100                 }
101
102                 case UNT_VALID_FS_MSN_REQ:
103                 case UNT_VALID_FS2_MSN_REQ: {
104                         vmt_validate_mission_req_struct *mis_req = (vmt_validate_mission_req_struct *)&uph->data;
105
106                         PXO_ADD_UINT(mis_req->checksum);
107
108                         memcpy(data+packet_size, mis_req->file_name, strlen(mis_req->file_name));
109                         packet_size += strlen(mis_req->file_name);
110
111                         data[packet_size] = '\0';
112                         packet_size++;
113
114                         break;
115                 }
116
117                 case UNT_VALID_SW_MSN_REQ: {
118                         squad_war_request *sw_req = (squad_war_request *)&uph->data;
119
120                         for (i = 0; i < MAX_SQUAD_PLAYERS; i++) {
121                                 PXO_ADD_INT(sw_req->squad_plr1[i]);
122                         }
123
124                         for (i = 0; i < MAX_SQUAD_PLAYERS; i++) {
125                                 PXO_ADD_INT(sw_req->squad_plr2[i]);
126                         }
127
128                         PXO_ADD_DATA(sw_req->squad_count1);
129                         PXO_ADD_DATA(sw_req->squad_count2);
130
131                         PXO_ADD_DATA(sw_req->match_code);
132
133                         PXO_ADD_DATA(sw_req->mission_filename);
134                         PXO_ADD_INT(sw_req->mission_checksum);
135
136                         break;
137                 }
138
139                 // we shouldn't be sending any other packet types
140                 default:
141                         Int3();
142                         break;
143         }
144
145         SDL_assert(packet_size >= (int)PACKED_HEADER_ONLY_SIZE);
146         SDL_assert(packet_size == (int)uph->len);
147
148         return packet_size;
149 }
150
151 static void DeserializeValidatePacket(const ubyte *data, const int data_size, udp_packet_header *uph)
152 {
153         int offset = 0;
154 #ifdef MAKE_FS1
155         char h_pad;
156 #endif
157
158         memset(uph, 0, sizeof(udp_packet_header));
159
160         // make sure we received a complete base packet
161         if (data_size < (int)PACKED_HEADER_ONLY_SIZE) {
162                 uph->len = 0;
163                 uph->type = 0xff;
164
165                 return;
166         }
167
168         PXO_GET_DATA(uph->type);
169 #ifdef MAKE_FS1
170         PXO_GET_DATA(h_pad);
171 #endif
172         PXO_GET_USHORT(uph->len);
173         PXO_GET_UINT(uph->code);
174         PXO_GET_USHORT(uph->xcode);
175 #ifdef MAKE_FS1
176         PXO_GET_DATA(h_pad);
177         PXO_GET_DATA(h_pad);
178 #endif
179         PXO_GET_UINT(uph->sig);
180         PXO_GET_UINT(uph->security);
181
182         // sanity check data size to make sure we reveived all of the expected packet
183 #ifndef MAKE_FS1
184         // (the -1 is because psnet2 pops off one byte)
185         if ((int)uph->len-1 > data_size) {
186 #else
187         if ((int)uph->len > data_size) {
188 #endif
189                 uph->len = 0;
190                 uph->type = 0xff;
191
192                 return;
193         }
194
195         switch (uph->type) {
196                 // no extra data for these
197                 case UNT_CONTROL:
198                 case UNT_CONTROL_VALIDATION:
199                 case UNT_LOGIN_NO_AUTH:
200                 case UNT_VALID_FS_MSN_RSP:
201                 case UNT_VALID_FS2_MSN_RSP:
202                         break;
203
204                 case UNT_LOGIN_AUTHENTICATED: {
205                         SDL_strlcpy((char *)uph->data, (const char *)(data+offset), SDL_arraysize(uph->data));
206                         break;
207                 }
208
209                 case UNT_VALID_SW_MSN_RSP: {
210                         squad_war_response *sw_resp = (squad_war_response *)&uph->data;
211
212                         PXO_GET_DATA(sw_resp->reason);
213                         PXO_GET_DATA(sw_resp->accepted);
214
215                         break;
216                 }
217
218                 default:
219                         break;
220         }
221
222         //SDL_assert(offset == data_size);
223 }
224
225
226 int InitValidateClient(void)
227 {
228         struct sockaddr_in sockaddr;
229         in_addr_t iaddr;
230         ValidFirstSent = 0;
231         ValidLastSent = 0;
232         ValidState = VALID_STATE_IDLE;
233         
234         MissionValidFirstSent = 0;
235         MissionValidLastSent = 0;
236         MissionValidState = VALID_STATE_IDLE;
237
238         SquadWarFirstSent = 0;
239         SquadWarLastSent = 0;
240         SquadWarValidState = VALID_STATE_IDLE;
241
242 #ifdef MAKE_FS1
243         validsock = socket(AF_INET,SOCK_DGRAM,0);       
244         if ( validsock == (SOCKET)INVALID_SOCKET )
245         {
246                 mprintf(("Unable to open a socket.\n"));
247                 return 0;
248         }
249 #endif
250         
251         memset( &sockaddr, 0, sizeof(struct sockaddr_in) );
252         sockaddr.sin_family = AF_INET; 
253         sockaddr.sin_addr.s_addr = INADDR_ANY; 
254         sockaddr.sin_port = 0;
255         
256 #ifdef MAKE_FS1
257         if (SOCKET_ERROR==bind(validsock, (struct sockaddr*)&sockaddr, sizeof (sockaddr)))
258         {       
259                 mprintf(("Unable to bind a socket.\n"));
260                 mprintf(("WSAGetLastError() returned %d.\n",WSAGetLastError()));
261                 return 0;
262         }
263 #endif
264
265         rtrackaddr.sin_family = AF_INET; 
266         iaddr = inet_addr( Multi_options_g.user_tracker_ip );
267         if ( iaddr == INADDR_NONE ) {
268                 struct hostent *he;
269                 he = gethostbyname( Multi_options_g.user_tracker_ip );
270                 if(!he)
271                         return 0;
272         /*
273                 {               
274                         // try and resolve by address
275                         unsigned int n_order = inet_addr(Multi_user_tracker_ip_address);
276                         he = gethostbyaddr((char*)&n_order,4,PF_INET);
277
278                         if(!he){
279                                 return 0;
280                         }
281                 }
282         */
283                 iaddr = ((in_addr *)(he->h_addr))->s_addr;
284         }
285         
286         rtrackaddr.sin_addr.s_addr = iaddr;
287         rtrackaddr.sin_port = htons(REGPORT);
288         
289         return 1;
290
291 }
292
293 //Call with a valid struct to validate a user
294 //Call with NULL to poll
295
296 //Return codes:
297 // -3   Still waiting (returned if we were waiting for a tracker response and ValidateUser was called with a non-NULL value
298 // -2 Timeout waiting for tracker to respond
299 // -1   User invalid
300 //  0   Still waiting for response from tracker/Idle
301 //  1   User valid
302 int ValidateUser(validate_id_request *valid_id, char *trackerid)
303 {
304         ubyte packet_data[sizeof(udp_packet_header)];
305         int packet_length = 0;
306
307         ValidIdle();
308         if(valid_id==NULL)
309         {
310                 switch(ValidState)
311                 {
312                 case VALID_STATE_IDLE:
313                         return 0;
314                         break;
315                 case VALID_STATE_WAITING:
316                         return 0;
317                         break;
318                 case VALID_STATE_VALID:
319                         ValidState = VALID_STATE_IDLE;
320                         return 1;
321                         break;
322                 case VALID_STATE_INVALID:
323                         ValidState = VALID_STATE_IDLE;
324                         return -1;
325                 case VALID_STATE_TIMEOUT:
326                         ValidState = VALID_STATE_IDLE;
327                         return -2;
328                 }
329                 return 0;
330         }
331         else
332         {
333                 if(ValidState==VALID_STATE_IDLE)
334                 {
335                         //First, flush the input buffer for the socket
336                         fd_set read_fds;                   
337                         struct timeval timeout;
338                         
339                         timeout.tv_sec=0;            
340                         timeout.tv_usec=0;
341                         
342                         FD_ZERO(&read_fds);
343                         FD_SET(VALIDSOCKET, &read_fds);
344
345                         while(PXO_SELECT(VALIDSOCKET+1,&read_fds,NULL,NULL,&timeout, PSNET_TYPE_VALIDATION))
346                         {
347                                 int addrsize;
348                                 struct sockaddr_in fromaddr;
349
350                                 udp_packet_header inpacket;
351                                 addrsize = sizeof(struct sockaddr_in);
352                                 PXO_RECVFROM(VALIDSOCKET, (char *)&inpacket,sizeof(udp_packet_header),0,(struct sockaddr *)&fromaddr,&addrsize, PSNET_TYPE_VALIDATION);
353                         }
354                         Psztracker_id = trackerid;
355
356                         //Build the request packet
357                         PacketHeader.type = UNT_LOGIN_AUTH_REQUEST;
358                         PacketHeader.len = PACKED_HEADER_ONLY_SIZE+sizeof(validate_id_request);
359                         ValidIDReq=(validate_id_request *)&PacketHeader.data;
360                         SDL_strlcpy(ValidIDReq->login, valid_id->login, SDL_arraysize(ValidIDReq->login));
361                         SDL_strlcpy(ValidIDReq->password, valid_id->password, SDL_arraysize(ValidIDReq->password));
362
363                         packet_length = SerializeValidatePacket(&PacketHeader, packet_data);
364                         PXO_SENDTO(VALIDSOCKET, (char *)&packet_data, packet_length, 0, (struct sockaddr *)&rtrackaddr, sizeof(struct sockaddr), PSNET_TYPE_VALIDATION);
365                         ValidState = VALID_STATE_WAITING;
366                         ValidFirstSent = timer_get_milliseconds();
367                         ValidLastSent = timer_get_milliseconds();
368                         return 0;
369                 }
370                 else
371                 {
372                         return -3;
373                 }
374         }
375 }
376
377
378 void ValidIdle()
379 {
380         fd_set read_fds;                   
381         struct timeval timeout;
382         ubyte packet_data[sizeof(udp_packet_header)];
383         int packet_length = 0;
384
385 #ifndef MAKE_FS1
386         PSNET_TOP_LAYER_PROCESS();
387 #endif
388
389         timeout.tv_sec=0;            
390         timeout.tv_usec=0;
391         
392         FD_ZERO(&read_fds);
393         FD_SET(VALIDSOCKET, &read_fds);
394
395         if(PXO_SELECT(VALIDSOCKET+1,&read_fds,NULL,NULL,&timeout, PSNET_TYPE_VALIDATION)){
396                 int bytesin;
397                 int addrsize;
398                 struct sockaddr_in fromaddr;
399
400                 udp_packet_header inpacket;
401
402                 SDL_zero(inpacket);
403                 addrsize = sizeof(struct sockaddr_in);
404
405                 bytesin = PXO_RECVFROM(VALIDSOCKET, (char *)&packet_data, sizeof(udp_packet_header), 0, (struct sockaddr *)&fromaddr, &addrsize, PSNET_TYPE_VALIDATION);
406
407                 if (bytesin > 0) {
408                         DeserializeValidatePacket(packet_data, bytesin, &inpacket);
409
410 #ifndef MAKE_FS1
411                         // decrease packet size by 1
412                         inpacket.len--;
413 #endif
414 #ifndef NDEBUG
415                 } else {
416                         int wserr=WSAGetLastError();
417                         mprintf(("recvfrom() failure. WSAGetLastError() returned %d\n",wserr));
418 #endif
419                 }
420
421                 FD_ZERO(&read_fds);
422                 FD_SET(VALIDSOCKET, &read_fds);    
423
424                 //Check to make sure the packets ok
425                 if ( (bytesin > 0) && (bytesin == inpacket.len) ) {
426                         switch(inpacket.type)
427                         {
428                                 case UNT_LOGIN_NO_AUTH:
429                                         if(ValidState == VALID_STATE_WAITING)
430                                         {
431                                                 ValidState = VALID_STATE_INVALID;                                               
432                                         }
433                                         break;
434                                 case UNT_LOGIN_AUTHENTICATED:
435                                         if(ValidState == VALID_STATE_WAITING)
436                                         {
437                                                 ValidState = VALID_STATE_VALID;
438                                                 SDL_strlcpy(Psztracker_id, (const char *)&inpacket.data, TRACKER_ID_LEN);
439                                         }
440                                         break;
441                                 // old - this is a Freespace 1 packet type
442                                 case UNT_VALID_FS_MSN_RSP:
443 #ifndef MAKE_FS1
444                                         Int3();
445                                         break;
446 #endif
447
448                                 // fs2 mission validation response
449                                 case UNT_VALID_FS2_MSN_RSP:
450                                         if(MissionValidState == VALID_STATE_WAITING){
451                                                 if(inpacket.code==2){
452                                                         MissionValidState = VALID_STATE_VALID;
453                                                 } else {
454                                                         MissionValidState = VALID_STATE_INVALID;
455                                                 }
456                                         }
457                                         break;
458
459                                 // fs2 squad war validation response
460                                 case UNT_VALID_SW_MSN_RSP:
461                                         if(SquadWarValidState == VALID_STATE_WAITING){
462                                                 // copy the data
463                                                 SDL_assert((bytesin - PACKED_HEADER_ONLY_SIZE) == sizeof(squad_war_response));
464                                                 if((bytesin - PACKED_HEADER_ONLY_SIZE) == sizeof(squad_war_response)){
465                                                         memset(&SquadWarValidateResponse, 0, sizeof(squad_war_response));
466                                                         memcpy(&SquadWarValidateResponse, inpacket.data, sizeof(squad_war_response));
467
468                                                         // now check to see if we're good
469                                                         if(SquadWarValidateResponse.accepted){
470                                                                 SquadWarValidState = VALID_STATE_VALID;
471                                                         } else {
472                                                                 SquadWarValidState = VALID_STATE_INVALID;
473                                                         }
474                                                 } else {
475                                                         SquadWarValidState = VALID_STATE_INVALID;
476                                                 }                                               
477                                         }
478                                         break;
479
480                                 case UNT_CONTROL_VALIDATION:
481                                         Int3();
482                                         break;
483
484                                 case UNT_CONTROL:
485                                         Int3();
486                                         break;
487                         }
488                         AckValidServer(inpacket.sig);
489                 }
490         }
491
492         if(ValidState == VALID_STATE_WAITING)
493         {
494                 if((timer_get_milliseconds()-ValidFirstSent)>=PILOT_REQ_TIMEOUT)
495                 {
496                         ValidState = VALID_STATE_TIMEOUT;
497
498                 }               
499                 else if((timer_get_milliseconds()-ValidLastSent)>=PILOT_REQ_RESEND_TIME)
500                 {
501                         //Send 'da packet
502                         packet_length = SerializeValidatePacket(&PacketHeader, packet_data);
503                         PXO_SENDTO(VALIDSOCKET, (char *)&packet_data, packet_length, 0, (struct sockaddr *)&rtrackaddr, sizeof(struct sockaddr), PSNET_TYPE_VALIDATION);
504                         ValidLastSent = timer_get_milliseconds();
505                 }
506         }
507
508         if(MissionValidState == VALID_STATE_WAITING)
509         {
510                 if((timer_get_milliseconds()-MissionValidFirstSent)>=PILOT_REQ_TIMEOUT)
511                 {
512                         MissionValidState = VALID_STATE_TIMEOUT;
513                 }
514         }
515
516         if(SquadWarValidState == VALID_STATE_WAITING)
517         {
518                 if((timer_get_milliseconds()-SquadWarFirstSent)>=PILOT_REQ_TIMEOUT)
519                 {
520                         SquadWarValidState = VALID_STATE_TIMEOUT;
521                 }
522         }
523 }
524
525
526 //Send an ACK to the server
527 void AckValidServer(unsigned int sig)
528 {
529         udp_packet_header ack_pack;
530         ubyte packet_data[sizeof(udp_packet_header)];
531         int packet_length = 0;
532
533         ack_pack.type = UNT_CONTROL;
534         ack_pack.sig = sig;
535         ack_pack.code = CMD_CLIENT_RECEIVED;
536         ack_pack.len = PACKED_HEADER_ONLY_SIZE;
537
538         packet_length = SerializeValidatePacket(&ack_pack, packet_data);
539         SDL_assert(packet_length == PACKED_HEADER_ONLY_SIZE);
540         PXO_SENDTO(VALIDSOCKET, (char *)&packet_data, packet_length, 0, (struct sockaddr *)&rtrackaddr, sizeof(struct sockaddr_in), PSNET_TYPE_VALIDATION);
541 }
542
543 // call with a valid struct to validate a mission
544 // call with NULL to poll
545
546 // Return codes:
547 // -3   Still waiting (returned if we were waiting for a tracker response and ValidateMission was called with a non-NULL value
548 // -2 Timeout waiting for tracker to respond
549 // -1   User invalid
550 //  0   Still waiting for response from tracker/Idle
551 //  1   User valid
552 int ValidateMission(vmt_validate_mission_req_struct *valid_msn)
553 {
554         ubyte packet_data[sizeof(udp_packet_header)];
555         int packet_length = 0;
556
557         ValidIdle();
558         if(valid_msn==NULL)
559         {
560                 switch(MissionValidState)
561                 {
562                 case VALID_STATE_IDLE:
563                         return 0;
564                         break;
565                 case VALID_STATE_WAITING:
566                         return 0;
567                         break;                  
568                 case VALID_STATE_VALID:
569                         MissionValidState = VALID_STATE_IDLE;
570                         return 1;
571                         break;
572                 case VALID_STATE_INVALID:
573                         MissionValidState = VALID_STATE_IDLE;
574                         return -1;
575                 case VALID_STATE_TIMEOUT:
576                         MissionValidState = VALID_STATE_IDLE;
577                         return -2;
578                 }
579                 return 0;
580         }
581         else
582         {
583                 if(MissionValidState==VALID_STATE_IDLE)
584                 {
585                         //First, flush the input buffer for the socket
586                         fd_set read_fds;                   
587                         struct timeval timeout;
588                         
589                         timeout.tv_sec=0;            
590                         timeout.tv_usec=0;
591                         
592                         FD_ZERO(&read_fds);
593                         FD_SET(VALIDSOCKET, &read_fds);
594
595                         while(PXO_SELECT(VALIDSOCKET+1,&read_fds,NULL,NULL,&timeout, PSNET_TYPE_VALIDATION))
596                         {
597                                 int addrsize;
598                                 struct sockaddr_in fromaddr;
599
600                                 udp_packet_header inpacket;
601                                 addrsize = sizeof(struct sockaddr_in);
602                                 PXO_RECVFROM(VALIDSOCKET, (char *)&inpacket,sizeof(udp_packet_header),0,(struct sockaddr *)&fromaddr,&addrsize, PSNET_TYPE_VALIDATION);
603                                 FD_ZERO(&read_fds);
604                                 FD_SET(VALIDSOCKET, &read_fds);
605                         }
606                         //only send the header, the checksum and the string length plus the null
607 #ifndef MAKE_FS1
608                         PacketHeader.type = UNT_VALID_FS2_MSN_REQ;
609 #else
610                         PacketHeader.type = UNT_VALID_FS_MSN_REQ;
611 #endif
612                         PacketHeader.len = (short)(PACKED_HEADER_ONLY_SIZE + sizeof(int)+1+strlen(valid_msn->file_name));
613                         memcpy(PacketHeader.data,valid_msn,PacketHeader.len-PACKED_HEADER_ONLY_SIZE);
614                         packet_length = SerializeValidatePacket(&PacketHeader, packet_data);
615                         PXO_SENDTO(VALIDSOCKET, (char *)&packet_data, packet_length, 0, (struct sockaddr *)&rtrackaddr, sizeof(struct sockaddr), PSNET_TYPE_VALIDATION);
616                         MissionValidState = VALID_STATE_WAITING;
617                         MissionValidFirstSent = timer_get_milliseconds();
618                         MissionValidLastSent = timer_get_milliseconds();
619                         return 0;
620                 }
621                 else
622                 {
623                         return -3;
624                 }
625         }
626 }
627
628 // query the usertracker to validate a squad war match
629 // call with a valid struct to validate a mission
630 // call with NULL to poll
631
632 // Return codes:
633 // -3   Still waiting (returned if we were waiting for a tracker response and ValidateSquadWae was called with a non-NULL value
634 // -2 Timeout waiting for tracker to respond
635 // -1   match invalid
636 //  0   Still waiting for response from tracker/Idle
637 //  1   match valid
638 int ValidateSquadWar(squad_war_request *sw_req, squad_war_response *sw_resp)
639 {
640         ubyte packet_data[sizeof(udp_packet_header)];
641         int packet_length = 0;
642
643         ValidIdle();
644         if(sw_req==NULL){
645                 switch(SquadWarValidState){
646                 case VALID_STATE_IDLE:
647                         return 0;
648                         break;
649                 case VALID_STATE_WAITING:
650                         return 0;
651                         break;
652
653                 // fill in the response
654                 case VALID_STATE_VALID:
655                         SquadWarValidState = VALID_STATE_IDLE;
656                         if(sw_resp != NULL){
657                                 memcpy(sw_resp, &SquadWarValidateResponse, sizeof(squad_war_response));
658                         }
659                         return 1;
660                         break;
661                 // fill in the response
662                 case VALID_STATE_INVALID:
663                         SquadWarValidState = VALID_STATE_IDLE;
664                         if(sw_resp != NULL){
665                                 memcpy(sw_resp, &SquadWarValidateResponse, sizeof(squad_war_response));
666                         }
667                         return -1;
668
669                 case VALID_STATE_TIMEOUT:
670                         SquadWarValidState = VALID_STATE_IDLE;
671                         return -2;
672                 }
673                 return 0;
674         } else {
675                 if(SquadWarValidState==VALID_STATE_IDLE){
676                         // First, flush the input buffer for the socket
677                         fd_set read_fds;                   
678                         struct timeval timeout;
679                         
680                         timeout.tv_sec=0;            
681                         timeout.tv_usec=0;
682                         
683                         FD_ZERO(&read_fds);
684                         FD_SET(VALIDSOCKET, &read_fds);
685
686                         while(PXO_SELECT(VALIDSOCKET+1,&read_fds,NULL,NULL,&timeout, PSNET_TYPE_VALIDATION)){
687                                 int addrsize;
688                                 struct sockaddr_in fromaddr;
689
690                                 udp_packet_header inpacket;
691                                 addrsize = sizeof(struct sockaddr_in);
692                                 PXO_RECVFROM(VALIDSOCKET, (char *)&inpacket,sizeof(udp_packet_header),0,(struct sockaddr *)&fromaddr,&addrsize, PSNET_TYPE_VALIDATION);
693                                 FD_ZERO(&read_fds);
694                                 FD_SET(VALIDSOCKET, &read_fds);
695                         }
696                         // only send the header, the checksum and the string length plus the null
697                         PacketHeader.type = UNT_VALID_SW_MSN_REQ;
698                         PacketHeader.len = (short)(PACKED_HEADER_ONLY_SIZE + sizeof(squad_war_request));
699                         memcpy(PacketHeader.data, sw_req, PacketHeader.len-PACKED_HEADER_ONLY_SIZE);
700                         packet_length = SerializeValidatePacket(&PacketHeader, packet_data);
701                         PXO_SENDTO(VALIDSOCKET, (char *)&packet_data, packet_length, 0, (struct sockaddr *)&rtrackaddr, sizeof(struct sockaddr), PSNET_TYPE_VALIDATION);
702                         SquadWarValidState = VALID_STATE_WAITING;
703                         SquadWarFirstSent = timer_get_milliseconds();
704                         SquadWarLastSent = timer_get_milliseconds();
705                         return 0;
706                 } else {
707                         return -3;
708                 }
709         }
710 }