gameserver monitor initial work
[carveJwlIkooP6JGAAIwe30JlM.git] / network.c
1 VG_STATIC void scores_update(void);
2
3 VG_STATIC void on_auth_ticket_recieved( void *result, void *context ){
4 EncryptedAppTicketResponse_t *response = result;
5
6 if( response->m_eResult == k_EResultOK ){
7 vg_info( " New app ticket ready\n" );
8 }
9 else{
10 vg_warn( " Could not request new encrypted app ticket (%u)\n",
11 response->m_eResult );
12 }
13
14 if( SteamAPI_ISteamUser_GetEncryptedAppTicket( hSteamUser,
15 network_client.app_symmetric_key,
16 vg_list_size(network_client.app_symmetric_key),
17 &network_client.app_key_length )){
18 vg_success( " Loaded app ticket\n" );
19 }
20 else{
21 vg_error( " No ticket availible\n" );
22 network_client.app_key_length = 0;
23 }
24 }
25
26 VG_STATIC void request_auth_ticket(void){
27 /*
28 * TODO Check for one thats cached on the disk and load it.
29 * This might be OK though because steam seems to cache the result
30 */
31
32 vg_info( "Requesting new authorization ticket\n" );
33
34 vg_steam_async_call *call = vg_alloc_async_steam_api_call();
35 call->userdata = NULL;
36 call->p_handler = on_auth_ticket_recieved;
37 call->id =
38 SteamAPI_ISteamUser_RequestEncryptedAppTicket( hSteamUser, NULL, 0 );
39 }
40
41 VG_STATIC void send_auth_ticket(void){
42 u32 size = sizeof(netmsg_auth) + network_client.app_key_length;
43 netmsg_auth *auth = alloca(size);
44
45 auth->inetmsg_id = k_inetmsg_auth;
46 auth->ticket_length = network_client.app_key_length;
47 for( int i=0; i<network_client.app_key_length; i++ )
48 auth->ticket[i] = network_client.app_symmetric_key[i];
49
50 SteamAPI_ISteamNetworkingSockets_SendMessageToConnection(
51 hSteamNetworkingSockets, network_client.remote, auth, size,
52 k_nSteamNetworkingSend_Reliable, NULL );
53 }
54
55 VG_STATIC void send_score_request(void){
56 vg_info( "Requesting scores\n" );
57 netmsg_scores_request req;
58 req.inetmsg_id = k_inetmsg_scores_request;
59
60 SteamAPI_ISteamNetworkingSockets_SendMessageToConnection(
61 hSteamNetworkingSockets, network_client.remote,
62 &req, sizeof(netmsg_scores_request),
63 k_nSteamNetworkingSend_Reliable, NULL );
64 }
65
66 VG_STATIC void send_score_update(void){
67 vg_info( "Sending scores\n" );
68 u32 size = sizeof(netmsg_set_score) +
69 vg_list_size(track_infos)*sizeof(struct netmsg_score_record);
70 netmsg_set_score *setscore = alloca( size );
71 setscore->inetmsg_id = k_inetmsg_set_score;
72
73 int count = 0;
74 for( u32 i=0; i<vg_list_size(track_infos); i++ ){
75 if( track_infos[i].push ){
76 track_infos[i].push = 0;
77
78 #if 0
79 highscore_record *user_record = highscore_find_user_record( 0, i );
80
81 if( !user_record ){
82 vg_error( "No score set but tried to upload for track %u\n", i );
83 continue;
84 }
85 #endif
86 highscore_record *user_record = &track_infos[i].record;
87
88 setscore->records[count].trackid = i;
89 setscore->records[count].playerid = 0;
90 setscore->records[count].points = user_record->points;
91 setscore->records[count].time = user_record->time;
92
93 count ++;
94 }
95 }
96
97 if( count == 0 ) return;
98 u32 send_size = sizeof(netmsg_set_score) +
99 count*sizeof(struct netmsg_score_record);
100 setscore->record_count = count;
101
102 SteamAPI_ISteamNetworkingSockets_SendMessageToConnection(
103 hSteamNetworkingSockets, network_client.remote, setscore, send_size,
104 k_nSteamNetworkingSend_Reliable, NULL );
105 }
106
107 VG_STATIC void send_nickname(void){
108 netmsg_set_nickname nick;
109 nick.inetmsg_id = k_inetmsg_set_nickname;
110
111 memset( nick.nickname, 0, 16 );
112 vg_strncpy( steam_username_at_startup, nick.nickname, 16,
113 k_strncpy_allow_cutoff );
114
115 SteamAPI_ISteamNetworkingSockets_SendMessageToConnection(
116 hSteamNetworkingSockets, network_client.remote,
117 &nick, sizeof(netmsg_set_nickname),
118 k_nSteamNetworkingSend_Reliable, NULL );
119
120 network_client.name_update = 0;
121 }
122
123 static void network_send_playerframe(void){
124 netmsg_playerframe frame;
125 frame.inetmsg_id = k_inetmsg_playerframe;
126 v3_copy( localplayer.rb.co, frame.pos_temp );
127
128 SteamAPI_ISteamNetworkingSockets_SendMessageToConnection(
129 hSteamNetworkingSockets, network_client.remote,
130 &frame, sizeof(frame),
131 k_nSteamNetworkingSend_Unreliable, NULL );
132 }
133
134 VG_STATIC void server_routine_update(void){
135 if( network_client.name_update )
136 send_nickname();
137
138 send_score_update();
139 send_score_request();
140 }
141
142 VG_STATIC void on_server_connect_status( CallbackMsg_t *msg ){
143 SteamNetConnectionStatusChangedCallback_t *info = (void *)msg->m_pubParam;
144 vg_info( " Connection status changed for %lu\n", info->m_hConn );
145 vg_info( " %s -> %s\n",
146 string_ESteamNetworkingConnectionState(info->m_eOldState),
147 string_ESteamNetworkingConnectionState(info->m_info.m_eState) );
148
149 if( info->m_hConn == network_client.remote ){
150 network_client.state = info->m_info.m_eState;
151 if( info->m_info.m_eState == k_ESteamNetworkingConnectionState_Connected ){
152 vg_success(" Connected to remote server.. authenticating\n");
153 send_auth_ticket();
154 }
155 }
156 else{
157 vg_warn( " Recieved signal from unknown connection\n" );
158 }
159 }
160
161 VG_STATIC void network_connect(void){
162 /* Connect to server if not connected */
163 SteamNetworkingIPAddr remoteAddr;
164
165 #ifdef SR_USE_LOCALHOST
166 SteamAPI_SteamNetworkingIPAddr_SetIPv6LocalHost( &remoteAddr, 27402 );
167 #else
168 const char *server_lon1 = "46.101.34.155:27402";
169 SteamAPI_SteamNetworkingIPAddr_ParseString( &remoteAddr, server_lon1 );
170 #endif
171
172 char buf[256];
173 SteamAPI_SteamNetworkingIPAddr_ToString( &remoteAddr, buf, 256, 1 );
174 vg_info( "connect to: %s\n", buf );
175
176 network_client.remote = SteamAPI_ISteamNetworkingSockets_ConnectByIPAddress(
177 hSteamNetworkingSockets, &remoteAddr, 0, NULL );
178 }
179
180 VG_STATIC void on_inet_scoreboard( SteamNetworkingMessage_t *msg ){
181 netmsg_scoreboard *sb = msg->m_pData;
182
183 u32 base_size = sizeof(netmsg_scoreboard)-
184 sizeof(struct netmsg_board)*vg_list_size(track_infos),
185 expected = base_size+sizeof(struct netmsg_board)*sb->board_count;
186
187 if( msg->m_cbSize != expected ){
188 vg_error( "Server scoreboard was corrupted. Size: %u != %u\n",
189 msg->m_cbSize, expected );
190 }
191 else{
192 if( vg_list_size(track_infos) > sb->board_count )
193 vg_warn( "Server is out of date, not enough boards recieved\n");
194 else if( vg_list_size(track_infos) < sb->board_count )
195 vg_warn( "Client out of date, server sent more boards than we have\n");
196 else
197 vg_success( "Recieved new scoreboards from server\n" );
198
199 for( int i=0; i < vg_min(sb->board_count,vg_list_size(track_infos)); i++){
200 scoreboard_client_data.boards[i] = sb->boards[i];
201 highscores_board_printf( stdout, sb->boards[i].data, 10 );
202 }
203 }
204
205 /* We dont need to stay on the server currently */
206 SteamAPI_ISteamNetworkingSockets_CloseConnection(
207 hSteamNetworkingSockets, network_client.remote, 0, NULL, 1 );
208
209 network_scores_updated = 1;
210 }
211
212 VG_STATIC void poll_remote_connection(void){
213 SteamNetworkingMessage_t *messages[32];
214 int len;
215
216 for( int i=0; i<10; i++ ){
217 len = SteamAPI_ISteamNetworkingSockets_ReceiveMessagesOnConnection(
218 hSteamNetworkingSockets, network_client.remote,
219 messages, vg_list_size(messages));
220
221 if( len <= 0 )
222 return;
223
224 for( int i=0; i<len; i++ ){
225 SteamNetworkingMessage_t *msg = messages[i];
226
227 if( msg->m_cbSize < sizeof(netmsg_blank) ){
228 vg_warn( "Discarding message (too small: %d)\n", msg->m_cbSize );
229 continue;
230 }
231
232 netmsg_blank *tmp = msg->m_pData;
233
234 if( tmp->inetmsg_id == k_inetmsg_scoreboard )
235 on_inet_scoreboard( msg );
236
237 SteamAPI_SteamNetworkingMessage_t_Release( msg );
238 }
239 }
240 }
241
242 VG_STATIC void network_update(void){
243 if( !steam_ready )
244 return;
245
246 ESteamNetworkingConnectionState state = network_client.state;
247
248 if( state == k_ESteamNetworkingConnectionState_Connected ){
249 poll_remote_connection();
250 f64 frame_delta = vg.time_real - network_client.last_frame;
251
252 if( frame_delta > 0.1 ){
253 network_client.last_frame = vg.time_real;
254 network_send_playerframe();
255 }
256 }
257 else {
258 if( (state == k_ESteamNetworkingConnectionState_Connecting) ||
259 (state == k_ESteamNetworkingConnectionState_FindingRoute) ){
260 return;
261 }
262 else {
263 f64 waited = vg.time_real - network_client.last_attempt,
264 min_wait = 1.0;
265
266 if( network_client.retries > 5 )
267 min_wait = 60.0;
268
269 if( waited < min_wait )
270 return;
271
272 network_connect();
273 network_client.retries ++;
274 network_client.last_attempt = vg.time_real;
275 }
276 }
277 }
278
279 VG_STATIC void network_init(void){
280 if( steam_ready ){
281 steam_register_callback( k_iSteamNetConnectionStatusChangedCallBack,
282 on_server_connect_status );
283 request_auth_ticket();
284 }
285 }
286
287 VG_STATIC void network_end(void){
288 /* TODO: Send buffered highscores that were not already */
289 if( (network_client.state == k_ESteamNetworkingConnectionState_Connected) ||
290 (network_client.state == k_ESteamNetworkingConnectionState_Connecting) )
291 {
292 SteamAPI_ISteamNetworkingSockets_CloseConnection(
293 hSteamNetworkingSockets, network_client.remote, 0, NULL, 1 );
294 }
295 }