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_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;
106 PXO_ADD_UINT(mis_req->checksum);
108 memcpy(data+packet_size, mis_req->file_name, strlen(mis_req->file_name));
109 packet_size += strlen(mis_req->file_name);
111 data[packet_size] = '\0';
117 case UNT_VALID_SW_MSN_REQ: {
118 squad_war_request *sw_req = (squad_war_request *)&uph->data;
120 for (i = 0; i < MAX_SQUAD_PLAYERS; i++) {
121 PXO_ADD_INT(sw_req->squad_plr1[i]);
124 for (i = 0; i < MAX_SQUAD_PLAYERS; i++) {
125 PXO_ADD_INT(sw_req->squad_plr2[i]);
128 PXO_ADD_DATA(sw_req->squad_count1);
129 PXO_ADD_DATA(sw_req->squad_count2);
131 PXO_ADD_DATA(sw_req->match_code);
133 PXO_ADD_DATA(sw_req->mission_filename);
134 PXO_ADD_INT(sw_req->mission_checksum);
139 // we shouldn't be sending any other packet types
145 SDL_assert(packet_size >= (int)PACKED_HEADER_ONLY_SIZE);
146 SDL_assert(packet_size == (int)uph->len);
151 static void DeserializeValidatePacket(const ubyte *data, const int data_size, udp_packet_header *uph)
158 memset(uph, 0, sizeof(udp_packet_header));
160 // make sure we received a complete base packet
161 if (data_size < (int)PACKED_HEADER_ONLY_SIZE) {
168 PXO_GET_DATA(uph->type);
172 PXO_GET_USHORT(uph->len);
173 PXO_GET_UINT(uph->code);
174 PXO_GET_USHORT(uph->xcode);
179 PXO_GET_UINT(uph->sig);
180 PXO_GET_UINT(uph->security);
182 // sanity check data size to make sure we reveived all of the expected packet
184 // (the -1 is because psnet2 pops off one byte)
185 if ((int)uph->len-1 > data_size) {
187 if ((int)uph->len > data_size) {
196 // no extra data for these
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:
204 case UNT_LOGIN_AUTHENTICATED: {
205 SDL_strlcpy((char *)uph->data, (const char *)(data+offset), SDL_arraysize(uph->data));
209 case UNT_VALID_SW_MSN_RSP: {
210 squad_war_response *sw_resp = (squad_war_response *)&uph->data;
212 PXO_GET_DATA(sw_resp->reason);
213 PXO_GET_DATA(sw_resp->accepted);
222 //SDL_assert(offset == data_size);
226 int InitValidateClient(void)
228 struct sockaddr_in sockaddr;
232 ValidState = VALID_STATE_IDLE;
234 MissionValidFirstSent = 0;
235 MissionValidLastSent = 0;
236 MissionValidState = VALID_STATE_IDLE;
238 SquadWarFirstSent = 0;
239 SquadWarLastSent = 0;
240 SquadWarValidState = VALID_STATE_IDLE;
243 validsock = socket(AF_INET,SOCK_DGRAM,0);
244 if ( validsock == (SOCKET)INVALID_SOCKET )
246 mprintf(("Unable to open a socket.\n"));
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;
257 if (SOCKET_ERROR==bind(validsock, (struct sockaddr*)&sockaddr, sizeof (sockaddr)))
259 mprintf(("Unable to bind a socket.\n"));
260 mprintf(("WSAGetLastError() returned %d.\n",WSAGetLastError()));
265 rtrackaddr.sin_family = AF_INET;
266 iaddr = inet_addr( Multi_options_g.user_tracker_ip );
267 if ( iaddr == INADDR_NONE ) {
269 he = gethostbyname( Multi_options_g.user_tracker_ip );
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);
283 iaddr = ((in_addr *)(he->h_addr))->s_addr;
286 rtrackaddr.sin_addr.s_addr = iaddr;
287 rtrackaddr.sin_port = htons(REGPORT);
293 //Call with a valid struct to validate a user
294 //Call with NULL to poll
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
300 // 0 Still waiting for response from tracker/Idle
302 int ValidateUser(validate_id_request *valid_id, char *trackerid)
304 ubyte packet_data[sizeof(udp_packet_header)];
305 int packet_length = 0;
312 case VALID_STATE_IDLE:
315 case VALID_STATE_WAITING:
318 case VALID_STATE_VALID:
319 ValidState = VALID_STATE_IDLE;
322 case VALID_STATE_INVALID:
323 ValidState = VALID_STATE_IDLE;
325 case VALID_STATE_TIMEOUT:
326 ValidState = VALID_STATE_IDLE;
333 if(ValidState==VALID_STATE_IDLE)
335 //First, flush the input buffer for the socket
337 struct timeval timeout;
343 FD_SET(VALIDSOCKET, &read_fds);
345 while(PXO_SELECT(VALIDSOCKET+1,&read_fds,NULL,NULL,&timeout, PSNET_TYPE_VALIDATION))
348 struct sockaddr_in fromaddr;
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);
354 Psztracker_id = trackerid;
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));
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();
381 struct timeval timeout;
382 ubyte packet_data[sizeof(udp_packet_header)];
383 int packet_length = 0;
386 PSNET_TOP_LAYER_PROCESS();
393 FD_SET(VALIDSOCKET, &read_fds);
395 if(PXO_SELECT(VALIDSOCKET+1,&read_fds,NULL,NULL,&timeout, PSNET_TYPE_VALIDATION)){
398 struct sockaddr_in fromaddr;
400 udp_packet_header inpacket;
403 addrsize = sizeof(struct sockaddr_in);
405 bytesin = PXO_RECVFROM(VALIDSOCKET, (char *)&packet_data, sizeof(udp_packet_header), 0, (struct sockaddr *)&fromaddr, &addrsize, PSNET_TYPE_VALIDATION);
408 DeserializeValidatePacket(packet_data, bytesin, &inpacket);
411 // decrease packet size by 1
416 int wserr=WSAGetLastError();
417 mprintf(("recvfrom() failure. WSAGetLastError() returned %d\n",wserr));
422 FD_SET(VALIDSOCKET, &read_fds);
424 //Check to make sure the packets ok
425 if ( (bytesin > 0) && (bytesin == inpacket.len) ) {
426 switch(inpacket.type)
428 case UNT_LOGIN_NO_AUTH:
429 if(ValidState == VALID_STATE_WAITING)
431 ValidState = VALID_STATE_INVALID;
434 case UNT_LOGIN_AUTHENTICATED:
435 if(ValidState == VALID_STATE_WAITING)
437 ValidState = VALID_STATE_VALID;
438 SDL_strlcpy(Psztracker_id, (const char *)&inpacket.data, TRACKER_ID_LEN);
441 // old - this is a Freespace 1 packet type
442 case UNT_VALID_FS_MSN_RSP:
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;
454 MissionValidState = VALID_STATE_INVALID;
459 // fs2 squad war validation response
460 case UNT_VALID_SW_MSN_RSP:
461 if(SquadWarValidState == VALID_STATE_WAITING){
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));
468 // now check to see if we're good
469 if(SquadWarValidateResponse.accepted){
470 SquadWarValidState = VALID_STATE_VALID;
472 SquadWarValidState = VALID_STATE_INVALID;
475 SquadWarValidState = VALID_STATE_INVALID;
480 case UNT_CONTROL_VALIDATION:
488 AckValidServer(inpacket.sig);
492 if(ValidState == VALID_STATE_WAITING)
494 if((timer_get_milliseconds()-ValidFirstSent)>=PILOT_REQ_TIMEOUT)
496 ValidState = VALID_STATE_TIMEOUT;
499 else if((timer_get_milliseconds()-ValidLastSent)>=PILOT_REQ_RESEND_TIME)
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();
510 //Send an ACK to the server
511 void AckValidServer(unsigned int sig)
513 udp_packet_header ack_pack;
514 ubyte packet_data[sizeof(udp_packet_header)];
515 int packet_length = 0;
517 ack_pack.type = UNT_CONTROL;
519 ack_pack.code = CMD_CLIENT_RECEIVED;
520 ack_pack.len = PACKED_HEADER_ONLY_SIZE;
522 packet_length = SerializeValidatePacket(&ack_pack, packet_data);
523 SDL_assert(packet_length == PACKED_HEADER_ONLY_SIZE);
524 PXO_SENDTO(VALIDSOCKET, (char *)&packet_data, packet_length, 0, (struct sockaddr *)&rtrackaddr, sizeof(struct sockaddr_in), PSNET_TYPE_VALIDATION);
527 // call with a valid struct to validate a mission
528 // call with NULL to poll
531 // -3 Still waiting (returned if we were waiting for a tracker response and ValidateMission was called with a non-NULL value
532 // -2 Timeout waiting for tracker to respond
534 // 0 Still waiting for response from tracker/Idle
536 int ValidateMission(vmt_validate_mission_req_struct *valid_msn)
538 ubyte packet_data[sizeof(udp_packet_header)];
539 int packet_length = 0;
544 switch(MissionValidState)
546 case VALID_STATE_IDLE:
549 case VALID_STATE_WAITING:
552 case VALID_STATE_VALID:
553 MissionValidState = VALID_STATE_IDLE;
556 case VALID_STATE_INVALID:
557 MissionValidState = VALID_STATE_IDLE;
559 case VALID_STATE_TIMEOUT:
560 MissionValidState = VALID_STATE_IDLE;
567 if(MissionValidState==VALID_STATE_IDLE)
569 //First, flush the input buffer for the socket
571 struct timeval timeout;
577 FD_SET(VALIDSOCKET, &read_fds);
579 while(PXO_SELECT(VALIDSOCKET+1,&read_fds,NULL,NULL,&timeout, PSNET_TYPE_VALIDATION))
582 struct sockaddr_in fromaddr;
584 udp_packet_header inpacket;
585 addrsize = sizeof(struct sockaddr_in);
586 PXO_RECVFROM(VALIDSOCKET, (char *)&inpacket,sizeof(udp_packet_header),0,(struct sockaddr *)&fromaddr,&addrsize, PSNET_TYPE_VALIDATION);
588 FD_SET(VALIDSOCKET, &read_fds);
590 //only send the header, the checksum and the string length plus the null
592 PacketHeader.type = UNT_VALID_FS2_MSN_REQ;
594 PacketHeader.type = UNT_VALID_FS_MSN_REQ;
596 PacketHeader.len = (short)(PACKED_HEADER_ONLY_SIZE + sizeof(int)+1+strlen(valid_msn->file_name));
597 memcpy(PacketHeader.data,valid_msn,PacketHeader.len-PACKED_HEADER_ONLY_SIZE);
598 packet_length = SerializeValidatePacket(&PacketHeader, packet_data);
599 PXO_SENDTO(VALIDSOCKET, (char *)&packet_data, packet_length, 0, (struct sockaddr *)&rtrackaddr, sizeof(struct sockaddr), PSNET_TYPE_VALIDATION);
600 MissionValidState = VALID_STATE_WAITING;
601 MissionValidFirstSent = timer_get_milliseconds();
602 MissionValidLastSent = timer_get_milliseconds();
612 // query the usertracker to validate a squad war match
613 // call with a valid struct to validate a mission
614 // call with NULL to poll
617 // -3 Still waiting (returned if we were waiting for a tracker response and ValidateSquadWae was called with a non-NULL value
618 // -2 Timeout waiting for tracker to respond
620 // 0 Still waiting for response from tracker/Idle
622 int ValidateSquadWar(squad_war_request *sw_req, squad_war_response *sw_resp)
624 ubyte packet_data[sizeof(udp_packet_header)];
625 int packet_length = 0;
629 switch(SquadWarValidState){
630 case VALID_STATE_IDLE:
633 case VALID_STATE_WAITING:
637 // fill in the response
638 case VALID_STATE_VALID:
639 SquadWarValidState = VALID_STATE_IDLE;
641 memcpy(sw_resp, &SquadWarValidateResponse, sizeof(squad_war_response));
645 // fill in the response
646 case VALID_STATE_INVALID:
647 SquadWarValidState = VALID_STATE_IDLE;
649 memcpy(sw_resp, &SquadWarValidateResponse, sizeof(squad_war_response));
653 case VALID_STATE_TIMEOUT:
654 SquadWarValidState = VALID_STATE_IDLE;
659 if(SquadWarValidState==VALID_STATE_IDLE){
660 // First, flush the input buffer for the socket
662 struct timeval timeout;
668 FD_SET(VALIDSOCKET, &read_fds);
670 while(PXO_SELECT(VALIDSOCKET+1,&read_fds,NULL,NULL,&timeout, PSNET_TYPE_VALIDATION)){
672 struct sockaddr_in fromaddr;
674 udp_packet_header inpacket;
675 addrsize = sizeof(struct sockaddr_in);
676 PXO_RECVFROM(VALIDSOCKET, (char *)&inpacket,sizeof(udp_packet_header),0,(struct sockaddr *)&fromaddr,&addrsize, PSNET_TYPE_VALIDATION);
678 FD_SET(VALIDSOCKET, &read_fds);
680 // only send the header, the checksum and the string length plus the null
681 PacketHeader.type = UNT_VALID_SW_MSN_REQ;
682 PacketHeader.len = (short)(PACKED_HEADER_ONLY_SIZE + sizeof(squad_war_request));
683 memcpy(PacketHeader.data, sw_req, PacketHeader.len-PACKED_HEADER_ONLY_SIZE);
684 packet_length = SerializeValidatePacket(&PacketHeader, packet_data);
685 PXO_SENDTO(VALIDSOCKET, (char *)&packet_data, packet_length, 0, (struct sockaddr *)&rtrackaddr, sizeof(struct sockaddr), PSNET_TYPE_VALIDATION);
686 SquadWarValidState = VALID_STATE_WAITING;
687 SquadWarFirstSent = timer_get_milliseconds();
688 SquadWarLastSent = timer_get_milliseconds();