1 #include "network_cmd_ingame.h"
2 #include "network.h"
3 #include "network_file_transfer.h"
4 #include "network_packet.h"
5 #include "network_socket_list.h"
6 #include "network_cmp_pakset.h"
7 #include "network_cmd_scenario.h"
8
9 #include "../dataobj/loadsave.h"
10 #include "../dataobj/gameinfo.h"
11 #include "../dataobj/scenario.h"
12 #include "../simmenu.h"
13 #include "../simversion.h"
14 #include "../gui/simwin.h"
15 #include "../simmesg.h"
16 #include "../simsys.h"
17 #include "../dataobj/environment.h"
18 #include "../player/simplay.h"
19 #include "../gui/player_frame_t.h"
20 #include "../utils/simrandom.h"
21 #include "../utils/cbuffer_t.h"
22 #include "../utils/csv.h"
23 #include "../display/viewport.h"
24 #include "../script/script.h" // callback for calls to tools
25
26
read_from_packet(packet_t * p)27 network_command_t* network_command_t::read_from_packet(packet_t *p)
28 {
29 // check data
30 if (p==NULL || p->has_failed() || !p->check_version()) {
31 delete p;
32 dbg->warning("network_command_t::read_from_packet", "error in packet");
33 return NULL;
34 }
35 network_command_t* nwc = NULL;
36 switch (p->get_id()) {
37 case NWC_GAMEINFO: nwc = new nwc_gameinfo_t(); break;
38 case NWC_NICK: nwc = new nwc_nick_t(); break;
39 case NWC_CHAT: nwc = new nwc_chat_t(); break;
40 case NWC_JOIN: nwc = new nwc_join_t(); break;
41 case NWC_SYNC: nwc = new nwc_sync_t(); break;
42 case NWC_GAME: nwc = new nwc_game_t(); break;
43 case NWC_READY: nwc = new nwc_ready_t(); break;
44 case NWC_TOOL: nwc = new nwc_tool_t(); break;
45 case NWC_CHECK: nwc = new nwc_check_t(); break;
46 case NWC_PAKSETINFO: nwc = new nwc_pakset_info_t(); break;
47 case NWC_SERVICE: nwc = new nwc_service_t(); break;
48 case NWC_AUTH_PLAYER: nwc = new nwc_auth_player_t(); break;
49 case NWC_CHG_PLAYER: nwc = new nwc_chg_player_t(); break;
50 case NWC_SCENARIO: nwc = new nwc_scenario_t(); break;
51 case NWC_SCENARIO_RULES:
52 nwc = new nwc_scenario_rules_t(); break;
53 case NWC_STEP: nwc = new nwc_step_t(); break;
54 default:
55 dbg->warning("network_command_t::read_from_socket", "received unknown packet id %d", p->get_id());
56 }
57 if (nwc) {
58 if (!nwc->receive(p) || p->has_failed()) {
59 dbg->warning("network_command_t::read_from_packet", "error while reading cmd from packet");
60 delete nwc;
61 nwc = NULL;
62 }
63 }
64 return nwc;
65 }
66
67
rdwr()68 void nwc_gameinfo_t::rdwr()
69 {
70 network_command_t::rdwr();
71 packet->rdwr_long(len);
72
73 }
74
75
76 // will send the gameinfo to the client
execute(karte_t * welt)77 bool nwc_gameinfo_t::execute(karte_t *welt)
78 {
79 if (env_t::server) {
80 dbg->message("nwc_gameinfo_t::execute", "");
81 // TODO: check whether we can send a file
82 nwc_gameinfo_t nwgi;
83 // init the rest of the packet
84 SOCKET s = packet->get_sender();
85 loadsave_t fd;
86 if( fd.wr_open( "serverinfo.sve", loadsave_t::xml_bzip2, "info", SERVER_SAVEGAME_VER_NR ) ) {
87 gameinfo_t gi(welt);
88 gi.rdwr( &fd );
89 fd.close();
90 // get gameinfo size
91 FILE *fh = dr_fopen( "serverinfo.sve", "rb" );
92 fseek( fh, 0, SEEK_END );
93 nwgi.len = ftell( fh );
94 rewind( fh );
95 // nwj.client_id = network_get_client_id(s);
96 nwgi.rdwr();
97 if ( nwgi.send( s ) ) {
98 // send gameinfo
99 while( !feof(fh) ) {
100 char buffer[1024];
101 int bytes_read = (int)fread( buffer, 1, sizeof(buffer), fh );
102 uint16 dummy;
103 if( !network_send_data(s,buffer,bytes_read,dummy,250)) {
104 dbg->warning( "nwc_gameinfo_t::execute", "Client closed connection during transfer" );
105 break;
106 }
107 }
108 }
109 else {
110 dbg->warning( "nwc_gameinfo_t::execute", "send of NWC_GAMEINFO failed" );
111 }
112 fclose( fh );
113 dr_remove("serverinfo.sve");
114 }
115 socket_list_t::remove_client( s );
116 }
117 else {
118 len = 0;
119 }
120 return true;
121 }
122
123
rdwr()124 void nwc_nick_t::rdwr()
125 {
126 network_command_t::rdwr();
127 packet->rdwr_str(nickname);
128 }
129
130
131 /**
132 * if server: checks whether nickname is taken and generates default nick
133 */
execute(karte_t * welt)134 bool nwc_nick_t::execute(karte_t *welt)
135 {
136 if(env_t::server) {
137 uint32 client_id = socket_list_t::get_client_id(packet->get_sender());
138
139 if(nickname==NULL) {
140 goto generate_default_nick;
141 }
142
143 // check for same nick
144 for(uint32 i = 0; i<socket_list_t::get_count(); i++) {
145 socket_info_t& info = socket_list_t::get_client(i);
146 if ( (info.state == socket_info_t::playing || i==0)
147 && i != client_id
148 && (nickname == info.nickname.c_str() || nickname == "Admin") )
149 {
150 goto generate_default_nick;
151 }
152 }
153 if (id == NWC_NICK) {
154 // do not call this tool if called by nwc_join_t::execute
155 nwc_nick_t::server_tools(welt, client_id, CHANGE_NICK, nickname);
156 }
157 return true;
158
159 generate_default_nick:
160 // nick exists already
161 // generate default nick
162 cbuffer_t buf;
163 buf.printf("Client#%d", client_id);
164 nickname = (const char*)buf;
165 return true;
166 }
167 else {
168 env_t::nickname = nickname!=NULL ? nickname.c_str() : "(null)";
169 }
170 return true;
171 }
172
173
server_tools(karte_t * welt,uint32 client_id,uint8 what,const char * nick)174 void nwc_nick_t::server_tools(karte_t *welt, uint32 client_id, uint8 what, const char* nick)
175 {
176 if (!socket_list_t::is_valid_client_id(client_id)) {
177 return;
178 }
179 socket_info_t &info = socket_list_t::get_client(client_id);
180
181 cbuffer_t buf;
182 buf.printf("%d,", message_t::general | message_t::local_flag);
183
184 switch(what) {
185 case WELCOME: {
186 // welcome message
187 buf.printf(translator::translate("Welcome, %s!", welt->get_settings().get_name_language_id()),
188 info.nickname.c_str());
189
190 // Log chat message - please don't change order of fields
191 CSV_t csv;
192 csv.add_field( "connect" );
193 csv.add_field( client_id );
194 csv.add_field( info.address.get_str() );
195 csv.add_field( info.nickname.c_str() );
196 dbg->warning( "__ChatLog__", "%s", csv.get_str() );
197 break;
198 }
199
200 case CHANGE_NICK: {
201 if (nick==NULL || info.nickname == nick) {
202 return;
203 }
204 // change nickname
205 buf.printf(translator::translate("%s now known as %s.", welt->get_settings().get_name_language_id()),
206 info.nickname.c_str(), nick);
207
208 // record nickname change
209 for(uint8 i=0; i<PLAYER_UNOWNED; i++) {
210 FOR(slist_tpl<connection_info_t>, &iter, nwc_chg_player_t::company_active_clients[i]) {
211 if (iter == info) {
212 iter.nickname = nick;
213 }
214 }
215 }
216
217 // Log chat message - please don't change order of fields
218 CSV_t csv;
219 csv.add_field( "namechange" );
220 csv.add_field( client_id );
221 csv.add_field( info.address.get_str() );
222 csv.add_field( info.nickname.c_str() );
223 csv.add_field( nick );
224 dbg->warning( "__ChatLog__", "%s", csv.get_str() );
225
226 info.nickname = nick;
227
228 if (client_id > 0) {
229 // send new nickname back to client
230 nwc_nick_t nwc(nick);
231 nwc.send(info.socket);
232 }
233 else {
234 // human at server
235 env_t::nickname = nick;
236 }
237 break;
238 }
239 case FAREWELL: {
240 buf.printf(translator::translate("%s has left.", welt->get_settings().get_name_language_id()),
241 info.nickname.c_str());
242
243 // Log chat message - please don't change order of fields
244 CSV_t csv;
245 csv.add_field( "disconnect" );
246 csv.add_field( client_id );
247 csv.add_field( info.address.get_str() );
248 csv.add_field( info.nickname.c_str() );
249 dbg->warning( "__ChatLog__", "%s", csv.get_str() );
250
251 break;
252 }
253 default: return;
254 }
255 tool_t *tmp_tool = create_tool( TOOL_ADD_MESSAGE | SIMPLE_TOOL );
256 tmp_tool->set_default_param( buf );
257 // queue tool for network
258 nwc_tool_t *nwc = new nwc_tool_t(NULL, tmp_tool, koord3d::invalid, 0, welt->get_map_counter(), true);
259 network_send_server(nwc);
260 // since init always returns false, it is safe to delete immediately
261 delete tmp_tool;
262 }
263
264
rdwr()265 void nwc_chat_t::rdwr()
266 {
267 network_command_t::rdwr();
268 packet->rdwr_str( message );
269 packet->rdwr_byte( player_nr );
270 packet->rdwr_str( clientname );
271 packet->rdwr_str( destination );
272
273 dbg->warning("nwc_chat_t::rdwr", "rdwr message=%s plnr=%d clientname=%s destination=%s", message.c_str(), player_nr, clientname.c_str(), destination.c_str());
274 }
275
276
add_message(karte_t * welt) const277 void nwc_chat_t::add_message (karte_t* welt) const
278 {
279 dbg->warning("nwc_chat_t::add_message", "");
280 cbuffer_t buf; // Output which will be printed to chat window
281
282 FLAGGED_PIXVAL color = player_nr < PLAYER_UNOWNED ? color_idx_to_rgb(welt->get_player( player_nr )->get_player_color1()) : color_idx_to_rgb(COL_WHITE);
283 uint16 flag = message_t::chat;
284
285 if ( destination == NULL ) {
286 if ( player_nr < PLAYER_UNOWNED ) {
287 buf.printf( "%s <%s>: %s", clientname.c_str(), welt->get_player( player_nr )->get_name(), message.c_str() );
288 }
289 else {
290 buf.printf( "%s: %s", clientname.c_str(), message.c_str() );
291 }
292 }
293 else {
294 // Whisper, do not store message in savegame
295 flag |= message_t::local_flag;
296 if ( player_nr < PLAYER_UNOWNED ) {
297 buf.printf( "%s <%s> --> %s: %s", clientname.c_str(), welt->get_player( player_nr )->get_name(), destination.c_str(), message.c_str() );
298 }
299 else {
300 buf.printf( "%s --> %s: %s", clientname.c_str(), destination.c_str(), message.c_str() );
301 }
302 }
303 welt->get_message()->add_message( buf.get_str(), koord::invalid, flag, color, IMG_EMPTY );
304 }
305
306
execute(karte_t * welt)307 bool nwc_chat_t::execute (karte_t* welt)
308 {
309 if ( message == NULL ) {
310 dbg->warning("nwc_chat_t::execute", "null message");
311 return true;
312 }
313
314 // Relay message to all listening clients
315 if ( env_t::server ) {
316 uint32 client_id = socket_list_t::get_client_id( packet->get_sender() );
317
318 dbg->warning("nwc_chat_t::execute", "server, client id: %d", client_id);
319
320 // Clients can only send messages as companies they have unlocked
321 if ( player_nr < PLAYER_UNOWNED && !socket_list_t::get_client( client_id ).is_player_unlocked( player_nr ) ) {
322 dbg->warning("nwc_chat_t::execute", "attempt to send message as locked company by client %d, redirecting to PLAYER_UNOWNED", client_id);
323 player_nr = PLAYER_UNOWNED;
324 }
325
326 // Otherwise forward message as appropriate
327 socket_info_t &info = socket_list_t::get_client( client_id );
328
329 nwc_chat_t* nwchat = new nwc_chat_t( message, player_nr, info.nickname.c_str(), destination );
330
331 if ( destination == NULL ) {
332 // Do not send messages to ourself (server)
333 network_send_all( nwchat, true );
334
335 // Act on message (for display of messages on server, and to keep record of messages for new clients joining)
336 add_message(welt);
337
338 // Log chat message - please don't change order of fields
339 CSV_t csv;
340 csv.add_field( "chat" );
341 csv.add_field( client_id );
342 csv.add_field( info.address.get_str() );
343 csv.add_field( info.nickname.c_str() );
344 csv.add_field( player_nr );
345 csv.add_field( player_nr < PLAYER_UNOWNED ? welt->get_player( player_nr )->get_name() : "" );
346 csv.add_field( message.c_str() );
347 dbg->warning( "__ChatLog__", "%s", csv.get_str() );
348 }
349 else {
350 // Send to a specific client
351 // Look up a client with a matching name, if none matches
352 // send a message back saying that client doesn't exist
353
354 // Check if destination nick exists
355 for ( uint32 i = 0; i < socket_list_t::get_count(); i++ ) {
356 socket_info_t& dest_info = socket_list_t::get_client(i);
357 if ( (dest_info.state == socket_info_t::playing || i == 0 )
358 && i != client_id
359 && destination == dest_info.nickname.c_str() )
360 {
361 nwchat->send( dest_info.socket );
362 }
363 }
364
365 // TODO also send a copy back to sending client for logging
366
367 delete nwchat;
368
369 // Log chat message - please don't change order of fields
370 CSV_t csv;
371 csv.add_field( "private" );
372 csv.add_field( client_id );
373 csv.add_field( info.address.get_str() );
374 csv.add_field( info.nickname.c_str() );
375 csv.add_field( player_nr );
376 csv.add_field( player_nr < PLAYER_UNOWNED ? welt->get_player( player_nr )->get_name() : "" );
377 csv.add_field( destination.c_str() );
378 csv.add_field( message.c_str() );
379 dbg->warning( "__ChatLog__", "%s", csv.get_str() );
380 }
381 }
382 else {
383 add_message(welt);
384 }
385 return true;
386 }
387
388
389
390 SOCKET nwc_join_t::pending_join_client = INVALID_SOCKET;
391
rdwr()392 void nwc_join_t::rdwr()
393 {
394 nwc_nick_t::rdwr();
395 packet->rdwr_long(client_id);
396 packet->rdwr_byte(answer);
397 }
398
399
execute(karte_t * welt)400 bool nwc_join_t::execute(karte_t *welt)
401 {
402 if(env_t::server) {
403 dbg->message("nwc_join_t::execute", "");
404 // TODO: check whether we can send a file
405 nwc_join_t nwj;
406 nwj.client_id = socket_list_t::get_client_id(packet->get_sender());
407 //save nickname
408 if (socket_list_t::is_valid_client_id(nwj.client_id)) {
409 // check nickname
410 nwc_nick_t::execute(welt);
411 nwj.nickname = nickname;
412 socket_list_t::get_client(nwj.client_id).nickname = nickname;
413 }
414
415 // no other joining process active?
416 nwj.answer = socket_list_t::get_client(nwj.client_id).is_active() && pending_join_client == INVALID_SOCKET ? 1 : 0;
417 DBG_MESSAGE( "nwc_join_t::execute", "client_id=%i active=%i pending_join_client=%i active=%d", socket_list_t::get_client_id(packet->get_sender()), socket_list_t::get_client(nwj.client_id).is_active(), pending_join_client, nwj.answer );
418 nwj.rdwr();
419 if( nwj.send( packet->get_sender() ) ) {
420 if( nwj.answer==1 ) {
421 // now send sync command
422 const uint32 new_map_counter = welt->generate_new_map_counter();
423 // since network_send_all() does not include non-playing clients -> send sync command separately to the joining client
424 nwc_sync_t nw_sync(welt->get_sync_steps() + 1, welt->get_map_counter(), nwj.client_id, new_map_counter);
425 nw_sync.rdwr();
426 if( nw_sync.send( packet->get_sender() ) ) {
427 // now send sync command to the server and the remaining clients
428 nwc_sync_t *nws = new nwc_sync_t(welt->get_sync_steps() + 1, welt->get_map_counter(), nwj.client_id, new_map_counter);
429 network_send_all(nws, false);
430 pending_join_client = packet->get_sender();
431 DBG_MESSAGE( "nwc_join_t::execute", "pending_join_client now %i", pending_join_client);
432 // unpause world
433 if (welt->is_paused()) {
434 welt->set_pause(false);
435 }
436 }
437 else {
438 dbg->warning("nwc_join_t::execute", "send of NWC_SYNC to the joining client failed");
439 }
440 }
441 }
442 else {
443 dbg->warning( "nwc_join_t::execute", "send of NWC_JOIN failed" );
444 }
445 }
446 return true;
447 }
448
449
450 /**
451 * saves the history of map counters
452 * the current one is at index zero, the older ones behind
453 */
454 #define MAX_MAP_COUNTERS (7)
455 vector_tpl<uint32> nwc_ready_t::all_map_counters(MAX_MAP_COUNTERS);
456
457
append_map_counter(uint32 map_counter_)458 void nwc_ready_t::append_map_counter(uint32 map_counter_)
459 {
460 if (all_map_counters.get_count() == MAX_MAP_COUNTERS) {
461 all_map_counters.pop_back();
462 }
463 all_map_counters.insert_at(0, map_counter_);
464 }
465
466
clear_map_counters()467 void nwc_ready_t::clear_map_counters()
468 {
469 all_map_counters.clear();
470 }
471
472
execute(karte_t * welt)473 bool nwc_ready_t::execute(karte_t *welt)
474 {
475 if( env_t::server ) {
476 // compare checklist
477 if( welt->is_checklist_available(sync_step) && checklist!=welt->get_checklist_at(sync_step) ) {
478 // client has gone out of sync
479 socket_list_t::remove_client( get_sender() );
480 char buf[256];
481 welt->get_checklist_at(sync_step).print(buf, "server");
482 checklist.print(buf, "client");
483 dbg->warning("nwc_ready_t::execute", "disconnect client due to checklist mismatch : sync_step=%u %s", sync_step, buf);
484 return true;
485 }
486 // check the validity of the map counter
487 FOR(vector_tpl<uint32>, const i, all_map_counters) {
488 if (i == map_counter) {
489 // unpause the sender by sending nwc_ready_t back
490 nwc_ready_t nwc(sync_step, map_counter, checklist);
491 if( !nwc.send( get_sender()) ) {
492 dbg->warning("nwc_ready_t::execute", "send of NWC_READY failed");
493 }
494 return true;
495 }
496 }
497 // no matching map counter -> disconnect client
498 socket_list_t::remove_client( get_sender() );
499 dbg->warning("nwc_ready_t::execute", "disconnect client id=%u due to invalid map counter", our_client_id);
500 }
501 else {
502 dbg->warning("nwc_ready_t::execute", "set sync_step=%d where map_counter=%d", sync_step, map_counter);
503 if( map_counter==welt->get_map_counter() ) {
504 welt->network_game_set_pause(false, sync_step);
505 welt->set_checklist_at(sync_step, checklist);
506 }
507 else {
508 welt->network_disconnect();
509 dbg->warning("nwc_ready_t::execute", "disconnecting due to map counter mismatch");
510 }
511 }
512 return true;
513 }
514
515
rdwr()516 void nwc_ready_t::rdwr()
517 {
518 network_command_t::rdwr();
519 packet->rdwr_long(sync_step);
520 packet->rdwr_long(map_counter);
521 checklist.rdwr(packet);
522 }
523
524
rdwr()525 void nwc_game_t::rdwr()
526 {
527 network_command_t::rdwr();
528 packet->rdwr_long(len);
529 }
530
531
execute(karte_t * welt)532 bool nwc_auth_player_t::execute(karte_t *welt)
533 {
534 dbg->message("nwc_auth_player_t::execute","plnr = %d unlock = %d our_client_id = %d", player_nr, player_unlocked, our_client_id);
535
536 if( env_t::server && !(our_client_id==0 && player_nr==255)) {
537 // sent to server, and not sent to player playing on server
538 if (socket_list_t::is_valid_client_id(our_client_id)) {
539
540 // player activated for this client? or admin connection via nettool?
541 socket_info_t &info = socket_list_t::get_client(our_client_id);
542 if (info.is_player_unlocked(player_nr) || info.state == socket_info_t::admin) {
543 dbg->message("nwc_auth_player_t::execute","set pwd for plnr = %d", player_nr);
544
545 // change password
546 if (welt->get_player(player_nr)->access_password_hash() != hash) {
547 welt->get_player(player_nr)->access_password_hash() = hash;
548 // unlock all clients if new password is empty
549 // otherwise lock all
550 socket_list_t::unlock_player_all(player_nr, hash.empty(), our_client_id);
551 }
552 }
553 else if (player_nr < PLAYER_UNOWNED) {
554 // players with public service player access always pass password checks
555 if( info.is_player_unlocked(1) ) {
556 info.unlock_player(player_nr);
557 }
558 // check password
559 else if (welt->get_player(player_nr)->access_password_hash() == hash) {
560
561 dbg->message("nwc_auth_player_t::execute","unlock plnr = %d at our_client_id = %d", player_nr, our_client_id);
562
563 info.unlock_player(player_nr);
564 }
565 }
566
567 // report back to client who sent the command
568 if (our_client_id == 0) {
569 // unlock player on the server and clear unlock_pending flag
570 welt->get_player(player_nr)->unlock(info.is_player_unlocked(player_nr), false);
571 }
572 else {
573 // send unlock-info to player on the client (to clear unlock_pending flag)
574 nwc_auth_player_t nwc;
575 nwc.player_unlocked = info.player_unlocked;
576 nwc.send( get_sender());
577 }
578 }
579 }
580 else {
581 for(uint8 i=0; i<PLAYER_UNOWNED; i++) {
582 if (player_t *player = welt->get_player(i)) {
583 player->unlock( player_unlocked & (1<<i), false);
584 }
585 }
586 }
587 // update the player window
588 ki_kontroll_t* playerwin = (ki_kontroll_t*)win_get_magic(magic_ki_kontroll_t);
589 if (playerwin) {
590 playerwin->update_data();
591 }
592 return true;
593 }
594
595
init_player_lock_server(karte_t * welt)596 void nwc_auth_player_t::init_player_lock_server(karte_t *welt)
597 {
598 uint16 player_unlocked = 0;
599 for(uint8 i=0; i<PLAYER_UNOWNED; i++) {
600 // player not activated or password matches stored password
601 player_t *player = welt->get_player(i);
602 if (player == NULL || player->access_password_hash() == welt->get_player_password_hash(i) ) {
603 player_unlocked |= 1<<i;
604 }
605 if (player) {
606 player->unlock( player_unlocked & (1<<i), false);
607 }
608 }
609 // get the local server socket
610 socket_info_t &info = socket_list_t::get_client(0);
611 info.player_unlocked = player_unlocked;
612 dbg->message("nwc_auth_player_t::init_player_lock_server", "new = %d", player_unlocked);
613 }
614
615
network_world_command_t(uint16 id,uint32 sync_step,uint32 map_counter)616 network_world_command_t::network_world_command_t(uint16 id, uint32 sync_step, uint32 map_counter)
617 : network_command_t(id)
618 {
619 this->sync_step = sync_step;
620 this->map_counter = map_counter;
621 }
622
623
rdwr()624 void network_world_command_t::rdwr()
625 {
626 network_command_t::rdwr();
627 packet->rdwr_long(sync_step);
628 packet->rdwr_long(map_counter);
629 }
630
631
execute(karte_t * welt)632 bool network_world_command_t::execute(karte_t *welt)
633 {
634 DBG_MESSAGE("network_world_command_t::execute","do_command %d at sync_step %d world now at %d", get_id(), get_sync_step(), welt->get_sync_steps());
635 // want to execute something in the past?
636 if (get_sync_step() < welt->get_sync_steps()) {
637 if (!ignore_old_events()) {
638 dbg->warning("network_world_command_t::execute", "wanted to execute(%d) in the past", get_id());
639 welt->network_disconnect();
640 }
641 return true; // to delete cmd
642 }
643 if (map_counter != welt->get_map_counter()) {
644 // command from another world
645 // could happen if we are behind and still have to execute the next sync command
646 dbg->warning("network_world_command_t::execute", "wanted to execute(%d) from another world (mpc=%d)", get_id(), map_counter);
647 if (env_t::server) {
648 return true; // to delete cmd
649 }
650 // map_counter has to be checked before calling do_command()
651 }
652 welt->command_queue_append(this);
653 return false;
654 }
655
656
rdwr()657 void nwc_sync_t::rdwr()
658 {
659 network_world_command_t::rdwr();
660 packet->rdwr_long(client_id);
661 packet->rdwr_long(new_map_counter);
662 }
663
664
665 // save, load, pause, if server send game
do_command(karte_t * welt)666 void nwc_sync_t::do_command(karte_t *welt)
667 {
668 dbg->warning("nwc_sync_t::do_command", "sync_steps %d", get_sync_step());
669 // save screen coordinates & offsets
670 const koord ij = welt->get_viewport()->get_world_position();
671 const sint16 xoff = welt->get_viewport()->get_x_off();
672 const sint16 yoff = welt->get_viewport()->get_y_off();
673 // save active player
674 const uint8 active_player = welt->get_active_player_nr();
675 // save lock state
676 uint16 player_unlocked = 0;
677 for(uint8 i=0; i<PLAYER_UNOWNED; i++) {
678 if (player_t *player = welt->get_player(i)) {
679 if (!player->is_locked()) {
680 player_unlocked |= 1<<i;
681 }
682 }
683 }
684 // transfer game, all clients need to sync (save, reload, and pause)
685 // now save and send
686 dr_chdir( env_t::user_dir );
687 if( !env_t::server ) {
688 char fn[256];
689 sprintf( fn, "client%i-network.sve", network_get_client_id() );
690
691 bool old_restore_UI = env_t::restore_UI;
692 env_t::restore_UI = true;
693
694 welt->save( fn, loadsave_t::autosave_mode, SERVER_SAVEGAME_VER_NR, false );
695 uint32 old_sync_steps = welt->get_sync_steps();
696 welt->load( fn );
697 env_t::restore_UI = old_restore_UI;
698
699 // pause clients, restore steps
700 welt->network_game_set_pause( true, old_sync_steps);
701
702 // apply new map counter
703 welt->set_map_counter(new_map_counter);
704
705 // tell server we are ready
706 network_command_t *nwc = new nwc_ready_t( old_sync_steps, welt->get_map_counter(), welt->get_checklist_at(old_sync_steps) );
707 network_send_server(nwc);
708 }
709 else {
710 char fn[256];
711 // first save password hashes
712 sprintf( fn, "server%d-pwdhash.sve", env_t::server );
713 loadsave_t file;
714 if(file.wr_open(fn, loadsave_t::zipped, "hashes", SAVEGAME_VER_NR )) {
715 welt->rdwr_player_password_hashes( &file );
716 file.close();
717 }
718
719 // remove passwords before transfer on the server and set default client mask
720 // they will be restored in karte_t::laden
721 uint16 unlocked_players = 0;
722 for( int i=0; i<PLAYER_UNOWNED; i++ ) {
723 player_t *player = welt->get_player(i);
724 if( player==NULL || player->access_password_hash().empty() ) {
725 unlocked_players |= (1<<i);
726 }
727 else {
728 player->access_password_hash().clear();
729 }
730 }
731
732 // save game
733 sprintf( fn, "server%d-network.sve", env_t::server );
734 bool old_restore_UI = env_t::restore_UI;
735 env_t::restore_UI = true;
736 welt->save( fn, loadsave_t::save_mode, SERVER_SAVEGAME_VER_NR, false );
737
738 // ok, now sending game
739 // this sends nwc_game_t
740 const char *err = network_send_file( client_id, fn );
741 if (err) {
742 dbg->warning("nwc_sync_t::do_command","send game failed with: %s", err);
743 }
744
745 uint32 old_sync_steps = welt->get_sync_steps();
746 welt->load( fn );
747 env_t::restore_UI = old_restore_UI;
748
749 // restore steps
750 welt->network_game_set_pause( false, old_sync_steps);
751
752 // apply new map counter
753 welt->set_map_counter(new_map_counter);
754
755 // unpause the client that received the game
756 // we do not want to wait for him (maybe loading failed due to pakset-errors)
757 SOCKET sock = socket_list_t::get_socket(client_id);
758 if( sock != INVALID_SOCKET ) {
759 nwc_ready_t nwc( old_sync_steps, welt->get_map_counter(), welt->get_checklist_at(old_sync_steps) );
760 if (nwc.send(sock)) {
761 socket_list_t::change_state( client_id, socket_info_t::playing);
762 if (socket_list_t::is_valid_client_id(client_id)) {
763 socket_list_t::get_client(client_id).player_unlocked = unlocked_players;
764 // send information about locked state
765 nwc_auth_player_t nwc;
766 nwc.player_unlocked = unlocked_players;
767 nwc.send(sock);
768
769 // welcome message
770 nwc_nick_t::server_tools(welt, client_id, nwc_nick_t::WELCOME, NULL);
771 }
772 }
773 else {
774 dbg->warning( "nwc_sync_t::do_command", "send of NWC_READY failed" );
775 }
776 }
777 nwc_join_t::pending_join_client = INVALID_SOCKET;
778 }
779 // restore screen coordinates & offsets
780 welt->get_viewport()->change_world_position(ij, xoff, yoff);
781 welt->switch_active_player(active_player,true);
782 // restore lock state
783 for(uint8 i=0; i<PLAYER_UNOWNED; i++) {
784 if (player_t *player = welt->get_player(i)) {
785 player->unlock(player_unlocked & (1<<i));
786 }
787 }
788 }
789
790
rdwr()791 void nwc_check_t::rdwr()
792 {
793 network_world_command_t::rdwr();
794 server_checklist.rdwr(packet);
795 packet->rdwr_long(server_sync_step);
796 if (packet->is_loading() && env_t::server) {
797 // server does not receive nwc_check_t-commands
798 packet->failed();
799 }
800 }
801
802
rdwr()803 void network_broadcast_world_command_t::rdwr()
804 {
805 network_world_command_t::rdwr();
806 packet->rdwr_bool(exec);
807
808 if (packet->is_loading() && env_t::server && exec) {
809 // server does not receive exec-commands
810 packet->failed();
811 }
812 }
813
814
execute(karte_t * welt)815 bool network_broadcast_world_command_t::execute(karte_t *welt)
816 {
817 if (exec) {
818 // append to command queue
819 return network_world_command_t::execute(welt);
820 }
821 else if (env_t::server) {
822 // check map_counter
823 if (map_counter != welt->get_map_counter()) {
824 // command from another world
825 dbg->warning("network_broadcast_world_command_t::execute", "wanted to execute(%d) from another world", get_id());
826 return true;
827 }
828 // clone
829 network_broadcast_world_command_t *nwc = clone(welt);
830 if (nwc == NULL) {
831 return true;
832 }
833 // next call to execute will put it in command queue
834 nwc->exec = true;
835 nwc->sync_step = welt->get_sync_steps() + 1;
836 // broadcast
837 network_send_all(nwc, false);
838 // return true to delete this command only if clone() returned something new
839 return true;
840 }
841 else {
842 dbg->warning("network_broadcast_world_command_t::execute", "should not reach here!");
843 }
844 return true;
845 }
846
847
~nwc_chg_player_t()848 nwc_chg_player_t::~nwc_chg_player_t()
849 {
850 delete pending_company_creator;
851 }
852
853
rdwr()854 void nwc_chg_player_t::rdwr()
855 {
856 network_broadcast_world_command_t::rdwr();
857 packet->rdwr_byte(cmd);
858 packet->rdwr_byte(player_nr);
859 packet->rdwr_short(param);
860 packet->rdwr_bool(scripted_call);
861 }
862
863
clone(karte_t * welt)864 network_broadcast_world_command_t* nwc_chg_player_t::clone(karte_t *welt)
865 {
866 if (!socket_list_t::is_valid_client_id(our_client_id)) {
867 return NULL;
868 }
869 socket_info_t const& info = socket_list_t::get_client(our_client_id);
870
871 // scripts only run on server
872 if (socket_list_t::get_client_id(packet->get_sender()) != 0) {
873 // not sent by server, clear flag
874 scripted_call = false;
875 }
876
877 if (!welt->change_player_tool(cmd, player_nr, param, info.is_player_unlocked(1) || scripted_call, false)) {
878 return NULL;
879 }
880 // now create the new command
881 nwc_chg_player_t* nwc = new nwc_chg_player_t(get_sync_step(), get_map_counter(), cmd, player_nr, param);
882
883 // .. and store company_creator if necessary
884 if (cmd == karte_t::new_player) {
885 nwc->pending_company_creator = new connection_info_t(info);
886
887 dbg->warning("nwc_chg_player_t::clone", "pending_company_creator for %d is set to %s/%s", player_nr, info.address.get_str(), info.nickname.c_str());
888 }
889
890 return nwc;
891 }
892
893
894 connection_info_t* nwc_chg_player_t::company_creator[PLAYER_UNOWNED] = {
895 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
896
897 slist_tpl<connection_info_t> nwc_chg_player_t::company_active_clients[PLAYER_UNOWNED];
898
899
company_removed(uint8 player_nr)900 void nwc_chg_player_t::company_removed(uint8 player_nr)
901 {
902 // delete history
903 delete company_creator[player_nr];
904 company_creator[player_nr] = NULL;
905 company_active_clients[player_nr].clear();
906 }
907
908
do_command(karte_t * welt)909 void nwc_chg_player_t::do_command(karte_t *welt)
910 {
911 welt->change_player_tool(cmd, player_nr, param, true, true);
912
913 // store IP of client who created this company
914 if (env_t::server && cmd == karte_t::new_player && player_nr < lengthof(company_creator)) {
915 company_creator[player_nr] = pending_company_creator;
916
917 if (pending_company_creator) {
918 dbg->warning("nwc_chg_player_t::do_command", "company_creator for %d is set to %s/%s", player_nr,
919 pending_company_creator->address.get_str(), pending_company_creator->nickname.c_str());
920 }
921 pending_company_creator = NULL; // to prevent deletion in ~nwc_chg_player_t
922 }
923
924 // reset locked state
925 if (cmd == karte_t::new_player || cmd == karte_t::delete_player) {
926 socket_list_t::unlock_player_all(player_nr, true);
927 }
928
929 // update the window
930 ki_kontroll_t* playerwin = (ki_kontroll_t*)win_get_magic(magic_ki_kontroll_t);
931 if (playerwin) {
932 playerwin->update_data();
933 }
934 }
935
936
nwc_tool_t()937 nwc_tool_t::nwc_tool_t() : network_broadcast_world_command_t(NWC_TOOL, 0, 0),
938 custom_data(custom_data_buf, lengthof(custom_data_buf), true)
939 {
940 tool = NULL;
941 }
942
943
nwc_tool_t(player_t * player,tool_t * tool_,koord3d pos_,uint32 sync_steps,uint32 map_counter,bool init_)944 nwc_tool_t::nwc_tool_t(player_t *player, tool_t *tool_, koord3d pos_, uint32 sync_steps, uint32 map_counter, bool init_)
945 : network_broadcast_world_command_t(NWC_TOOL, sync_steps, map_counter),
946 custom_data(custom_data_buf, lengthof(custom_data_buf), true)
947 {
948 pos = pos_;
949 player_nr = player ? player->get_player_nr() : -1;
950 tool_id = tool_->get_id();
951 wt = tool_->get_waytype();
952 default_param = tool_->get_default_param(player);
953 init = init_;
954 tool_client_id = 0;
955 flags = tool_->flags;
956
957 karte_ptr_t welt;
958 last_sync_step = welt->get_last_checklist_sync_step();
959 last_checklist = welt->get_last_checklist();
960
961 callback_id = tool_->callback_id;
962 // write custom data of tool_ to our internal buffer
963 if (player) {
964 tool_->rdwr_custom_data(&custom_data);
965 }
966 tool = NULL;
967 }
968
969
nwc_tool_t(const nwc_tool_t & nwt)970 nwc_tool_t::nwc_tool_t(const nwc_tool_t &nwt)
971 : network_broadcast_world_command_t(NWC_TOOL, nwt.get_sync_step(), nwt.get_map_counter()),
972 custom_data(custom_data_buf, lengthof(custom_data_buf), true)
973 {
974 pos = nwt.pos;
975 player_nr = nwt.player_nr;
976 tool_id = nwt.tool_id;
977 wt = nwt.wt;
978 default_param = nwt.default_param;
979 init = nwt.init;
980 tool_client_id = nwt.our_client_id;
981 flags = nwt.flags;
982 callback_id = nwt.callback_id;
983 // copy custom data of tool to our internal buffer
984 custom_data.append(nwt.custom_data);
985 tool = NULL;
986 }
987
988
~nwc_tool_t()989 nwc_tool_t::~nwc_tool_t()
990 {
991 delete tool;
992 }
993
994
rdwr()995 void nwc_tool_t::rdwr()
996 {
997 network_broadcast_world_command_t::rdwr();
998 packet->rdwr_long(last_sync_step);
999 last_checklist.rdwr(packet);
1000 packet->rdwr_byte(player_nr);
1001 sint16 posx = pos.x; packet->rdwr_short(posx); pos.x = posx;
1002 sint16 posy = pos.y; packet->rdwr_short(posy); pos.y = posy;
1003 sint8 posz = pos.z; packet->rdwr_byte(posz); pos.z = posz;
1004 packet->rdwr_short(tool_id);
1005 packet->rdwr_short(wt);
1006 packet->rdwr_str(default_param);
1007 packet->rdwr_bool(init);
1008 packet->rdwr_long(tool_client_id);
1009 packet->rdwr_byte(flags);
1010 packet->rdwr_long(callback_id);
1011 // copy custom data of tool to/from packet
1012 if (packet->is_saving()) {
1013 // write to packet
1014 packet->append(custom_data);
1015 }
1016 else {
1017 // read from packet
1018 custom_data.append_tail(*packet);
1019 }
1020
1021 //if (packet->is_loading()) {
1022 dbg->warning("nwc_tool_t::rdwr", "rdwr id=%d client=%d plnr=%d pos=%s tool_id=%d defpar=%s init=%d flags=%d", id, tool_client_id, player_nr, pos.get_str(), tool_id, (char const*)default_param, init, flags);
1023 //}
1024 }
1025
1026
init_tool()1027 void nwc_tool_t::init_tool()
1028 {
1029 delete tool;
1030 // create new memory_rw_t that is in reading mode to read tool data
1031 memory_rw_t new_custom_data(custom_data_buf, custom_data.get_current_index(), false);
1032
1033 if ( (tool = create_tool(tool_id)) ) {
1034 tool->set_default_param(default_param);
1035 tool->rdwr_custom_data(&new_custom_data);
1036 }
1037 }
1038
1039
clone(karte_t * welt)1040 network_broadcast_world_command_t* nwc_tool_t::clone(karte_t *welt)
1041 {
1042 init_tool();
1043 if (tool == NULL) {
1044 // invalid id
1045 return NULL;
1046 }
1047
1048 // do not open dialog windows across network
1049 if ( init ? tool->is_init_network_save() : tool->is_work_network_save() ){
1050 // no reason to send request over network
1051 return NULL;
1052 }
1053
1054 // scenario scripts only run on server
1055 if (socket_list_t::get_client_id(packet->get_sender()) != 0) {
1056 // not sent by server, clear flag
1057 flags &= ~tool_t::WFL_NO_CHK;
1058 }
1059 // scripted calls do not need authentication check
1060 bool const needs_check = (flags & tool_t::WFL_NO_CHK) == 0;
1061
1062 // check authentication and scenario rules
1063 if (needs_check) {
1064
1065 scenario_t *scen = welt->get_scenario();
1066 // check for map editor tools - they need unlocked public player
1067 // scenario should check itself
1068 if (!scen->is_scripted()) {
1069 switch( tool_id ) {
1070 case TOOL_CHANGE_CITY_SIZE | GENERAL_TOOL:
1071 case TOOL_BUILD_HOUSE | GENERAL_TOOL:
1072 case TOOL_BUILD_LAND_CHAIN | GENERAL_TOOL:
1073 case TOOL_CITY_CHAIN | GENERAL_TOOL:
1074 case TOOL_BUILD_FACTORY | GENERAL_TOOL:
1075 case TOOL_LINK_FACTORY | GENERAL_TOOL:
1076 case TOOL_ADD_CITYCAR | GENERAL_TOOL:
1077 case TOOL_INCREASE_INDUSTRY | SIMPLE_TOOL:
1078 case TOOL_STEP_YEAR | SIMPLE_TOOL:
1079 case TOOL_FILL_TREES | SIMPLE_TOOL:
1080 player_nr = 1;
1081 default: ;
1082 }
1083 }
1084
1085 // check whether player is authorized do this
1086 socket_info_t const& info = socket_list_t::get_client(our_client_id);
1087 if ( player_nr < PLAYER_UNOWNED && !info.is_player_unlocked(player_nr) ) {
1088 if (tool_id == (TOOL_ADD_MESSAGE|SIMPLE_TOOL)) {
1089 player_nr = PLAYER_UNOWNED;
1090 }
1091 else {
1092 dbg->warning("nwc_tool_t::clone", "client %d not allowed to act as player %d", our_client_id, player_nr);
1093 return NULL; // indicate failure
1094 }
1095 }
1096 // log that this client acted as this player
1097 if ( player_nr < PLAYER_UNOWNED) {
1098 nwc_chg_player_t::company_active_clients[player_nr].append_unique( connection_info_t(info) );
1099 }
1100
1101 // do scenario checks here, send error message back
1102 if ( scen->is_scripted() ) {
1103 if (!scen->is_tool_allowed(welt->get_player(player_nr), tool_id, wt)) {
1104 dbg->warning("nwc_tool_t::clone", "tool_id=%d wt=%d tool not allowed", tool_id, wt);
1105 // TODO return error message ?
1106 return NULL;
1107 }
1108 if (!init) {
1109 const char *err = scen->is_work_allowed_here(welt->get_player(player_nr), tool_id, wt, pos);
1110 if (err == NULL) {
1111 if (two_click_tool_t *two_ctool = dynamic_cast<two_click_tool_t*>(tool)) {
1112 if (!two_ctool->is_first_click()) {
1113 err = scen->is_work_allowed_here(welt->get_player(player_nr), tool_id, wt, two_ctool->get_start_pos());
1114 }
1115 }
1116 }
1117 if (err) {
1118 nwc_tool_t *nwt = new nwc_tool_t(*this);
1119 nwt->tool_id = TOOL_ERROR_MESSAGE | GENERAL_TOOL;
1120 nwt->default_param = err;
1121 nwt->last_sync_step = welt->get_last_checklist_sync_step();
1122 nwt->last_checklist = welt->get_last_checklist();
1123 dbg->warning("nwc_tool_t::clone", "send sync_steps=%d tool_id=%d error=%s", nwt->get_sync_step(), tool_id, err);
1124 return nwt;
1125 }
1126 }
1127 }
1128 }
1129
1130 // copy data, sets tool_client_id to sender client_id
1131 nwc_tool_t *nwt = new nwc_tool_t(*this);
1132 nwt->last_sync_step = welt->get_last_checklist_sync_step();
1133 nwt->last_checklist = welt->get_last_checklist();
1134 dbg->warning("nwc_tool_t::clone", "send sync_steps=%d tool_id=%d %s", nwt->get_sync_step(), tool_id, init ? "init" : "work");
1135 return nwt;
1136 }
1137
1138
ignore_old_events() const1139 bool nwc_tool_t::ignore_old_events() const
1140 {
1141 // messages are allowed to arrive at any time (return true if message)
1142 return tool_id==(SIMPLE_TOOL|TOOL_ADD_MESSAGE);
1143 }
1144
1145
do_command(karte_t * welt)1146 void nwc_tool_t::do_command(karte_t *welt)
1147 {
1148 if (tool == NULL) {
1149 init_tool();
1150 }
1151 DBG_MESSAGE("nwc_tool_t::do_command", "steps %d tool_id %d %s", get_sync_step(), tool_id, init ? "init" : "work");
1152
1153 // commands are treated differently if they come from this client or not
1154 bool local = tool_client_id == network_get_client_id();
1155
1156 player_t *player = player_nr < PLAYER_UNOWNED ? welt->get_player(player_nr) : NULL;
1157
1158 // before calling work initialize new tool
1159 assert(tool);
1160 bool init_successfull = true;
1161 if (!init) {
1162 // init command was not sent if tool->is_init_network_safe() returned true
1163 tool->flags = 0;
1164 // init tool
1165 init_successfull = tool->init(player);
1166 }
1167
1168 // read custom data (again, necessary for two_click_tool_t)
1169 {
1170 memory_rw_t new_custom_data(custom_data_buf, custom_data.get_current_index(), false);
1171 tool->rdwr_custom_data(&new_custom_data);
1172 }
1173 // set flags correctly
1174 if (local) {
1175 tool->flags = flags | tool_t::WFL_LOCAL;
1176 }
1177 else {
1178 tool->flags = flags & ~tool_t::WFL_LOCAL;
1179 }
1180 DBG_MESSAGE("nwc_tool_t::do_command","id=%d init=%d defpar=%s flag=%d",tool_id&0xFFF,init,(const char*)default_param,tool->flags);
1181
1182 const char* err = NULL;
1183 bool res = false;
1184 // call INIT
1185 if( init ) {
1186 // we should be here only if tool->init() returns false
1187 // no need to change active tool of world
1188 res = tool->init(player);
1189 }
1190 // call WORK
1191 else if (init_successfull) {
1192 // remove preview tiles of active tool
1193 two_click_tool_t *active_tool = dynamic_cast<two_click_tool_t*>(welt->get_tool(welt->get_active_player_nr()));
1194 if(active_tool && active_tool->remove_preview_necessary()) {
1195 active_tool->cleanup();
1196 }
1197 err = tool->work( player, pos );
1198 // only local players get the callback
1199 if (local && callback_id == 0) {
1200 player->tell_tool_result(tool, pos, err);
1201 }
1202 if (err) {
1203 dbg->warning("nwc_tool_t::do_command","failed with '%s'",err);
1204 }
1205 tool->exit(player);
1206 }
1207 else {
1208 err = "Init was not succesfull, returned false.";
1209 }
1210
1211 // callback to script here
1212 if (local && callback_id != 0) {
1213 if (init) {
1214 suspended_scripts_t::tell_return_value(callback_id, res);
1215 }
1216 else {
1217 suspended_scripts_t::tell_return_value(callback_id, err);
1218 }
1219 }
1220 }
1221
1222
1223 extern address_list_t blacklist;
1224
execute(karte_t * welt)1225 bool nwc_service_t::execute(karte_t *welt)
1226 {
1227 if (flag>=SRVC_MAX || !env_t::server) {
1228 // wrong flag, no server
1229 return true; // to delete
1230 }
1231 // check whether admin connection is established
1232 const uint32 sender_id = socket_list_t::get_client_id(packet->get_sender());
1233 const bool admin_logged_in = socket_list_t::get_client(sender_id).state == socket_info_t::admin;
1234 if (!admin_logged_in && (flag != SRVC_LOGIN_ADMIN && flag != SRVC_ANNOUNCE_SERVER) ) {
1235 return true; // to delete
1236 }
1237
1238 switch(flag) {
1239 case SRVC_LOGIN_ADMIN: {
1240 nwc_service_t nws;
1241 nws.flag = SRVC_LOGIN_ADMIN;
1242 // check password
1243 bool ok = !env_t::server_admin_pw.empty() && env_t::server_admin_pw.compare(text)==0;
1244 if (ok) {
1245 socket_list_t::get_client(sender_id).state = socket_info_t::admin;
1246 }
1247 nws.number = ok ? sender_id : 0;
1248 nws.send(packet->get_sender());
1249 break;
1250 }
1251
1252 case SRVC_ANNOUNCE_SERVER:
1253 // Startup announce, to force full details resend
1254 welt->announce_server( 0 );
1255 break;
1256
1257 case SRVC_GET_CLIENT_LIST: {
1258 nwc_service_t nws;
1259 nws.flag = SRVC_GET_CLIENT_LIST;
1260 // send, socket list will be written in rdwr
1261 nws.send(packet->get_sender());
1262 break;
1263 }
1264
1265 case SRVC_KICK_CLIENT:
1266 case SRVC_BAN_CLIENT: {
1267 bool ban = flag == SRVC_BAN_CLIENT;
1268 uint32 client_id = number;
1269 net_address_t address;
1270 SOCKET kick = socket_list_t::get_socket(client_id);
1271 if (kick!=INVALID_SOCKET) {
1272 socket_info_t &info = socket_list_t::get_client(client_id);
1273 address.ip = info.address.ip;
1274 if (info.state == socket_info_t::playing) {
1275 socket_list_t::remove_client(info.socket);
1276 }
1277 }
1278 if (ban && address.ip) {
1279 fd_set fd;
1280 FD_ZERO(&fd);
1281 socket_list_t::fill_set(&fd);
1282 socket_list_t::client_socket_iterator_t iter(&fd);
1283 while(iter.next()) {
1284 SOCKET sock = iter.get_current();
1285 socket_info_t& info = socket_list_t::get_client(socket_list_t::get_client_id(sock));
1286 if (address.matches(info.address)) {
1287 socket_list_t::remove_client(sock);
1288 }
1289 }
1290 blacklist.append(address);
1291 }
1292 break;
1293 }
1294 case SRVC_GET_BLACK_LIST: {
1295 nwc_service_t nws;
1296 nws.flag = SRVC_GET_BLACK_LIST;
1297 // send, blacklist will be written in rdwr
1298 nws.send(packet->get_sender());
1299 break;
1300 }
1301
1302 case SRVC_BAN_IP:
1303 case SRVC_UNBAN_IP: {
1304 net_address_t address(text);
1305 if (address.ip) {
1306 if (flag==SRVC_BAN_IP) {
1307 blacklist.append(address);
1308 }
1309 else {
1310 blacklist.remove(address);
1311 }
1312 }
1313 break;
1314 }
1315
1316 case SRVC_ADMIN_MSG:
1317 if (text) {
1318 // Send message to all clients as Public Service
1319 // with reserved username Admin
1320 nwc_chat_t* nwchat = new nwc_chat_t( text, 1, "Admin" );
1321 network_send_all( nwchat, false );
1322
1323 // Log chat message - please don't change order of fields
1324 CSV_t csv;
1325 csv.add_field( "adminmsg" );
1326 csv.add_field( text );
1327 dbg->warning( "__ChatLog__", "%s", csv.get_str() );
1328 }
1329 break;
1330
1331 case SRVC_SHUTDOWN: {
1332 welt->stop( true );
1333 break;
1334 }
1335
1336 case SRVC_FORCE_SYNC: {
1337 const uint32 new_map_counter = welt->generate_new_map_counter();
1338 nwc_sync_t *nw_sync = new nwc_sync_t(welt->get_sync_steps() + 1, welt->get_map_counter(), -1, new_map_counter);
1339
1340 if (welt->is_paused()) {
1341 if (socket_list_t::get_playing_clients() == 0) {
1342 // we can save directly without disturbing clients
1343 nw_sync->do_command(welt);
1344 }
1345 delete nw_sync;
1346 }
1347 else {
1348 // send sync command
1349 network_send_all(nw_sync, false);
1350 }
1351 break;
1352 }
1353
1354 case SRVC_GET_COMPANY_LIST:
1355 case SRVC_GET_COMPANY_INFO: {
1356 bool detailed = flag == SRVC_GET_COMPANY_INFO && number < PLAYER_UNOWNED;
1357 uint8 min_index = detailed ? number : 0;
1358 uint8 max_index = detailed ? number+1 : PLAYER_UNOWNED;
1359
1360 cbuffer_t buf;
1361 for (uint8 i=min_index; i<max_index; i++) {
1362 if (player_t *player = welt->get_player(i)) {
1363 buf.printf("Company #%d: %s\n", i, player->get_name());
1364 buf.printf(" Password: %sset\n", player->access_password_hash().empty() ? "NOT " :"");
1365 // print creator information
1366 if (i < lengthof(nwc_chg_player_t::company_creator)) {
1367 if (connection_info_t const* creator = nwc_chg_player_t::company_creator[i]) {
1368 buf.printf(" founded by %s at %s\n", creator->nickname.c_str(), creator->address.get_str());
1369 }
1370 }
1371 // print clients who have this player unlocked
1372 for(uint32 j = 0; j < socket_list_t::get_count(); j++) {
1373 socket_info_t const& info = socket_list_t::get_client(j);
1374 if (info.is_active() && info.is_player_unlocked(i)) {
1375 buf.printf(" unlocked for [%d] %s at %s\n", j, info.nickname.c_str(), info.address.get_str());
1376 }
1377 }
1378 // print clients who played for this company
1379 uint32 j=0;
1380 FOR(slist_tpl<connection_info_t>, &iter, nwc_chg_player_t::company_active_clients[i]) {
1381 if (!detailed && j > 3 && nwc_chg_player_t::company_active_clients[i].get_count() > 5) {
1382 buf.printf(" .. and %d more.\n", nwc_chg_player_t::company_active_clients[i].get_count()-j);
1383 break;
1384 }
1385 buf.printf(" played by %s at %s\n", iter.nickname.c_str(), iter.address.get_str());
1386 j++;
1387 }
1388 }
1389 }
1390
1391 nwc_service_t nws;
1392 nws.flag = flag;
1393 nws.text = strdup(buf);
1394 if (text && (strlen(text) > MAX_PACKET_LEN - 256)) {
1395 text[MAX_PACKET_LEN - 256] = 0;
1396 }
1397 nws.send(packet->get_sender());
1398 break;
1399 }
1400
1401 case SRVC_UNLOCK_COMPANY: {
1402 if (number >= PLAYER_UNOWNED) {
1403 break; // invalid number
1404 }
1405 uint8 player_nr = number;
1406 // empty password
1407 player_t *player = welt->get_player(player_nr);
1408 if (player) {
1409 player->access_password_hash().clear();
1410 // unlock all clients
1411 socket_list_t::unlock_player_all(player_nr, true, packet->get_sender());
1412 // unlock player on the server
1413 player->unlock(true, false);
1414 }
1415 break;
1416 }
1417
1418 case SRVC_REMOVE_COMPANY: {
1419 if (number >= PLAYER_UNOWNED) {
1420 break; // invalid number
1421 }
1422
1423 nwc_chg_player_t *nwc = new nwc_chg_player_t(welt->get_sync_steps(), welt->get_map_counter(), karte_t::delete_player, number);
1424 if (nwc->execute(welt)) {
1425 delete nwc;
1426 }
1427 break;
1428 }
1429
1430 default: ;
1431 }
1432 return true; // to delete
1433 }
1434