2 * Copyright (C) Volition, Inc. 2005. All rights reserved.
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
11 //Validate tracker user class
15 #include <arpa/inet.h>
16 #include <netinet/in.h>
28 // check structs for size compatibility
29 SDL_COMPILE_TIME_ASSERT(vmt_validate_mission_req_struct, sizeof(vmt_validate_mission_req_struct) == 104);
33 udp_packet_header PacketHeader;
34 validate_id_request *ValidIDReq;
40 #define VALIDSOCKET validsock
42 #define VALIDSOCKET Unreliable_socket
44 struct sockaddr_in rtrackaddr;
52 int MissionValidState;
53 int MissionValidFirstSent;
54 int MissionValidLastSent;
56 // squad war validation
57 int SquadWarValidState;
58 int SquadWarFirstSent;
62 squad_war_response SquadWarValidateResponse;
65 static int SerializeValidatePacket(const udp_packet_header *uph, ubyte *data)
73 PXO_ADD_DATA(uph->type);
77 PXO_ADD_USHORT(uph->len);
78 PXO_ADD_UINT(uph->code);
79 PXO_ADD_USHORT(uph->xcode);
84 PXO_ADD_UINT(uph->sig);
85 PXO_ADD_UINT(uph->security);
88 // no extra data for this
92 case UNT_LOGIN_AUTH_REQUEST: {
93 validate_id_request *id_req = (validate_id_request *)&uph->data;
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
102 case UNT_VALID_FS2_MSN_REQ: {
103 vmt_validate_mission_req_struct *mis_req = (vmt_validate_mission_req_struct *)&uph->data;
105 PXO_ADD_UINT(mis_req->checksum);
107 memcpy(data+packet_size, mis_req->file_name, strlen(mis_req->file_name));
108 packet_size += strlen(mis_req->file_name);
110 data[packet_size] = '\0';
116 case UNT_VALID_SW_MSN_REQ: {
117 squad_war_request *sw_req = (squad_war_request *)&uph->data;
119 for (i = 0; i < MAX_SQUAD_PLAYERS; i++) {
120 PXO_ADD_INT(sw_req->squad_plr1[i]);
123 for (i = 0; i < MAX_SQUAD_PLAYERS; i++) {
124 PXO_ADD_INT(sw_req->squad_plr2[i]);
127 PXO_ADD_DATA(sw_req->squad_count1);
128 PXO_ADD_DATA(sw_req->squad_count2);
130 PXO_ADD_DATA(sw_req->match_code);
132 PXO_ADD_DATA(sw_req->mission_filename);
133 PXO_ADD_INT(sw_req->mission_checksum);
138 // we shouldn't be sending any other packet types
144 SDL_assert(packet_size >= (int)PACKED_HEADER_ONLY_SIZE);
145 SDL_assert(packet_size == (int)uph->len);
150 static void DeserializeValidatePacket(const ubyte *data, const int data_size, udp_packet_header *uph)
157 memset(uph, 0, sizeof(udp_packet_header));
159 // make sure we received a complete base packet
160 if (data_size < (int)PACKED_HEADER_ONLY_SIZE) {
167 PXO_GET_DATA(uph->type);
171 PXO_GET_USHORT(uph->len);
172 PXO_GET_UINT(uph->code);
173 PXO_GET_USHORT(uph->xcode);
178 PXO_GET_UINT(uph->sig);
179 PXO_GET_UINT(uph->security);
181 // sanity check data size to make sure we reveived all of the expected packet
183 // (the -1 is because psnet2 pops off one byte)
184 if ((int)uph->len-1 > data_size) {
186 if ((int)uph->len > data_size) {
195 // no extra data for these
197 case UNT_CONTROL_VALIDATION:
198 case UNT_LOGIN_NO_AUTH:
199 case UNT_VALID_FS_MSN_RSP:
200 case UNT_VALID_FS2_MSN_RSP:
203 case UNT_LOGIN_AUTHENTICATED: {
204 SDL_strlcpy((char *)uph->data, (const char *)(data+offset), SDL_arraysize(uph->data));
208 case UNT_VALID_SW_MSN_RSP: {
209 squad_war_response *sw_resp = (squad_war_response *)&uph->data;
211 PXO_GET_DATA(sw_resp->reason);
212 PXO_GET_DATA(sw_resp->accepted);
221 //SDL_assert(offset == data_size);
225 int InitValidateClient(void)
227 struct sockaddr_in sockaddr;
231 ValidState = VALID_STATE_IDLE;
233 MissionValidFirstSent = 0;
234 MissionValidLastSent = 0;
235 MissionValidState = VALID_STATE_IDLE;
237 SquadWarFirstSent = 0;
238 SquadWarLastSent = 0;
239 SquadWarValidState = VALID_STATE_IDLE;
242 validsock = socket(AF_INET,SOCK_DGRAM,0);
243 if ( validsock == (SOCKET)INVALID_SOCKET )
245 mprintf(("Unable to open a socket.\n"));
250 memset( &sockaddr, 0, sizeof(struct sockaddr_in) );
251 sockaddr.sin_family = AF_INET;
252 sockaddr.sin_addr.s_addr = INADDR_ANY;
253 sockaddr.sin_port = 0;
256 if (SOCKET_ERROR==bind(validsock, (struct sockaddr*)&sockaddr, sizeof (sockaddr)))
258 mprintf(("Unable to bind a socket.\n"));
259 mprintf(("WSAGetLastError() returned %d.\n",WSAGetLastError()));
264 rtrackaddr.sin_family = AF_INET;
265 iaddr = inet_addr( Multi_options_g.user_tracker_ip );
266 if ( iaddr == INADDR_NONE ) {
268 he = gethostbyname( Multi_options_g.user_tracker_ip );
273 // try and resolve by address
274 unsigned int n_order = inet_addr(Multi_user_tracker_ip_address);
275 he = gethostbyaddr((char*)&n_order,4,PF_INET);
282 iaddr = ((in_addr *)(he->h_addr))->s_addr;
285 rtrackaddr.sin_addr.s_addr = iaddr;
286 rtrackaddr.sin_port = htons(REGPORT);
292 //Call with a valid struct to validate a user
293 //Call with NULL to poll
296 // -3 Still waiting (returned if we were waiting for a tracker response and ValidateUser was called with a non-NULL value
297 // -2 Timeout waiting for tracker to respond
299 // 0 Still waiting for response from tracker/Idle
301 int ValidateUser(validate_id_request *valid_id, char *trackerid)
303 ubyte packet_data[sizeof(udp_packet_header)];
304 int packet_length = 0;
311 case VALID_STATE_IDLE:
314 case VALID_STATE_WAITING:
317 case VALID_STATE_VALID:
318 ValidState = VALID_STATE_IDLE;
321 case VALID_STATE_INVALID:
322 ValidState = VALID_STATE_IDLE;
324 case VALID_STATE_TIMEOUT:
325 ValidState = VALID_STATE_IDLE;
332 if(ValidState==VALID_STATE_IDLE)
334 //First, flush the input buffer for the socket
336 struct timeval timeout;
342 FD_SET(VALIDSOCKET, &read_fds);
344 while(PXO_SELECT(VALIDSOCKET+1,&read_fds,NULL,NULL,&timeout, PSNET_TYPE_VALIDATION))
347 struct sockaddr_in fromaddr;
349 udp_packet_header inpacket;
350 addrsize = sizeof(struct sockaddr_in);
351 PXO_RECVFROM(VALIDSOCKET, (char *)&inpacket,sizeof(udp_packet_header),0,(struct sockaddr *)&fromaddr,&addrsize, PSNET_TYPE_VALIDATION);
353 Psztracker_id = trackerid;
355 //Build the request packet
356 PacketHeader.type = UNT_LOGIN_AUTH_REQUEST;
357 PacketHeader.len = PACKED_HEADER_ONLY_SIZE+sizeof(validate_id_request);
358 ValidIDReq=(validate_id_request *)&PacketHeader.data;
359 SDL_strlcpy(ValidIDReq->login, valid_id->login, SDL_arraysize(ValidIDReq->login));
360 SDL_strlcpy(ValidIDReq->password, valid_id->password, SDL_arraysize(ValidIDReq->password));
362 packet_length = SerializeValidatePacket(&PacketHeader, packet_data);
363 PXO_SENDTO(VALIDSOCKET, (char *)&packet_data, packet_length, 0, (struct sockaddr *)&rtrackaddr, sizeof(struct sockaddr), PSNET_TYPE_VALIDATION);
364 ValidState = VALID_STATE_WAITING;
365 ValidFirstSent = timer_get_milliseconds();
366 ValidLastSent = timer_get_milliseconds();
380 struct timeval timeout;
381 ubyte packet_data[sizeof(udp_packet_header)];
382 int packet_length = 0;
385 PSNET_TOP_LAYER_PROCESS();
392 FD_SET(VALIDSOCKET, &read_fds);
394 if(PXO_SELECT(VALIDSOCKET+1,&read_fds,NULL,NULL,&timeout, PSNET_TYPE_VALIDATION)){
397 struct sockaddr_in fromaddr;
399 udp_packet_header inpacket;
402 addrsize = sizeof(struct sockaddr_in);
404 bytesin = PXO_RECVFROM(VALIDSOCKET, (char *)&packet_data, sizeof(udp_packet_header), 0, (struct sockaddr *)&fromaddr, &addrsize, PSNET_TYPE_VALIDATION);
407 DeserializeValidatePacket(packet_data, bytesin, &inpacket);
410 // decrease packet size by 1
415 int wserr=WSAGetLastError();
416 mprintf(("recvfrom() failure. WSAGetLastError() returned %d\n",wserr));
421 FD_SET(VALIDSOCKET, &read_fds);
423 //Check to make sure the packets ok
424 if ( (bytesin > 0) && (bytesin == inpacket.len) ) {
425 switch(inpacket.type)
427 case UNT_LOGIN_NO_AUTH:
428 if(ValidState == VALID_STATE_WAITING)
430 ValidState = VALID_STATE_INVALID;
433 case UNT_LOGIN_AUTHENTICATED:
434 if(ValidState == VALID_STATE_WAITING)
436 ValidState = VALID_STATE_VALID;
437 SDL_strlcpy(Psztracker_id, (const char *)&inpacket.data, TRACKER_ID_LEN);
440 // old - this is a Freespace 1 packet type
441 case UNT_VALID_FS_MSN_RSP:
445 // fs2 mission validation response
446 case UNT_VALID_FS2_MSN_RSP:
447 if(MissionValidState == VALID_STATE_WAITING){
448 if(inpacket.code==2){
449 MissionValidState = VALID_STATE_VALID;
451 MissionValidState = VALID_STATE_INVALID;
456 // fs2 squad war validation response
457 case UNT_VALID_SW_MSN_RSP:
458 if(SquadWarValidState == VALID_STATE_WAITING){
460 SDL_assert((bytesin - PACKED_HEADER_ONLY_SIZE) == sizeof(squad_war_response));
461 if((bytesin - PACKED_HEADER_ONLY_SIZE) == sizeof(squad_war_response)){
462 memset(&SquadWarValidateResponse, 0, sizeof(squad_war_response));
463 memcpy(&SquadWarValidateResponse, inpacket.data, sizeof(squad_war_response));
465 // now check to see if we're good
466 if(SquadWarValidateResponse.accepted){
467 SquadWarValidState = VALID_STATE_VALID;
469 SquadWarValidState = VALID_STATE_INVALID;
472 SquadWarValidState = VALID_STATE_INVALID;
477 case UNT_CONTROL_VALIDATION:
485 AckValidServer(inpacket.sig);
489 if(ValidState == VALID_STATE_WAITING)
491 if((timer_get_milliseconds()-ValidFirstSent)>=PILOT_REQ_TIMEOUT)
493 ValidState = VALID_STATE_TIMEOUT;
496 else if((timer_get_milliseconds()-ValidLastSent)>=PILOT_REQ_RESEND_TIME)
499 packet_length = SerializeValidatePacket(&PacketHeader, packet_data);
500 PXO_SENDTO(VALIDSOCKET, (char *)&packet_data, packet_length, 0, (struct sockaddr *)&rtrackaddr, sizeof(struct sockaddr), PSNET_TYPE_VALIDATION);
501 ValidLastSent = timer_get_milliseconds();
507 //Send an ACK to the server
508 void AckValidServer(unsigned int sig)
510 udp_packet_header ack_pack;
511 ubyte packet_data[sizeof(udp_packet_header)];
512 int packet_length = 0;
514 ack_pack.type = UNT_CONTROL;
516 ack_pack.code = CMD_CLIENT_RECEIVED;
517 ack_pack.len = PACKED_HEADER_ONLY_SIZE;
519 packet_length = SerializeValidatePacket(&ack_pack, packet_data);
520 SDL_assert(packet_length == PACKED_HEADER_ONLY_SIZE);
521 PXO_SENDTO(VALIDSOCKET, (char *)&packet_data, packet_length, 0, (struct sockaddr *)&rtrackaddr, sizeof(struct sockaddr_in), PSNET_TYPE_VALIDATION);
524 // call with a valid struct to validate a mission
525 // call with NULL to poll
528 // -3 Still waiting (returned if we were waiting for a tracker response and ValidateMission was called with a non-NULL value
529 // -2 Timeout waiting for tracker to respond
531 // 0 Still waiting for response from tracker/Idle
533 int ValidateMission(vmt_validate_mission_req_struct *valid_msn)
535 ubyte packet_data[sizeof(udp_packet_header)];
536 int packet_length = 0;
541 switch(MissionValidState)
543 case VALID_STATE_IDLE:
546 case VALID_STATE_WAITING:
549 case VALID_STATE_VALID:
550 MissionValidState = VALID_STATE_IDLE;
553 case VALID_STATE_INVALID:
554 MissionValidState = VALID_STATE_IDLE;
556 case VALID_STATE_TIMEOUT:
557 MissionValidState = VALID_STATE_IDLE;
564 if(MissionValidState==VALID_STATE_IDLE)
566 //First, flush the input buffer for the socket
568 struct timeval timeout;
574 FD_SET(VALIDSOCKET, &read_fds);
576 while(PXO_SELECT(VALIDSOCKET+1,&read_fds,NULL,NULL,&timeout, PSNET_TYPE_VALIDATION))
579 struct sockaddr_in fromaddr;
581 udp_packet_header inpacket;
582 addrsize = sizeof(struct sockaddr_in);
583 PXO_RECVFROM(VALIDSOCKET, (char *)&inpacket,sizeof(udp_packet_header),0,(struct sockaddr *)&fromaddr,&addrsize, PSNET_TYPE_VALIDATION);
585 FD_SET(VALIDSOCKET, &read_fds);
587 //only send the header, the checksum and the string length plus the null
588 PacketHeader.type = UNT_VALID_FS2_MSN_REQ;
589 PacketHeader.len = (short)(PACKED_HEADER_ONLY_SIZE + sizeof(int)+1+strlen(valid_msn->file_name));
590 memcpy(PacketHeader.data,valid_msn,PacketHeader.len-PACKED_HEADER_ONLY_SIZE);
591 packet_length = SerializeValidatePacket(&PacketHeader, packet_data);
592 PXO_SENDTO(VALIDSOCKET, (char *)&packet_data, packet_length, 0, (struct sockaddr *)&rtrackaddr, sizeof(struct sockaddr), PSNET_TYPE_VALIDATION);
593 MissionValidState = VALID_STATE_WAITING;
594 MissionValidFirstSent = timer_get_milliseconds();
595 MissionValidLastSent = timer_get_milliseconds();
605 // query the usertracker to validate a squad war match
606 // call with a valid struct to validate a mission
607 // call with NULL to poll
610 // -3 Still waiting (returned if we were waiting for a tracker response and ValidateSquadWae was called with a non-NULL value
611 // -2 Timeout waiting for tracker to respond
613 // 0 Still waiting for response from tracker/Idle
615 int ValidateSquadWar(squad_war_request *sw_req, squad_war_response *sw_resp)
617 ubyte packet_data[sizeof(udp_packet_header)];
618 int packet_length = 0;
622 switch(SquadWarValidState){
623 case VALID_STATE_IDLE:
626 case VALID_STATE_WAITING:
630 // fill in the response
631 case VALID_STATE_VALID:
632 SquadWarValidState = VALID_STATE_IDLE;
634 memcpy(sw_resp, &SquadWarValidateResponse, sizeof(squad_war_response));
638 // fill in the response
639 case VALID_STATE_INVALID:
640 SquadWarValidState = VALID_STATE_IDLE;
642 memcpy(sw_resp, &SquadWarValidateResponse, sizeof(squad_war_response));
646 case VALID_STATE_TIMEOUT:
647 SquadWarValidState = VALID_STATE_IDLE;
652 if(SquadWarValidState==VALID_STATE_IDLE){
653 // First, flush the input buffer for the socket
655 struct timeval timeout;
661 FD_SET(VALIDSOCKET, &read_fds);
663 while(PXO_SELECT(VALIDSOCKET+1,&read_fds,NULL,NULL,&timeout, PSNET_TYPE_VALIDATION)){
665 struct sockaddr_in fromaddr;
667 udp_packet_header inpacket;
668 addrsize = sizeof(struct sockaddr_in);
669 PXO_RECVFROM(VALIDSOCKET, (char *)&inpacket,sizeof(udp_packet_header),0,(struct sockaddr *)&fromaddr,&addrsize, PSNET_TYPE_VALIDATION);
671 FD_SET(VALIDSOCKET, &read_fds);
673 // only send the header, the checksum and the string length plus the null
674 PacketHeader.type = UNT_VALID_SW_MSN_REQ;
675 PacketHeader.len = (short)(PACKED_HEADER_ONLY_SIZE + sizeof(squad_war_request));
676 memcpy(PacketHeader.data, sw_req, PacketHeader.len-PACKED_HEADER_ONLY_SIZE);
677 packet_length = SerializeValidatePacket(&PacketHeader, packet_data);
678 PXO_SENDTO(VALIDSOCKET, (char *)&packet_data, packet_length, 0, (struct sockaddr *)&rtrackaddr, sizeof(struct sockaddr), PSNET_TYPE_VALIDATION);
679 SquadWarValidState = VALID_STATE_WAITING;
680 SquadWarFirstSent = timer_get_milliseconds();
681 SquadWarLastSent = timer_get_milliseconds();