Fork of Poseidon providing Bukkit #1060 to older Beta versions (b1.0-b1.7.3)
1package net.minecraft.server;
2
3import java.io.BufferedOutputStream;
4import java.io.DataInputStream;
5import java.io.DataOutputStream;
6import java.net.InetSocketAddress;
7import java.net.Socket;
8import java.net.SocketAddress;
9import java.net.SocketException;
10import java.util.ArrayList;
11import java.util.Collections;
12import java.util.List;
13
14import org.bukkit.Bukkit;
15import org.bukkit.ChatColor;
16
17import com.legacyminecraft.poseidon.PoseidonConfig;
18import com.legacyminecraft.poseidon.event.PlayerReceivePacketEvent;
19
20import uk.betacraft.uberbukkit.Uberbukkit;
21import uk.betacraft.uberbukkit.protocol.Protocol;
22
23public class NetworkManager {
24
25 public static final Object a = new Object();
26 public static int b;
27 public static int c;
28 private Object g = new Object();
29 public Socket socket; // CraftBukkit - private -> public
30 private SocketAddress i; //Project Poseidon - remove final statement
31 private DataInputStream input;
32 private DataOutputStream output;
33 private boolean l = true;
34 private List m = Collections.synchronizedList(new ArrayList());
35 private List highPriorityQueue = Collections.synchronizedList(new ArrayList());
36 private List lowPriorityQueue = Collections.synchronizedList(new ArrayList());
37 private NetHandler p;
38 private boolean q = false;
39 private Thread r;
40 private Thread s;
41 private boolean t = false;
42 private String u = "";
43 private Object[] v;
44 private int w = 0;
45 private int x = 0;
46 public static int[] d = new int[256];
47 public static int[] e = new int[256];
48 public int f = 0;
49 private int lowPriorityQueueDelay = 50;
50 private final boolean firePacketEvents;
51
52 private final boolean spamDetection;
53
54 private final int threshold;
55
56 // uberbukkit
57 public int pvn = 0;
58 public Protocol protocol = null;
59
60 public NetworkManager(Socket socket, String s, NetHandler nethandler) {
61 this.socket = socket;
62 this.i = socket.getRemoteSocketAddress();
63 this.p = nethandler;
64
65 //Poseidon
66 this.firePacketEvents = PoseidonConfig.getInstance().getBoolean("settings.packet-events.enabled", false);
67 this.spamDetection = PoseidonConfig.getInstance().getBoolean("settings.packet-spam-detection.enabled", true);
68 this.threshold = PoseidonConfig.getInstance().getInt("settings.packet-spam-detection.threshold", 1000);
69
70 //Debug for packet spam detection
71// System.out.println("[Poseidon] Packet spam detection is " + (this.spamDetection ? "enabled" : "disabled") + " with a threshold of " + this.threshold + " packets");
72
73 // CraftBukkit start - IPv6 stack in Java on BSD/OSX doesn't support setTrafficClass
74 try {
75 socket.setTrafficClass(24);
76 } catch (SocketException e) {
77 }
78 // CraftBukkit end
79
80 try {
81 // CraftBukkit start - cant compile these outside the try
82 socket.setSoTimeout(30000);
83 if (PoseidonConfig.getEmptyNode().getBoolean("settings.enable-tpc-nodelay", false)) {
84 socket.setTcpNoDelay(true);
85 }
86
87 // uberbukkit
88 if (Uberbukkit.getTargetPVN() >= 11) {
89 this.input = new DataInputStream(socket.getInputStream());
90 this.output = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream(), 5120));
91 } else {
92 this.input = new DataInputStream(socket.getInputStream());
93 this.output = new DataOutputStream(socket.getOutputStream());
94 }
95 } catch (java.io.IOException socketexception) {
96 // CraftBukkit end
97 System.err.println(socketexception.getMessage());
98 }
99
100 /* CraftBukkit start - moved up
101 this.input = new DataInputStream(socket.getInputStream());
102 this.output = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream(), 5120));
103 // CraftBukkit end */
104 this.s = new NetworkReaderThread(this, s + " read thread");
105 this.r = new NetworkWriterThread(this, s + " write thread");
106 this.s.start();
107 this.r.start();
108 }
109
110 //Project Poseidon Start
111 public void setSocketAddress(SocketAddress socketAddress) {
112 this.i = socketAddress;
113 }
114
115 public SocketAddress generateSocketAddress(String hostname, int port) {
116 return new InetSocketAddress(hostname, port);
117 }
118
119 //Project Poseidon End
120
121 public void a(NetHandler nethandler) {
122 this.p = nethandler;
123 }
124
125 public void queue(Packet packet) {
126 if (!this.q) {
127 Object object = this.g;
128
129 // uberbukkit
130 if (this.protocol != null && !this.protocol.canReceivePacket(packet.b())) return;
131
132 // uberbukkit
133 if (this.pvn != 0) packet.pvn = this.pvn;
134
135 synchronized (this.g) {
136 this.x += packet.a() + 1;
137 if (packet.k) {
138 this.lowPriorityQueue.add(packet);
139 } else {
140 this.highPriorityQueue.add(packet);
141 }
142 }
143 }
144 }
145
146 private boolean f() {
147 boolean flag = false;
148
149 try {
150 Object object;
151 Packet packet;
152 int i;
153 int[] aint;
154
155 if (!this.highPriorityQueue.isEmpty() && (this.f == 0 || System.currentTimeMillis() - ((Packet) this.highPriorityQueue.get(0)).timestamp >= (long) this.f)) {
156 object = this.g;
157 synchronized (this.g) {
158 packet = (Packet) this.highPriorityQueue.remove(0);
159 this.x -= packet.a() + 1;
160 }
161
162 Packet.a(packet, this.output);
163 aint = e;
164 i = packet.b();
165 aint[i] += packet.a() + 1;
166 flag = true;
167 }
168
169 // CraftBukkit - don't allow low priority packet to be sent unless it was placed in the queue before the first packet on the high priority queue
170 if ((flag || this.lowPriorityQueueDelay-- <= 0) && !this.lowPriorityQueue.isEmpty() && (this.highPriorityQueue.isEmpty() || ((Packet) this.highPriorityQueue.get(0)).timestamp > ((Packet) this.lowPriorityQueue.get(0)).timestamp)) {
171 object = this.g;
172 synchronized (this.g) {
173 packet = (Packet) this.lowPriorityQueue.remove(0);
174 this.x -= packet.a() + 1;
175 }
176
177 Packet.a(packet, this.output);
178 aint = e;
179 i = packet.b();
180 aint[i] += packet.a() + 1;
181 this.lowPriorityQueueDelay = 0;
182 flag = true;
183 }
184
185 return flag;
186 } catch (Exception exception) {
187 if (!this.t) {
188 this.a(exception);
189 }
190
191 return false;
192 }
193 }
194
195 public void a() {
196 this.s.interrupt();
197 this.r.interrupt();
198 }
199
200 private boolean g() {
201 boolean flag = false;
202
203 try {
204 Packet packet = Packet.a(this.input, this.p.c(), this.pvn); // uberbukkit - allows packets to be read accordingly to client version
205
206 if (packet != null) {
207 int[] aint = d;
208 int i = packet.b();
209
210 aint[i] += packet.a() + 1;
211 this.m.add(packet);
212 flag = true;
213 } else {
214 this.a("disconnect.endOfStream", new Object[0]);
215 }
216
217 return flag;
218 } catch (Exception exception) {
219 if (!this.t) {
220 this.a(exception);
221 }
222
223 return false;
224 }
225 }
226
227 private void a(Exception exception) {
228 exception.printStackTrace();
229 this.a("disconnect.genericReason", new Object[] { "Internal exception: " + exception.toString() });
230 }
231
232 public void a(String s, Object... aobject) {
233 if (this.l) {
234 this.t = true;
235 this.u = s;
236 this.v = aobject;
237 (new NetworkMasterThread(this)).start();
238 this.l = false;
239
240 try {
241 this.input.close();
242 this.input = null;
243 } catch (Throwable throwable) {
244 ;
245 }
246
247 try {
248 this.output.close();
249 this.output = null;
250 } catch (Throwable throwable1) {
251 ;
252 }
253
254 try {
255 this.socket.close();
256 this.socket = null;
257 } catch (Throwable throwable2) {
258 ;
259 }
260 }
261 }
262
263 public void b() {
264 boolean fast = PoseidonConfig.getInstance().getBoolean("settings.faster-packets.enabled", true);
265 if (this.x > (fast ? 2097152 : 1048576)) {
266 this.a("disconnect.overflow", new Object[0]);
267 }
268
269 if (this.m.isEmpty()) {
270 if (this.w++ == 1200) {
271 this.a("disconnect.timeout", new Object[0]);
272 }
273 } else {
274 this.w = 0;
275 }
276
277 int i = (fast ? 1000 : 100);
278
279 //Poseidon - Packet spam detection
280 if (spamDetection) {
281 if (this.m.size() > threshold) {
282 String playerUsername = "Unknown";
283 if (this.p instanceof NetServerHandler) {
284 playerUsername = ((NetServerHandler) this.p).player.name;
285 ((NetServerHandler) this.p).disconnect(ChatColor.RED + "[Poseidon] You have been kicked for packet spamming.");
286 } else {
287 this.a("disconnect.spam", new Object[0]);
288 }
289 System.out.println("[Poseidon] Player " + playerUsername + " has been kicked for packet spamming. The queue size was " + this.m.size() + " and the threshold was " + threshold + ".");
290 }
291 }
292
293// if(this.m.size() > 1000) {
294// String playerUsername = "Unknown";
295// if (this.p instanceof NetServerHandler) {
296// System.out.println("The packet queue size is " + this.m.size() + " for player " + ((NetServerHandler) this.p).player.name + ".");
297// }
298// }
299
300
301 while (!this.m.isEmpty() && i-- >= 0) {
302 Packet packet = (Packet) this.m.remove(0);
303
304 //Poseidon Start - Packet Receive Event
305 if (firePacketEvents && this.p instanceof NetServerHandler) {
306 PlayerReceivePacketEvent event = new PlayerReceivePacketEvent(((NetServerHandler) this.p).player.name, packet);
307 Bukkit.getPluginManager().callEvent(event);
308 packet = event.getPacket();
309 if (!event.isCancelled()) {
310 packet.a(this.p);
311 }
312
313 } else {
314 packet.a(this.p);
315 }
316
317 //Poseidon End
318
319 // packet.a(this.p);
320 }
321
322 this.a();
323 if (this.t && this.m.isEmpty()) {
324 this.p.a(this.u, this.v);
325 }
326 }
327
328 public SocketAddress getSocketAddress() {
329 return this.i;
330 }
331
332 public void d() {
333 this.a();
334 this.q = true;
335 this.s.interrupt();
336 (new ThreadMonitorConnection(this)).start();
337 }
338
339 public int e() {
340 return this.lowPriorityQueue.size();
341 }
342
343 static boolean a(NetworkManager networkmanager) {
344 return networkmanager.l;
345 }
346
347 static boolean b(NetworkManager networkmanager) {
348 return networkmanager.q;
349 }
350
351 static boolean c(NetworkManager networkmanager) {
352 return networkmanager.g();
353 }
354
355 static boolean d(NetworkManager networkmanager) {
356 return networkmanager.f();
357 }
358
359 static DataOutputStream e(NetworkManager networkmanager) {
360 return networkmanager.output;
361 }
362
363 static boolean f(NetworkManager networkmanager) {
364 return networkmanager.t;
365 }
366
367 static void a(NetworkManager networkmanager, Exception exception) {
368 networkmanager.a(exception);
369 }
370
371 static Thread g(NetworkManager networkmanager) {
372 return networkmanager.s;
373 }
374
375 static Thread h(NetworkManager networkmanager) {
376 return networkmanager.r;
377 }
378}