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;
}
|