diff --git a/PlayerTracker b/PlayerTracker index 96d9eca..6caf362 100755 Binary files a/PlayerTracker and b/PlayerTracker differ diff --git a/include/parcer.c b/include/parcer.c index 922693c..510d3f6 100644 --- a/include/parcer.c +++ b/include/parcer.c @@ -1,4 +1,5 @@ #include "parcer.h" +#include "server_structs.h" #include int ensure(size_t recv_len, size_t offset, size_t need) { @@ -39,28 +40,28 @@ u_int32_t read_uint32(const u_int8_t *buf, size_t recv_len, size_t *offset, int } int32_t read_int32(const u_int8_t *buf, size_t recv_len, size_t *offset, int *ok) { - if (!ensure(recv_len, *offset, sizeof(int32_t))) { - *ok = 0; - return 0; - } - int32_t v; - memcpy(&v, buf + *offset, sizeof(v)); - *offset += sizeof(v); - return (int32_t)ntohl(v); + if (!ensure(recv_len, *offset, sizeof(int32_t))) { + *ok = 0; + return 0; + } + int32_t v; + memcpy(&v, buf + *offset, sizeof(v)); + *offset += sizeof(v); + return (int32_t)ntohl(v); } float read_float(const u_int8_t *buf, size_t recv_len, size_t *offset, int *ok) { - if (!ensure(recv_len, *offset, sizeof(float))) { - *ok = 0; - return 0.0f; - } - u_int32_t v_int; - memcpy(&v_int, buf + *offset, sizeof(v_int)); - *offset += sizeof(v_int); - v_int = ntohl(v_int); - float v_float; - memcpy(&v_float, &v_int, sizeof(v_float)); - return v_float; + if (!ensure(recv_len, *offset, sizeof(float))) { + *ok = 0; + return 0.0f; + } + u_int32_t v_int; + memcpy(&v_int, buf + *offset, sizeof(v_int)); + *offset += sizeof(v_int); + v_int = ntohl(v_int); + float v_float; + memcpy(&v_float, &v_int, sizeof(v_float)); + return v_float; } void read_bytes(const u_int8_t *buf, size_t recv_len, size_t *offset, u_int8_t *out, size_t len, int *ok) { @@ -138,4 +139,3 @@ void read_string(const u_int8_t *buf, size_t recv_len, size_t *offset, char *out *ok = 1; } - diff --git a/include/parcer.h b/include/parcer.h index ca39f5b..55565da 100644 --- a/include/parcer.h +++ b/include/parcer.h @@ -13,6 +13,8 @@ extern "C" { #include #include +#include "server_structs.h" + // Ensures that there are at least 'need' bytes available in the buffer // starting from 'offset'. Returns 1 if enough bytes are available, 0 otherwise. int ensure(size_t recv_len, size_t offset, size_t need); diff --git a/include/server_structs.h b/include/server_structs.h index 6c1344f..ef7c1f0 100644 --- a/include/server_structs.h +++ b/include/server_structs.h @@ -1,12 +1,10 @@ #ifndef SERVER_STRUCTS_H #define SERVER_STRUCTS_H -#include -#include #include #include -struct handshake { +typedef struct handshake { // [not used in the current Remote Telemtry version by AC] // In future versions it will identify the platform type of the client. // This will be used to adjust a specific behaviour for each platform. (eIPadDevice for now (1)) @@ -31,9 +29,9 @@ struct handshake { // DISMISS = 3 : // This operation identifier must be set when the client wants to leave the comunication with ACServer. int32_t operationId; -} __attribute__((packed)); +} __attribute__((packed)) handshake; -struct handshackerResponse { +typedef struct handshackerResponse { // is the name of the car that the player is driving on the AC Server char carName[50]; @@ -52,23 +50,23 @@ struct handshackerResponse { // is the track configuration on the AC Server char trackConfig[50]; -} __attribute__((packed)); +} __attribute__((packed)) handshackerResponse; -struct postion { +typedef struct postion { float x; float y; float z; -} __attribute__((packed)); +} __attribute__((packed)) postion; -enum flag { +typedef enum flag { NO_FLAG = 0, YELLOW_FLAG = 1, BLUE_FLAG = 2, BLACK_FLAG = 3, CHECKERED_FLAG = 4, -} __attribute__((packed)); +} __attribute__((packed)) flag; -struct carAtributes { +typedef struct carAtributes { // Related to ACSP_CAR_INFO u_char isConnected; // 1 = connected, 0 = disconnected u_char isLoading; // 1 = loading, 0 = not isLoading @@ -96,16 +94,48 @@ struct carAtributes { flag current_flag; // TODO: implement flag status updates // TAG:3 - float_t normalizedSplinePos; -} __attribute__((packed)); + float normalizedSplinePos; +} __attribute__((packed)) carAtributes; -enum SessionType { +typedef struct carAtributesAPI { + // Related to ACSP_CAR_INFO + u_char isConnected; // 1 = connected, 0 = disconnected + u_char isLoading; // 1 = loading, 0 = not isLoading + + char car_model[64]; + char car_skin[64]; + char driver_name[64]; + char driver_team[64]; + char driver_GUID[64]; + + // Related to ACSP_CAR_UPDATE + u_int8_t carID; + postion position; + postion velocity; + u_int8_t carGear; + u_int16_t carRPM; + u_int32_t lap_time; + u_int32_t cuts; + u_int32_t total_cuts; + u_int32_t total_cuts_alltime; + u_int16_t total_laps_completed; + u_int16_t contacts; + u_int16_t total_contacts; + + flag current_flag; // TODO: implement flag status updates + // TAG:3 + + float normalizedSplinePos; +} __attribute__((packed)) carAtributesAPI; + + +typedef enum SessionType { PRACTICE = 0, RACE = 1, QUALIFYING = 2, -}; +} __attribute__((packed)) SessionType; -struct trackAtributes { +typedef struct trackAtributes { u_int8_t protocol_version; u_int8_t session_index; @@ -127,7 +157,40 @@ struct trackAtributes { char *weather_graphics; u_int32_t elapsed_ms; -} __attribute__((packed)); +} __attribute__((packed)) trackAtributes; + +typedef struct trackAtributesAPI { + u_int8_t protocol_version; + + u_int8_t session_index; + u_int8_t current_session_index; + u_int8_t session_count; + SessionType session_type; + + char server_name[128]; + char track[64]; + char track_config[64]; + char session_name[64]; + + u_int8_t typ; + u_int16_t time; + u_int16_t laps; + u_int16_t wait_time; + u_int8_t ambient_temp; + u_int8_t road_temp; + + char weather_graphics[64]; + u_int32_t elapsed_ms; +} __attribute__((packed)) trackAtributesAPI; + +typedef struct api_packet { + u_int8_t tracker_id; + u_int8_t last_updated_carid; + + carAtributesAPI cars[64]; + trackAtributesAPI track_info; + +} __attribute__((packed)) api_packet; enum ACSP_MessageType { // ============================ diff --git a/source/main.cpp b/source/main.cpp index 9b2b9ea..9549755 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -2,12 +2,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include #include "parcer.h" @@ -20,7 +22,132 @@ const int SERVER_OUT_PORT = 12000; const int SERVER_IN_PORT = 11000; const char *SERVER_OUT_IP = "127.0.0.1"; +const char *API_SOCKET_PATH = "/tmp/ACplayer_socket"; + const int MAX_PLAYERS = 64; +const int SERVER_ID = 130; + +api_packet current_packet; + +// INFO: This assumes Players pointer to be the same size of MAX_PLAYERS +void update_api_packet(trackAtributes trackInfo, carAtributes *players, u_int8_t last_updated_carid) { + current_packet.tracker_id = SERVER_ID; + + // Update track info + current_packet.track_info.protocol_version = trackInfo.protocol_version; + current_packet.track_info.session_index = trackInfo.session_index; + current_packet.track_info.current_session_index = trackInfo.current_session_index; + current_packet.track_info.session_count = trackInfo.session_count; + current_packet.track_info.session_type = trackInfo.session_type; + strncpy(current_packet.track_info.server_name, trackInfo.server_name, sizeof(current_packet.track_info.server_name) - 1); + strncpy(current_packet.track_info.track, trackInfo.track, sizeof(current_packet.track_info.track) - 1); + strncpy(current_packet.track_info.track_config, trackInfo.track_config, sizeof(current_packet.track_info.track_config) - 1); + strncpy(current_packet.track_info.session_name, trackInfo.session_name, sizeof(current_packet.track_info.session_name) - 1); + current_packet.track_info.typ = trackInfo.typ; + current_packet.track_info.time = trackInfo.time; + current_packet.track_info.laps = trackInfo.laps; + current_packet.track_info.wait_time = trackInfo.wait_time; + current_packet.track_info.ambient_temp = trackInfo.ambient_temp; + current_packet.track_info.road_temp = trackInfo.road_temp; + strncpy(current_packet.track_info.weather_graphics, trackInfo.weather_graphics, sizeof(current_packet.track_info.weather_graphics) - 1); + current_packet.track_info.elapsed_ms = trackInfo.elapsed_ms; + + // Update car INFO + for (int i = 0; i < MAX_PLAYERS; i++) { + current_packet.cars[i].isConnected = players[i].isConnected; + current_packet.cars[i].isLoading = players[i].isLoading; + + strncpy(current_packet.cars[i].car_model, players[i].car_model, sizeof(current_packet.cars[i].car_model) - 1); + strncpy(current_packet.cars[i].driver_GUID, players[i].driver_GUID, sizeof(current_packet.cars[i].driver_GUID) - 1); + strncpy(current_packet.cars[i].car_skin, players[i].car_skin, sizeof(current_packet.cars[i].car_skin) - 1); + strncpy(current_packet.cars[i].driver_name, players[i].driver_name, sizeof(current_packet.cars[i].driver_name) - 1); + strncpy(current_packet.cars[i].driver_team, players[i].driver_team, sizeof(current_packet.cars[i].driver_team) - 1); + + current_packet.cars[i].carID = players[i].carID; + + current_packet.cars[i].position = players[i].position; + current_packet.cars[i].velocity = players[i].velocity; + + current_packet.cars[i].carGear = players[i].carGear; + current_packet.cars[i].carRPM = players[i].carRPM; + current_packet.cars[i].lap_time = players[i].lap_time; + current_packet.cars[i].cuts = players[i].cuts; + current_packet.cars[i].total_cuts = players[i].total_cuts; + current_packet.cars[i].total_cuts_alltime = players[i].total_cuts_alltime; + + current_packet.cars[i].total_laps_completed = players[i].total_laps_completed; + current_packet.cars[i].contacts = players[i].contacts; + current_packet.cars[i].total_contacts = players[i].total_contacts; + + current_packet.cars[i].normalizedSplinePos = players[i].normalizedSplinePos; + } + + if (last_updated_carid == NULL) { + current_packet.last_updated_carid = 0xFF; // No specific car updated + } else { + current_packet.last_updated_carid = last_updated_carid; + } +} + +void *send_to_api_socket(void *arg) { + int sock_fd; + struct sockaddr_un addr; + + addr.sun_family = AF_UNIX; + strcpy(addr.sun_path, API_SOCKET_PATH); + + // --- Connect loop --- + while (1) { + sock_fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (sock_fd < 0) { + usleep(500000); + continue; + } + + if (connect(sock_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + close(sock_fd); + usleep(500000); + continue; + } + break; // connected + } + + printf("[+] Connected to API socket at %s\n", API_SOCKET_PATH); + + while (1) { + if (current_packet.tracker_id == (u_int8_t)-1) { + usleep(10000); + continue; + } + ssize_t sent_bytes = send(sock_fd, ¤t_packet, sizeof(api_packet), 0); + if (sent_bytes < 0) { + fprintf(stderr, "[!] Failed to send data to API socket, reconnecting...\n"); + close(sock_fd); + + // Reconnect loop + while (1) { + sock_fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (sock_fd < 0) { + usleep(500000); + continue; + } + + if (connect(sock_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + close(sock_fd); + usleep(500000); + continue; + } + break; // connected + } + + printf("[+] Reconnected to API socket at %s\n", API_SOCKET_PATH); + } + + usleep(10000); // 10ms + } + + return NULL; +} void init_carupdate(carAtributes *car) { car->isConnected = 0; @@ -67,6 +194,8 @@ int main(void) { printf("[+] Server listening on port %d\n", SERVER_IN_PORT); printf("[+] Server sending to %s:%d\n\n", SERVER_OUT_IP, SERVER_OUT_PORT); + current_packet.tracker_id = (u_int8_t)-1; // Mark as uninitialized + int send_sock_fd = connect_udp_socket("127.0.0.1", 11000); // SEND requests to Server int recv_sock_fd = create_bound_udp_socket("0.0.0.0", 12000); // LISTEN to server updates @@ -79,6 +208,15 @@ int main(void) { int ok = 1; char buffer[1024]; + // Start thread to send data to API socket + pthread_t api_thread; + if (pthread_create(&api_thread, NULL, send_to_api_socket, NULL) != 0) { + fprintf(stderr, "[!] Failed to create API socket thread\n"); + return EXIT_FAILURE; + } + + pthread_detach(api_thread); + trackAtributes trackInfo; carAtributes players[MAX_PLAYERS]; @@ -98,7 +236,6 @@ int main(void) { char message[124] = {0}; // just a place to put info messages from the server itself - printf("\n"); while (1) { offset = 0; @@ -479,7 +616,7 @@ int main(void) { // // ============================ // CLIENT → SERVER COMMANDS - // NOTE: These are not meant to be here, these are comands to SEND to the server + // NOTE: These are not meant to be here, these are comands to SEND to the server // ============================ case ACSP_REALTIMEPOS_INTERVAL: printf("[+] Command: ACSP_REALTIMEPOS_INTERVAL\n"); @@ -517,12 +654,12 @@ int main(void) { printf("[+] Command: ACSP_RESTART_SESSION\n"); break; - case ACSP_ADMIN_COMMAND: { // DONE: + case ACSP_ADMIN_COMMAND: { // DONE: printf("[+] Command: ACSP_ADMIN_COMMAND\n"); - char *buffer = (char *)malloc(256); + char *__buffer = (char *)malloc(256); char command[256] = "/settime 19:00"; // TEST: - buffer[0] = (char)ACSP_ADMIN_COMMAND; + __buffer[0] = (char)ACSP_ADMIN_COMMAND; for (int i = 1; i <= strlen(command); i++) { buffer[i] = command[i - 1]; } @@ -540,6 +677,9 @@ int main(void) { break; } + // OPTIMIZE: This should be done inside each case where data is updated otherwise we lose performance + update_api_packet(trackInfo, players, update.carID); + usleep(10000); // Sleep for 10ms } close(send_sock_fd);