Explorar o código

BETA: Fixes:
* Thread-safe rework for CharSummonTable and NPE vulnerabilities fixes.
* Reported by: badboy29
* Minor fix for [6062].
* Reported by: badboy29
* Tested by: badboy29

Zoey76 %!s(int64=12) %!d(string=hai) anos
pai
achega
e125e38dc5

+ 102 - 93
L2J_Server_BETA/java/com/l2jserver/gameserver/datatables/CharSummonTable.java

@@ -23,7 +23,8 @@ import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.sql.Statement;
-import java.util.logging.Level;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.logging.Logger;
 
 import com.l2jserver.Config;
@@ -40,28 +41,30 @@ import com.l2jserver.gameserver.model.items.instance.L2ItemInstance;
 import com.l2jserver.gameserver.model.skills.l2skills.L2SkillSummon;
 import com.l2jserver.gameserver.network.serverpackets.PetItemList;
 
-import gnu.trove.map.hash.TIntIntHashMap;
-
 /**
  * @author Nyaran
  */
 public class CharSummonTable
 {
-	private static Logger _log = Logger.getLogger(CharSummonTable.class.getName());
+	private static final Logger _log = Logger.getLogger(CharSummonTable.class.getName());
+	private static final Map<Integer, Integer> _pets = new ConcurrentHashMap<>();
+	private static final Map<Integer, Integer> _servitors = new ConcurrentHashMap<>();
 	
-	private static final String INIT_SUMMONS = "SELECT ownerId, summonSkillId FROM character_summons";
+	// SQL
 	private static final String INIT_PET = "SELECT ownerId, item_obj_id FROM pets WHERE restore = 'true'";
-	
-	private static final String SAVE_SUMMON = "REPLACE INTO character_summons (ownerId,summonSkillId,curHp,curMp,time) VALUES (?,?,?,?,?)";
+	private static final String INIT_SUMMONS = "SELECT ownerId, summonSkillId FROM character_summons";
 	private static final String LOAD_SUMMON = "SELECT curHp, curMp, time FROM character_summons WHERE ownerId = ? AND summonSkillId = ?";
 	private static final String REMOVE_SUMMON = "DELETE FROM character_summons WHERE ownerId = ?";
+	private static final String SAVE_SUMMON = "REPLACE INTO character_summons (ownerId,summonSkillId,curHp,curMp,time) VALUES (?,?,?,?,?)";
 	
-	private static final TIntIntHashMap _servitors = new TIntIntHashMap();
-	private static final TIntIntHashMap _pets = new TIntIntHashMap();
+	public Map<Integer, Integer> getPets()
+	{
+		return _pets;
+	}
 	
-	public static CharSummonTable getInstance()
+	public Map<Integer, Integer> getServitors()
 	{
-		return SingletonHolder._instance;
+		return _servitors;
 	}
 	
 	public void init()
@@ -79,7 +82,7 @@ public class CharSummonTable
 			}
 			catch (Exception e)
 			{
-				_log.log(Level.SEVERE, getClass().getSimpleName() + ": Error while loading saved summons", e);
+				_log.warning(getClass().getSimpleName() + ": Error while loading saved servitor: " + e);
 			}
 		}
 		
@@ -96,44 +99,91 @@ public class CharSummonTable
 			}
 			catch (Exception e)
 			{
-				_log.log(Level.SEVERE, getClass().getSimpleName() + ": Error while loading saved summons", e);
+				_log.warning(getClass().getSimpleName() + ": Error while loading saved pet: " + e);
 			}
 		}
 	}
 	
-	public TIntIntHashMap getServitors()
-	{
-		return _servitors;
-	}
-	
-	public TIntIntHashMap getPets()
+	public void removeServitor(L2PcInstance activeChar)
 	{
-		return _pets;
+		_servitors.remove(activeChar.getObjectId());
+		try (Connection con = L2DatabaseFactory.getInstance().getConnection();
+			PreparedStatement ps = con.prepareStatement(REMOVE_SUMMON))
+		{
+			ps.setInt(1, activeChar.getObjectId());
+			ps.execute();
+		}
+		catch (SQLException e)
+		{
+			_log.warning(getClass().getSimpleName() + ": Summon cannot be removed: " + e);
+		}
 	}
 	
