aboutsummaryrefslogtreecommitdiff
path: root/src/server/c2s_handler.c
blob: 4406aa7801bf06e46d658c094ddf6af95d7e505f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
#include <basic/basic.h>
#include <messages/messages.h>
#include <server/client_connections.h>
#include <server/c2s_handler.h>
#include <server/s2c_sender.h>


internal_fn void
handle_c2s_chat_message(ClientConnections *conns, ClientConnection *conn)
{
    // Todo: verify package size
    C2S_ChatMessage *chat_message = (C2S_ChatMessage*)conn->recv_buff;
    chat_message->content = (void*)chat_message + (size_t)chat_message->content;

    Time now = os_time_get_now();

    // Todo: make proper groups
    for (size_t i = 0; i < conns->max_connection_count; i++) {
        ClientConnection *connection = conns->connections + i;
        if (connection->username->len > 0) {
            send_s2c_chat_message(connection, conn->username, chat_message->content, now);
        }
    }
}


internal_fn void
handle_c2s_login(ClientConnections *conns, ClientConnection *conn)
{
    // init package
    C2S_Login *login = (C2S_Login*)conn->recv_buff;
    login->username = (void*)login + (size_t)login->username;
    login->password = (void*)login + (size_t)login->password;


    // verify package
    if (login->username->len <= 0) {
        printf("handle_c2s_login error: username len %d is invalid\n", login->username->len);
    }
    if (login->username->len > MESSAGES_MAX_USERNAME_LEN) {
        printf("handle_c2s_login error: username len %d/%d\n", login->username->len, MESSAGES_MAX_USERNAME_LEN);
        return; // Todo: rm connection
    }
    if (login->username->len > MESSAGES_MAX_PASSWORD_LEN) {
        printf("handle_c2s_login error: password len %d/%d\n", login->password->len, MESSAGES_MAX_PASSWORD_LEN);
        return; // Todo: rm connection
    }
    size_t message_size = sizeof(C2S_Login) + 2*sizeof(String32) + sizeof(u32) * (login->username->len + login->password->len);
    if (message_size != conn->recv_buff_size_used) {
        printf("handle_c2s_login error: message size is %zu/%d\n", message_size, conn->recv_buff_size_used);
        return; // Todo: rm connection
    }


    // temporary check if username already connected (use a hashmap for this)
    b32 login_success = true;
    for (size_t i = 0; i < conns->max_connection_count; i++) {
        ClientConnection *connection = conns->connections + i;
        if (string32_equal(connection->username, login->username)) {
            login_success = false;
            break;
        }
    }


    // login
    for (size_t i = 0; i < login->username->len; i++) {
        conn->username->codepoints[i] = login->username->codepoints[i];
    }
    conn->username->len = login->username->len;


    if (!login_success) {
        send_s2c_login(conn, S2C_LOGIN_ERROR);
    }


    send_s2c_login(conn, S2C_LOGIN_SUCCESS);

    // send everyone else's user update to conn
    // Todo: make proper groups
    for (size_t i = 0; i < conns->max_connection_count; i++) {
        ClientConnection *connection = conns->connections + i;
        if (string32_equal(connection->username, conn->username)) {
            continue;
        }
        if (connection->username->len > 0) {
            send_s2c_user_update(conn, connection->username, S2C_USER_UPDATE_ONLINE);
        }
    }

    // send conn's user update to everyone else
    // Todo: make proper groups
    for (size_t i = 0; i < conns->max_connection_count; i++) {
        ClientConnection *connection = conns->connections + i;
        if (connection->username->len > 0) {
            send_s2c_user_update(connection, conn->username, S2C_USER_UPDATE_ONLINE);
        }
    }

    // Todo: make function string32_printf
    printf("<");
    string32_print(conn->username);;
    printf("> connected to the server\n");
}


b32
handle_c2s(ClientConnections *conns, ClientConnection *conn)
{
    // recv header
    if (conn->recv_buff_size_used < sizeof(MessageHeader)) {
        size_t size_to_recv = sizeof(MessageHeader) - conn->recv_buff_size_used;
        i64 size_recvd = os_net_secure_stream_recv(conn->secure_stream_id, conn->recv_buff + conn->recv_buff_size_used, size_to_recv);
        if (size_recvd < 0) {
            return false;
        }
        else if (size_recvd == 0) {
            return false;
        }

        conn->recv_buff_size_used += size_recvd;
        if (conn->recv_buff_size_used < sizeof(MessageHeader)) {
            return true;
        }
    }


    // recv body
    MessageHeader *header = (MessageHeader*)conn->recv_buff;
    if (conn->recv_buff_size_used < header->size) {
        size_t size_to_recv = header->size - conn->recv_buff_size_used;
        i64 size_recvd = os_net_secure_stream_recv(conn->secure_stream_id, conn->recv_buff + conn->recv_buff_size_used, size_to_recv);
        if (size_recvd < 0) {
            return false;
        }
        else if (size_recvd == 0) {
            return false;
        }

        conn->recv_buff_size_used += size_recvd;
        if (conn->recv_buff_size_used < header->size) {
            return true;
        }
    }


    // dispatch
    switch (header->type) {
        case C2S_LOGIN:        handle_c2s_login(conns, conn);        break;
        case C2S_CHAT_MESSAGE: handle_c2s_chat_message(conns, conn); break;
    }


    // cleanup
    conn->recv_buff_size_used = 0;
    return true;
}