|
1 #include "netconn_internal.h" |
|
2 |
|
3 #include "../util/logging.h" |
|
4 #include "../util/util.h" |
|
5 #include "../util/buffer.h" |
|
6 #include "../md5/md5.h" |
|
7 #include "../base64/base64.h" |
|
8 |
|
9 #include <stdlib.h> |
|
10 #include <string.h> |
|
11 #include <zlib.h> |
|
12 |
|
13 // TODO state changes |
|
14 |
|
15 // cmdname is always given as literal from functions in this file, so it is never null. |
|
16 static int sendVoid(flib_netconn *conn, const char *cmdname) { |
|
17 if(!conn) { |
|
18 flib_log_e("null parameter trying to send %s command.", cmdname); |
|
19 return -1; |
|
20 } |
|
21 return flib_netbase_sendf(conn->netBase, "%s\n\n", cmdname); |
|
22 } |
|
23 |
|
24 static int sendStr(flib_netconn *conn, const char *cmdname, const char *str) { |
|
25 if(!conn || !str) { |
|
26 flib_log_e("null parameter trying to send %s command.", cmdname); |
|
27 return -1; |
|
28 } |
|
29 return flib_netbase_sendf(conn->netBase, "%s\n%s\n\n", cmdname, str); |
|
30 } |
|
31 |
|
32 static int sendInt(flib_netconn *conn, const char *cmdname, int param) { |
|
33 if(!conn) { |
|
34 flib_log_e("null parameter trying to send %s command.", cmdname); |
|
35 return -1; |
|
36 } |
|
37 return flib_netbase_sendf(conn->netBase, "%s\n%i\n\n", cmdname, param); |
|
38 } |
|
39 |
|
40 int flib_netconn_send_quit(flib_netconn *conn, const char *quitmsg) { |
|
41 return sendStr(conn, "QUIT", quitmsg ? quitmsg : "User quit"); |
|
42 } |
|
43 |
|
44 int flib_netconn_send_chat(flib_netconn *conn, const char *chat) { |
|
45 return sendStr(conn, "CHAT", chat); |
|
46 } |
|
47 |
|
48 int flib_netconn_send_teamchat(flib_netconn *conn, const char *chat) { |
|
49 return sendStr(conn, "TEAMCHAT", chat); |
|
50 } |
|
51 |
|
52 int flib_netconn_send_nick(flib_netconn *conn, const char *nick) { |
|
53 int result = -1; |
|
54 if(!conn || !nick) { |
|
55 flib_log_e("null parameter in flib_netconn_send_nick"); |
|
56 } else { |
|
57 char *tmpName = flib_strdupnull(nick); |
|
58 if(tmpName) { |
|
59 if(!flib_netbase_sendf(conn->netBase, "%s\n%s\n\n", "NICK", nick)) { |
|
60 free(conn->playerName); |
|
61 conn->playerName = tmpName; |
|
62 tmpName = NULL; |
|
63 result = 0; |
|
64 } |
|
65 } |
|
66 free(tmpName); |
|
67 } |
|
68 return result; |
|
69 } |
|
70 |
|
71 int flib_netconn_send_password(flib_netconn *conn, const char *latin1Passwd) { |
|
72 int result = -1; |
|
73 if(!conn || !latin1Passwd) { |
|
74 flib_log_e("null parameter in flib_netconn_send_password"); |
|
75 } else { |
|
76 md5_state_t md5state; |
|
77 uint8_t md5bytes[16]; |
|
78 char md5hex[33]; |
|
79 md5_init(&md5state); |
|
80 md5_append(&md5state, (unsigned char*)latin1Passwd, strlen(latin1Passwd)); |
|
81 md5_finish(&md5state, md5bytes); |
|
82 for(int i=0;i<sizeof(md5bytes); i++) { |
|
83 // Needs to be lowercase - server checks case sensitive |
|
84 snprintf(md5hex+i*2, 3, "%02x", (unsigned)md5bytes[i]); |
|
85 } |
|
86 result = flib_netbase_sendf(conn->netBase, "%s\n%s\n\n", "PASSWORD", md5hex); |
|
87 } |
|
88 return result; |
|
89 } |
|
90 |
|
91 int flib_netconn_send_joinRoom(flib_netconn *conn, const char *room) { |
|
92 return sendStr(conn, "JOIN_ROOM", room); |
|
93 } |
|
94 |
|
95 int flib_netconn_send_createRoom(flib_netconn *conn, const char *room) { |
|
96 return sendStr(conn, "CREATE_ROOM", room); |
|
97 } |
|
98 |
|
99 int flib_netconn_send_renameRoom(flib_netconn *conn, const char *roomName) { |
|
100 return sendStr(conn, "ROOM_NAME", roomName); |
|
101 } |
|
102 |
|
103 int flib_netconn_send_leaveRoom(flib_netconn *conn) { |
|
104 return sendVoid(conn, "PART"); |
|
105 } |
|
106 |
|
107 int flib_netconn_send_toggleReady(flib_netconn *conn) { |
|
108 return sendVoid(conn, "TOGGLE_READY"); |
|
109 } |
|
110 |
|
111 int flib_netconn_send_addTeam(flib_netconn *conn, const flib_team *team) { |
|
112 int result = -1; |
|
113 if(!conn || !team) { |
|
114 flib_log_e("null parameter in flib_netconn_send_addTeam"); |
|
115 } else { |
|
116 bool missingInfo = !team->name || !team->color || !team->grave || !team->fort || !team->voicepack || !team->flag; |
|
117 for(int i=0; i<HEDGEHOGS_PER_TEAM; i++) { |
|
118 missingInfo |= !team->hogs[i].name || !team->hogs[i].hat; |
|
119 } |
|
120 if(missingInfo) { |
|
121 flib_log_e("Incomplete team definition for flib_netconn_send_addTeam"); |
|
122 } else { |
|
123 flib_vector *vec = flib_vector_create(); |
|
124 if(vec) { |
|
125 bool error = false; |
|
126 error |= flib_vector_appendf(vec, "ADD_TEAM\n%s\n%lu\n%s\n%s\n%s\n%s\n%i\n", team->name, (unsigned long)team->color, team->grave, team->fort, team->voicepack, team->flag, team->hogs[0].difficulty); |
|
127 for(int i=0; i<HEDGEHOGS_PER_TEAM; i++) { |
|
128 error |= flib_vector_appendf(vec, "%s\n%s\n", team->hogs[i].name, team->hogs[i].hat); |
|
129 } |
|
130 error |= flib_vector_appendf(vec, "\n"); |
|
131 if(!error) { |
|
132 result = flib_netbase_send_raw(conn->netBase, flib_vector_data(vec), flib_vector_size(vec)); |
|
133 } |
|
134 } |
|
135 flib_vector_destroy(vec); |
|
136 } |
|
137 } |
|
138 return result; |
|
139 } |
|
140 |
|
141 int flib_netconn_send_removeTeam(flib_netconn *conn, const char *teamname) { |
|
142 return sendStr(conn, "REMOVE_TEAM", teamname); |
|
143 } |
|
144 |
|
145 int flib_netconn_send_engineMessage(flib_netconn *conn, const uint8_t *message, size_t size) { |
|
146 int result = -1; |
|
147 if(!conn || (!message && size>0)) { |
|
148 flib_log_e("null parameter in flib_netconn_send_engineMessage"); |
|
149 } else { |
|
150 char *base64encout = NULL; |
|
151 base64_encode_alloc((const char*)message, size, &base64encout); |
|
152 if(base64encout) { |
|
153 result = flib_netbase_sendf(conn->netBase, "EM\n%s\n\n", base64encout); |
|
154 } |
|
155 free(base64encout); |
|
156 } |
|
157 return result; |
|
158 } |
|
159 |
|
160 int flib_netconn_send_teamHogCount(flib_netconn *conn, const char *teamname, int hogcount) { |
|
161 if(!conn || !teamname || hogcount<1 || hogcount>HEDGEHOGS_PER_TEAM) { |
|
162 flib_log_e("invalid parameter in flib_netconn_send_teamHogCount"); |
|
163 return -1; |
|
164 } |
|
165 return flib_netbase_sendf(conn->netBase, "HH_NUM\n%s\n%i\n\n", teamname, hogcount); |
|
166 } |
|
167 |
|
168 int flib_netconn_send_teamColor(flib_netconn *conn, const char *teamname, uint32_t colorRGB) { |
|
169 if(!conn || !teamname) { |
|
170 flib_log_e("null parameter in flib_netconn_send_teamColor"); |
|
171 return -1; |
|
172 } |
|
173 return flib_netbase_sendf(conn->netBase, "TEAM_COLOR\n%s\n%lu\n\n", teamname, (unsigned long)colorRGB); |
|
174 } |
|
175 |
|
176 int flib_netconn_send_weaponset(flib_netconn *conn, const flib_weaponset *weaponset) { |
|
177 if(!conn || !weaponset) { |
|
178 flib_log_e("null parameter in flib_netconn_send_weaponset"); |
|
179 return -1; |
|
180 } |
|
181 |
|
182 char ammostring[WEAPONS_COUNT*4+1]; |
|
183 strcpy(ammostring, weaponset->loadout); |
|
184 strcat(ammostring, weaponset->crateprob); |
|
185 strcat(ammostring, weaponset->delay); |
|
186 strcat(ammostring, weaponset->crateammo); |
|
187 return flib_netbase_sendf(conn->netBase, "CFG\nAMMO\n%s\n%s\n\n", weaponset->name, ammostring); |
|
188 } |
|
189 |
|
190 int flib_netconn_send_map(flib_netconn *conn, const flib_map *map) { |
|
191 if(!conn || !map) { |
|
192 flib_log_e("null parameter in flib_netconn_send_map"); |
|
193 return -1; |
|
194 } |
|
195 bool error = false; |
|
196 |
|
197 if(map->seed) { |
|
198 error |= flib_netconn_send_mapSeed(conn, map->seed); |
|
199 } |
|
200 error |= flib_netconn_send_mapTemplate(conn, map->templateFilter); |
|
201 if(map->theme) { |
|
202 error |= flib_netconn_send_mapTheme(conn, map->theme); |
|
203 } |
|
204 error |= flib_netconn_send_mapGen(conn, map->mapgen); |
|
205 error |= flib_netconn_send_mapMazeSize(conn, map->mazeSize); |
|
206 if(map->name) { |
|
207 error |= flib_netconn_send_mapName(conn, map->name); |
|
208 } |
|
209 if(map->drawData && map->drawDataSize>0) { |
|
210 error |= flib_netconn_send_mapDrawdata(conn, map->drawData, map->drawDataSize); |
|
211 } |
|
212 return error; |
|
213 } |
|
214 |
|
215 int flib_netconn_send_mapName(flib_netconn *conn, const char *mapName) { |
|
216 return sendStr(conn, "CFG\nMAP", mapName); |
|
217 } |
|
218 |
|
219 int flib_netconn_send_mapGen(flib_netconn *conn, int mapGen) { |
|
220 return sendInt(conn, "CFG\nMAPGEN", mapGen); |
|
221 } |
|
222 |
|
223 int flib_netconn_send_mapTemplate(flib_netconn *conn, int templateFilter) { |
|
224 return sendInt(conn, "CFG\nTEMPLATE", templateFilter); |
|
225 } |
|
226 |
|
227 int flib_netconn_send_mapMazeSize(flib_netconn *conn, int mazeSize) { |
|
228 return sendInt(conn, "CFG\nMAZE_SIZE", mazeSize); |
|
229 } |
|
230 |
|
231 int flib_netconn_send_mapSeed(flib_netconn *conn, const char *seed) { |
|
232 return sendStr(conn, "CFG\nSEED", seed); |
|
233 } |
|
234 |
|
235 int flib_netconn_send_mapTheme(flib_netconn *conn, const char *theme) { |
|
236 return sendStr(conn, "CFG\nTHEME", theme); |
|
237 } |
|
238 |
|
239 int flib_netconn_send_mapDrawdata(flib_netconn *conn, const uint8_t *drawData, size_t size) { |
|
240 int result = -1; |
|
241 if(!conn || (!drawData && size>0) || size>SIZE_MAX/2) { |
|
242 flib_log_e("invalid parameter in flib_netconn_send_map"); |
|
243 } else { |
|
244 uLongf zippedSize = compressBound(size); |
|
245 uint8_t *zipped = flib_malloc(zippedSize+4); // 4 extra bytes for header |
|
246 if(zipped) { |
|
247 // Create the QCompress size header (uint32 big endian) |
|
248 zipped[0] = (size>>24) & 0xff; |
|
249 zipped[1] = (size>>16) & 0xff; |
|
250 zipped[2] = (size>>8) & 0xff; |
|
251 zipped[3] = (size) & 0xff; |
|
252 |
|
253 if(compress(zipped+4, &zippedSize, drawData, size) != Z_OK) { |
|
254 flib_log_e("Error compressing drawn map data."); |
|
255 } else { |
|
256 char *base64encout = NULL; |
|
257 base64_encode_alloc((const char*)zipped, zippedSize+4, &base64encout); |
|
258 if(!base64encout) { |
|
259 flib_log_e("Error base64-encoding drawn map data."); |
|
260 } else { |
|
261 result = flib_netbase_sendf(conn->netBase, "CFG\nDRAWNMAP\n%s\n\n", base64encout); |
|
262 } |
|
263 free(base64encout); |
|
264 } |
|
265 } |
|
266 free(zipped); |
|
267 } |
|
268 return result; |
|
269 } |
|
270 |
|
271 int flib_netconn_send_script(flib_netconn *conn, const char *scriptName) { |
|
272 return sendStr(conn, "CFG\nSCRIPT", scriptName); |
|
273 } |
|
274 |
|
275 int flib_netconn_send_scheme(flib_netconn *conn, const flib_cfg *scheme) { |
|
276 int result = -1; |
|
277 if(!conn || !scheme) { |
|
278 flib_log_e("null parameter in flib_netconn_send_scheme"); |
|
279 } else { |
|
280 flib_vector *vec = flib_vector_create(); |
|
281 if(vec) { |
|
282 bool error = false; |
|
283 error |= flib_vector_appendf(vec, "CFG\nSCHEME\n%s\n", scheme->name); |
|
284 for(int i=0; i<scheme->meta->modCount; i++) { |
|
285 error |= flib_vector_appendf(vec, "%s\n", scheme->mods[i] ? "true" : "false"); |
|
286 } |
|
287 for(int i=0; i<scheme->meta->settingCount; i++) { |
|
288 error |= flib_vector_appendf(vec, "%i\n", scheme->settings[i]); |
|
289 } |
|
290 error |= flib_vector_appendf(vec, "\n"); |
|
291 if(!error) { |
|
292 result = flib_netbase_send_raw(conn->netBase, flib_vector_data(vec), flib_vector_size(vec)); |
|
293 } |
|
294 } |
|
295 flib_vector_destroy(vec); |
|
296 } |
|
297 return result; |
|
298 } |
|
299 |
|
300 int flib_netconn_send_roundfinished(flib_netconn *conn, bool withoutError) { |
|
301 return sendInt(conn, "ROUNDFINISHED", withoutError ? 1 : 0); |
|
302 } |
|
303 |
|
304 int flib_netconn_send_ban(flib_netconn *conn, const char *playerName) { |
|
305 return sendStr(conn, "BAN", playerName); |
|
306 } |
|
307 |
|
308 int flib_netconn_send_kick(flib_netconn *conn, const char *playerName) { |
|
309 return sendStr(conn, "KICK", playerName); |
|
310 } |
|
311 |
|
312 int flib_netconn_send_playerInfo(flib_netconn *conn, const char *playerName) { |
|
313 return sendStr(conn, "INFO", playerName); |
|
314 } |
|
315 |
|
316 int flib_netconn_send_playerFollow(flib_netconn *conn, const char *playerName) { |
|
317 return sendStr(conn, "FOLLOW", playerName); |
|
318 } |
|
319 |
|
320 int flib_netconn_send_startGame(flib_netconn *conn) { |
|
321 return sendVoid(conn, "START_GAME"); |
|
322 } |
|
323 |
|
324 int flib_netconn_send_toggleRestrictJoins(flib_netconn *conn) { |
|
325 return sendVoid(conn, "TOGGLE_RESTRICT_JOINS"); |
|
326 } |
|
327 |
|
328 int flib_netconn_send_toggleRestrictTeams(flib_netconn *conn) { |
|
329 return sendVoid(conn, "TOGGLE_RESTRICT_TEAMS"); |
|
330 } |
|
331 |
|
332 int flib_netconn_send_clearAccountsCache(flib_netconn *conn) { |
|
333 return sendVoid(conn, "CLEAR_ACCOUNTS_CACHE"); |
|
334 } |
|
335 |
|
336 int flib_netconn_send_setServerVar(flib_netconn *conn, const char *name, const char *value) { |
|
337 if(!conn || !name || !value) { |
|
338 flib_log_e("null parameter trying to send SET_SERVER_VAR command."); |
|
339 return -1; |
|
340 } |
|
341 return flib_netbase_sendf(conn->netBase, "%s\n%s\n%s\n\n", "SET_SERVER_VAR", name, value); |
|
342 } |
|
343 |
|
344 int flib_netconn_send_getServerVars(flib_netconn *conn) { |
|
345 return sendVoid(conn, "GET_SERVER_VAR"); |
|
346 } |