network_server.c
changeset 1804 fbe724472bb4
parent 1795 06f7b463ee52
child 1805 1dba0eb4cb47
equal deleted inserted replaced
1803:8fd9dca6d2c6 1804:fbe724472bb4
   773 		// Wrong status for this packet, give a warning to client, and close connection
   773 		// Wrong status for this packet, give a warning to client, and close connection
   774 		SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_NOT_EXPECTED);
   774 		SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_NOT_EXPECTED);
   775 	}
   775 	}
   776 }
   776 }
   777 
   777 
       
   778 static inline const char* GetPlayerIP(const NetworkClientInfo *ci) {return inet_ntoa(*(struct in_addr *)&ci->client_ip);}
       
   779 
       
   780 /** Enforce the command flags.
       
   781  * Eg a server-only command can only be executed by a server, etc.
       
   782  * @param *cp the commandpacket that is going to be checked
       
   783  * @param *ci client information for debugging output to console
       
   784  */
       
   785 static bool CheckCommandFlags(const CommandPacket *cp, const NetworkClientInfo *ci)
       
   786 {
       
   787 	byte flags = GetCommandFlags(cp->cmd);
       
   788 
       
   789 	if (flags & CMD_SERVER && ci->client_index != NETWORK_SERVER_INDEX) {
       
   790 		IConsolePrintF(_iconsole_color_error, "WARNING: server only command from player %d (IP: %s), kicking...", ci->client_playas, GetPlayerIP(ci));
       
   791 		return false;
       
   792 	}
       
   793 
       
   794 	if (flags & CMD_OFFLINE) {
       
   795 		IConsolePrintF(_iconsole_color_error, "WARNING: offline only command from player %d (IP: %s), kicking...", ci->client_playas, GetPlayerIP(ci));
       
   796 		return false;
       
   797 	}
       
   798 	return true;
       
   799 }
       
   800 
       
   801 /** The client has done a command and wants us to handle it
       
   802  * @param *cs the connected client that has sent the command
       
   803  * @param *p the packet in which the command was sent
       
   804  */
   778 DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_COMMAND)
   805 DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_COMMAND)
   779 {
   806 {
   780 	// The client has done a command and wants us to handle it
   807 	NetworkClientState *new_cs;
       
   808 	const NetworkClientInfo *ci;
       
   809 	char *dparam_char;
   781 	uint i;
   810 	uint i;
   782 	byte callback;
   811 	byte callback;
   783 	NetworkClientState *new_cs;
       
   784 	NetworkClientInfo *ci;
       
   785 	char *dparam_char;
       
   786 
   812 
   787 	CommandPacket *cp = malloc(sizeof(CommandPacket));
   813 	CommandPacket *cp = malloc(sizeof(CommandPacket));
   788 
   814 
   789 	// The client was never joined.. so this is impossible, right?
   815 	// The client was never joined.. so this is impossible, right?
   790 	//  Ignore the packet, give the client a warning, and close his connection
   816 	//  Ignore the packet, give the client a warning, and close his connection
   796 	cp->player = NetworkRecv_uint8(cs, p);
   822 	cp->player = NetworkRecv_uint8(cs, p);
   797 	cp->cmd    = NetworkRecv_uint32(cs, p);
   823 	cp->cmd    = NetworkRecv_uint32(cs, p);
   798 	cp->p1     = NetworkRecv_uint32(cs, p);
   824 	cp->p1     = NetworkRecv_uint32(cs, p);
   799 	cp->p2     = NetworkRecv_uint32(cs, p);
   825 	cp->p2     = NetworkRecv_uint32(cs, p);
   800 	cp->tile   = NetworkRecv_uint32(cs, p);
   826 	cp->tile   = NetworkRecv_uint32(cs, p);
   801 	/* We are going to send them byte by byte, because dparam is misused
   827 	/** @todo We are going to send dparams byte by byte, because dparam is misused
   802 	    for chars (if it is used), and else we have a BigEndian / LittleEndian
   828 	 * for charstrings (if it is used), and else we have a Big/Little Endian
   803 	    problem.. we should fix the misuse of dparam... -- TrueLight */
   829 	 * problem.. we should fix the misuse of dparam... -- TrueLight
       
   830 	 */
   804 	dparam_char = (char *)&cp->dp[0];
   831 	dparam_char = (char *)&cp->dp[0];
   805 	for (i = 0; i < lengthof(cp->dp) * 4; i++) {
   832 	for (i = 0; i < lengthof(cp->dp) * 4; i++) {
   806 		*dparam_char = NetworkRecv_uint8(cs, p);
   833 		*dparam_char = NetworkRecv_uint8(cs, p);
   807 		dparam_char++;
   834 		dparam_char++;
   808 	}
   835 	}
   809 
   836 
   810 	callback = NetworkRecv_uint8(cs, p);
   837 	callback = NetworkRecv_uint8(cs, p);
   811 
   838 
   812 	if (cs->quited)
   839 	if (cs->quited) return;
   813 		return;
   840 
       
   841 	ci = DEREF_CLIENT_INFO(cs);
   814 
   842 
   815 	/* Check if cp->cmd is valid */
   843 	/* Check if cp->cmd is valid */
   816 	if (!IsValidCommand(cp->cmd)) {
   844 	if (!IsValidCommand(cp->cmd)) {
       
   845 		IConsolePrintF(_iconsole_color_error, "WARNING: invalid command from player %d (IP: %s).", ci->client_playas, GetPlayerIP(ci));
   817 		SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_NOT_EXPECTED);
   846 		SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_NOT_EXPECTED);
   818 		return;
   847 		return;
   819 	}
   848 	}
   820 
   849 
   821 	ci = DEREF_CLIENT_INFO(cs);
   850 	if (!CheckCommandFlags(cp, ci)) {
   822 	// Only CMD_PLAYER_CTRL is always allowed, for the rest, playas needs
   851 		SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_KICKED);
   823 	//  to match the player in the packet
   852 		return;
   824 	if (!(cp->cmd == CMD_PLAYER_CTRL && cp->p1 == 0) && ci->client_playas-1 != cp->player) {
   853 	}
       
   854 
       
   855 	/** Only CMD_PLAYER_CTRL is always allowed, for the rest, playas needs
       
   856 	 * to match the player in the packet. If it doesn't, the client has done
       
   857 	 * something pretty naughty (or a bug), and will be kicked
       
   858 	 */
       
   859 	if (!(cp->cmd == CMD_PLAYER_CTRL && cp->p1 == 0) && ci->client_playas - 1 != cp->player) {
   825 		IConsolePrintF(_iconsole_color_error, "WARNING: player %d (IP: %s) tried to execute a command as player %d, kicking...",
   860 		IConsolePrintF(_iconsole_color_error, "WARNING: player %d (IP: %s) tried to execute a command as player %d, kicking...",
   826 									 ci->client_playas - 1, inet_ntoa(*(struct in_addr *)&ci->client_ip), cp->player);
   861 									 ci->client_playas, GetPlayerIP(ci), cp->player);
   827 		// The player did a command with the wrong player_id.. bad!!
       
   828 		SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_PLAYER_MISMATCH);
   862 		SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_PLAYER_MISMATCH);
   829 		return;
   863 		return;
   830 	}
   864 	}
   831 	switch (cp->cmd) {
   865 
   832 		/* Player_ctrl is not always allowed */
   866 	/** @todo CMD_PLAYER_CTRL with p1 = 0 announces a new player to the server. To give the
   833 		case CMD_PLAYER_CTRL:
   867 	 * player the correct ID, the server injects p2 and executes the command. Any other p1
   834 		{
   868 	 * is prohibited. Pretty ugly and should be redone together with its function.
   835 			/* cp->p1 == 0, is allowed */
   869 	 * @see CmdPlayerCtrl() players.c:655
   836 			if (cp->p1 == 0) {
   870 	 */
   837 				// UGLY! p2 is mis-used to get the client-id in CmdPlayerCtrl
   871 	if (cp->cmd == CMD_PLAYER_CTRL) {
   838 				cp->p2 = cs - _clients;
   872 		if (cp->p1 != 0) {
   839 			} else {
   873 			SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_CHEATER);
   840 			/* The rest are cheats */
   874 			return;
   841 				SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_CHEATER);
   875 		}
   842 				return;
   876 
   843 			}
   877 		// XXX - UGLY! p2 is mis-used to get the client-id in CmdPlayerCtrl
   844 		} break;
   878 		cp->p2 = cs - _clients;
   845 
   879 	}
   846 		/* Don't allow those commands if server == advertising (considered cheating) */
       
   847 		case CMD_MONEY_CHEAT:
       
   848 		{
       
   849 			if (_network_advertise) {
       
   850 				SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_CHEATER);
       
   851 				return;
       
   852 			}
       
   853 		} break;
       
   854 	}
       
   855 
       
   856 
   880 
   857 	// The frame can be executed in the same frame as the next frame-packet
   881 	// The frame can be executed in the same frame as the next frame-packet
   858 	//  That frame just before that frame is saved in _frame_counter_max
   882 	//  That frame just before that frame is saved in _frame_counter_max
   859 	cp->frame = _frame_counter_max + 1;
   883 	cp->frame = _frame_counter_max + 1;
   860 	cp->next  = NULL;
   884 	cp->next  = NULL;
   863 	//   if they can handle it ;))
   887 	//   if they can handle it ;))
   864 	FOR_ALL_CLIENTS(new_cs) {
   888 	FOR_ALL_CLIENTS(new_cs) {
   865 		if (new_cs->status > STATUS_AUTH) {
   889 		if (new_cs->status > STATUS_AUTH) {
   866 			// Callbacks are only send back to the client who sent them in the
   890 			// Callbacks are only send back to the client who sent them in the
   867 			//  first place. This filters that out.
   891 			//  first place. This filters that out.
   868 			if (new_cs != cs)
   892 			cp->callback = (new_cs != cs) ? 0 : callback;
   869 				cp->callback = 0;
       
   870 			else
       
   871 				cp->callback = callback;
       
   872 
       
   873 			NetworkAddCommandQueue(new_cs, cp);
   893 			NetworkAddCommandQueue(new_cs, cp);
   874 		}
   894 		}
   875 	}
   895 	}
   876 
   896 
   877 	cp->callback = 0;
   897 	cp->callback = 0;