-	public void saveSummon(L2ServitorInstance summon)
+	public void restorePet(L2PcInstance activeChar)
 	{
-		if ((summon == null) || (summon.getTimeRemaining() <= 0))
+		final L2ItemInstance item = activeChar.getInventory().getItemByObjectId(_pets.get(activeChar.getObjectId()));
+		if (item == null)
 		{
+			_log.warning(getClass().getSimpleName() + ": Null pet summoning item for: " + activeChar);
+			return;
+		}
+		final L2PetData petData = PetDataTable.getInstance().getPetDataByItemId(item.getItemId());
+		if (petData == null)
+		{
+			_log.warning(getClass().getSimpleName() + ": Null pet data for: " + activeChar + " and summoning item: " + item);
+			return;
+		}
+		final L2NpcTemplate npcTemplate = NpcTable.getInstance().getTemplate(petData.getNpcId());
+		if (npcTemplate == null)
+		{
+			_log.warning(getClass().getSimpleName() + ": Null pet NPC template for: " + activeChar + " and pet Id:" + petData.getNpcId());
 			return;
 		}
-		_servitors.put(summon.getOwner().getObjectId(), summon.getReferenceSkill());
 		
-		try (Connection con = L2DatabaseFactory.getInstance().getConnection();
-			PreparedStatement ps = con.prepareStatement(SAVE_SUMMON))
+		final L2PetInstance pet = L2PetInstance.spawnPet(npcTemplate, activeChar, item);
+		if (pet == null)
 		{
-			ps.setInt(1, summon.getOwner().getObjectId());
-			ps.setInt(2, summon.getReferenceSkill());
-			ps.setInt(3, (int) Math.round(summon.getCurrentHp()));
-			ps.setInt(4, (int) Math.round(summon.getCurrentMp()));
-			ps.setInt(5, summon.getTimeRemaining());
-			ps.execute();
+			_log.warning(getClass().getSimpleName() + ": Null pet instance for: " + activeChar + " and pet NPC template:" + npcTemplate);
+			return;
 		}
-		catch (Exception e)
+		
+		pet.setShowSummonAnimation(true);
+		pet.setTitle(activeChar.getName());
+		
+		if (!pet.isRespawned())
+		{
+			pet.setCurrentHp(pet.getMaxHp());
+			pet.setCurrentMp(pet.getMaxMp());
+			pet.getStat().setExp(pet.getExpForThisLevel());
+			pet.setCurrentFed(pet.getMaxFed());
+		}
+		
+		pet.setRunning();
+		
+		if (!pet.isRespawned())
 		{
-			_log.log(Level.SEVERE, getClass().getSimpleName() + ": Failed to store summon [SummonId: " + summon.getNpcId() + "] from Char [CharId: " + summon.getOwner().getObjectId() + "] data", e);
+			pet.store();
 		}
 		
+		activeChar.setPet(pet);
+		
+		pet.spawnMe(activeChar.getX() + 50, activeChar.getY() + 100, activeChar.getZ());
+		pet.startFeed();
+		item.setEnchantLevel(pet.getLevel());
+		
+		if (pet.getCurrentFed() <= 0)
+		{
+			pet.unSummon(activeChar);
+		}
+		else
+		{
+			pet.startFeed();
+		}
+		
+		pet.setFollowStatus(true);
+		
+		pet.getOwner().sendPacket(new PetItemList(pet.getInventory().getItems()));
+		pet.broadcastStatusUpdate();
 	}
 	
 	public void restoreServitor(L2PcInstance activeChar)
@@ -212,86 +262,45 @@ public class CharSummonTable
 					
 					summon.setTimeRemaining(time);
 					
-					// L2World.getInstance().storeObject(summon);
 					summon.spawnMe(activeChar.getX() + 20, activeChar.getY() + 20, activeChar.getZ());
 				}
 			}
 		}
 		catch (SQLException e)
 		{
-			_log.log(Level.WARNING, getClass().getSimpleName() + ": Summon cannot be restored: ", e);
-		}
-	}
-	
-	public void removeServitor(L2PcInstance activeChar)
-	{
-		_servitors.remove(activeChar.getObjectId());
-		try (Connection con = L2DatabaseFactory.getInstance().getConnection();
-			PreparedStatement ps = con.prepareStatement(REMOVE_SUMMON))
-		{
-			ps.setInt(1, activeChar.getObjectId());
-			ps.execute();
-		}
-		catch (SQLException e)
-		{
-			_log.log(Level.WARNING, getClass().getSimpleName() + ": Summon cannot be removed: ", e);
+			_log.warning(getClass().getSimpleName() + ": Servitor cannot be restored: " + e);
 		}
 	}
 	
