diff --git a/main.c b/main.c index 7b7d3cf..fefe17f 100644 --- a/main.c +++ b/main.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -12,6 +13,10 @@ #define SEGMENT_BITS 0x7F #define CONTINUE_BIT 0x80 +#define UUID_STR_LEN (32 + 4) + +#define sizeof_member(type, member) (sizeof( ((type *)0)->member )) + typedef uint8_t byte; typedef struct MCString_view { @@ -19,9 +24,14 @@ typedef struct MCString_view { unsigned char* str; } MCString_view; +typedef struct MCUUID { + byte byte[16]; + char str[UUID_STR_LEN]; +} MCUUID; + typedef struct File { - int len; char* data; + int len; } File; byte buffer[BUFFER_SIZE] = {0}; @@ -64,9 +74,9 @@ byte read_byte(int client_fd) if (bytes_received > 0) { buffer[bytes_received] = '\0'; printf("[TCP] %ld bytes reçu :\n", bytes_received); - print_hex((const char*)buffer, bytes_received); + print_hex((const char*)buffer, bytes_received > 20 ? 20 : bytes_received); // print_str(buffer, bytes_received); - printf("\n[TCP] fin %ld bytes\n", bytes_received); + printf("%s\n[TCP] fin %ld bytes\n", bytes_received > 20 ? "..." : "", bytes_received); } else if (bytes_received < 0) { perror("[ERR] Erreur lors de la réception des données"); @@ -108,6 +118,47 @@ MCString_view read_String_view(int client_fd) return str; } +char byte_to_char(byte b) +{ + return b >= 10 ? b-10 + 'a' : b + '0'; +} + +MCUUID read_UUID(int client_fd) +{ + MCUUID uuid = {0}; + int c = 0; + for (int i = 0; i < 4; i++) { + uuid.byte[i] = read_byte(client_fd); + uuid.str[c++] = byte_to_char(uuid.byte[i] >> 4); + uuid.str[c++] = byte_to_char((uint8_t)(uuid.byte[i] << 4) >> 4); + } + uuid.str[c++] = '-'; + for (int i = 4; i < 6; i++) { + uuid.byte[i] = read_byte(client_fd); + uuid.str[c++] = byte_to_char(uuid.byte[i] >> 4); + uuid.str[c++] = byte_to_char((uint8_t)(uuid.byte[i] << 4) >> 4); + } + uuid.str[c++] = '-'; + for (int i = 6; i < 8; i++) { + uuid.byte[i] = read_byte(client_fd); + uuid.str[c++] = byte_to_char(uuid.byte[i] >> 4); + uuid.str[c++] = byte_to_char((uint8_t)(uuid.byte[i] << 4) >> 4); + } + uuid.str[c++] = '-'; + for (int i = 8; i < 10; i++) { + uuid.byte[i] = read_byte(client_fd); + uuid.str[c++] = byte_to_char(uuid.byte[i] >> 4); + uuid.str[c++] = byte_to_char((uint8_t)(uuid.byte[i] << 4) >> 4); + } + uuid.str[c++] = '-'; + for (int i = 10; i < 16; i++) { + uuid.byte[i] = read_byte(client_fd); + uuid.str[c++] = byte_to_char(uuid.byte[i] >> 4); + uuid.str[c++] = byte_to_char((uint8_t)(uuid.byte[i] << 4) >> 4); + } + return uuid; +} + uint16_t read_UShort(int client_fd) { uint8_t var1 = read_byte(client_fd); @@ -123,6 +174,18 @@ void write_byte(int client_fd, int value) request[req_current_byte++] = value; } +void write_UUID(int client_fd, MCUUID value) +{ + for (int i = 0; i < (int) sizeof_member(MCUUID, byte); i++) { + write_byte(client_fd, value.byte[i]); + } +} + +void write_Boolean(int client_fd, bool value) +{ + write_byte(client_fd, value); +} + void write_VarInt(int client_fd, int value) { while (true) { @@ -159,7 +222,7 @@ void send_request(int client_fd) printf("[INFO] %d byte request sent: ", req_current_byte); print_hex((const char*) request, req_current_byte > 10 ? 10 : req_current_byte); - printf("...\n"); + printf("%s\n", req_current_byte > 10 ? "..." : ""); req_current_byte = 0; } @@ -181,11 +244,94 @@ File read_entire_file(const char *filename) }; } +void write_entire_file(const char *filename, File file) +{ + FILE *f = fopen(filename, "w"); + fwrite(file.data, file.len, 1, f); + fclose(f); +} + void file_free(File file) { free(file.data); } +void status_protocol(int client_fd) +{ + File status_rep = read_entire_file("status_response.json"); + + // TODO: get VarInt byte size from int, for /*str len*/ + write_VarInt(client_fd, 1 /*packet id*/ + 2 /*str len*/ + status_rep.len); // packet length + write_VarInt(client_fd, 0); + write_String(client_fd, status_rep.data, status_rep.len); + + send_request(client_fd); + + printf("\n[STEP] Ping Status\n"); + + file_free(status_rep); + + int request_status_len = read_VarInt(client_fd); + int request_status_id = read_VarInt(client_fd); + printf("[MCPACKET %d] packet length: %d\n", request_status_id, request_status_len); + if (request_status_id != 0 || request_status_len != 1) { + printf("[ERR] client not in the status state\n"); + close_connection(client_fd); + return; + } + + write_VarInt(client_fd, 1 /*packet id*/ + 8 /*Long len*/); + write_VarInt(client_fd, 1); // protocol id + write_Long(client_fd, (long)time(NULL)); + + send_request(client_fd); + + printf("\n[STEP] Switch To Login Start\n"); + + int login_len = read_VarInt(client_fd); + int login_id = read_VarInt(client_fd); + printf("[MCPACKET %d] packet length: %d\n", login_id, login_len); + printf("[NOTE] je ne sais pas a quoi sert cet requete du client\n"); + + close_connection(client_fd); +} + +void login_protocol(int client_fd) +{ + printf("\n[STEP] Login Start\n"); + + int request_len = read_VarInt(client_fd); + int request_id = read_VarInt(client_fd); + printf("[MCPACKET %d] packet length: %d\n", request_id, request_len); + + MCString_view pseudo = read_String_view(client_fd); + // NOTE: le client envoie l'uuid a la fin de la requete et je n'ai aucune + // idée de ce qu'il envoie entre le pseudo et l'uuid + current_byte = bytes_received - sizeof_member(MCUUID, byte); + MCUUID uuid = read_UUID(client_fd); + printf("[INFO] player pseudo = %.*s\n", pseudo.len, pseudo.str); + printf("[INFO] player UUID = %.*s\n", UUID_STR_LEN, uuid.str); + + printf("\n[STEP] Login Success / Acknowledge\n"); + + write_VarInt(client_fd, 1 /*id*/ + 16 /*uuid*/ + pseudo.len + 2 /*list len & bool*/); + write_VarInt(client_fd, 2); + write_UUID(client_fd, uuid); + write_String(client_fd, (char*)pseudo.str, pseudo.len); + write_VarInt(client_fd, 0); // len list de property + // write_Boolean(client_fd, true); + + write_entire_file("debug.hex", (File){(char*)request, req_current_byte}); + + send_request(client_fd); + + request_len = read_VarInt(client_fd); + request_id = read_VarInt(client_fd); + printf("[MCPACKET %d] packet length: %d\n", request_id, request_len); + + close_connection(client_fd); +} + int main() { int server_fd, client_fd; @@ -232,6 +378,8 @@ int main() printf("[TCP] connection %s:%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); + printf("\n[STEP] Handshake / List Ping\n"); + int packet_length = read_VarInt(client_fd); int packet_id = read_VarInt(client_fd); printf("[MCPACKET %d] packet length: %d\n", packet_id, packet_length); @@ -252,33 +400,22 @@ int main() int next_state = read_VarInt(client_fd); printf("[INFO] next state: %d\n", next_state); - File status_rep = read_entire_file("status_response.json"); - - // TODO: get VarInt byte size from int, for /*str len*/ - write_VarInt(client_fd, 1 /*packet id*/ + 2 /*str len*/ + status_rep.len); // packet length - write_VarInt(client_fd, packet_id); - write_String(client_fd, status_rep.data, status_rep.len); - - send_request(client_fd); - - file_free(status_rep); - - int request_status_len = read_VarInt(client_fd); - int request_status_id = read_VarInt(client_fd); - printf("[MCPACKET %d] packet length: %d\n", request_status_id, request_status_len); - if (request_status_id != 0 || request_status_len != 1) { - printf("[ERR] client not in the status state\n"); + switch (next_state) { + case 1: // status + status_protocol(client_fd); + break; + case 2: // login + login_protocol(client_fd); + break; + case 3: // transfer + printf("[TODO] transfer protocol not programmed\n"); + close_connection(client_fd); + break; + default: + printf("[ERR] state n°%d not supported\n", next_state); close_connection(client_fd); continue; } - - write_VarInt(client_fd, 1 /*packet id*/ + 8 /*Long len*/); - write_VarInt(client_fd, 1); // protocol id - write_Long(client_fd, (long)time(NULL)); - - send_request(client_fd); - - close_connection(client_fd); } // Fermeture de la socket du serveur diff --git a/status_response.json b/status_response.json index 5ec7a91..b06cd32 100644 --- a/status_response.json +++ b/status_response.json @@ -4,10 +4,12 @@ "protocol": 760 }, "players": { - "max": 100, - "online": 1, + "max": 20, + "online": 2, "sample": [ { + "id": "4566e69f-c907-48ee-8d71-d7ba5aa00d20", + "name": "thinkofdeath", "name": "Le caca est cuit ?", "id": "83e2e372-1df3-485d-a360-d9c4caf8b8c4" }