From 881001d916152945ebad590d8e856dca8506ed32 Mon Sep 17 00:00:00 2001 From: Server Ubunto - HOME Date: Wed, 15 Oct 2025 14:28:30 +0100 Subject: [PATCH] Feature: First handshakes and Information Tradding --- .clang-format | 7 ++++ CMakeLists.txt | 63 +++++++++++++++++----------------- PlayerTracker | Bin 46656 -> 68384 bytes include/server_structs.h | 27 +++++++++++++-- include/socket.c | 14 +++++--- include/socket.h | 25 +++++++++++--- source/main.cpp | 71 +++++++++++++++++++++++++++++---------- 7 files changed, 145 insertions(+), 62 deletions(-) create mode 100644 .clang-format diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..22eb0c8 --- /dev/null +++ b/.clang-format @@ -0,0 +1,7 @@ +BasedOnStyle: LLVM +IndentWidth: 4 +UseTab: ForIndentation +TabWidth: 4 +ColumnLimit: 180 +BreakBeforeBraces: Attach +AllowShortFunctionsOnASingleLine: Empty diff --git a/CMakeLists.txt b/CMakeLists.txt index e50de42..bfb8296 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.20) -project(CPP_TEMPLATE VERSION 0.1.0 LANGUAGES CXX) +project(CPP_TEMPLATE VERSION 0.1.0 LANGUAGES C CXX) set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_STANDARD_REQUIRED ON) @@ -15,58 +15,57 @@ include_directories(${CMAKE_SOURCE_DIR}/libraries) # Gather all source files (.cpp, .c) file(GLOB_RECURSE PROJECT_SOURCES -${CMAKE_SOURCE_DIR}/include/*.cpp -${CMAKE_SOURCE_DIR}/include/*.c -${CMAKE_SOURCE_DIR}/libraries/*.cpp -${CMAKE_SOURCE_DIR}/libraries/*.c -${CMAKE_SOURCE_DIR}/source/*.cpp -${CMAKE_SOURCE_DIR}/source/*.c + ${CMAKE_SOURCE_DIR}/include/*.cpp + ${CMAKE_SOURCE_DIR}/include/*.c + ${CMAKE_SOURCE_DIR}/libraries/*.cpp + ${CMAKE_SOURCE_DIR}/libraries/*.c + ${CMAKE_SOURCE_DIR}/source/*.cpp + ${CMAKE_SOURCE_DIR}/source/*.c ) # Gather all header files (.hpp, .h) file(GLOB_RECURSE PROJECT_HEADERS -${CMAKE_SOURCE_DIR}/include/*.hpp -${CMAKE_SOURCE_DIR}/include/*.h -${CMAKE_SOURCE_DIR}/libraries/*.hpp -${CMAKE_SOURCE_DIR}/libraries/*.h -${CMAKE_SOURCE_DIR}/source/*.hpp -${CMAKE_SOURCE_DIR}/source/*.h + ${CMAKE_SOURCE_DIR}/include/*.hpp + ${CMAKE_SOURCE_DIR}/include/*.h + ${CMAKE_SOURCE_DIR}/libraries/*.hpp + ${CMAKE_SOURCE_DIR}/libraries/*.h + ${CMAKE_SOURCE_DIR}/source/*.hpp + ${CMAKE_SOURCE_DIR}/source/*.h ) # Allow user to set output program name option(OUTPUT_NAME "Name of the output executable" "") if(OUTPUT_NAME STREQUAL "") -set(EXECUTABLE_NAME ${PROJECT_NAME}) + set(EXECUTABLE_NAME ${PROJECT_NAME}) else() -set(EXECUTABLE_NAME ${OUTPUT_NAME}) + set(EXECUTABLE_NAME ${OUTPUT_NAME}) endif() # Add executable with all sources add_executable(${EXECUTABLE_NAME} -${PROJECT_SOURCES} + ${PROJECT_SOURCES} ) -# Set output name property (for consistency) set_target_properties(${EXECUTABLE_NAME} PROPERTIES OUTPUT_NAME ${EXECUTABLE_NAME}) # Enable warnings and extra diagnostics if (MSVC) -target_compile_options(${EXECUTABLE_NAME} PRIVATE /W4 /permissive- /analyze) + target_compile_options(${EXECUTABLE_NAME} PRIVATE /W4 /permissive- /analyze) else() -target_compile_options(${EXECUTABLE_NAME} PRIVATE - -Wall - -Wextra - -Wpedantic - -Wshadow - -Wconversion - -Wsign-conversion - -Wuninitialized - -Wunused - -Werror=return-type - -fsanitize=address,undefined - -g -) -target_link_options(${EXECUTABLE_NAME} PRIVATE -fsanitize=address,undefined) + target_compile_options(${EXECUTABLE_NAME} PRIVATE + -Wall + -Wextra + -Wpedantic + -Wshadow + -Wconversion + -Wsign-conversion + -Wuninitialized + -Wunused + -Werror=return-type + -fsanitize=address,undefined + -g + ) + target_link_options(${EXECUTABLE_NAME} PRIVATE -fsanitize=address,undefined) endif() # Optionally, enable testing diff --git a/PlayerTracker b/PlayerTracker index 558aff294ccf254a7a01611a990048bcf258f70c..43c2e04c7129d5615a1079089c3f91371f2bb6b6 100755 GIT binary patch literal 68384 zcmeFa33!{u@jw1*by)W6Gj<&3v>XzX5GOw3Bu+@cjx9$bzVMNQOOb8a7O^cO$vL2a zX@KH}P|gxsj`S`C3N28M0yRfDN{^IMno>&B3zC*n%2jUvKQsHTB)_pqpkJQf^ZcL4 zkKf&$ot>SXotd58_tmTO-F3CXV$sycs-2)wY2+9QsWd9~B;ZtP6C7BiR%v28?yu6oH>ESuBwVG5?MODB(`3Cly*F3FpEOd{j>JXnhKzRRbdw=Zl`44> zkMv(*$kUvbppHH&HMi?A+L_ZD*-TR@^+BJOzehViO@B>BJ8i9`V@`Vwuu4^bC!-z7 zk##eO=?e+Ue)~@xk+-PQJDNlqm&E{Deb% zQyape58)eA9xKmAj&N8{EEf=55NryE3%irzEhcxtVp=tf&8R|vdTKp z*?4fv1n{3uK&J`}jz=eb0(j~K^v|0Bzj=awS5AO`)dcYD3Ht4r0KaMi{DTwVUp)bz zr%izWrwQP{nSjn~6X4fQfL}NPzGnjXS0|wJ^9kVJnSjo}CcuAe0(`Oq7yiwko(b>) z9v8o80{HP0%wrMYv(25N+=KrtZMx=+$V#$R`pgAB!8HS}{Ho^jb@zq(eUYd?9QFA$ zpSQK%*BJ;0x`UBuAlzDC-5cr;wEEk71F~-X8lOMn@An1!gHaIVJP3Ad_VxLDdqW+* z5(NznM1$z9GY}1QM5$BY3`PPze-}FQg#*#SaKF|U=!*nmgu;P=5Lk;uL*YP~qLT}=mYil?d4QSy&#}-pP560JTf>Nt-f#sU-l$K~& zX)qM=wfiA1IQ_6cyqyJ3v@e>vDVaiS66S? z;9Ic3sxV2EB&d|f>kLFC#a3 z*Q?*T7A3oO4X&~utG3gqr*cj(h{(#Oeba#5b;Xyl+*!5n8|A@i!DLz)?=#vr8S#>` zzh5k1vf2g{{N=?GzR3jNV=SIMCiv|JodFa4DTB^76MU0F$GJ)Nqxex}mkB;pCGmz# zaD}(q1lLwe{5>YPqBAl9e4h!PVbIxcf-5?jU*nJBe}APc=b7M>4LU9pT+yjC!wotc zOz`OjolPdVqBCTIS5`@WcAMY@2Aw@7xS}&+f>#>+>@&fSHR$X&!4(~?UG}f!Gh*OZ zn&6u}5^v80aIIr39fiMX0{F-Ta98K}bcQB?@1Fo(85p0=o(bSu*ZBCGCV-Dj0C#nd zPiJTX`2Gptl|AFr*<*t5H|FJz3E(3W!1tQqYQFYQ0Do-)xE37Cr{X)$1h;u5p34MR z{Z^XbN-i5r@W}?9O(wXaGh~7*x$ic?3k^DZOmIbK!~}O4^R&+dUuMwRZ-Og2+L>eJ zqx2@v1os$pTqd}pQ)z}9`nSOZ-)PX;WP&R?LngS=``sq^nFgIbCb*(AVuCBX+Gm2F zW6;@ef-5@O=CSfocAIB{U#jF|f-5?eCb;qo8%*#UlzdEZMQ6waSAJ)=3I2U09}`^B z88N|KhM(GJg8xLx#{^e&G~)olDaE8IznN!(?^W_K!4;iKGu-gM8%*#&EBTn^ICb*)1hY7Cy{)h>_$DqH@1XuL;o8XH6 zYbLl_KeYa_a#nFeo(aB2$=L)~^h-=|wGLI7;AzG_w9*70GUAgBCU~2g7ZY6dJ79vV zb#BN6uQcfIHo-d$`g=@pMgI;HT&!#y#=Pg5;NMsBF~Jp`N)x=&kn;u;{B9*56I{_5GQo!oI=fBqA1nEo z;EK+O3BKQu^F9;&VI?0ET+z|OW93t6%zK^*{)Cc`39jf=n&2bKzD)36D*2e;iq4P; zK4j3@ZG!(+$;Sj&bVkf@r9US43rapFxT2%(Ggu&|$x>8&-RF}92a?$d@cjw!)CBl} z1o+GZ_-hI9`~>(r32;{eT%A+e0h^NmSLd1pKPCbG&Ka_hgoMTr`xx{IE@D7Ub0)y8 z3GmDWxGe#mmjI`})yI_pCmE^FyaYJ)tv)3Qa24}WT}1*sSs^2>On|2(z�YJpta7 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 RbA4K>KH&k@a>}RW{x2${x-0+y diff --git a/include/server_structs.h b/include/server_structs.h index d3b5178..101780a 100644 --- a/include/server_structs.h +++ b/include/server_structs.h @@ -1,15 +1,16 @@ #ifndef SERVER_STRUCTS_H #define SERVER_STRUCTS_H +#include 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)) - int identifier; + int32_t identifier; // [not used in the current Remote Telemtry version by AC] // In future version this field will identify the AC Remote Telemetry version that the device expects to speak with. - int version; + int32_t version; // This is the type of operation required by the client. // The following operations are now available: @@ -25,8 +26,28 @@ struct handshake { // // DISMISS = 3 : // This operation identifier must be set when the client wants to leave the comunication with ACServer. - int operationId; + int32_t operationId; } __attribute__((packed)); +struct handshackerResponse{ + // is the name of the car that the player is driving on the AC Server + char carName[50]; + + // is the name of the driver running on the AC Server + char driverName[50]; + + // for now is just 4242, this code will identify different status, + // as “NOT AVAILABLE” for connection + int32_t identifier; + + // for now is set to 1, this will identify the version running on the AC Server + int32_t version; + + // is the name of the track on the AC Server + char trackName[50]; + + // is the track configuration on the AC Server + char trackConfig[50]; +} __attribute__((packed)); #endif // SERVER_STRUCTS_H diff --git a/include/socket.c b/include/socket.c index 25ba240..ff14f1a 100644 --- a/include/socket.c +++ b/include/socket.c @@ -1,6 +1,12 @@ #include "socket.h" -int connect_udp_socket(const char* ip, int port) { +// ========================= +// UDP SOCKET FUCNTIONS +// ========================= +// @param ip: IP address to connect to +// @param port: Port number to connect to +// @return: Socket file descriptor, or -1 on error +int connect_udp_socket(const char* ip, uint16_t port) { int sockfd = socket(AF_INET, SOCK_DGRAM, 0); if (sockfd < 0) { perror("socket creation failed"); @@ -23,7 +29,7 @@ int connect_udp_socket(const char* ip, int port) { return sockfd; } -int bind_udp_socket(int sockfd, const char* ip, int port) { +int bind_udp_socket(int sockfd, const char* ip, uint16_t port) { struct sockaddr_in servaddr; memset(&servaddr, 0, sizeof(servaddr)); @@ -40,7 +46,7 @@ int bind_udp_socket(int sockfd, const char* ip, int port) { return 0; } -int send_udp_message(int sockfd, const char *message, const char *dest_ip, int dest_port) { +ssize_t send_udp_message(int sockfd, const char *message, const char *dest_ip, uint16_t dest_port) { struct sockaddr_in destaddr; memset(&destaddr, 0, sizeof(destaddr)); @@ -48,7 +54,7 @@ int send_udp_message(int sockfd, const char *message, const char *dest_ip, int d destaddr.sin_port = htons(dest_port); destaddr.sin_addr.s_addr = inet_addr(dest_ip); - int n = sendto(sockfd, message, strlen(message), 0, (const struct sockaddr*)&destaddr, sizeof(destaddr)); + ssize_t n = sendto(sockfd, message, strlen(message), 0, (const struct sockaddr*)&destaddr, sizeof(destaddr)); if (n < 0) { perror("sendto failed"); return -1; diff --git a/include/socket.h b/include/socket.h index 0d169ff..339feca 100644 --- a/include/socket.h +++ b/include/socket.h @@ -1,11 +1,22 @@ #ifndef SOCKET_H #define SOCKET_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _WIN32 +#include +#include +#pragma comment(lib, "ws2_32.lib") // link Winsock +#else #include #include #include +#include #include -#include +#include +#endif // ========================= // UDP SOCKET FUCNTIONS @@ -13,11 +24,15 @@ // Server hosts a UDP socket at 127.0.0.1:12000 // Client sends a message to the server at 11000 -int connect_udp_socket(const char* ip, int port); +int connect_udp_socket(const char *ip, uint16_t port); -int bind_udp_socket(int sockfd, const char* ip, int port); +int bind_udp_socket(int sockfd, const char *ip, uint16_t port); -int send_udp_message(int sockfd, const char* message, const char* dest_ip, int dest_port); +ssize_t send_udp_message(int sockfd, const char *message, const char *dest_ip, + uint16_t dest_port); + +#ifdef __cplusplus +} +#endif #endif // SOCKET_H - diff --git a/source/main.cpp b/source/main.cpp index 62aecc7..52abda1 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -1,8 +1,11 @@ +#include #include #include #include #include #include +#include +#include #include #include "server_structs.h" @@ -10,27 +13,59 @@ const int SERVER_OUT_PORT = 12000; const int SERVER_IN_PORT = 11000; -const char *SERVER_IP = "127.0.0.1"; +const char *SERVER_OUT_IP = "127.0.0.1"; int main(void) { - - printf("[+] Starting server...\n"); - int n = connect_udp_socket(SERVER_IP, SERVER_OUT_PORT); - if (n < 0) { - fprintf(stderr, "[-] Failed to connect to UDP socket at %s:%d\n", SERVER_IP, SERVER_OUT_PORT); - return -1; - } - // TEST to see what server is sending: - char buffer[1024]; - n = recvfrom(0, buffer, sizeof(buffer)-1, 0, NULL, NULL); - if (n < 0) { - perror("recvfrom failed"); - return -1; - } + printf("[+] Starting server...\n"); + // Printf information about the server + printf("[+] Server listening on port %d\n", SERVER_IN_PORT); + printf("[+] Server sending to %s:%d\n", SERVER_OUT_IP, SERVER_OUT_PORT); - buffer[n] = '\0'; // Null-terminate the received message - printf("Received message: %s\n", buffer); + // Create UDP socket + int sock_FD = connect_udp_socket(SERVER_OUT_IP, SERVER_OUT_PORT); + if (sock_FD < 0) { + fprintf(stderr, "[-] Failed to create UDP socket\n"); + return -1; + } - return 0; + handshake hs; + hs.identifier = 1; + hs.operationId = 1; + hs.version = 0; + // Send handshake message + + printf("[+] Sending handshake message...\t"); + ssize_t bytes_sent = send_udp_message((int)sock_FD, (const char *)&hs, SERVER_OUT_IP, uint16_t(SERVER_OUT_PORT)); + if (bytes_sent >= 0) { + printf("OK (%zd bytes)\n", bytes_sent); + } else { + fprintf(stderr, "ERROR. \n"); + close((int)sock_FD); + return -2; + } + + uint8_t buffer[512]; // bigger than struct + ssize_t bytes_received = recv(sock_FD, buffer, sizeof(buffer), 0); + + if (bytes_received >= sizeof(handshackerResponse)) { + handshackerResponse resp; + memcpy(&resp, buffer, sizeof(handshackerResponse)); + + printf("[+] Received handshake response:\n"); + printf(" Car: %0x\n", resp.carName); + printf(" Driver: %0x\n", resp.driverName); + printf(" Identifier: %d\n", resp.identifier); + printf(" Version: %0x\n", resp.version); + printf(" Track: %0x\n", resp.trackName); + printf(" Config: %0x\n", resp.trackConfig); + } else { + printf("[!] Packet too short for handshake response (%zd bytes)\n", bytes_received); + } + + + + + + return 0; }