port
[carveJwlIkooP6JGAAIwe30JlM.git] / gameserver.c
1 /*
2 * Copyright (C) 2021-2023 Mt.ZERO Software, Harry Godden - All Rights Reserved
3 */
4
5 #define _DEFAULT_SOURCE
6 #include <signal.h>
7 #include <unistd.h>
8 #include <time.h>
9
10 volatile sig_atomic_t sig_stop;
11
12 #include "gameserver.h"
13 #include "highscores.c"
14 #include "servermonitor_server.c"
15 #include "vg/vg_opt.h"
16 #include "network_common.h"
17 #include "gameserver_db.h"
18 #include "vg/vg_m.h"
19 #include "vg/vg_msg.h"
20
21 static void inthandler( int signum ) {
22 sig_stop = 1;
23 }
24
25 static const u64 k_connection_unauthorized = 0xffffffffffffffff;
26
27 static u64_steamid get_connection_authsteamid( SteamNetworkingMessage_t *msg ){
28 i64 userdata = SteamAPI_ISteamNetworkingSockets_GetConnectionUserData(
29 hSteamNetworkingSockets, msg->m_conn );
30
31 return *((u64_steamid *)&userdata);
32 }
33
34 static void set_connection_authsteamid(HSteamNetConnection con, u64_steamid id){
35 i64 userdata = *((i64 *)&id);
36
37 SteamAPI_ISteamNetworkingSockets_SetConnectionUserData(
38 hSteamNetworkingSockets, con, userdata );
39 }
40
41 static void gameserver_send_to_all( int ignore,
42 const void *pData, u32 cbData,
43 int nSendFlags ){
44 for( int i=0; i<vg_list_size(gameserver.clients); i++ ){
45 struct gameserver_client *client = &gameserver.clients[i];
46
47 if( (i==ignore) || !client->active )
48 continue;
49
50 SteamAPI_ISteamNetworkingSockets_SendMessageToConnection(
51 hSteamNetworkingSockets, client->connection,
52 pData, cbData, nSendFlags, NULL );
53 }
54 }
55
56 static void gameserver_player_join( int index ){
57 struct gameserver_client *joiner = &gameserver.clients[index];
58
59 netmsg_playerjoin join = { .inetmsg_id = k_inetmsg_playerjoin,
60 .index = index };
61 gameserver_send_to_all( index, &join, sizeof(join),
62 k_nSteamNetworkingSend_Reliable );
63
64 /* update the joining user about current connections */
65
66 netmsg_playerusername *username =
67 alloca( sizeof(netmsg_playerusername) + NETWORK_USERNAME_MAX );
68 username->inetmsg_id = k_inetmsg_playerusername;
69
70 netmsg_playeritem *item =
71 alloca( sizeof(netmsg_playeritem) + ADDON_UID_MAX );
72 item->inetmsg_id = k_inetmsg_playeritem;
73
74 for( int i=0; i<vg_list_size(gameserver.clients); i++ ){
75 struct gameserver_client *client = &gameserver.clients[i];
76
77 if( (i==index) || !client->active )
78 continue;
79
80 /* join */
81 netmsg_playerjoin init = { .inetmsg_id = k_inetmsg_playerjoin,
82 .index = i };
83 SteamAPI_ISteamNetworkingSockets_SendMessageToConnection(
84 hSteamNetworkingSockets, joiner->connection,
85 &init, sizeof(init), k_nSteamNetworkingSend_Reliable, NULL );
86
87 /* username */
88 username->index = i;
89 u32 chs = vg_strncpy( client->username, username->name,
90 NETWORK_USERNAME_MAX,
91 k_strncpy_always_add_null );
92 u32 size = sizeof(netmsg_playerusername) + chs + 1;
93 SteamAPI_ISteamNetworkingSockets_SendMessageToConnection(
94 hSteamNetworkingSockets, joiner->connection,
95 username, size, k_nSteamNetworkingSend_Reliable, NULL );
96
97 /* items */
98 for( int j=0; j<k_netmsg_playeritem_max; j++ ){
99 chs = vg_strncpy( client->items[j], item->uid, ADDON_UID_MAX,
100 k_strncpy_always_add_null );
101 item->type_index = j;
102 item->client = i;
103 size = sizeof(netmsg_playeritem) + chs + 1;
104 SteamAPI_ISteamNetworkingSockets_SendMessageToConnection(
105 hSteamNetworkingSockets, joiner->connection,
106 item, size, k_nSteamNetworkingSend_Reliable, NULL );
107 }
108 }
109 }
110
111 static void gameserver_player_leave( int index ){
112 netmsg_playerjoin leave;
113 leave.inetmsg_id = k_inetmsg_playerleave;
114 leave.index = index;
115
116 vg_info( "Player leave (%d)\n", index );
117 gameserver_send_to_all( index, &leave, sizeof(leave),
118 k_nSteamNetworkingSend_Reliable );
119 }
120
121 static void new_client_connecting( HSteamNetConnection client ){
122 int index = -1;
123
124 /* TODO: LRU */
125 for( int i=0; i<vg_list_size(gameserver.clients); i++ ){
126 if( !gameserver.clients[i].active ){
127 index = i;
128 break;
129 }
130 }
131
132 if( index == -1 ){
133 vg_error( "Server full\n" );
134 SteamAPI_ISteamNetworkingSockets_CloseConnection(
135 hSteamNetworkingSockets, client,
136 4500,
137 NULL, 1 );
138 return;
139 }
140
141 EResult accept_status = SteamAPI_ISteamNetworkingSockets_AcceptConnection(
142 hSteamNetworkingSockets, client );
143 if( accept_status == k_EResultOK ){
144 vg_success( "Accepted client (id: %u, index: %d)\n", client, index );
145 memset( &gameserver.clients[index], 0, sizeof(struct gameserver_client) );
146
147 gameserver.clients[index].active = 1;
148 gameserver.clients[index].connection = client;
149
150 SteamAPI_ISteamNetworkingSockets_SetConnectionPollGroup(
151 hSteamNetworkingSockets,
152 client, gameserver.client_group );
153
154 /* Just to be sure */
155 set_connection_authsteamid( client, -1 );
156 gameserver_player_join( index );
157 }
158 else{
159 vg_warn( "Error accepting client (id: %u)\n", client );
160 SteamAPI_ISteamNetworkingSockets_CloseConnection(
161 hSteamNetworkingSockets, client,
162 k_ESteamNetConnectionEnd_Misc_InternalError,
163 NULL, 1 );
164 gameserver.clients[index].active = 0;
165 gameserver.clients[index].connection = 0;
166 }
167 }
168
169 static void on_auth_status( CallbackMsg_t *msg ){
170 SteamNetAuthenticationStatus_t *info = (void *)msg->m_pubParam;
171 vg_info( " Authentication availibility: %s\n",
172 string_ESteamNetworkingAvailability(info->m_eAvail) );
173 vg_info( " %s\n", info->m_debugMsg );
174 }
175
176 static int gameserver_client_index( HSteamNetConnection hconn ){
177 for( int i=0; i<vg_list_size(gameserver.clients); i++ ){
178 struct gameserver_client *client = &gameserver.clients[i];
179
180 if( client->active ){
181 if( client->connection == hconn ){
182 return i;
183 }
184 }
185 }
186 return -1;
187 }
188
189 static void on_connect_status( CallbackMsg_t *msg ){
190 SteamNetConnectionStatusChangedCallback_t *info = (void *)msg->m_pubParam;
191 vg_info( " Connection status changed for %lu\n", info->m_hConn );
192
193 vg_info( " %s -> %s\n",
194 string_ESteamNetworkingConnectionState(info->m_eOldState),
195 string_ESteamNetworkingConnectionState(info->m_info.m_eState) );
196
197 if( info->m_info.m_eState==k_ESteamNetworkingConnectionState_Connecting ){
198 new_client_connecting( info->m_hConn );
199 }
200
201 if( (info->m_info.m_eState ==
202 k_ESteamNetworkingConnectionState_ClosedByPeer ) ||
203 (info->m_info.m_eState ==
204 k_ESteamNetworkingConnectionState_ProblemDetectedLocally ) ){
205
206 int client_id = gameserver_client_index( info->m_hConn );
207 if( client_id != -1 ){
208 struct gameserver_client *client = &gameserver.clients[client_id];
209 client->connection = 0;
210 client->active = 0;
211 gameserver_player_leave(client_id);
212 }
213
214 vg_info( "End reason: %d\n", info->m_info.m_eEndReason );
215 SteamAPI_ISteamNetworkingSockets_CloseConnection(
216 hSteamNetworkingSockets, info->m_hConn, 0, NULL, 0 );
217 }
218 }
219
220 static void gameserver_rx_auth( SteamNetworkingMessage_t *msg ){
221 if( gameserver.auth_mode != eServerModeAuthentication ){
222 vg_error( "Running server without authentication. "
223 "Connection %u tried to authenticate.\n", msg->m_conn );
224 return;
225 }
226
227 if( get_connection_authsteamid( msg ) != k_connection_unauthorized ){
228 vg_warn( "Already authorized this user but app ticket was sent"
229 " again (%u)\n", msg->m_conn );
230 return;
231 }
232
233 vg_low( "Attempting to verify user\n" );
234
235 if( msg->m_cbSize < sizeof(netmsg_auth) ){
236 vg_error( "Malformed auth ticket, too small (%u)\n", msg->m_conn );
237 return;
238 }
239
240 netmsg_auth *auth = msg->m_pData;
241
242 if( msg->m_cbSize < sizeof(netmsg_auth)+auth->ticket_length ||
243 auth->ticket_length > 1024 ){
244 vg_error( "Malformed auth ticket, ticket_length incorrect (%u)\n",
245 auth->ticket_length );
246 return;
247 }
248
249 u8 decrypted[1024];
250 u32 ticket_len = 1024;
251
252 int success = SteamEncryptedAppTicket_BDecryptTicket(
253 auth->ticket, auth->ticket_length, decrypted,
254 &ticket_len, gameserver.app_symmetric_key,
255 k_nSteamEncryptedAppTicketSymmetricKeyLen );
256
257 if( !success ){
258 vg_error( "Failed to decrypt users ticket (client %u)\n", msg->m_conn );
259 vg_error( " ticket length: %u\n", auth->ticket_length );
260
261 SteamAPI_ISteamNetworkingSockets_CloseConnection(
262 hSteamNetworkingSockets,
263 msg->m_conn, 0, NULL, 1 );
264 return;
265 }
266
267 if( SteamEncryptedAppTicket_GetTicketIssueTime( decrypted, ticket_len )){
268 RTime32 ctime = time(NULL),
269 tickettime = SteamEncryptedAppTicket_GetTicketIssueTime(
270 decrypted, ticket_len ),
271 expiretime = tickettime + 24*3*60*60;
272
273 if( ctime > expiretime ){
274 vg_error( "Ticket expired (client %u)\n", msg->m_conn );
275
276 /* TODO: Send expired information */
277 SteamAPI_ISteamNetworkingSockets_CloseConnection(
278 hSteamNetworkingSockets,
279 msg->m_conn, 0, NULL, 1 );
280 return;
281 }
282 }
283
284 CSteamID steamid;
285 SteamEncryptedAppTicket_GetTicketSteamID( decrypted, ticket_len, &steamid );
286 vg_success( "User is authenticated! steamid %lu (%u)\n",
287 steamid.m_unAll64Bits, msg->m_conn );
288
289 set_connection_authsteamid( msg->m_conn, steamid.m_unAll64Bits );
290 }
291
292 static int inet_require_auth( SteamNetworkingMessage_t *msg ){
293 if( gameserver.auth_mode == eServerModeNoAuthentication )
294 return 1;
295
296 if( get_connection_authsteamid( msg ) == k_connection_unauthorized ){
297 vg_warn( "Unauthorized request! Disconnecting client: %u\n",
298 msg->m_conn );
299
300 SteamAPI_ISteamNetworkingSockets_CloseConnection(
301 hSteamNetworkingSockets,
302 msg->m_conn, 0, NULL, 1 );
303
304 return 0;
305 }
306 else return 1;
307 }
308
309 /*
310 * Player updates sent to us
311 * -----------------------------------------------------------------------------
312 */
313
314 static int packet_minsize( SteamNetworkingMessage_t *msg, u32 size ){
315 if( msg->m_cbSize < size ) {
316 vg_error( "Invalid packet size (must be at least %u)\n", size );
317 return 0;
318 }
319 else{
320 return 1;
321 }
322 }
323
324 struct db_set_username_thread_data {
325 u64 steamid;
326 char username[ NETWORK_USERNAME_MAX ];
327 };
328
329 static void gameserver_update_db_username( db_request *db_req ){
330 struct db_set_username_thread_data *inf = (void *)db_req->data;
331
332 if( inf->steamid == k_connection_unauthorized )
333 return;
334
335 int admin = 0;
336 if( inf->steamid == 76561198072130043 )
337 admin = 2;
338
339 db_updateuser( inf->steamid, inf->username, admin );
340 }
341
342 static void gameserver_rx_200_300( SteamNetworkingMessage_t *msg ){
343 netmsg_blank *tmp = msg->m_pData;
344
345 int client_id = gameserver_client_index( msg->m_conn );
346 if( client_id == -1 ) return;
347
348 if( tmp->inetmsg_id == k_inetmsg_playerusername ){
349 if( !packet_minsize( msg, sizeof(netmsg_playerusername)+1 ))
350 return;
351
352 struct gameserver_client *client = &gameserver.clients[ client_id ];
353 netmsg_playerusername *src = msg->m_pData;
354
355 u32 name_len = network_msgstring( src->name, msg->m_cbSize,
356 sizeof(netmsg_playerusername),
357 client->username,
358 NETWORK_USERNAME_MAX );
359
360 /* update other users about this change */
361 netmsg_playerusername *prop = alloca(sizeof(netmsg_playerusername)+
362 NETWORK_USERNAME_MAX );
363
364 prop->inetmsg_id = k_inetmsg_playerusername;
365 prop->index = client_id;
366 u32 chs = vg_strncpy( client->username, prop->name, NETWORK_USERNAME_MAX,
367 k_strncpy_always_add_null );
368
369 vg_info( "client #%d changed name to: %s\n", client_id, prop->name );
370
371 u32 propsize = sizeof(netmsg_playerusername) + chs + 1;
372 gameserver_send_to_all( client_id, prop, propsize,
373 k_nSteamNetworkingSend_Reliable );
374
375 /* update database about this */
376 db_request *call = db_alloc_request(
377 sizeof(struct db_set_username_thread_data) );
378 struct db_set_username_thread_data *inf = (void *)call->data;
379 inf->steamid = get_connection_authsteamid( msg );
380 vg_strncpy( client->username, inf->username,
381 sizeof(inf->username), k_strncpy_always_add_null );
382 call->handler = gameserver_update_db_username;
383 db_send_request( call );
384 }
385 else if( tmp->inetmsg_id == k_inetmsg_playerframe ){
386 /* propogate */
387 netmsg_playerframe *frame = alloca(msg->m_cbSize);
388 memcpy( frame, msg->m_pData, msg->m_cbSize );
389 frame->client = client_id;
390 gameserver_send_to_all( client_id, frame, msg->m_cbSize,
391 k_nSteamNetworkingSend_Unreliable );
392 }
393 else if( tmp->inetmsg_id == k_inetmsg_playeritem ){
394 netmsg_playeritem *item = msg->m_pData;
395
396 /* record */
397 struct gameserver_client *client = &gameserver.clients[ client_id ];
398
399 if( item->type_index >= k_netmsg_playeritem_max ){
400 vg_warn( "Client #%d invalid equip type %u\n",
401 client_id, (u32)item->type_index );
402 return;
403 }
404
405 char *dest = client->items[ item->type_index ];
406
407 network_msgstring( item->uid, msg->m_cbSize, sizeof(netmsg_playeritem),
408 dest, ADDON_UID_MAX );
409
410 vg_info( "Client #%d equiped: [%s] %s\n",
411 client_id,
412 (const char *[]){[k_netmsg_playeritem_board]="board",
413 [k_netmsg_playeritem_player]="player",
414 [k_netmsg_playeritem_world0]="world0",
415 [k_netmsg_playeritem_world1]="world1"
416 }[item->type_index], item->uid );
417
418 /* propogate */
419 netmsg_playeritem *prop = alloca(msg->m_cbSize);
420 memcpy( prop, msg->m_pData, msg->m_cbSize );
421 prop->client = client_id;
422 gameserver_send_to_all( client_id, prop, msg->m_cbSize,
423 k_nSteamNetworkingSend_Reliable );
424 }
425 else {
426 vg_warn( "Unknown inetmsg_id recieved from client. (%u)\n",
427 tmp->inetmsg_id );
428 }
429 }
430
431 static void gameserver_request_respond( enum request_status status,
432 netmsg_request *res, vg_msg *body,
433 SteamNetworkingMessage_t *msg ){
434 int client_id = gameserver_client_index( msg->m_conn );
435 u32 len = 0;
436 if( body ){
437 len = body->cur.co;
438 vg_low( "[%d#%d] Response: %d\n", client_id, (i32)res->id, status );
439 vg_msg_print( body, len );
440 }
441
442 res->status = status;
443
444 SteamAPI_ISteamNetworkingSockets_SendMessageToConnection(
445 hSteamNetworkingSockets, msg->m_conn,
446 res, sizeof(netmsg_request) + len,
447 k_nSteamNetworkingSend_Reliable, NULL );
448 SteamAPI_SteamNetworkingMessage_t_Release( msg );
449 }
450
451 struct user_request_thread_data {
452 SteamNetworkingMessage_t *msg;
453 };
454
455 static u32 gameserver_get_current_week(void){
456 return time(NULL) / (7*24*60*60);
457 }
458
459 static enum request_status gameserver_cat_table(
460 vg_msg *msg,
461 const char *mod, const char *route, u32 week, const char *alias )
462 {
463 char table_name[ DB_TABLE_UID_MAX ];
464 if( !db_get_highscore_table_name( mod, route, week, table_name ) )
465 return k_request_status_out_of_memory;
466
467 char buf[512];
468 vg_str q;
469 vg_strnull( &q, buf, 512 );
470 vg_strcat( &q, "SELECT * FROM \"" );
471 vg_strcat( &q, table_name );
472 vg_strcat( &q, "\" ORDER BY time DESC LIMIT 10;" );
473 if( !vg_strgood(&q) )
474 return k_request_status_out_of_memory;
475
476 sqlite3_stmt *stmt = db_stmt( q.buffer );
477 if( !stmt )
478 return k_request_status_database_error;
479
480 vg_msg_frame( msg, alias );
481 for( u32 i=0; i<10; i ++ ){
482 int fc = sqlite3_step( stmt );
483
484 if( fc == SQLITE_ROW ){
485 i32 time = sqlite3_column_int( stmt, 1 );
486 i64 steamid_i64 = sqlite3_column_int64( stmt, 0 );
487 u64 steamid = *((u64 *)&steamid_i64);
488
489 if( steamid == k_connection_unauthorized )
490 continue;
491
492 vg_msg_frame( msg, "" );
493 vg_msg_wkvu32( msg, "time", time );
494 vg_msg_wkvu64( msg, "steamid", steamid );
495
496 char username[32];
497 if( db_getuserinfo( steamid, username, sizeof(username), NULL ) )
498 vg_msg_wkvstr( msg, "username", username );
499 vg_msg_end_frame( msg );
500 }
501 else if( fc == SQLITE_DONE ){
502 break;
503 }
504 else {
505 log_sqlite3( fc );
506 break;
507 }
508 }
509
510 sqlite3_finalize( stmt );
511 vg_msg_end_frame( msg );
512 return k_request_status_ok;
513 }
514
515 static void gameserver_process_user_request( db_request *db_req ){
516 struct user_request_thread_data *inf = (void *)db_req->data;
517 SteamNetworkingMessage_t *msg = inf->msg;
518
519 int client_id = gameserver_client_index( msg->m_conn );
520 if( client_id == -1 ){
521 SteamAPI_SteamNetworkingMessage_t_Release( msg );
522 return;
523 }
524
525 netmsg_request *req = (netmsg_request *)msg->m_pData;
526 vg_msg data;
527 vg_msg_init( &data, req->q, msg->m_cbSize - sizeof(netmsg_request) );
528
529 /* create response packet */
530 netmsg_request *res = alloca( sizeof(netmsg_request) + 512 );
531 res->inetmsg_id = k_inetmsg_response;
532 res->id = req->id;
533 vg_msg body;
534 vg_msg_init( &body, res->q, 512 );
535
536 const char *endpoint = vg_msg_getkvstr( &data, "endpoint" );
537
538 if( !endpoint ){
539 gameserver_request_respond( k_request_status_invalid_endpoint,
540 res, NULL, msg );
541 return;
542 }
543
544 if( !strcmp( endpoint, "scoreboard" ) ){
545 const char *mod = vg_msg_getkvstr( &data, "mod" );
546 const char *route = vg_msg_getkvstr( &data, "route" );
547 u32 week = vg_msg_getkvu32( &data, "week", 0 );
548
549 if( week == NETWORK_LEADERBOARD_CURRENT_WEEK ){
550 gameserver_cat_table( &body, mod, route,
551 gameserver_get_current_week(), "rows_weekly" );
552 }
553 else if( week == NETWORK_LEADERBOARD_ALLTIME_AND_CURRENT_WEEK ){
554 gameserver_cat_table( &body, mod, route, 0, "rows" );
555 gameserver_cat_table( &body, mod, route,
556 gameserver_get_current_week(), "rows_weekly" );
557 }
558 else
559 gameserver_cat_table( &body, mod, route, week, "rows" );
560
561 if( body.error != k_vg_msg_error_OK ){
562 gameserver_request_respond( k_request_status_out_of_memory,
563 res, NULL, msg );
564 return;
565 }
566
567 gameserver_request_respond( k_request_status_ok, res, &body, msg );
568 }
569 else if( !strcmp( endpoint, "setlap" ) ){
570 /* TODO: we can change userdata to be the client ID and store that in
571 * the client structure. it also would save us scanning the
572 * client array over and over..?
573 */
574 u64 steamid = get_connection_authsteamid( msg );
575 if( steamid == k_connection_unauthorized ){
576 gameserver_request_respond( k_request_status_unauthorized,
577 res, NULL, msg );
578 return;
579 }
580
581 const char *mod = vg_msg_getkvstr( &data, "mod" );
582 const char *route = vg_msg_getkvstr( &data, "route" );
583
584 char weekly_table[ DB_TABLE_UID_MAX ],
585 alltime_table[ DB_TABLE_UID_MAX ];
586
587 u32 week = gameserver_get_current_week();
588
589 if( !db_get_highscore_table_name( mod, route, 0, alltime_table ) ||
590 !db_get_highscore_table_name( mod, route, week, weekly_table ) ){
591 gameserver_request_respond( k_request_status_out_of_memory,
592 res, NULL, msg );
593 return;
594 }
595
596 i32 centiseconds = vg_msg_getkvi32( &data, "time", -1 );
597 if( centiseconds < 5*100 ){
598 gameserver_request_respond( k_request_status_client_error,
599 res, NULL, msg );
600 return;
601 }
602
603 db_writeusertime( alltime_table, steamid, centiseconds, 1 );
604 db_writeusertime( weekly_table, steamid, centiseconds, 1 );
605
606 gameserver_request_respond( k_request_status_ok, res, NULL, msg );
607 }
608 else{
609 gameserver_request_respond( k_request_status_invalid_endpoint,
610 res, NULL, msg );
611 }
612 }
613
614 static void gameserver_rx_300_400( SteamNetworkingMessage_t *msg ){
615 netmsg_blank *tmp = msg->m_pData;
616
617 int client_id = gameserver_client_index( msg->m_conn );
618 if( client_id == -1 ){
619 SteamAPI_SteamNetworkingMessage_t_Release( msg );
620 return;
621 }
622
623 if( tmp->inetmsg_id == k_inetmsg_request ){
624 if( !packet_minsize( msg, sizeof(netmsg_request)+1 ))
625 return;
626
627 db_request *call = db_alloc_request(
628 sizeof(struct user_request_thread_data) );
629 struct user_request_thread_data *inf = (void *)call->data;
630 inf->msg = msg;
631 call->handler = gameserver_process_user_request;
632 db_send_request( call );
633 }
634 else {
635 vg_warn( "Unknown inetmsg_id recieved from client. (%u)\n",
636 tmp->inetmsg_id );
637 SteamAPI_SteamNetworkingMessage_t_Release( msg );
638 }
639 }
640
641 static void poll_connections(void){
642 SteamNetworkingMessage_t *messages[32];
643 int len;
644
645 while(1){
646 len = SteamAPI_ISteamNetworkingSockets_ReceiveMessagesOnPollGroup(
647 hSteamNetworkingSockets,
648 gameserver.client_group, messages, vg_list_size(messages) );
649
650 if( len <= 0 )
651 return;
652
653 for( int i=0; i<len; i++ ){
654 SteamNetworkingMessage_t *msg = messages[i];
655
656 if( msg->m_cbSize < sizeof(netmsg_blank) ){
657 vg_warn( "Discarding message (too small: %d)\n",
658 msg->m_cbSize );
659 continue;
660 }
661
662 netmsg_blank *tmp = msg->m_pData;
663
664 if( (tmp->inetmsg_id >= 200) && (tmp->inetmsg_id < 300) ){
665 gameserver_rx_200_300( msg );
666 SteamAPI_SteamNetworkingMessage_t_Release( msg );
667 }
668 else if( (tmp->inetmsg_id >= 300) && (tmp->inetmsg_id < 400) ){
669 gameserver_rx_300_400( msg );
670 }
671 else{
672 if( tmp->inetmsg_id == k_inetmsg_auth )
673 gameserver_rx_auth( msg );
674 else {
675 vg_warn( "Unknown inetmsg_id recieved from client. (%u)\n",
676 tmp->inetmsg_id );
677 }
678 SteamAPI_SteamNetworkingMessage_t_Release( msg );
679 }
680 }
681 }
682 }
683
684 static u64 seconds_to_server_ticks( double s ){
685 return s / 0.01;
686 }
687
688 static void test_runner( db_request *req ){
689 vg_warn( "RUNNER\n" );
690 char table[DB_TABLE_UID_MAX];
691 if( db_get_highscore_table_name( "sr002-local-mp_mtzero",
692 "Coastal Run", 0, table ) ){
693 if( db_writeusertime( table, 76561198072130043, 232, 1 ) ){
694 vg_success( "Written time\n" );
695 i32 v = db_readusertime( table, 76561198072130043 );
696 vg_success( "Returned time: %u\n", v );
697 }
698 }
699 }
700
701 int main( int argc, char *argv[] ){
702 signal( SIGINT, inthandler );
703 signal( SIGQUIT, inthandler );
704 signal( SIGPIPE, SIG_IGN );
705
706 char *arg;
707 while( vg_argp( argc, argv ) ){
708 if( vg_long_opt( "noauth" ) )
709 gameserver.auth_mode = eServerModeNoAuthentication;
710
711 /* TODO: Options to override, ammend, remove etc */
712 }
713
714 vg_set_mem_quota( 80*1024*1024 );
715 vg_alloc_quota();
716
717 db_init();
718 db_request *req = db_alloc_request(0);
719 if( req ){
720 req->handler = test_runner;
721 db_send_request(req);
722 }
723
724 monitor_start_server(); /* UNIX socket monitor */
725
726 /* steamworks init
727 * --------------------------------------------------------------- */
728 steamworks_ensure_txt( "2103940" );
729 if( gameserver.auth_mode == eServerModeAuthentication ){
730 if( !vg_load_steam_symetric_key( "application_key",
731 gameserver.app_symmetric_key )){
732 return 0;
733 }
734 }
735 else{
736 vg_warn( "Running without user authentication.\n" );
737 }
738
739 if( !SteamGameServer_Init( 0, NETWORK_PORT+1, NETWORK_PORT,
740 gameserver.auth_mode, "1.0.0.0" ) ){
741 vg_error( "SteamGameServer_Init failed\n" );
742 return 0;
743 }
744
745 void *hSteamGameServer = SteamAPI_SteamGameServer();
746 SteamAPI_ISteamGameServer_LogOnAnonymous( hSteamGameServer );
747
748 SteamAPI_ManualDispatch_Init();
749 HSteamPipe hsteampipe = SteamGameServer_GetHSteamPipe();
750 hSteamNetworkingSockets =
751 SteamAPI_SteamGameServerNetworkingSockets_SteamAPI();
752
753 steam_register_callback( k_iSteamNetAuthenticationStatus, on_auth_status );
754 steam_register_callback( k_iSteamNetConnectionStatusChangedCallBack,
755 on_connect_status );
756
757 vg_success( "Steamworks API running\n" );
758 steamworks_event_loop( hsteampipe );
759
760 /*
761 * Create a listener
762 */
763 HSteamListenSocket listener;
764 SteamNetworkingIPAddr localAddr;
765 SteamAPI_SteamNetworkingIPAddr_Clear( &localAddr );
766 localAddr.m_port = NETWORK_PORT;
767
768 listener = SteamAPI_ISteamNetworkingSockets_CreateListenSocketIP(
769 hSteamNetworkingSockets, &localAddr, 0, NULL );
770 gameserver.client_group = SteamAPI_ISteamNetworkingSockets_CreatePollGroup(
771 hSteamNetworkingSockets );
772
773 u64 server_ticks = 8000,
774 last_record_save = 8000,
775 last_scoreboard_gen = 0,
776 last_monitor_heartbeat = 0;
777
778 while( !sig_stop ){
779 monitor_event_loop();
780 steamworks_event_loop( hsteampipe );
781 poll_connections();
782
783 usleep(10000);
784 server_ticks ++;
785
786 if( server_ticks >
787 (last_monitor_heartbeat + seconds_to_server_ticks(10.0))){
788 last_monitor_heartbeat = server_ticks;
789 monitor_heartbeat();
790 }
791
792 if( db_killed() )
793 break;
794 }
795
796 SteamAPI_ISteamNetworkingSockets_DestroyPollGroup( hSteamNetworkingSockets,
797 gameserver.client_group );
798 SteamAPI_ISteamNetworkingSockets_CloseListenSocket(
799 hSteamNetworkingSockets, listener );
800
801 vg_info( "Shutting down\n..." );
802 SteamGameServer_Shutdown();
803 db_kill();
804 db_free();
805
806 return 0;
807 }