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;
39 struct sockaddr_in rtrackaddr;
47 int MissionValidState;
48 int MissionValidFirstSent;
49 int MissionValidLastSent;
51 // squad war validation
52 int SquadWarValidState;
53 int SquadWarFirstSent;
57 squad_war_response SquadWarValidateResponse;
60 static int SerializeValidatePacket(const udp_packet_header *uph, ubyte *data)
65 PXO_ADD_DATA(uph->type);
66 PXO_ADD_USHORT(uph->len);
67 PXO_ADD_UINT(uph->code);
68 PXO_ADD_USHORT(uph->xcode);
69 PXO_ADD_UINT(uph->sig);
70 PXO_ADD_UINT(uph->security);
73 // no extra data for this
77 case UNT_LOGIN_AUTH_REQUEST: {
78 validate_id_request *id_req = (validate_id_request *)&uph->data;
80 PXO_ADD_DATA(id_req->login);
81 PXO_ADD_DATA(id_req->password);
82 PXO_ADD_DATA(id_req->tracker_id); // junk here, just for size
87 case UNT_VALID_FS2_MSN_REQ: {
88 vmt_validate_mission_req_struct *mis_req = (vmt_validate_mission_req_struct *)&uph->data;
90 PXO_ADD_UINT(mis_req->checksum);
92 memcpy(data+packet_size, mis_req->file_name, strlen(mis_req->file_name));
93 packet_size += strlen(mis_req->file_name);
95 data[packet_size] = '\0';
101 case UNT_VALID_SW_MSN_REQ: {
102 squad_war_request *sw_req = (squad_war_request *)&uph->data;
104 for (i = 0; i < MAX_SQUAD_PLAYERS; i++) {
105 PXO_ADD_INT(sw_req->squad_plr1[i]);
108 for (i = 0; i < MAX_SQUAD_PLAYERS; i++) {
109 PXO_ADD_INT(sw_req->squad_plr2[i]);
112 PXO_ADD_DATA(sw_req->squad_count1);
113 PXO_ADD_DATA(sw_req->squad_count2);
115 PXO_ADD_DATA(sw_req->match_code);
117 PXO_ADD_DATA(sw_req->mission_filename);
118 PXO_ADD_INT(sw_req->mission_checksum);
123 // we shouldn't be sending any other packet types
129 SDL_assert(packet_size >= (int)PACKED_HEADER_ONLY_SIZE);
130 SDL_assert(packet_size == (int)uph->len);
135 static void DeserializeValidatePacket(const ubyte *data, const int data_size, udp_packet_header *uph)
139 memset(uph, 0, sizeof(udp_packet_header));
141 // make sure we received a complete base packet
142 if (data_size < (int)PACKED_HEADER_ONLY_SIZE) {
149 PXO_GET_DATA(uph->type);
150 PXO_GET_USHORT(uph->len);
151 PXO_GET_UINT(uph->code);
152 PXO_GET_USHORT(uph->xcode);
153 PXO_GET_UINT(uph->sig);
154 PXO_GET_UINT(uph->security);
156 // sanity check data size to make sure we reveived all of the expected packet
157 // (not exactly sure what -1 is for, but that's how it is later)
158 if ((int)uph->len-1 > data_size) {
166 // no extra data for these
168 case UNT_CONTROL_VALIDATION:
169 case UNT_LOGIN_NO_AUTH:
170 case UNT_VALID_FS_MSN_RSP:
171 case UNT_VALID_FS2_MSN_RSP:
174 case UNT_LOGIN_AUTHENTICATED: {
175 SDL_strlcpy((char *)uph->data, (const char *)(data+offset), TRACKER_ID_LEN);
179 case UNT_VALID_SW_MSN_RSP: {
180 squad_war_response *sw_resp = (squad_war_response *)&uph->data;
182 PXO_GET_DATA(sw_resp->reason);
183 PXO_GET_DATA(sw_resp->accepted);
192 //SDL_assert(offset == data_size);
196 int InitValidateClient(void)
198 struct sockaddr_in sockaddr;
202 ValidState = VALID_STATE_IDLE;
204 MissionValidFirstSent = 0;
205 MissionValidLastSent = 0;
206 MissionValidState = VALID_STATE_IDLE;
208 SquadWarFirstSent = 0;
209 SquadWarLastSent = 0;
210 SquadWarValidState = VALID_STATE_IDLE;
213 validsock = socket(AF_INET,SOCK_DGRAM,0);
214 if ( validsock == INVALID_SOCKET )
216 printf("Unable to open a socket.\n");
221 memset( &sockaddr, 0, sizeof(struct sockaddr_in) );
222 sockaddr.sin_family = AF_INET;
223 sockaddr.sin_addr.s_addr = INADDR_ANY;
224 sockaddr.sin_port = 0;
227 if (SOCKET_ERROR==bind(validsock, (struct sockaddr*)&sockaddr, sizeof (sockaddr)))
229 printf("Unable to bind a socket.\n");
230 printf("WSAGetLastError() returned %d.\n",WSAGetLastError());
235 rtrackaddr.sin_family = AF_INET;
236 iaddr = inet_addr( Multi_options_g.user_tracker_ip );
237 if ( iaddr == INADDR_NONE ) {
239 he = gethostbyname( Multi_options_g.user_tracker_ip );
244 // try and resolve by address
245 unsigned int n_order = inet_addr(Multi_user_tracker_ip_address);
246 he = gethostbyaddr((char*)&n_order,4,PF_INET);
253 memcpy(&iaddr, he->h_addr_list[0],4);
256 memcpy(&rtrackaddr.sin_addr.s_addr, &iaddr, 4);
257 rtrackaddr.sin_port = htons(REGPORT);
263 //Call with a valid struct to validate a user
264 //Call with NULL to poll
267 // -3 Still waiting (returned if we were waiting for a tracker response and ValidateUser was called with a non-NULL value
268 // -2 Timeout waiting for tracker to respond
270 // 0 Still waiting for response from tracker/Idle
272 int ValidateUser(validate_id_request *valid_id, char *trackerid)
274 ubyte packet_data[sizeof(udp_packet_header)];
275 int packet_length = 0;
282 case VALID_STATE_IDLE:
285 case VALID_STATE_WAITING:
288 case VALID_STATE_VALID:
289 ValidState = VALID_STATE_IDLE;
292 case VALID_STATE_INVALID:
293 ValidState = VALID_STATE_IDLE;
295 case VALID_STATE_TIMEOUT:
296 ValidState = VALID_STATE_IDLE;
303 if(ValidState==VALID_STATE_IDLE)
305 //First, flush the input buffer for the socket
307 struct timeval timeout;
313 FD_SET(Unreliable_socket, &read_fds);
316 while(SELECT(0,&read_fds,NULL,NULL,&timeout, PSNET_TYPE_VALIDATION))
318 while(SELECT(Unreliable_socket+1,&read_fds,NULL,NULL,&timeout, PSNET_TYPE_VALIDATION))
322 struct sockaddr_in fromaddr;
324 udp_packet_header inpacket;
325 addrsize = sizeof(struct sockaddr_in);
326 RECVFROM(Unreliable_socket, (char *)&inpacket,sizeof(udp_packet_header),0,(struct sockaddr *)&fromaddr,&addrsize, PSNET_TYPE_VALIDATION);
328 Psztracker_id = trackerid;
330 //Build the request packet
331 PacketHeader.type = UNT_LOGIN_AUTH_REQUEST;
332 PacketHeader.len = PACKED_HEADER_ONLY_SIZE+sizeof(validate_id_request);
333 ValidIDReq=(validate_id_request *)&PacketHeader.data;
334 strcpy(ValidIDReq->login,valid_id->login);
335 strcpy(ValidIDReq->password,valid_id->password);
337 packet_length = SerializeValidatePacket(&PacketHeader, packet_data);
338 SENDTO(Unreliable_socket, (char *)&packet_data, packet_length, 0, (struct sockaddr *)&rtrackaddr, sizeof(struct sockaddr), PSNET_TYPE_VALIDATION);
339 ValidState = VALID_STATE_WAITING;
340 ValidFirstSent = timer_get_milliseconds();
341 ValidLastSent = timer_get_milliseconds();
355 struct timeval timeout;
356 ubyte packet_data[sizeof(udp_packet_header)];
357 int packet_length = 0;
359 PSNET_TOP_LAYER_PROCESS();
365 FD_SET(Unreliable_socket, &read_fds);
368 if(SELECT(0,&read_fds,NULL,NULL,&timeout, PSNET_TYPE_VALIDATION)){
370 if(SELECT(Unreliable_socket+1,&read_fds,NULL,NULL,&timeout, PSNET_TYPE_VALIDATION)){
374 struct sockaddr_in fromaddr;
376 udp_packet_header inpacket;
377 addrsize = sizeof(struct sockaddr_in);
379 bytesin = RECVFROM(Unreliable_socket, (char *)&packet_data, sizeof(udp_packet_header), 0, (struct sockaddr *)&fromaddr, &addrsize, PSNET_TYPE_VALIDATION);
380 DeserializeValidatePacket(packet_data, bytesin, &inpacket);
382 int wserr=WSAGetLastError();
383 printf("recvfrom() failure. WSAGetLastError() returned %d\n",wserr);
387 FD_SET(Unreliable_socket, &read_fds);
389 // decrease packet size by 1
392 //Check to make sure the packets ok
393 if(bytesin==inpacket.len){
394 switch(inpacket.type)
396 case UNT_LOGIN_NO_AUTH:
397 if(ValidState == VALID_STATE_WAITING)
399 ValidState = VALID_STATE_INVALID;
402 case UNT_LOGIN_AUTHENTICATED:
403 if(ValidState == VALID_STATE_WAITING)
405 ValidState = VALID_STATE_VALID;
406 strncpy(Psztracker_id, (const char *)&inpacket.data, TRACKER_ID_LEN);
409 // old - this is a Freespace 1 packet type
410 case UNT_VALID_FS_MSN_RSP:
414 // fs2 mission validation response
415 case UNT_VALID_FS2_MSN_RSP:
416 if(MissionValidState == VALID_STATE_WAITING){
417 if(inpacket.code==2){
418 MissionValidState = VALID_STATE_VALID;
420 MissionValidState = VALID_STATE_INVALID;
425 // fs2 squad war validation response
426 case UNT_VALID_SW_MSN_RSP:
427 if(SquadWarValidState == VALID_STATE_WAITING){
429 SDL_assert((bytesin - PACKED_HEADER_ONLY_SIZE) == sizeof(squad_war_response));
430 if((bytesin - PACKED_HEADER_ONLY_SIZE) == sizeof(squad_war_response)){
431 memset(&SquadWarValidateResponse, 0, sizeof(squad_war_response));
432 memcpy(&SquadWarValidateResponse, inpacket.data, sizeof(squad_war_response));
434 // now check to see if we're good
435 if(SquadWarValidateResponse.accepted){
436 SquadWarValidState = VALID_STATE_VALID;
438 SquadWarValidState = VALID_STATE_INVALID;
441 SquadWarValidState = VALID_STATE_INVALID;
446 case UNT_CONTROL_VALIDATION:
454 AckValidServer(inpacket.sig);
458 if(ValidState == VALID_STATE_WAITING)
460 if((timer_get_milliseconds()-ValidFirstSent)>=PILOT_REQ_TIMEOUT)
462 ValidState = VALID_STATE_TIMEOUT;
465 else if((timer_get_milliseconds()-ValidLastSent)>=PILOT_REQ_RESEND_TIME)
468 packet_length = SerializeValidatePacket(&PacketHeader, packet_data);
469 SENDTO(Unreliable_socket, (char *)&packet_data, packet_length, 0, (struct sockaddr *)&rtrackaddr, sizeof(struct sockaddr), PSNET_TYPE_VALIDATION);
470 ValidLastSent = timer_get_milliseconds();
476 //Send an ACK to the server
477 void AckValidServer(unsigned int sig)
479 udp_packet_header ack_pack;
480 ubyte packet_data[sizeof(udp_packet_header)];
481 int packet_length = 0;
483 ack_pack.type = UNT_CONTROL;
485 ack_pack.code = CMD_CLIENT_RECEIVED;
486 ack_pack.len = PACKED_HEADER_ONLY_SIZE;
488 packet_length = SerializeValidatePacket(&ack_pack, packet_data);
489 SDL_assert(packet_length == PACKED_HEADER_ONLY_SIZE);
490 SENDTO(Unreliable_socket, (char *)&packet_data, packet_length, 0, (struct sockaddr *)&rtrackaddr, sizeof(struct sockaddr_in), PSNET_TYPE_VALIDATION);
493 // call with a valid struct to validate a mission
494 // call with NULL to poll
497 // -3 Still waiting (returned if we were waiting for a tracker response and ValidateMission was called with a non-NULL value
498 // -2 Timeout waiting for tracker to respond
500 // 0 Still waiting for response from tracker/Idle
502 int ValidateMission(vmt_validate_mission_req_struct *valid_msn)
504 ubyte packet_data[sizeof(udp_packet_header)];
505 int packet_length = 0;
510 switch(MissionValidState)
512 case VALID_STATE_IDLE:
515 case VALID_STATE_WAITING:
518 case VALID_STATE_VALID:
519 MissionValidState = VALID_STATE_IDLE;
522 case VALID_STATE_INVALID:
523 MissionValidState = VALID_STATE_IDLE;
525 case VALID_STATE_TIMEOUT:
526 MissionValidState = VALID_STATE_IDLE;
533 if(MissionValidState==VALID_STATE_IDLE)
535 //First, flush the input buffer for the socket
537 struct timeval timeout;
543 FD_SET(Unreliable_socket, &read_fds);
546 while(SELECT(0,&read_fds,NULL,NULL,&timeout, PSNET_TYPE_VALIDATION))
548 while(SELECT(Unreliable_socket+1,&read_fds,NULL,NULL,&timeout, PSNET_TYPE_VALIDATION))
552 struct sockaddr_in fromaddr;
554 udp_packet_header inpacket;
555 addrsize = sizeof(struct sockaddr_in);
556 RECVFROM(Unreliable_socket, (char *)&inpacket,sizeof(udp_packet_header),0,(struct sockaddr *)&fromaddr,&addrsize, PSNET_TYPE_VALIDATION);
558 FD_SET(Unreliable_socket, &read_fds);
560 //only send the header, the checksum and the string length plus the null
561 PacketHeader.type = UNT_VALID_FS2_MSN_REQ;
562 PacketHeader.len = (short)(PACKED_HEADER_ONLY_SIZE + sizeof(int)+1+strlen(valid_msn->file_name));
563 memcpy(PacketHeader.data,valid_msn,PacketHeader.len-PACKED_HEADER_ONLY_SIZE);
564 packet_length = SerializeValidatePacket(&PacketHeader, packet_data);
565 SENDTO(Unreliable_socket, (char *)&packet_data, packet_length, 0, (struct sockaddr *)&rtrackaddr, sizeof(struct sockaddr), PSNET_TYPE_VALIDATION);
566 MissionValidState = VALID_STATE_WAITING;
567 MissionValidFirstSent = timer_get_milliseconds();
568 MissionValidLastSent = timer_get_milliseconds();
578 // query the usertracker to validate a squad war match
579 // call with a valid struct to validate a mission
580 // call with NULL to poll
583 // -3 Still waiting (returned if we were waiting for a tracker response and ValidateSquadWae was called with a non-NULL value
584 // -2 Timeout waiting for tracker to respond
586 // 0 Still waiting for response from tracker/Idle
588 int ValidateSquadWar(squad_war_request *sw_req, squad_war_response *sw_resp)
590 ubyte packet_data[sizeof(udp_packet_header)];
591 int packet_length = 0;
595 switch(SquadWarValidState){
596 case VALID_STATE_IDLE:
599 case VALID_STATE_WAITING:
603 // fill in the response
604 case VALID_STATE_VALID:
605 SquadWarValidState = VALID_STATE_IDLE;
607 memcpy(sw_resp, &SquadWarValidateResponse, sizeof(squad_war_response));
611 // fill in the response
612 case VALID_STATE_INVALID:
613 SquadWarValidState = VALID_STATE_IDLE;
615 memcpy(sw_resp, &SquadWarValidateResponse, sizeof(squad_war_response));
619 case VALID_STATE_TIMEOUT:
620 SquadWarValidState = VALID_STATE_IDLE;
625 if(SquadWarValidState==VALID_STATE_IDLE){
626 // First, flush the input buffer for the socket
628 struct timeval timeout;
634 FD_SET(Unreliable_socket, &read_fds);
637 while(SELECT(0,&read_fds,NULL,NULL,&timeout, PSNET_TYPE_VALIDATION)){
639 while(SELECT(Unreliable_socket+1,&read_fds,NULL,NULL,&timeout, PSNET_TYPE_VALIDATION)){
642 struct sockaddr_in fromaddr;
644 udp_packet_header inpacket;
645 addrsize = sizeof(struct sockaddr_in);
646 RECVFROM(Unreliable_socket, (char *)&inpacket,sizeof(udp_packet_header),0,(struct sockaddr *)&fromaddr,&addrsize, PSNET_TYPE_VALIDATION);
648 FD_SET(Unreliable_socket, &read_fds);
650 // only send the header, the checksum and the string length plus the null
651 PacketHeader.type = UNT_VALID_SW_MSN_REQ;
652 PacketHeader.len = (short)(PACKED_HEADER_ONLY_SIZE + sizeof(squad_war_request));
653 memcpy(PacketHeader.data, sw_req, PacketHeader.len-PACKED_HEADER_ONLY_SIZE);
654 packet_length = SerializeValidatePacket(&PacketHeader, packet_data);
655 SENDTO(Unreliable_socket, (char *)&packet_data, packet_length, 0, (struct sockaddr *)&rtrackaddr, sizeof(struct sockaddr), PSNET_TYPE_VALIDATION);
656 SquadWarValidState = VALID_STATE_WAITING;
657 SquadWarFirstSent = timer_get_milliseconds();
658 SquadWarLastSent = timer_get_milliseconds();