#include "v1.h" str validateUsername_cstr(char username[USERNAME_SIZE_MAX+1], str* out_username_str){ // must end with 0 if(username[USERNAME_SIZE_MAX] != '\0'){ return str_copy(STR("Username string doesn't end correctly")); } str u = str_from_cstr(username); str error_str = validateUsername_str(u); if(error_str.data) return error_str; *out_username_str = u; return str_null; } str validateUsername_str(str username){ if(username.len < USERNAME_SIZE_MIN || username.len > USERNAME_SIZE_MAX){ return str_from_cstr( sprintf_malloc( "username length (in bytes) must be >= %i and <= %i\n", USERNAME_SIZE_MIN, USERNAME_SIZE_MAX ) ); } for(u32 i = 0; i < username.len; i++){ char c = username.data[i]; if (char_isLatinLower(c) || char_isLatinUpper(c) || char_isDigit(c) || c == '.' || c == '_' || c == '-') continue; return str_copy(STR("Username contains restricted characters. " "Allowed characters: latin, digits, ._-")); } return str_null; } #define _PacketHeader_construct(T) \ PacketHeader_construct(header, PROTOCOL_VERSION, PacketType_##T, sizeof(T)) void ErrorMessage_construct(ErrorMessage* ptr, PacketHeader* header, u32 msg_size){ _PacketHeader_construct(ErrorMessage); zeroStruct(ptr); ptr->msg_size = msg_size; } Result(void) ClientHandshake_tryConstruct(ClientHandshake* ptr, PacketHeader* header, Array(u8) session_key) { Deferral(1); _PacketHeader_construct(ClientHandshake); zeroStruct(ptr); try_assert(session_key.len == sizeof(ptr->session_key)); memcpy(ptr->session_key, session_key.data, session_key.len); Return RESULT_VOID; } void ServerHandshake_construct(ServerHandshake* ptr, PacketHeader* header, i64 session_id) { _PacketHeader_construct(ServerHandshake); zeroStruct(ptr); ptr->session_id = session_id; } void ServerPublicInfoRequest_construct(ServerPublicInfoRequest *ptr, PacketHeader* header, ServerPublicInfo property) { _PacketHeader_construct(ServerPublicInfoRequest); zeroStruct(ptr); ptr->property = property; } void ServerPublicInfoResponse_construct(ServerPublicInfoResponse* ptr, PacketHeader* header, u32 data_size) { _PacketHeader_construct(ServerPublicInfoResponse); zeroStruct(ptr); ptr->data_size = data_size; } Result(void) LoginRequest_tryConstruct(LoginRequest *ptr, PacketHeader* header, str username, Array(u8) token) { Deferral(1); _PacketHeader_construct(LoginRequest); zeroStruct(ptr); str name_error_str = validateUsername_str(username); if(name_error_str.data){ Return RESULT_ERROR(name_error_str, true); } memcpy(ptr->username, username.data, username.len); try_assert(token.len == sizeof(ptr->token)); memcpy(ptr->token, token.data, token.len); Return RESULT_VOID; } void LoginResponse_construct(LoginResponse* ptr, PacketHeader* header, i64 user_id, i64 landing_channel_id) { _PacketHeader_construct(LoginResponse); zeroStruct(ptr); ptr->user_id = user_id; ptr->landing_channel_id = landing_channel_id; } Result(void) RegisterRequest_tryConstruct(RegisterRequest *ptr, PacketHeader* header, str username, Array(u8) token) { Deferral(1); _PacketHeader_construct(RegisterRequest); zeroStruct(ptr); str name_error_str = validateUsername_str(username); if(name_error_str.data){ Return RESULT_ERROR(name_error_str, true); } memcpy(ptr->username, username.data, username.len); try_assert(token.len == sizeof(ptr->token)); memcpy(ptr->token, token.data, token.len); Return RESULT_VOID; } void RegisterResponse_construct(RegisterResponse *ptr, PacketHeader* header, i64 user_id) { _PacketHeader_construct(RegisterResponse); zeroStruct(ptr); ptr->user_id = user_id; } Result(u32) MessageBlock_writeMessage( MessageMeta* msg, Array(u8) msg_content, MessageBlockMeta* block_meta, Array(u8)* block_free_part) { Deferral(1); try_assert(msg->data_size >= MESSAGE_SIZE_MIN && msg->data_size <= MESSAGE_SIZE_MAX); try_assert(msg->data_size <= msg_content.len); u32 offset_increment = sizeof(MessageMeta) + msg->data_size; if(block_free_part->len < offset_increment){ Return RESULT_VALUE(u, 0); } memcpy(block_free_part->data, msg, sizeof(MessageMeta)); block_free_part->data += sizeof(MessageMeta); block_free_part->len -= sizeof(MessageMeta); memcpy(block_free_part->data, msg_content.data, msg->data_size); block_free_part->data += msg->data_size; block_free_part->len -= msg->data_size; if(block_meta->message_count == 0) block_meta->first_message_id = msg->id; block_meta->message_count++; block_meta->data_size += offset_increment; Return RESULT_VALUE(u, offset_increment); } Result(u32) MessageBlock_readMessage( Array(u8)* block_unread_part, MessageMeta* msg, Array(u8) msg_content) { Deferral(1); try_assert(block_unread_part->len >= sizeof(MessageMeta) + MESSAGE_SIZE_MIN); try_assert(msg_content.len >= MESSAGE_SIZE_MIN && msg_content.len <= MESSAGE_SIZE_MAX); memcpy(msg, block_unread_part->data, sizeof(MessageMeta)); block_unread_part->data += sizeof(MessageMeta); block_unread_part->len -= sizeof(MessageMeta); if(msg->magic.n != MESSAGE_MAGIC.n){ Return RESULT_VALUE(u, 0); } try_assert(block_unread_part->len >= msg->data_size); try_assert(msg->data_size >= MESSAGE_SIZE_MIN && msg->data_size <= MESSAGE_SIZE_MAX); try_assert(msg->id > 0); try_assert(msg->sender_id > 0); try_assert(msg->timestamp.d.year > 2024); memcpy(msg_content.data, block_unread_part->data, msg->data_size); block_unread_part->data += msg->data_size; block_unread_part->len -= msg->data_size; u32 offset_increment = sizeof(MessageMeta) + msg->data_size; Return RESULT_VALUE(u, offset_increment); } void SendMessageRequest_construct(SendMessageRequest *ptr, PacketHeader *header, i64 channel_id, u16 data_size) { _PacketHeader_construct(SendMessageRequest); zeroStruct(ptr); ptr->channel_id = channel_id; ptr->data_size = data_size; } void SendMessageResponse_construct(SendMessageResponse *ptr, PacketHeader *header, i64 message_id, DateTime timestamp) { _PacketHeader_construct(SendMessageResponse); zeroStruct(ptr); ptr->message_id = message_id; ptr->timestamp = timestamp; } void GetMessageBlockRequest_construct(GetMessageBlockRequest *ptr, PacketHeader *header, i64 channel_id, i64 first_message_id, u32 message_count) { _PacketHeader_construct(GetMessageBlockRequest); zeroStruct(ptr); ptr->channel_id = channel_id; ptr->first_message_id = first_message_id; ptr->message_count = message_count; } void GetMessageBlockResponse_construct(GetMessageBlockResponse *ptr, PacketHeader *header, MessageBlockMeta* block_meta) { _PacketHeader_construct(GetMessageBlockResponse); zeroStruct(ptr); memcpy(&ptr->block_meta, block_meta, sizeof(MessageBlockMeta)); }