21 #include "netconn.h" |
21 #include "netconn.h" |
22 #include "netbase.h" |
22 #include "netbase.h" |
23 #include "netprotocol.h" |
23 #include "netprotocol.h" |
24 #include "../util/logging.h" |
24 #include "../util/logging.h" |
25 #include "../util/util.h" |
25 #include "../util/util.h" |
|
26 #include "../model/roomlist.h" |
|
27 #include "../md5/md5.h" |
26 |
28 |
27 #include <stdbool.h> |
29 #include <stdbool.h> |
28 #include <stdlib.h> |
30 #include <stdlib.h> |
29 #include <string.h> |
31 #include <string.h> |
30 #include <errno.h> |
32 #include <errno.h> |
|
33 #include <ctype.h> |
31 |
34 |
32 struct _flib_netconn { |
35 struct _flib_netconn { |
33 flib_netbase *netBase; |
36 flib_netbase *netBase; |
34 char *playerName; |
37 char *playerName; |
|
38 flib_cfg_meta *metaCfg; |
|
39 flib_roomlist *roomList; |
35 |
40 |
36 int netconnState; // One of the NETCONN_STATE constants |
41 int netconnState; // One of the NETCONN_STATE constants |
37 |
42 |
38 void (*onErrorCb)(void* context, int errorCode, const char *errorMsg); |
43 bool isAdmin; // Player is server administrator |
39 void *onErrorCtx; |
44 bool isChief; // Player can modify the current room |
40 |
45 |
41 void (*onConnectedCb)(void *context, const char *serverMessage); |
46 |
|
47 void (*onMessageCb)(void *context, int msgtype, const char *msg); |
|
48 void *onMessageCtx; |
|
49 |
|
50 void (*onConnectedCb)(void *context); |
42 void *onConnectedCtx; |
51 void *onConnectedCtx; |
|
52 |
|
53 void (*onDisconnectedCb)(void *context, int reason, const char *message); |
|
54 void *onDisconnectedCtx; |
|
55 |
|
56 void (*onRoomAddCb)(void *context, const flib_roomlist_room *room); |
|
57 void *onRoomAddCtx; |
|
58 |
|
59 void (*onRoomDeleteCb)(void *context, const char *name); |
|
60 void *onRoomDeleteCtx; |
|
61 |
|
62 void (*onRoomUpdateCb)(void *context, const char *oldName, const flib_roomlist_room *room); |
|
63 void *onRoomUpdateCtx; |
|
64 |
|
65 void (*onChatCb)(void *context, const char *nick, const char *msg); |
|
66 void *onChatCtx; |
|
67 |
|
68 void (*onLobbyJoinCb)(void *context, const char *nick); |
|
69 void *onLobbyJoinCtx; |
|
70 |
|
71 void (*onLobbyLeaveCb)(void *context, const char *nick, const char *partMessage); |
|
72 void *onLobbyLeaveCtx; |
|
73 |
|
74 void (*onRoomJoinCb)(void *context, const char *nick); |
|
75 void *onRoomJoinCtx; |
|
76 |
|
77 void (*onRoomLeaveCb)(void *context, const char *nick, const char *partMessage); |
|
78 void *onRoomLeaveCtx; |
|
79 |
|
80 void (*onNickTakenCb)(void *context, const char *nick); |
|
81 void *onNickTakenCtx; |
|
82 |
|
83 void (*onNickAcceptCb)(void *context, const char *nick); |
|
84 void *onNickAcceptCtx; |
|
85 |
|
86 void (*onPasswordRequestCb)(void *context, const char *nick); |
|
87 void *onPasswordRequestCtx; |
|
88 |
|
89 void (*onRoomChiefStatusCb)(void *context, bool isChief); |
|
90 void *onRoomChiefStatusCtx; |
|
91 |
|
92 void (*onReadyStateCb)(void *context, const char *nick, bool ready); |
|
93 void *onReadyStateCtx; |
|
94 |
|
95 void (*onEnterRoomCb)(void *context, bool chief); |
|
96 void *onEnterRoomCtx; |
|
97 |
|
98 void (*onLeaveRoomCb)(void *context, int reason, const char *message); |
|
99 void *onLeaveRoomCtx; |
|
100 |
|
101 void (*onTeamAddCb)(void *context, flib_team *team); |
|
102 void *onTeamAddCtx; |
43 |
103 |
44 bool running; |
104 bool running; |
45 bool destroyRequested; |
105 bool destroyRequested; |
46 }; |
106 }; |
47 |
107 |
48 static void defaultCallback_onError(void* context, int errorCode, const char *errormsg) {} |
108 static void defaultCallback_onMessage(void *context, int msgtype, const char *msg) { |
49 static void defaultCallback_onConnected(void *context, const char *serverMessage) {} |
109 flib_log_i("Net: [%i] %s", msgtype, msg); |
|
110 } |
|
111 |
|
112 static void defaultCallback_void(void *context) {} |
|
113 static void defaultCallback_bool(void *context, bool isChief) {} |
|
114 static void defaultCallback_str(void *context, const char *str) {} |
|
115 static void defaultCallback_int_str(void *context, int i, const char *str) {} |
|
116 static void defaultCallback_str_str(void *context, const char *str1, const char *str2) {} |
|
117 static void defaultCallback_str_bool(void *context, const char *str, bool b) {} |
|
118 |
|
119 static void defaultCallback_onRoomAdd(void *context, const flib_roomlist_room *room) {} |
|
120 static void defaultCallback_onRoomUpdate(void *context, const char *oldName, const flib_roomlist_room *room) {} |
|
121 static void defaultCallback_onChat(void *context, const char *nick, const char *msg) { |
|
122 flib_log_i("%s: %s", nick, msg); |
|
123 } |
|
124 |
|
125 // Change the name by suffixing it with a number. If it already ends in a number, increase that number by 1. |
|
126 static void defaultCallback_onNickTaken(void *context, const char *requestedNick) { |
|
127 flib_netconn *conn = context; |
|
128 size_t namelen = strlen(requestedNick); |
|
129 int digits = 0; |
|
130 while(digits<namelen && isdigit(requestedNick[namelen-1-digits])) { |
|
131 digits++; |
|
132 } |
|
133 long suffix = 0; |
|
134 if(digits>0) { |
|
135 suffix = atol(requestedNick+namelen-digits)+1; |
|
136 } |
|
137 char *newPlayerName = flib_asprintf("%.*s%li", namelen-digits, requestedNick, suffix); |
|
138 if(newPlayerName) { |
|
139 flib_netconn_send_nick(conn, newPlayerName); |
|
140 } else { |
|
141 flib_netconn_send_quit(conn, "Nick already taken."); |
|
142 } |
|
143 free(newPlayerName); |
|
144 } |
|
145 |
|
146 // Default behavior: Quit |
|
147 static void defaultCallback_onPasswordRequest(void *context, const char *requestedNick) { |
|
148 flib_netconn_send_quit((flib_netconn*)context, "Authentication failed"); |
|
149 } |
|
150 |
|
151 static void defaultCallback_onTeamAdd(void *context, flib_team *team) {} |
50 |
152 |
51 static void clearCallbacks(flib_netconn *conn) { |
153 static void clearCallbacks(flib_netconn *conn) { |
52 conn->onErrorCb = &defaultCallback_onError; |
154 flib_netconn_onMessage(conn, NULL, NULL); |
53 conn->onConnectedCb = &defaultCallback_onConnected; |
155 flib_netconn_onConnected(conn, NULL, NULL); |
54 } |
156 flib_netconn_onDisconnected(conn, NULL, NULL); |
55 |
157 flib_netconn_onRoomAdd(conn, NULL, NULL); |
56 |
158 flib_netconn_onRoomDelete(conn, NULL, NULL); |
57 flib_netconn *flib_netconn_create(const char *playerName, const char *host, uint16_t port) { |
159 flib_netconn_onRoomUpdate(conn, NULL, NULL); |
|
160 flib_netconn_onChat(conn, NULL, NULL); |
|
161 flib_netconn_onLobbyJoin(conn, NULL, NULL); |
|
162 flib_netconn_onLobbyLeave(conn, NULL, NULL); |
|
163 flib_netconn_onRoomJoin(conn, NULL, NULL); |
|
164 flib_netconn_onRoomLeave(conn, NULL, NULL); |
|
165 flib_netconn_onNickTaken(conn, NULL, NULL); |
|
166 flib_netconn_onNickAccept(conn, NULL, NULL); |
|
167 flib_netconn_onPasswordRequest(conn, NULL, NULL); |
|
168 flib_netconn_onRoomChiefStatus(conn, NULL, NULL); |
|
169 flib_netconn_onReadyStateCb(conn, NULL, NULL); |
|
170 flib_netconn_onEnterRoomCb(conn, NULL, NULL); |
|
171 flib_netconn_onTeamAddCb(conn, NULL, NULL); |
|
172 } |
|
173 |
|
174 flib_netconn *flib_netconn_create(const char *playerName, flib_cfg_meta *metacfg, const char *host, uint16_t port) { |
58 flib_netconn *result = NULL; |
175 flib_netconn *result = NULL; |
59 flib_netconn *newConn = flib_calloc(1, sizeof(flib_netconn)); |
176 if(!playerName || !metacfg || !host) { |
60 if(newConn) { |
177 flib_log_e("null parameter in flib_netconn_create"); |
61 newConn->netconnState = NETCONN_STATE_AWAIT_CONNECTED; |
178 } else { |
62 newConn->running = false; |
179 flib_netconn *newConn = flib_calloc(1, sizeof(flib_netconn)); |
63 newConn->destroyRequested = false; |
180 if(newConn) { |
64 clearCallbacks(newConn); |
181 newConn->netconnState = NETCONN_STATE_CONNECTING; |
65 newConn->netBase = flib_netbase_create(host, port); |
182 newConn->isAdmin = false; |
66 newConn->playerName = flib_strdupnull(playerName); |
183 newConn->isChief = false; |
67 if(newConn->netBase && newConn->playerName) { |
184 newConn->metaCfg = flib_cfg_meta_retain(metacfg); |
68 result = newConn; |
185 newConn->roomList = flib_roomlist_create(); |
69 newConn = NULL; |
186 newConn->running = false; |
|
187 newConn->destroyRequested = false; |
|
188 clearCallbacks(newConn); |
|
189 newConn->netBase = flib_netbase_create(host, port); |
|
190 newConn->playerName = flib_strdupnull(playerName); |
|
191 if(newConn->netBase && newConn->playerName && newConn->roomList) { |
|
192 result = newConn; |
|
193 newConn = NULL; |
|
194 } |
70 } |
195 } |
71 } |
196 flib_netconn_destroy(newConn); |
72 flib_netconn_destroy(newConn); |
197 } |
73 return result; |
198 return result; |
74 } |
199 } |
75 |
200 |
76 void flib_netconn_destroy(flib_netconn *conn) { |
201 void flib_netconn_destroy(flib_netconn *conn) { |
77 if(conn) { |
202 if(conn) { |
83 */ |
208 */ |
84 clearCallbacks(conn); |
209 clearCallbacks(conn); |
85 conn->destroyRequested = true; |
210 conn->destroyRequested = true; |
86 } else { |
211 } else { |
87 flib_netbase_destroy(conn->netBase); |
212 flib_netbase_destroy(conn->netBase); |
|
213 flib_cfg_meta_release(conn->metaCfg); |
|
214 flib_roomlist_destroy(conn->roomList); |
88 free(conn->playerName); |
215 free(conn->playerName); |
89 free(conn); |
216 free(conn); |
90 } |
217 } |
91 } |
218 } |
92 } |
219 } |
93 |
220 |
94 void flib_netconn_onError(flib_netconn *conn, void (*callback)(void *context, int errorCode, const char *errorMsg), void* context) { |
221 const flib_roomlist *flib_netconn_get_roomlist(flib_netconn *conn) { |
95 if(!conn) { |
222 const flib_roomlist *result = NULL; |
96 flib_log_e("null parameter in flib_netconn_onError"); |
223 if(!conn) { |
97 } else { |
224 flib_log_e("null parameter in flib_netconn_get_roomlist"); |
98 conn->onErrorCb = callback ? callback : &defaultCallback_onError; |
225 } else { |
99 conn->onErrorCtx = context; |
226 result = conn->roomList; |
100 } |
227 } |
101 } |
228 return result; |
102 |
229 } |
103 void flib_netconn_onConnected(flib_netconn *conn, void (*callback)(void *context, const char *serverMessage), void* context) { |
230 |
|
231 bool flib_netconn_is_chief(flib_netconn *conn) { |
|
232 bool result = false; |
|
233 if(!conn) { |
|
234 flib_log_e("null parameter in flib_netconn_is_chief"); |
|
235 } else if(conn->netconnState == NETCONN_STATE_ROOM || conn->netconnState == NETCONN_STATE_INGAME) { |
|
236 result = conn->isChief; |
|
237 } |
|
238 return result; |
|
239 } |
|
240 |
|
241 int flib_netconn_send_quit(flib_netconn *conn, const char *quitmsg) { |
|
242 int result = -1; |
|
243 if(!conn) { |
|
244 flib_log_e("null parameter in flib_netconn_send_quit"); |
|
245 } else { |
|
246 result = flib_netbase_sendf(conn->netBase, "%s\n%s\n\n", "QUIT", quitmsg ? quitmsg : "User quit"); |
|
247 } |
|
248 return result; |
|
249 } |
|
250 |
|
251 int flib_netconn_send_chat(flib_netconn *conn, const char *chat) { |
|
252 int result = -1; |
|
253 if(!conn || !chat) { |
|
254 flib_log_e("null parameter in flib_netconn_send_chat"); |
|
255 } else { |
|
256 result = flib_netbase_sendf(conn->netBase, "%s\n%s\n\n", "CHAT", chat); |
|
257 } |
|
258 return result; |
|
259 } |
|
260 |
|
261 int flib_netconn_send_nick(flib_netconn *conn, const char *nick) { |
|
262 int result = -1; |
|
263 if(!conn || !nick) { |
|
264 flib_log_e("null parameter in flib_netconn_send_nick"); |
|
265 } else { |
|
266 char *tmpName = flib_strdupnull(nick); |
|
267 if(tmpName) { |
|
268 if(!flib_netbase_sendf(conn->netBase, "%s\n%s\n\n", "NICK", nick)) { |
|
269 free(conn->playerName); |
|
270 conn->playerName = tmpName; |
|
271 tmpName = NULL; |
|
272 result = 0; |
|
273 } |
|
274 } |
|
275 free(tmpName); |
|
276 } |
|
277 return result; |
|
278 } |
|
279 |
|
280 int flib_netconn_send_password(flib_netconn *conn, const char *latin1Passwd) { |
|
281 int result = -1; |
|
282 if(!conn || !latin1Passwd) { |
|
283 flib_log_e("null parameter in flib_netconn_send_password"); |
|
284 } else { |
|
285 md5_state_t md5state; |
|
286 uint8_t md5bytes[16]; |
|
287 char md5hex[33]; |
|
288 md5_init(&md5state); |
|
289 md5_append(&md5state, (unsigned char*)latin1Passwd, strlen(latin1Passwd)); |
|
290 md5_finish(&md5state, md5bytes); |
|
291 for(int i=0;i<sizeof(md5bytes); i++) { |
|
292 // Needs to be lowercase - server checks case sensitive |
|
293 snprintf(md5hex+i*2, 3, "%02x", (unsigned)md5bytes[i]); |
|
294 } |
|
295 result = flib_netbase_sendf(conn->netBase, "%s\n%s\n\n", "PASSWORD", md5hex); |
|
296 } |
|
297 return result; |
|
298 } |
|
299 |
|
300 /* |
|
301 * Callback registration functions |
|
302 */ |
|
303 |
|
304 void flib_netconn_onMessage(flib_netconn *conn, void (*callback)(void *context, int msgtype, const char *msg), void* context) { |
|
305 if(!conn) { |
|
306 flib_log_e("null parameter in flib_netconn_onMessage"); |
|
307 } else { |
|
308 conn->onMessageCb = callback ? callback : &defaultCallback_onMessage; |
|
309 conn->onMessageCtx = context; |
|
310 } |
|
311 } |
|
312 |
|
313 void flib_netconn_onConnected(flib_netconn *conn, void (*callback)(void *context), void* context) { |
104 if(!conn) { |
314 if(!conn) { |
105 flib_log_e("null parameter in flib_netconn_onConnected"); |
315 flib_log_e("null parameter in flib_netconn_onConnected"); |
106 } else { |
316 } else { |
107 conn->onConnectedCb = callback ? callback : &defaultCallback_onConnected; |
317 conn->onConnectedCb = callback ? callback : &defaultCallback_void; |
108 conn->onConnectedCtx = context; |
318 conn->onConnectedCtx = context; |
|
319 } |
|
320 } |
|
321 |
|
322 void flib_netconn_onDisconnected(flib_netconn *conn, void (*callback)(void *context, int reason, const char *message), void* context) { |
|
323 if(!conn) { |
|
324 flib_log_e("null parameter in flib_netconn_onDisconnected"); |
|
325 } else { |
|
326 conn->onDisconnectedCb = callback ? callback : &defaultCallback_int_str; |
|
327 conn->onDisconnectedCtx = context; |
|
328 } |
|
329 } |
|
330 |
|
331 void flib_netconn_onRoomAdd(flib_netconn *conn, void (*callback)(void *context, const flib_roomlist_room *room), void* context) { |
|
332 if(!conn) { |
|
333 flib_log_e("null parameter in flib_netconn_onRoomAdd"); |
|
334 } else { |
|
335 conn->onRoomAddCb = callback ? callback : &defaultCallback_onRoomAdd; |
|
336 conn->onRoomAddCtx = context; |
|
337 } |
|
338 } |
|
339 |
|
340 void flib_netconn_onRoomDelete(flib_netconn *conn, void (*callback)(void *context, const char *name), void* context) { |
|
341 if(!conn) { |
|
342 flib_log_e("null parameter in flib_netconn_onRoomDelete"); |
|
343 } else { |
|
344 conn->onRoomDeleteCb = callback ? callback : &defaultCallback_str; |
|
345 conn->onRoomDeleteCtx = context; |
|
346 } |
|
347 } |
|
348 |
|
349 void flib_netconn_onRoomUpdate(flib_netconn *conn, void (*callback)(void *context, const char *oldName, const flib_roomlist_room *room), void* context) { |
|
350 if(!conn) { |
|
351 flib_log_e("null parameter in flib_netconn_onRoomUpdate"); |
|
352 } else { |
|
353 conn->onRoomUpdateCb = callback ? callback : &defaultCallback_onRoomUpdate; |
|
354 conn->onRoomUpdateCtx = context; |
|
355 } |
|
356 } |
|
357 |
|
358 void flib_netconn_onChat(flib_netconn *conn, void (*callback)(void *context, const char *nick, const char *msg), void* context) { |
|
359 if(!conn) { |
|
360 flib_log_e("null parameter in flib_netconn_onChat"); |
|
361 } else { |
|
362 conn->onChatCb = callback ? callback : &defaultCallback_onChat; |
|
363 conn->onChatCtx = context; |
|
364 } |
|
365 } |
|
366 |
|
367 void flib_netconn_onLobbyJoin(flib_netconn *conn, void (*callback)(void *context, const char *nick), void* context) { |
|
368 if(!conn) { |
|
369 flib_log_e("null parameter in flib_netconn_onLobbyJoin"); |
|
370 } else { |
|
371 conn->onLobbyJoinCb = callback ? callback : &defaultCallback_str; |
|
372 conn->onLobbyJoinCtx = context; |
|
373 } |
|
374 } |
|
375 |
|
376 void flib_netconn_onLobbyLeave(flib_netconn *conn, void (*callback)(void *context, const char *nick, const char *partMsg), void* context) { |
|
377 if(!conn) { |
|
378 flib_log_e("null parameter in flib_netconn_onLobbyLeave"); |
|
379 } else { |
|
380 conn->onLobbyLeaveCb = callback ? callback : &defaultCallback_str_str; |
|
381 conn->onLobbyLeaveCtx = context; |
|
382 } |
|
383 } |
|
384 |
|
385 void flib_netconn_onRoomJoin(flib_netconn *conn, void (*callback)(void *context, const char *nick), void* context) { |
|
386 if(!conn) { |
|
387 flib_log_e("null parameter in flib_netconn_onRoomJoin"); |
|
388 } else { |
|
389 conn->onRoomJoinCb = callback ? callback : &defaultCallback_str; |
|
390 conn->onRoomJoinCtx = context; |
|
391 } |
|
392 } |
|
393 |
|
394 void flib_netconn_onRoomLeave(flib_netconn *conn, void (*callback)(void *context, const char *nick, const char *partMessage), void* context) { |
|
395 if(!conn) { |
|
396 flib_log_e("null parameter in flib_netconn_onRoomLeave"); |
|
397 } else { |
|
398 conn->onRoomLeaveCb = callback ? callback : &defaultCallback_str_str; |
|
399 conn->onRoomLeaveCtx = context; |
|
400 } |
|
401 } |
|
402 |
|
403 void flib_netconn_onNickTaken(flib_netconn *conn, void (*callback)(void *context, const char *nick), void* context) { |
|
404 if(!conn) { |
|
405 flib_log_e("null parameter in flib_netconn_onNickTaken"); |
|
406 } else if(!callback) { |
|
407 conn->onNickTakenCb = &defaultCallback_onNickTaken; |
|
408 conn->onNickTakenCtx = conn; |
|
409 } else { |
|
410 conn->onNickTakenCb = callback; |
|
411 conn->onNickTakenCtx = context; |
|
412 } |
|
413 } |
|
414 |
|
415 void flib_netconn_onNickAccept(flib_netconn *conn, void (*callback)(void *context, const char *nick), void* context) { |
|
416 if(!conn) { |
|
417 flib_log_e("null parameter in flib_netconn_onNickAccept"); |
|
418 } else { |
|
419 conn->onNickAcceptCb = callback ? callback : &defaultCallback_str; |
|
420 conn->onNickAcceptCtx = context; |
|
421 } |
|
422 } |
|
423 |
|
424 void flib_netconn_onPasswordRequest(flib_netconn *conn, void (*callback)(void *context, const char *nick), void* context) { |
|
425 if(!conn) { |
|
426 flib_log_e("null parameter in flib_netconn_onPasswordRequest"); |
|
427 } else if(!callback) { |
|
428 conn->onPasswordRequestCb = &defaultCallback_onPasswordRequest; |
|
429 conn->onPasswordRequestCtx = conn; |
|
430 } else { |
|
431 conn->onPasswordRequestCb = callback; |
|
432 conn->onPasswordRequestCtx = context; |
|
433 } |
|
434 } |
|
435 |
|
436 void flib_netconn_onRoomChiefStatus(flib_netconn *conn, void (*callback)(void *context, bool chief), void* context) { |
|
437 if(!conn) { |
|
438 flib_log_e("null parameter in flib_netconn_onRoomChiefStatus"); |
|
439 } else { |
|
440 conn->onRoomChiefStatusCb = callback ? callback : &defaultCallback_bool; |
|
441 conn->onRoomChiefStatusCtx = context; |
|
442 } |
|
443 } |
|
444 |
|
445 void flib_netconn_onReadyStateCb(flib_netconn *conn, void (*callback)(void *context, const char *nick, bool ready), void* context) { |
|
446 if(!conn) { |
|
447 flib_log_e("null parameter in flib_netconn_onReadyStateCb"); |
|
448 } else { |
|
449 conn->onReadyStateCb = callback ? callback : &defaultCallback_str_bool; |
|
450 conn->onReadyStateCtx = context; |
|
451 } |
|
452 } |
|
453 |
|
454 void flib_netconn_onEnterRoomCb(flib_netconn *conn, void (*callback)(void *context, bool chief), void *context) { |
|
455 if(!conn) { |
|
456 flib_log_e("null parameter in flib_netconn_onEnterRoomCb"); |
|
457 } else { |
|
458 conn->onEnterRoomCb = callback ? callback : &defaultCallback_bool; |
|
459 conn->onEnterRoomCtx = context; |
|
460 } |
|
461 } |
|
462 |
|
463 void flib_netconn_onLeaveRoomCb(flib_netconn *conn, void (*callback)(void *context, int reason, const char *message), void *context) { |
|
464 if(!conn) { |
|
465 flib_log_e("null parameter in flib_netconn_onLeaveRoomCb"); |
|
466 } else { |
|
467 conn->onLeaveRoomCb = callback ? callback : &defaultCallback_int_str; |
|
468 conn->onLeaveRoomCtx = context; |
|
469 } |
|
470 } |
|
471 |
|
472 void flib_netconn_onTeamAddCb(flib_netconn *conn, void (*callback)(void *context, flib_team *team), void *context) { |
|
473 if(!conn) { |
|
474 flib_log_e("null parameter in flib_netconn_onTeamAddCb"); |
|
475 } else { |
|
476 conn->onTeamAddCb = callback ? callback : &defaultCallback_onTeamAdd; |
|
477 conn->onTeamAddCtx = context; |
109 } |
478 } |
110 } |
479 } |
111 |
480 |
112 static void flib_netconn_wrappedtick(flib_netconn *conn) { |
481 static void flib_netconn_wrappedtick(flib_netconn *conn) { |
113 flib_netmsg *netmsg; |
482 flib_netmsg *netmsg; |
118 if(netmsg->partCount==0) { |
487 if(netmsg->partCount==0) { |
119 flib_log_w("Empty server message"); |
488 flib_log_w("Empty server message"); |
120 continue; |
489 continue; |
121 } |
490 } |
122 |
491 |
|
492 if(flib_log_isActive(FLIB_LOGLEVEL_DEBUG)) { |
|
493 char *buf = flib_join(netmsg->parts, netmsg->partCount, "|"); |
|
494 if(buf) { |
|
495 flib_log_d("[Net In]%s", buf); |
|
496 } |
|
497 free(buf); |
|
498 } |
|
499 |
123 const char *cmd = netmsg->parts[0]; |
500 const char *cmd = netmsg->parts[0]; |
124 |
501 |
125 if (!strcmp(cmd, "NICK") && netmsg->partCount>=2) { |
502 if (!strcmp(cmd, "NICK") && netmsg->partCount>=2) { |
126 free(conn->playerName); |
503 if(netmsg->partCount<2) { |
127 conn->playerName = flib_strdupnull(netmsg->parts[1]); |
504 flib_log_w("Net: Malformed NICK message"); |
128 if(!conn->playerName) { |
505 } else { |
129 // TODO handle error |
506 free(conn->playerName); |
|
507 conn->playerName = flib_strdupnull(netmsg->parts[1]); |
|
508 if(!conn->playerName) { |
|
509 conn->netconnState = NETCONN_STATE_DISCONNECTED; |
|
510 conn->onDisconnectedCb(conn->onDisconnectedCtx, NETCONN_DISCONNECT_INTERNAL_ERROR, "Out of memory"); |
|
511 exit = true; |
|
512 } else { |
|
513 conn->onNickAcceptCb(conn->onNickAcceptCtx, conn->playerName); |
|
514 } |
130 } |
515 } |
131 // TODO callback? |
|
132 } else if (!strcmp(cmd, "PROTO")) { |
516 } else if (!strcmp(cmd, "PROTO")) { |
133 // The server just echoes this back apparently |
517 // The server just echoes this back apparently |
134 } else if (!strcmp(cmd, "ERROR")) { |
518 } else if (!strcmp(cmd, "ERROR")) { |
135 // TODO: onErrorMessage? |
519 if (netmsg->partCount >= 2) { |
136 if (netmsg->partCount == 2) { |
520 conn->onMessageCb(conn->onMessageCtx, NETCONN_MSG_TYPE_ERROR, netmsg->parts[1]); |
137 conn->onErrorCb(conn->onErrorCtx, NETCONN_ERROR_FROM_SERVER, netmsg->parts[1]); |
|
138 } else { |
521 } else { |
139 conn->onErrorCb(conn->onErrorCtx, NETCONN_ERROR_FROM_SERVER, "Unknown Error"); |
522 conn->onMessageCb(conn->onMessageCtx, NETCONN_MSG_TYPE_ERROR, "Unknown Error"); |
140 } |
523 } |
141 } else if(!strcmp(cmd, "WARNING")) { |
524 } else if(!strcmp(cmd, "WARNING")) { |
142 // TODO: onWarnMessage? |
525 if (netmsg->partCount >= 2) { |
143 if (netmsg->partCount == 2) { |
526 conn->onMessageCb(conn->onMessageCtx, NETCONN_MSG_TYPE_WARNING, netmsg->parts[1]); |
144 conn->onErrorCb(conn->onErrorCtx, NETCONN_ERROR_FROM_SERVER, netmsg->parts[1]); |
|
145 } else { |
527 } else { |
146 conn->onErrorCb(conn->onErrorCtx, NETCONN_ERROR_FROM_SERVER, "Unknown Warning"); |
528 conn->onMessageCb(conn->onMessageCtx, NETCONN_MSG_TYPE_WARNING, "Unknown Warning"); |
147 } |
529 } |
148 } else if(!strcmp(cmd, "CONNECTED")) { |
530 } else if(!strcmp(cmd, "CONNECTED")) { |
149 if(netmsg->partCount<3 || atol(netmsg->parts[2])<MIN_SERVER_VERSION) { |
531 if(netmsg->partCount<3 || atol(netmsg->parts[2])<MIN_SERVER_VERSION) { |
150 flib_log_w("Server too old"); |
532 flib_log_w("Net: Server too old"); |
151 flib_netbase_sendf(net, "%s\n%s\n\n", "QUIT", "Server too old"); |
533 flib_netbase_sendf(net, "%s\n%s\n\n", "QUIT", "Server too old"); |
152 // TODO actually disconnect? |
|
153 conn->netconnState = NETCONN_STATE_DISCONNECTED; |
534 conn->netconnState = NETCONN_STATE_DISCONNECTED; |
154 conn->onErrorCb(conn->onErrorCtx, NETCONN_ERROR_SERVER_TOO_OLD, "Server too old"); |
535 conn->onDisconnectedCb(conn->onDisconnectedCtx, NETCONN_DISCONNECT_SERVER_TOO_OLD, "Server too old"); |
155 exit = true; |
536 exit = true; |
156 } else { |
537 } else { |
157 flib_netbase_sendf(net, "%s\n%s\n\n", "NICK", conn->playerName); |
538 flib_netbase_sendf(net, "%s\n%s\n\n", "NICK", conn->playerName); |
158 flib_netbase_sendf(net, "%s\n%i\n\n", "PROTO", (int)PROTOCOL_VERSION); |
539 flib_netbase_sendf(net, "%s\n%i\n\n", "PROTO", (int)PROTOCOL_VERSION); |
159 conn->netconnState = NETCONN_STATE_LOBBY; |
|
160 } |
540 } |
161 } else if(!strcmp(cmd, "PING")) { |
541 } else if(!strcmp(cmd, "PING")) { |
162 if (netmsg->partCount > 1) { |
542 if (netmsg->partCount > 1) { |
163 flib_netbase_sendf(net, "%s\n%s\n\n", "PONG", netmsg->parts[1]); |
543 flib_netbase_sendf(net, "%s\n%s\n\n", "PONG", netmsg->parts[1]); |
164 } else { |
544 } else { |
166 } |
546 } |
167 } else if(!strcmp(cmd, "ROOMS")) { |
547 } else if(!strcmp(cmd, "ROOMS")) { |
168 if(netmsg->partCount % 8 != 1) { |
548 if(netmsg->partCount % 8 != 1) { |
169 flib_log_w("Net: Malformed ROOMS message"); |
549 flib_log_w("Net: Malformed ROOMS message"); |
170 } else { |
550 } else { |
171 // TODO |
551 flib_roomlist_clear(conn->roomList); |
172 //QStringList tmp = lst; |
552 for(int i=1; i<netmsg->partCount; i+=8) { |
173 //tmp.removeFirst(); |
553 if(flib_roomlist_add(conn->roomList, netmsg->parts+i)) { |
174 //m_roomsListModel->setRoomsList(tmp); |
554 flib_log_e("Error adding room to list in ROOMS message"); |
|
555 } |
|
556 } |
|
557 if(conn->netconnState == NETCONN_STATE_CONNECTING) { |
|
558 // We delay the "connected" callback until now to ensure the room list is avaliable. |
|
559 conn->onConnectedCb(conn->onConnectedCtx); |
|
560 conn->netconnState = NETCONN_STATE_LOBBY; |
|
561 } |
175 } |
562 } |
176 } else if (!strcmp(cmd, "SERVER_MESSAGE")) { |
563 } else if (!strcmp(cmd, "SERVER_MESSAGE")) { |
177 if(netmsg->partCount < 2) { |
564 if(netmsg->partCount < 2) { |
178 flib_log_w("Net: Empty SERVERMESSAGE message"); |
565 flib_log_w("Net: Empty SERVERMESSAGE message"); |
179 } else { |
566 } else { |
180 // TODO |
567 conn->onMessageCb(conn->onMessageCtx, NETCONN_MSG_TYPE_SERVERMESSAGE, netmsg->parts[1]); |
181 // emit serverMessage(lst[1]); |
|
182 } |
568 } |
183 } else if (!strcmp(cmd, "CHAT")) { |
569 } else if (!strcmp(cmd, "CHAT")) { |
184 if(netmsg->partCount < 3) { |
570 if(netmsg->partCount < 3) { |
185 flib_log_w("Net: Empty CHAT message"); |
571 flib_log_w("Net: Empty CHAT message"); |
186 } else { |
572 } else { |
187 // TODO |
573 conn->onChatCb(conn->onChatCtx, netmsg->parts[1], netmsg->parts[2]); |
188 // if (netClientState == InLobby) |
|
189 // emit chatStringLobby(lst[1], HWProto::formatChatMsgForFrontend(lst[2])); |
|
190 // else |
|
191 // emit chatStringFromNet(HWProto::formatChatMsg(lst[1], lst[2])); |
|
192 } |
574 } |
193 } else if (!strcmp(cmd, "INFO")) { |
575 } else if (!strcmp(cmd, "INFO")) { |
194 if(netmsg->partCount < 5) { |
576 if(netmsg->partCount < 5) { |
195 flib_log_w("Net: Malformed INFO message"); |
577 flib_log_w("Net: Malformed INFO message"); |
196 } else { |
578 } else { |
197 // TODO |
579 char *joined = flib_join(netmsg->parts+1, netmsg->partCount-1, "\n"); |
198 // QStringList tmp = lst; |
580 if(joined) { |
199 // tmp.removeFirst(); |
581 conn->onMessageCb(conn->onMessageCtx, NETCONN_MSG_TYPE_PLAYERINFO, joined); |
200 // if (netClientState == InLobby) |
582 } |
201 // emit chatStringLobby(tmp.join("\n").prepend('\x01')); |
583 free(joined); |
202 // else |
|
203 // emit chatStringFromNet(tmp.join("\n").prepend('\x01')); |
|
204 } |
584 } |
205 } else if(!strcmp(cmd, "SERVER_VARS")) { |
585 } else if(!strcmp(cmd, "SERVER_VARS")) { |
206 // TODO |
586 // TODO |
207 // QStringList tmp = lst; |
587 // QStringList tmp = lst; |
208 // tmp.removeFirst(); |
588 // tmp.removeFirst(); |
243 } |
623 } |
244 } else if (!strcmp(cmd, "ADD_TEAM")) { |
624 } else if (!strcmp(cmd, "ADD_TEAM")) { |
245 if(netmsg->partCount != 24) { |
625 if(netmsg->partCount != 24) { |
246 flib_log_w("Net: Bad ADD_TEAM message"); |
626 flib_log_w("Net: Bad ADD_TEAM message"); |
247 } else { |
627 } else { |
248 // TODO |
628 flib_team *team = flib_team_from_netmsg(netmsg->parts+1); |
249 // QStringList tmp = lst; |
629 if(!team) { |
250 // tmp.removeFirst(); |
630 conn->netconnState = NETCONN_STATE_DISCONNECTED; |
251 // emit AddNetTeam(tmp); |
631 conn->onDisconnectedCb(conn->onDisconnectedCtx, NETCONN_DISCONNECT_INTERNAL_ERROR, "Internal error"); |
|
632 exit = true; |
|
633 } else { |
|
634 conn->onTeamAddCb(conn->onTeamAddCtx, team); |
|
635 } |
252 } |
636 } |
253 } else if (!strcmp(cmd, "REMOVE_TEAM")) { |
637 } else if (!strcmp(cmd, "REMOVE_TEAM")) { |
254 if(netmsg->partCount != 2) { |
638 if(netmsg->partCount != 2) { |
255 flib_log_w("Net: Bad REMOVETEAM message"); |
639 flib_log_w("Net: Bad REMOVETEAM message"); |
256 } else { |
640 } else { |
257 // TODO |
641 // TODO |
258 // emit RemoveNetTeam(HWTeam(lst[1])); |
642 // emit RemoveNetTeam(HWTeam(lst[1])); |
259 } |
643 } |
260 } else if(!strcmp(cmd, "ROOMABANDONED")) { |
644 } else if(!strcmp(cmd, "ROOMABANDONED")) { |
261 conn->netconnState = NETCONN_STATE_LOBBY; |
645 conn->netconnState = NETCONN_STATE_LOBBY; |
262 // TODO |
646 conn->onLeaveRoomCb(conn->onLeaveRoomCtx, NETCONN_ROOMLEAVE_ABANDONED, "Room destroyed"); |
263 // askRoomsList(); |
|
264 // emit LeftRoom(tr("Room destroyed")); |
|
265 } else if(!strcmp(cmd, "KICKED")) { |
647 } else if(!strcmp(cmd, "KICKED")) { |
266 conn->netconnState = NETCONN_STATE_LOBBY; |
648 conn->netconnState = NETCONN_STATE_LOBBY; |
267 // TODO |
649 conn->onLeaveRoomCb(conn->onLeaveRoomCtx, NETCONN_ROOMLEAVE_KICKED, "You got kicked"); |
268 // askRoomsList(); |
|
269 // emit LeftRoom(tr("You got kicked")); |
|
270 } else if(!strcmp(cmd, "JOINED")) { |
650 } else if(!strcmp(cmd, "JOINED")) { |
271 if(netmsg->partCount < 2) { |
651 if(netmsg->partCount < 2) { |
272 flib_log_w("Net: Bad JOINED message"); |
652 flib_log_w("Net: Bad JOINED message"); |
273 } else { |
653 } else { |
274 for(int i = 1; i < netmsg->partCount; ++i) |
654 for(int i = 1; i < netmsg->partCount; ++i) |
275 { |
655 { |
276 bool isMe = !strcmp(conn->playerName, netmsg->parts[i]); |
656 bool isMe = !strcmp(conn->playerName, netmsg->parts[i]); |
277 if (isMe) { |
657 if (isMe) { |
278 conn->netconnState = NETCONN_STATE_ROOM; |
658 conn->netconnState = NETCONN_STATE_ROOM; |
279 // TODO |
659 conn->onEnterRoomCb(conn->onEnterRoomCtx, conn->isChief); |
280 // emit EnteredGame(); |
|
281 // emit roomMaster(isChief); |
|
282 // if (isChief) |
|
283 // emit configAsked(); |
|
284 } |
660 } |
285 |
661 |
286 // TODO |
662 conn->onRoomJoinCb(conn->onRoomJoinCtx, netmsg->parts[i]); |
287 // emit nickAdded(lst[i], isChief && !isMe)); |
|
288 // emit chatStringFromNet(tr("%1 *** %2 has joined the room").arg('\x03').arg(lst[i])); |
|
289 } |
663 } |
290 } |
664 } |
291 } else if(!strcmp(cmd, "LOBBY:JOINED")) { |
665 } else if(!strcmp(cmd, "LOBBY:JOINED")) { |
292 if(netmsg->partCount < 2) { |
666 if(netmsg->partCount < 2) { |
293 flib_log_w("Net: Bad JOINED message"); |
667 flib_log_w("Net: Bad JOINED message"); |
294 } else { |
668 } else { |
295 for(int i = 1; i < netmsg->partCount; ++i) |
669 for(int i = 1; i < netmsg->partCount; ++i) |
296 { |
670 { |
297 bool isMe = !strcmp(conn->playerName, netmsg->parts[i]); |
671 bool isMe = !strcmp(conn->playerName, netmsg->parts[i]); |
298 if (isMe) { |
672 if (isMe) { |
299 conn->netconnState = NETCONN_STATE_LOBBY; |
673 if(flib_netbase_sendf(conn->netBase, "%s\n\n", "LIST")) { |
300 // TODO |
674 // If sending this fails, the protocol breaks (we'd be waiting infinitely for the room list) |
301 // RawSendNet(QString("LIST")); |
675 flib_netbase_sendf(net, "%s\n%s\n\n", "QUIT", "Client error"); |
302 // emit connected(); |
676 conn->netconnState = NETCONN_STATE_DISCONNECTED; |
|
677 conn->onDisconnectedCb(conn->onDisconnectedCtx, NETCONN_DISCONNECT_INTERNAL_ERROR, "Failed to send a critical message."); |
|
678 exit = true; |
|
679 } |
303 } |
680 } |
304 // TODO |
681 conn->onLobbyJoinCb(conn->onLobbyJoinCtx, netmsg->parts[i]); |
305 // emit nickAddedLobby(lst[i], false); |
|
306 // emit chatStringLobby(lst[i], tr("%1 *** %2 has joined").arg('\x03').arg("|nick|")); |
|
307 } |
682 } |
308 } |
683 } |
309 } else if(!strcmp(cmd, "LEFT")) { |
684 } else if(!strcmp(cmd, "LEFT")) { |
310 if(netmsg->partCount < 2) { |
685 if(netmsg->partCount < 2) { |
311 flib_log_w("Net: Bad LEFT message"); |
686 flib_log_w("Net: Bad LEFT message"); |
312 } else { |
687 } else { |
313 // TODO |
688 conn->onRoomLeaveCb(conn->onRoomLeaveCtx, netmsg->parts[1], netmsg->partCount>2 ? netmsg->parts[2] : NULL); |
314 // emit nickRemoved(lst[1]); |
|
315 // if (netmsg->partCount < 3) |
|
316 // emit chatStringFromNet(tr("%1 *** %2 has left").arg('\x03').arg(lst[1])); |
|
317 // else |
|
318 // emit chatStringFromNet(tr("%1 *** %2 has left (%3)").arg('\x03').arg(lst[1], lst[2])); |
|
319 } |
689 } |
320 } else if(!strcmp(cmd, "ROOM") && netmsg->partCount >= 2) { |
690 } else if(!strcmp(cmd, "ROOM") && netmsg->partCount >= 2) { |
321 const char *subcmd = netmsg->parts[1]; |
691 const char *subcmd = netmsg->parts[1]; |
322 if(!strcmp(subcmd, "ADD") && netmsg->partCount == 10) { |
692 if(!strcmp(subcmd, "ADD") && netmsg->partCount == 10) { |
323 // TODO |
693 if(flib_roomlist_add(conn->roomList, netmsg->parts+2)) { |
324 // QStringList tmp = lst; |
694 flib_log_e("Error adding new room to list"); |
325 // tmp.removeFirst(); |
695 } else { |
326 // tmp.removeFirst(); |
696 conn->onRoomAddCb(conn->onRoomAddCtx, conn->roomList->rooms[0]); |
327 // |
697 } |
328 // m_roomsListModel->addRoom(tmp); |
|
329 } else if(!strcmp(subcmd, "UPD") && netmsg->partCount == 11) { |
698 } else if(!strcmp(subcmd, "UPD") && netmsg->partCount == 11) { |
330 // TODO |
699 if(flib_roomlist_update(conn->roomList, netmsg->parts[2], netmsg->parts+3)) { |
331 // QStringList tmp = lst; |
700 flib_log_e("Error updating room in list"); |
332 // tmp.removeFirst(); |
701 } else { |
333 // tmp.removeFirst(); |
702 conn->onRoomUpdateCb(conn->onRoomUpdateCtx, netmsg->parts[2], flib_roomlist_find(conn->roomList, netmsg->parts[2])); |
334 // |
703 } |
335 // QString roomName = tmp.takeFirst(); |
|
336 // m_roomsListModel->updateRoom(roomName, tmp); |
|
337 } else if(!strcmp(subcmd, "DEL") && netmsg->partCount == 3) { |
704 } else if(!strcmp(subcmd, "DEL") && netmsg->partCount == 3) { |
338 // TODO |
705 if(flib_roomlist_delete(conn->roomList, netmsg->parts[2])) { |
339 // m_roomsListModel->removeRoom(lst[2]); |
706 flib_log_e("Error deleting room from list"); |
|
707 } else { |
|
708 conn->onRoomDeleteCb(conn->onRoomDeleteCtx, netmsg->parts[2]); |
|
709 } |
340 } else { |
710 } else { |
341 flib_log_w("Net: Unknown or malformed ROOM subcommand: %s", subcmd); |
711 flib_log_w("Net: Unknown or malformed ROOM subcommand: %s", subcmd); |
342 } |
712 } |
343 } else if(!strcmp(cmd, "LOBBY:LEFT")) { |
713 } else if(!strcmp(cmd, "LOBBY:LEFT")) { |
344 if(netmsg->partCount < 2) { |
714 if(netmsg->partCount < 2) { |
345 flib_log_w("Net: Bad LOBBY:LEFT message"); |
715 flib_log_w("Net: Bad LOBBY:LEFT message"); |
346 } else { |
716 } else { |
347 // TODO |
717 conn->onLobbyLeaveCb(conn->onLobbyLeaveCtx, netmsg->parts[1], netmsg->partCount>2 ? netmsg->parts[2] : NULL); |
348 // emit nickRemovedLobby(lst[1]); |
|
349 // if (netmsg->partCount < 3) |
|
350 // emit chatStringLobby(tr("%1 *** %2 has left").arg('\x03').arg(lst[1])); |
|
351 // else |
|
352 // emit chatStringLobby(lst[1], tr("%1 *** %2 has left (%3)").arg('\x03').arg("|nick|", lst[2])); |
|
353 } |
718 } |
354 } else if (!strcmp(cmd, "RUN_GAME")) { |
719 } else if (!strcmp(cmd, "RUN_GAME")) { |
355 conn->netconnState = NETCONN_STATE_INGAME; |
720 conn->netconnState = NETCONN_STATE_INGAME; |
356 // TODO |
721 // TODO |
357 // emit AskForRunGame(); |
722 // emit AskForRunGame(); |
358 } else if (!strcmp(cmd, "ASKPASSWORD")) { |
723 } else if (!strcmp(cmd, "ASKPASSWORD")) { |
359 // TODO |
724 conn->onPasswordRequestCb(conn->onPasswordRequestCtx, conn->playerName); |
360 // emit AskForPassword(mynick); |
|
361 } else if (!strcmp(cmd, "NOTICE")) { |
725 } else if (!strcmp(cmd, "NOTICE")) { |
362 if(netmsg->partCount < 2) { |
726 if(netmsg->partCount < 2) { |
363 flib_log_w("Net: Bad NOTICE message"); |
727 flib_log_w("Net: Bad NOTICE message"); |
364 } else { |
728 } else { |
365 errno = 0; |
729 errno = 0; |
366 long n = strtol(netmsg->parts[1], NULL, 10); |
730 long n = strtol(netmsg->parts[1], NULL, 10); |
367 if(errno) { |
731 if(errno) { |
368 flib_log_w("Net: Bad NOTICE message"); |
732 flib_log_w("Net: Bad NOTICE message"); |
|
733 } else if(n==0) { |
|
734 conn->onNickTakenCb(conn->onNickTakenCtx, conn->playerName); |
369 } else { |
735 } else { |
370 // TODO |
736 flib_log_w("Net: Unknown NOTICE message: %l", n); |
371 // handleNotice(n); |
|
372 } |
737 } |
373 } |
738 } |
374 } else if (!strcmp(cmd, "TEAM_ACCEPTED")) { |
739 } else if (!strcmp(cmd, "TEAM_ACCEPTED")) { |
375 if (netmsg->partCount != 2) { |
740 if (netmsg->partCount != 2) { |
376 flib_log_w("Net: Bad TEAM_ACCEPTED message"); |
741 flib_log_w("Net: Bad TEAM_ACCEPTED message"); |