-	public void restorePet(L2PcInstance activeChar)
+	public void saveSummon(L2ServitorInstance summon)
 	{
-		L2ItemInstance item = activeChar.getInventory().getItemByObjectId(_pets.get(activeChar.getObjectId()));
-		final L2PetData petData = PetDataTable.getInstance().getPetDataByItemId(item.getItemId());
-		L2NpcTemplate npcTemplate = NpcTable.getInstance().getTemplate(petData.getNpcId());
-		
-		if (npcTemplate == null)
-		{
-			return;
-		}
-		
-		final L2PetInstance pet = L2PetInstance.spawnPet(npcTemplate, activeChar, item);
-		if (pet == null)
+		if ((summon == null) || (summon.getTimeRemaining() <= 0))
 		{
 			return;
 		}
 		
-		pet.setShowSummonAnimation(true);
-		pet.setTitle(activeChar.getName());
-		
-		if (!pet.isRespawned())
-		{
-			pet.setCurrentHp(pet.getMaxHp());
-			pet.setCurrentMp(pet.getMaxMp());
-			pet.getStat().setExp(pet.getExpForThisLevel());
-			pet.setCurrentFed(pet.getMaxFed());
-		}
-		
-		pet.setRunning();
-		
-		if (!pet.isRespawned())
-		{
-			pet.store();
-		}
-		
-		activeChar.setPet(pet);
-		
-		pet.spawnMe(activeChar.getX() + 50, activeChar.getY() + 100, activeChar.getZ());
-		pet.startFeed();
-		item.setEnchantLevel(pet.getLevel());
+		_servitors.put(summon.getOwner().getObjectId(), summon.getReferenceSkill());
 		
-		if (pet.getCurrentFed() <= 0)
+		try (Connection con = L2DatabaseFactory.getInstance().getConnection();
+			PreparedStatement ps = con.prepareStatement(SAVE_SUMMON))
 		{
-			pet.unSummon(activeChar);
+			ps.setInt(1, summon.getOwner().getObjectId());
+			ps.setInt(2, summon.getReferenceSkill());
+			ps.setInt(3, (int) Math.round(summon.getCurrentHp()));
+			ps.setInt(4, (int) Math.round(summon.getCurrentMp()));
+			ps.setInt(5, summon.getTimeRemaining());
+			ps.execute();
 		}
-		else
+		catch (Exception e)
 		{
-			pet.startFeed();
+			_log.warning(getClass().getSimpleName() + ": Failed to store summon: " + summon + " from " + summon.getOwner() + ", error: " + e);
 		}
 		
-		pet.setFollowStatus(true);
-		
-		pet.getOwner().sendPacket(new PetItemList(pet.getInventory().getItems()));
-		pet.broadcastStatusUpdate();
+	}
+	
+	public static CharSummonTable getInstance()
+	{
+		return SingletonHolder._instance;
 	}
 	
 	private static class SingletonHolder

+ 4 - 3
L2J_Server_BETA/java/com/l2jserver/gameserver/model/entity/Hero.java

@@ -117,10 +117,11 @@ public class Hero
 		_heroMessage.clear();
 		
 		try (Connection con = L2DatabaseFactory.getInstance().getConnection();
-			Statement s = con.createStatement();
-			ResultSet rset = s.executeQuery(GET_HEROES);
+			Statement s1 = con.createStatement();
+			ResultSet rset = s1.executeQuery(GET_HEROES);
 			PreparedStatement ps = con.prepareStatement(GET_CLAN_ALLY);
-			ResultSet rset2 = s.executeQuery(GET_ALL_HEROES))
+			Statement s2 = con.createStatement();
+			ResultSet rset2 = s2.executeQuery(GET_ALL_HEROES))
 		{
 			while (rset.next())
 			{