From fa63fc367627fb72fac61fe3038369c63716eaa3 Mon Sep 17 00:00:00 2001 From: lax1dude Date: Wed, 13 Nov 2024 20:50:39 -0800 Subject: [PATCH] {1.2} Fixed more deadlock issues with the shared world relay --- .../SharedWorldRelay-Latest.jar | Bin 258080 -> 258185 bytes .../v1_8/sp/relay/server/Constants.java | 2 +- .../v1_8/sp/relay/server/DebugLogger.java | 11 +- .../v1_8/sp/relay/server/EaglerSPClient.java | 16 +- .../v1_8/sp/relay/server/EaglerSPRelay.java | 159 +++++++++++------- .../sp/relay/server/EaglerSPRelayConfig.java | 2 +- .../server/EaglerSPRelayConfigRelayList.java | 4 +- .../v1_8/sp/relay/server/EaglerSPServer.java | 12 +- .../v1_8/sp/relay/server/RateLimiter.java | 80 ++++----- .../v1_8/sp/relay/server/Util.java | 3 + 10 files changed, 158 insertions(+), 131 deletions(-) diff --git a/sp-relay/SharedWorldRelay/SharedWorldRelay-Latest.jar b/sp-relay/SharedWorldRelay/SharedWorldRelay-Latest.jar index 136357390e95875575f0612b57eb4c4ef581ac3a..a84f6f56ab72cdf89b9296041c5dce02a7b1da5f 100644 GIT binary patch delta 26238 zcmY(JQ*bT{u%%<$wr$(ClO5Z3^2fGq+qP}**mknx%$b>oTeqsKdR0HJe(7&j7wjWO z9w5Ri$%2BR0Rcfl0il-JHNvY(f&SN)b{+&z1K8xi&% z(+axdz6g|yB9U0#SyTvzpVu)cc1L9kM@&|x6$%Mm{PT(YNUV)qQ3Pz!zFJmsO0}l! zn9n7?2>+DU^}q;UqoI_u$sRuhtA*$}LH?v*XGKbigmxpHdX=sot1@$^02Dhs$A)P1 z6k%TCsX@}Zp97o+92{Bwa#Y#hh(ic7&oQBcH~ee*WLp(F^GS#{DsNWcw#H=pAegeM zUc&$J8vH+NoBzrifq?x#C8V?n`u`QW+6pMb|D6eyaG5m00s$%GB@ZmKrSCU@!U7mf zY>ix8YPF#~)mE|j88eUJhfQSVq(IPCDkkNIuwsIsNo0v2np1_CKrYF=$Uu`bxmclv z!LIam(`8y~+iqc3w_t=(nP8}BR&`q2baZQL*EDQax2$Qk*!h2RIfu#Q`XET&o%jCy zo@_t;{@cC3PLIC^QK~UQOG>C2HU|)aSK=uA%QkACUshk)UbO9!SB##A;{fNc9=@F` zal!CB9cKUn$_?Z#W-S`@-)VlSC{{pda5#$h>J zUkeRpt7q%iUr}IT!d9&)?hWQKCtqNet5s!|A73nb!-7A8R4fSU`SKPfT_14b%2Vz6 zSq;pJV|rO4T3#+AW+hq2bp(w6tA?LqO+chfOjd7g5p1I(ZKJBwt)*sCs$i>q0{ebI zFq> zI5Nqc;c5l2EU_cmzJBlvw7Q}5U|4A}1!=*yh$+hqVMEZ6t=XclMqA@)MX-i)rs5FH z@;*8;;5$)Z1qKwU7eU^z+XT^(JJdY7;?{% zkYnG1f)*QrHE8vnPy*uUAuk=<0{TTn-SrQ--(Pq%tTMPVrk;3v`pj9+2V~@$kN8k5 zhb16!7E6jZ10q*JAB9ZetxjGzv;VMHhfB$zlN7E7VA^< z2Xee+-tyhtl=W+i8j(zfyK29tUmC{EDi;SigGYA>E$guI)dM=YEyF|*z>t@aITivH z;8_tIXw#TuZLsi*MzEFP6k4ujD;NSxr=}SmoWF_AP)v^l=b&?N!RBDW?+cN(P4`KB zMT7bABDOr$^n*Hw&Sl~BqNXP-4an>)XW%t0v3%|qXr4mkAsNQmAnS(OU48!!tag|a z;jV=bQDpKLRsu+|*uD=+cR8A;uAaO^X?Ez+PS&yC5b7vRM9Oe1)K2K<>f4XH)w)EQ zZek(&!tY#0FFEp9n2g(%{8XVMYzOkXZJX`eZ?g_;me$6QE&-h7R-Q$Z<4&#c(|-1(&LG*ji0zZz$SINNNPNKV(igYr0rysU!^ zwV3f>oZ9P$h9SIw`c}HR zCTQRnC94YY0CGAt4UXy>4-R5uDDi_TY0oHpZkiS3l<*O$gwneMjnopqTxZs24i9El zFM!to`{Mw#Bx3wE@jPjr6|9qlb$4ps5^4yLI7;F}a5CfiBS*oJAAFpWo|XlfDHo|W za4oSz26n@bVHg*gjwMQA^W;-7p%^?|7B^t|xZ{h*k9p2-p}R2mVjIB^mpADF zXPRw8>$Hh4t}GV_)XOuMU&0ib5!CpQaK$%P(W)mDR!?<&&sQ zP72POm>hEgUe~Kz{l^E^LsgunY_+pRMGN zF)8H|hDk?TE~QE;+PLt>Vr?IFYvi zx66W2M^!bGea~v3^9r7us;RS2>GEcB`1rP_!4KIAG_4kh?w8F)JlOD)0(iU{83i}v zp6D=QMBiNRP7R@RYM^7gNVmtJkH)S_j763B*ueQxO2datmb-!Vz?OCZxkRdQb1dyf zdt&xt$#;Me>tUSz(VXdK_!4iF;24Tq*_OivY@C9RJigc&q4a0}#Md|FS}b;;z7hv> ztWz8KG}K_iH%a3m#g~o80yM-W%clckFveroBqXEF3>(HZ7munh9@w{6ub2qepTK*t zX&pi5OqAM~=+>V?_|G58GRCtZymHKr5KkWJFds5{nink!R$H$$*!~%ri89Vr%H*+* zwq7ZyaV^i?1fHSkhS6Veq+oC*v)b}oUJP!X)KRk%NbXa_xX2s10T4lW9sU0RSMzJN zZ)Y0Ga@Rv*=6Gp0wUzd_4^Y#>csDpzKNUETn^HLPw(bqeIa0DXV!nHE#*OmBmHJGU z(^C!m$ua*k!5-J#7xrvGueSQWqN!2g0$}`1?X)qEsvqL7B~e!c-yJ%@L~8Vuzsgtx z#y>GoE*ks-op>~?0r|yRya6-wP*0=I2F*g7Qq1lO+cVowNDS@|{}A*x!>6I=QpwwF z|04J{L$2#smfDs1>~s)kZ+r!;w&-eK58Uu~XzKiHEC|ULlk6B~E&XA|2<^5H({BKO z4I0AVm_jgCOFFcrk~SOirs6Gy?A@&NX*YC@oO5XF^TFNO0tC=@go;Glta5TQT>D)7 zAS@YDvaXVrND}f$-@%i;m2QY1UMnxm5>vBmegX@Sx#rHu{1VBD1kW;G+O}1YvI8?q zuY!%3f*XU{e*5B-F(qDT;CxD*O-IM*Y%-SM@C{tbw0(Fbod=H{ChhxEXvx>rYl!Vi zxfyH4H5YzF0zfE(9}@|#X~-zzP;?J=ZL@>KUIpcIIWsSD0Uy_9?_@?^QJpVVCqHcH zU@}(ZOJAO@){8~i@{DPlkdy|fX0dk-1~J#ovm#8im69(kxp|;@^4#9UD9yWUQM8mByBDK+o)kFqv{1MAAv!v3lnV_ z8|*Lf95W!>8Y(d>PDao;BTXyFoy*T8&!=m^dFf$jYCk7Fdl*1K*yn(o}ppjR3H+n8|U zPxg)YKRECoa%oHWaN>!<00C`b0|AL7J4rDo2V_7c3z;GSeDqY;@qYrFp2zH9E2wZo%T5Y<+b*qyDT30XE z_`5v*?RNcJyZ!cGo4fT;5P^#S7+jhEBHebGuywt$Y|CBAUOm;k-0goy=dNS!G0W#R2`(!-=kiB!{*1@95&1|YTTP{q6cG2H)z8Zi!{{m!qSQZ zzCd3VbjE^hPG>Oz^MNfl$NbyL&W?qkhTRB4ORh(1f?j8)<>Lk7VKazy@fQ^?G)Ng4 z1YXY)kO&7Gh3)KDCF1#pJABOcVBQ*|QWtmp@~KXalN-oVlh~j!##3XVOO=HDI{~D0AcqCz8WaSR8veaCSus#Jt`(xg(`IOZf(Fq86vPozJ zRS4?|C{nk{T3=r!ee|_AN^~(cB4+wynX*7;f|-TQVRnt7vORAB7aE#;)Nj{xOoEsW z*ck%9qljLL)ahE0%5NtvQF9`CWm>T~&EoN~W4eqE875;?zJaqW4LXCeiNbjen~8+u zfMttK;k09^8~2AO78D<6>R({qEFeJ)@A@+a-(zU;={d<(5F9m`cWItJ+}gXeU8KT( zVt-&S^OTtROi`$lZmcjx)Sd+n38(}Ezyxm1%+TweHEi1HM?v>f#j`F_lMcY1Zku<{ z8vWa_`D=4yuiIQ)Il6exvJ_Sj1A11d`nT#&Yuwf)MmKUV7nN`-a%kGa=9xm;Pv{>oO)2S$+&F?^0RAr} z9K(fJ6e}o#a-z)@;l^ItzO8=mDjn1tk|+R<$IMwVXy(zo1a`a2f6+&25-avO$=rJ!uUSvz9n*^P=W$*8x^u}M$x&@b zG(xy*NwO{WZI299Jg4IRmwQ<3@`Zo&i7G_!ad6-VD$zSugONMaC?pD?u!=)c_<`0xaPzApL>ZH-j_D zsYj|!aGk)7qK?fi@{+piO5&{|<74-p zjaGJXu%p-~<(J3_oeP*}s-e?ucHjAUgvX`jP+#A$zH$3|g%8i0!}}*zzB_A&zMJ3Y zwe6Pm(8^a~=*-L)*Z|MNMh}dK8h8jx)fMA2Li+(9B40-m< zj%_f`88NngqF$ZsVEZ-8$z8ICl3Q6jAsXZhf{n{PlzE(Q5gl@&g0aT8?TEi){e*2E zd((`pSfwBd%jn1NPwVyLumuNs=pk^2&3G;>d?`_D1|p*cP=@|6t-s0lB$lV3N_{2z zURkk7Y5ADQtmGqY+OkDqP{QjXWnL{`0r!%c$If>y&B2+z@SOq?JT-q}6lcqt?f;1= z&)j`12OoVl{W8h&oC}t&Nssy$eQ(DnQ@vN{gwYp0`bJP2KR1sGQ1bc`sQn6%_$MmK zYS?OqHB*EO2r}gk>>-|ML_;*{D>a3RrmqffSYZiTM<`rqk`fF_Itp4vytt!LLDK@} zPg|Ub@vR|qt0OL~wmi}K(2YPrJK%oUQGyzZzc&$z@fVq5Vg8`b%pjN8mdeHYj*;;8 zR+!eNjrSLF_n%r^P9?tA>prPXpc1qtg=-R$8S!cwyv0NE(-g1Lcef%>yz3^QEHWj)Ysrx4N~r|-Nm^2x>b(m{TPP@YlxGG7Yf#J)RF zz-4QrcL(4+3_DoHLN?_3_mAEs32zHo4VVm=a>E-`U-TU&zwI*-L>v`1wy;Fu-@v5d8Di%nRir zDBd$U4v(Y*O+ol$Mfapa_XJhY51qDd0!TV>L0j_n{!koVma*5@QDTWv?6xG^iS7gs z&KMLmcEfXu&eJSuw9U6GTn$%=oGvy4a9N17v|PeUI8NpB&3X(*RJeUxi%7F7$?+phbL$ zlbsO0Su8DmPEhw4r{<4st{LV0P0arlYg27ElYYpAZ0PWeyyzKq6^NT3dyvDkGT8Cc z#qc>kIa55kSUWW0`_z(o83n^yP((k30_G9A+>@(9R6_3}S2r+MhW^H+&K&J8KiYeX z2kJ*+JQQIOupqu7`Td>HhGuNUtn_4takw3i{ssNt*Jo9r-u+Z^oqZhO_d@m?2t0Z} zSa5)le0MVqZ88|~^klb_@GOUy_22p(p&&5d=n*&TV#OEXJzn;yfH`3;$ckt?{BHHoC}3m640%z)HybSz=rh zW{8NNUwVVeokH`5NMmwH&7WIwonCx=gp|$1U@h%cvV?~^w!~P*XYSm-h2|?b9&drlue-G*g6t7se4(Ui3l0EYNbK zSyt7Gcs znPdOy0xtJV+WdyUVNkr*2qm3M*_cq+0fk1um#G<*pmw21X^3uzA2sR5-z~i(+-*kG zN7w-?g>wV8{Wx-V)B8W$*#WuG83Mn!GcTW=egWav{B_(~qokeyp#QzJtEl;*TS_1x zSiR&sM_GW{>gw4xC#!?`BNQ=lpb`End0+#CloA=S6cL#a2$qu51Yc6%q+CvBLkFYf zYFpg~OdCT%S(^r|h)7J7O0;aPY_*2X&boE=Xl;blkIStOYi1_gl=0`c&e^U<`hT48 z*?Cv0i0{8|1e8%i*AOhEG#>MCNt=C{V+dRg!vTO-YalhPd98Ul{^Sqr`l^zez^o`H z{=TM&7u3_hgbI5`QPh&0Akfb1sk2;Rf#f2V2bT}FPl#h8Es(Sv{dm}=sL!kSx%~33 z;5gPspETh0A6@x!H1U`E=fiOv{<5IMpCTAtNsYL+dQn(-@}aX6Z+k-vTF^% zLJ}Aq)RZMqitt>97;BBFRFK?pHvwXPnAuDkA!H4yrE8h}pB^&ww@*pRY9xZqW}fj3 zJgu0H|4}&QrsvcRV$1n5k_b4(4l?UEiv%|p$;s=X9u3OCTYE|W*2yMyl-e{zX?Df8 zuuL(S%lASEn9GlKg`|2TRHM?3lWpfh$OuBh=t;!Zu`6WN&WL=rPhA$ zgy0-B*Fm?2VTwP*?yjIFstpKQnI!`z%~AWbUgt7G{Yvt3haIX&tOU51M5**#alqSK z9O8?8(Z%l$aP&jhsU9GR5V%E+%2#V#5a+T@9j%JeY=`bg&833lWRrlY{A0sfMtDQt zt{tjpe}msn&iG>oCHV{ic2JybmR=qp)YFf8dlI}Y*+ZD=487b7-}Y3552c+O4flNd zr2y~Vn6;Hzf6^B)Ck-&DhUoTM5W%x-7zSN|l?;k?_e^-Jh3s+n%z&z^a)^@BeSla8 zFY!AbAjRPW;^exp^kIMFw+RzBxQpI6KqS*tk;v_ePnM;5xFR^M`+M}Sdy@LxpW}z= zbCHt$4RqTuTo7e38q@{^Z2J$ct>ryfPiP8k#XaR#K3(Y{MLu9}+Ud~BGfh$MGr#u8{JrU56w|a2DEQDkb1R7-zLVCqLgq0zaTKc?{M$NKjSm~q$J^iUa+?`2yJ5@x( z{1WI4dnP(_{~o}I@rhw5pyH?e70BH)UjY~Hol0Id81aCR#| zkKNlpa<3ec#HDB+YG*=t_VvR54kf-nGB2DE{j4PZQ!H4~3}2XNYDo6VZ-$O1krV!P z*n-BlZV=P<_gh5??Fh0`xmFO1g8dujr+5e$zAr2o3KbAHn@At`RuR^~{`Msn_{`># zIV6hXJ1yK=&S)E=%z_TkKEktN>M0N<2lcq0)>LjEHzM?tL_YG2pL~K?;B}wLYGHsr3&sXYo&zsHnc}E zz<(MV@E8x#F}u(cvg1jX<q*4i>n^(%Mv?9b!Dco!U!>Yp4qslUCOT1>obF}c~M{w|p2Xf;muerlk zGyn`6tszibRVNrJZtG1D-ZT<9J^$Nx3$(84U|~-1KzKAbW5i`HlNdrO!X3)muo)Vv6SwZlc8VESo-p&Op-VXwnaLz?GDOY7J>7Ex1e>!2 zCp&mv@k->D<#n0M?4uZ;6LfSGnu1K+EDMh|D&$0@e$5f6Ca)9u_Vjc8nj^eT1AtzP z!M*l&1Ol!CYo!5sUV@5CU~-yf^e9%~tAuq}hG$cG-8-gWhDtF;HcffFi8YSx(Dm({ z_P1pAXl(Sb7gThk2ODYZtmdx=+9!_hkxgW{pHqPxtthh z&Bo&Ip890pp41k_xrz7m4ZP>`3yz|PT8?M5Vt$T9w`>oydlL!*0Whmf?W-I!cEA#v zPJ2TcT}+s$hZkcTjqZsuC-X~C?LTBk-7&Cpy;BX5rR_N%JsQqTo_=B9fi6X>fcS>b|12Zn#^2?LDvCs0hRo`StMuSoZx z<_}_OGchKb;AMKl`}F>KWAVYR3W|>VJKq?gFV6MOd&1P0AOWJ!i9gjs SO^E6hB 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 loggers = new HashMap(); + private static final Map loggers = new HashMap<>(); public static DebugLogger getLogger(String name) { synchronized(loggers) { @@ -155,7 +155,6 @@ public class DebugLogger implements IRelayLogger { } private static final SimpleDateFormat fmt = new SimpleDateFormat("hh:mm:ss+SSS"); - private final Date dateInstance = new Date(); public static String formatParams(String msg, Object... params) { if(params.length > 0) { @@ -182,10 +181,12 @@ public class DebugLogger implements IRelayLogger { public void log(Level lvl, String msg, Object... params) { if(debugLoggingLevel.level >= lvl.level) { + Date d = new Date(); + d.setTime(System.currentTimeMillis()); + String str = "[" + fmt.format(d) + "][" + Thread.currentThread().getName() + "/" + lvl.label + "][" + name + "]: " + + (params.length == 0 ? msg : formatParams(msg, params)); synchronized(this) { - dateInstance.setTime(System.currentTimeMillis()); - System.out.println("[" + fmt.format(dateInstance) + "][" + Thread.currentThread().getName() + "/" + lvl.label + "][" + name + "]: " + - (params.length == 0 ? msg : formatParams(msg, params))); + System.out.println(str); } } } diff --git a/sp-relay/SharedWorldRelay/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/server/EaglerSPClient.java b/sp-relay/SharedWorldRelay/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/server/EaglerSPClient.java index bc758d6..f62b6ea 100644 --- a/sp-relay/SharedWorldRelay/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/server/EaglerSPClient.java +++ b/sp-relay/SharedWorldRelay/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/server/EaglerSPClient.java @@ -36,7 +36,7 @@ public class EaglerSPClient { this.socket = sock; this.server = srv; this.id = id; - this.createdOn = System.currentTimeMillis(); + this.createdOn = Util.millis(); this.address = addr; } @@ -45,13 +45,13 @@ public class EaglerSPClient { try { socket.send(RelayPacket.writePacket(packet, EaglerSPRelay.logger)); }catch(IOException ex) { - EaglerSPRelay.logger.debug("Error sending data to {}", socket.getAttachment()); + EaglerSPRelay.logger.debug("Error sending data to {}", (Object) socket.getAttachment()); EaglerSPRelay.logger.debug(ex); disconnect(RelayPacketFEDisconnectClient.TYPE_INTERNAL_ERROR, "Internal Server Error"); socket.close(); } }else { - EaglerSPRelay.logger.debug("WARNING: Tried to send data to {} after the connection closed.", socket.getAttachment()); + EaglerSPRelay.logger.debug("WARNING: Tried to send data to {} after the connection closed.", (Object) socket.getAttachment()); } } @@ -60,21 +60,21 @@ public class EaglerSPClient { if(LoginState.assertEquals(this, LoginState.RECIEVED_DESCRIPTION)) { state = LoginState.SENT_ICE_CANDIDATE; server.handleClientICECandidate(this, (RelayPacket03ICECandidate)packet); - EaglerSPRelay.logger.debug("[{}][Client -> Relay -> Server] PKT 0x03: ICECandidate", socket.getAttachment()); + EaglerSPRelay.logger.debug("[{}][Client -> Relay -> Server] PKT 0x03: ICECandidate", (Object) socket.getAttachment()); } return true; }else if(packet instanceof RelayPacket04Description) { if(LoginState.assertEquals(this, LoginState.INIT)) { state = LoginState.SENT_DESCRIPTION; server.handleClientDescription(this, (RelayPacket04Description)packet); - EaglerSPRelay.logger.debug("[{}][Client -> Relay -> Server] PKT 0x04: Description", socket.getAttachment()); + EaglerSPRelay.logger.debug("[{}][Client -> Relay -> Server] PKT 0x04: Description", (Object) socket.getAttachment()); } return true; }else if(packet instanceof RelayPacket05ClientSuccess) { if(LoginState.assertEquals(this, LoginState.RECIEVED_ICE_CANIDATE)) { state = LoginState.FINISHED; server.handleClientSuccess(this, (RelayPacket05ClientSuccess)packet); - EaglerSPRelay.logger.debug("[{}][Client -> Relay -> Server] PKT 0x05: ClientSuccess", socket.getAttachment()); + EaglerSPRelay.logger.debug("[{}][Client -> Relay -> Server] PKT 0x05: ClientSuccess", (Object) socket.getAttachment()); disconnect(RelayPacketFEDisconnectClient.TYPE_FINISHED_SUCCESS, "Successful connection"); } return true; @@ -82,7 +82,7 @@ public class EaglerSPClient { if(LoginState.assertEquals(this, LoginState.RECIEVED_ICE_CANIDATE)) { state = LoginState.FINISHED; server.handleClientFailure(this, (RelayPacket06ClientFailure)packet); - EaglerSPRelay.logger.debug("[{}][Client -> Relay -> Server] PKT 0x05: ClientFailure", socket.getAttachment()); + EaglerSPRelay.logger.debug("[{}][Client -> Relay -> Server] PKT 0x05: ClientFailure", (Object) socket.getAttachment()); disconnect(RelayPacketFEDisconnectClient.TYPE_FINISHED_FAILED, "Failed connection"); } return true; @@ -113,7 +113,7 @@ public class EaglerSPClient { send(pkt); socket.close(); } - EaglerSPRelay.logger.debug("[{}][Relay -> Client] PKT 0xFE: #{} {}", socket.getAttachment(), code, reason); + EaglerSPRelay.logger.debug("[{}][Relay -> Client] PKT 0xFE: #{} {}", (Object) socket.getAttachment(), code, reason); } public static final int clientCodeLength = 16; diff --git a/sp-relay/SharedWorldRelay/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/server/EaglerSPRelay.java b/sp-relay/SharedWorldRelay/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/server/EaglerSPRelay.java index fc4a7b7..237e15d 100644 --- a/sp-relay/SharedWorldRelay/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/server/EaglerSPRelay.java +++ b/sp-relay/SharedWorldRelay/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/server/EaglerSPRelay.java @@ -10,6 +10,7 @@ import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -79,15 +80,19 @@ public class EaglerSPRelay extends WebSocketServer { Thread tickThread = new Thread((() -> { int rateLimitUpdateCounter = 0; + final List pendingToClose = new LinkedList<>(); + final List clientToClose = new LinkedList<>(); while(true) { try { - long millis = System.currentTimeMillis(); + long millis = Util.millis(); + pendingToClose.clear(); + clientToClose.clear(); synchronized(pendingConnections) { Iterator> itr = pendingConnections.entrySet().iterator(); while(itr.hasNext()) { Entry etr = itr.next(); if(millis - etr.getValue().openTime > 500l) { - etr.getKey().close(); + pendingToClose.add(etr.getKey()); itr.remove(); } } @@ -97,10 +102,22 @@ public class EaglerSPRelay extends WebSocketServer { while(itr.hasNext()) { EaglerSPClient cl = itr.next(); if(millis - cl.createdOn > 10000l) { - cl.disconnect(RelayPacketFEDisconnectClient.TYPE_TIMEOUT, "Took too long to connect!"); + clientToClose.add(cl); } } } + if(!pendingToClose.isEmpty()) { + for(WebSocket cl : pendingToClose) { + cl.close(); + } + pendingToClose.clear(); + } + if(!clientToClose.isEmpty()) { + for(EaglerSPClient cl : clientToClose) { + cl.disconnect(RelayPacketFEDisconnectClient.TYPE_TIMEOUT, "Took too long to connect!"); + } + clientToClose.clear(); + } if(++rateLimitUpdateCounter > 300) { if(pingRateLimiter != null) { pingRateLimiter.update(); @@ -156,13 +173,13 @@ public class EaglerSPRelay extends WebSocketServer { } - private static final Map pendingConnections = new HashMap(); - private static final Map clientIds = new HashMap(); - private static final Map clientConnections = new HashMap(); - private static final Map serverCodes = new HashMap(); - private static final Map serverConnections = new HashMap(); - private static final Map> clientAddressSets = new HashMap(); - private static final Map> serverAddressSets = new HashMap(); + private static final Map pendingConnections = new HashMap<>(); + private static final Map clientIds = new HashMap<>(); + private static final Map clientConnections = new HashMap<>(); + private static final Map serverCodes = new HashMap<>(); + private static final Map serverConnections = new HashMap<>(); + private static final Map> clientAddressSets = new HashMap<>(); + private static final Map> serverAddressSets = new HashMap<>(); @Override public void onStart() { @@ -178,7 +195,7 @@ public class EaglerSPRelay extends WebSocketServer { } String addr; - long millis = System.currentTimeMillis(); + long millis = Util.millis(); if(config.isEnableRealIpHeader() && arg1.hasFieldValue(config.getRealIPHeaderName())) { addr = arg1.getFieldValue(config.getRealIPHeaderName()).toLowerCase(); }else { @@ -202,7 +219,7 @@ public class EaglerSPRelay extends WebSocketServer { } if(totalCons >= config.getConnectionsPerIP()) { - logger.debug("[{}]: Too many connections are open on this address", arg0.getAttachment()); + logger.debug("[{}]: Too many connections are open on this address", (Object) arg0.getAttachment()); arg0.send(RelayPacketFEDisconnectClient.ratelimitPacketTooMany); arg0.close(); return; @@ -231,7 +248,7 @@ public class EaglerSPRelay extends WebSocketServer { RelayPacket00Handshake ipkt = (RelayPacket00Handshake)pkt; if(ipkt.connectionVersion != Constants.protocolVersion) { logger.debug("[{}]: Connected with unsupported protocol version: {} (supported " - + "version: {})", arg0.getAttachment(), ipkt.connectionVersion, Constants.protocolVersion); + + "version: {})", (Object) arg0.getAttachment(), ipkt.connectionVersion, Constants.protocolVersion); if(ipkt.connectionVersion < Constants.protocolVersion) { arg0.send(RelayPacket.writePacket(new RelayPacketFFErrorCode(RelayPacketFFErrorCode.TYPE_PROTOCOL_VERSION, "Outdated Client! (v" + Constants.protocolVersion + " req)"), EaglerSPRelay.logger)); @@ -244,63 +261,76 @@ public class EaglerSPRelay extends WebSocketServer { } if(ipkt.connectionType == 0x01) { if(!rateLimit(worldRateLimiter, arg0, waiting.address)) { - logger.debug("[{}]: Got world ratelimited", arg0.getAttachment()); + logger.debug("[{}]: Got world ratelimited", (Object) arg0.getAttachment()); return; } + boolean fuck = false; synchronized(serverAddressSets) { List lst = serverAddressSets.get(waiting.address); if(lst != null) { if(lst.size() >= config.getWorldsPerIP()) { - logger.debug("[{}]: Too many worlds are open on this address", arg0.getAttachment()); - arg0.send(RelayPacketFEDisconnectClient.ratelimitPacketTooMany); - arg0.close(); - return; + fuck = true; } } } - logger.debug("[{}]: Connected as a server", arg0.getAttachment()); - EaglerSPServer srv; - synchronized(serverCodes) { - int j = 0; - String code; - do { - if(++j > 100) { - logger.error("Error: relay is running out of codes!"); - logger.error("Closing connection to {}", arg0.getAttachment()); - arg0.send(RelayPacket.writePacket(new RelayPacketFFErrorCode(RelayPacketFFErrorCode.TYPE_INTERNAL_ERROR, - "Internal Server Error"), EaglerSPRelay.logger)); - arg0.close(); - return; - } - code = config.generateCode(); - }while(serverCodes.containsKey(code)); - srv = new EaglerSPServer(arg0, code, ipkt.connectionCode, waiting.address); - serverCodes.put(code, srv); - ipkt.connectionCode = code; - arg0.send(RelayPacket.writePacket(ipkt, EaglerSPRelay.logger)); - logger.debug("[{}][Relay -> Server] PKT 0x00: Assign join code: {}", arg0.getAttachment(), code); + if(fuck) { + logger.debug("[{}]: Too many worlds are open on this address", (Object) arg0.getAttachment()); + arg0.send(RelayPacketFEDisconnectClient.ratelimitPacketTooMany); + arg0.close(); + return; } + logger.debug("[{}]: Connected as a server", (Object) arg0.getAttachment()); + + EaglerSPServer srv = null; + String code = null; + synchronized(serverCodes) { + eagler: { + int j = 0; + do { + if(++j > 20) { + logger.error("Error: relay is running out of codes!"); + logger.error("Closing connection to {}", (Object) arg0.getAttachment()); + break eagler; + } + code = config.generateCode(); + }while(serverCodes.containsKey(code)); + srv = new EaglerSPServer(arg0, code, ipkt.connectionCode, waiting.address); + serverCodes.put(code, srv); + } + } + + if(srv == null) { + arg0.send(RelayPacket.writePacket(new RelayPacketFFErrorCode(RelayPacketFFErrorCode.TYPE_INTERNAL_ERROR, + "Internal Server Error"), EaglerSPRelay.logger)); + arg0.close(); + return; + } + + ipkt.connectionCode = code; + arg0.send(RelayPacket.writePacket(ipkt, EaglerSPRelay.logger)); + logger.debug("[{}][Relay -> Server] PKT 0x00: Assign join code: {}", (Object) arg0.getAttachment(), code); + synchronized(serverConnections) { serverConnections.put(arg0, srv); } synchronized(serverAddressSets) { List lst = serverAddressSets.get(srv.serverAddress); if(lst == null) { - lst = new ArrayList(); + lst = new ArrayList<>(); serverAddressSets.put(srv.serverAddress, lst); } lst.add(srv); } srv.send(new RelayPacket01ICEServers(EaglerSPRelayConfigRelayList.relayServers)); - logger.debug("[{}][Relay -> Server] PKT 0x01: Send ICE server list to server", arg0.getAttachment()); + logger.debug("[{}][Relay -> Server] PKT 0x01: Send ICE server list to server", (Object) arg0.getAttachment()); }else { if(!rateLimit(pingRateLimiter, arg0, waiting.address)) { - logger.debug("[{}]: Got ping ratelimited", arg0.getAttachment()); + logger.debug("[{}]: Got ping ratelimited", (Object) arg0.getAttachment()); return; } if(ipkt.connectionType == 0x02) { String code = ipkt.connectionCode; - logger.debug("[{}]: Connected as a client, requested server code: {}", arg0.getAttachment(), code); + logger.debug("[{}]: Connected as a client, requested server code: {}", (Object) arg0.getAttachment(), code); if(code.length() != config.getCodeLength()) { logger.debug("The code '{}' is invalid because it's the wrong length, disconnecting", code); arg0.send(RelayPacket.writePacket(new RelayPacketFFErrorCode(RelayPacketFFErrorCode.TYPE_CODE_LENGTH, @@ -323,36 +353,35 @@ public class EaglerSPRelay extends WebSocketServer { String id; EaglerSPClient cl; synchronized(clientIds) { - int j = 0; do { id = EaglerSPClient.generateClientId(); }while(clientIds.containsKey(id)); cl = new EaglerSPClient(arg0, srv, id, waiting.address); clientIds.put(id, cl); - ipkt.connectionCode = id; - arg0.send(RelayPacket.writePacket(ipkt, EaglerSPRelay.logger)); - srv.handleNewClient(cl); } + ipkt.connectionCode = id; + arg0.send(RelayPacket.writePacket(ipkt, EaglerSPRelay.logger)); + srv.handleNewClient(cl); synchronized(clientConnections) { clientConnections.put(arg0, cl); } synchronized(clientAddressSets) { List lst = clientAddressSets.get(cl.address); if(lst == null) { - lst = new ArrayList(); + lst = new ArrayList<>(); clientAddressSets.put(cl.address, lst); } lst.add(cl); } cl.send(new RelayPacket01ICEServers(EaglerSPRelayConfigRelayList.relayServers)); - logger.debug("[{}][Relay -> Client] PKT 0x01: Send ICE server list to client", arg0.getAttachment()); + logger.debug("[{}][Relay -> Client] PKT 0x01: Send ICE server list to client", (Object) arg0.getAttachment()); } }else if(ipkt.connectionType == 0x03) { - logger.debug("[{}]: Pinging the server", arg0.getAttachment()); + logger.debug("[{}]: Pinging the server", (Object) arg0.getAttachment()); arg0.send(RelayPacket.writePacket(new RelayPacket69Pong(Constants.protocolVersion, config.getComment(), Constants.versionBrand), EaglerSPRelay.logger)); arg0.close(); }else if(ipkt.connectionType == 0x04) { - logger.debug("[{}]: Polling the server for other worlds", arg0.getAttachment()); + logger.debug("[{}]: Polling the server for other worlds", (Object) arg0.getAttachment()); if(config.isEnableShowLocals()) { arg0.send(RelayPacket.writePacket(new RelayPacket07LocalWorlds(getLocalWorlds(waiting.address)), EaglerSPRelay.logger)); }else { @@ -360,7 +389,7 @@ public class EaglerSPRelay extends WebSocketServer { } arg0.close(); }else { - logger.debug("[{}]: Unknown connection type: {}", arg0.getAttachment(), ipkt.connectionType); + logger.debug("[{}]: Unknown connection type: {}", (Object) arg0.getAttachment(), ipkt.connectionType); arg0.send(RelayPacket.writePacket(new RelayPacketFFErrorCode(RelayPacketFFErrorCode.TYPE_ILLEGAL_OPERATION, "Unexpected Init Packet"), EaglerSPRelay.logger)); arg0.close(); @@ -368,7 +397,7 @@ public class EaglerSPRelay extends WebSocketServer { } }else { logger.debug("[{}]: Pending connection did not send a 0x00 packet to identify " - + "as a client or server", arg0.getAttachment()); + + "as a client or server", (Object) arg0.getAttachment()); arg0.send(RelayPacket.writePacket(new RelayPacketFFErrorCode(RelayPacketFFErrorCode.TYPE_ILLEGAL_OPERATION, "Unexpected Init Packet"), EaglerSPRelay.logger)); arg0.close(); @@ -380,7 +409,7 @@ public class EaglerSPRelay extends WebSocketServer { } if(srv != null) { if(!srv.handle(pkt)) { - logger.debug("[{}]: Server sent invalid packet: {}", arg0.getAttachment(), pkt.getClass().getSimpleName()); + logger.debug("[{}]: Server sent invalid packet: {}", (Object) arg0.getAttachment(), pkt.getClass().getSimpleName()); arg0.send(RelayPacket.writePacket(new RelayPacketFFErrorCode(RelayPacketFFErrorCode.TYPE_INVALID_PACKET, "Invalid Packet Recieved"), EaglerSPRelay.logger)); arg0.close(); @@ -392,13 +421,13 @@ public class EaglerSPRelay extends WebSocketServer { } if(cl != null) { if(!cl.handle(pkt)) { - logger.debug("[{}]: Client sent invalid packet: {}", arg0.getAttachment(), pkt.getClass().getSimpleName()); + logger.debug("[{}]: Client sent invalid packet: {}", (Object) arg0.getAttachment(), pkt.getClass().getSimpleName()); arg0.send(RelayPacket.writePacket(new RelayPacketFFErrorCode(RelayPacketFFErrorCode.TYPE_INVALID_PACKET, "Invalid Packet Recieved"), EaglerSPRelay.logger)); arg0.close(); } }else { - logger.debug("[{}]: Connection has no client/server attached to it!", arg0.getAttachment()); + logger.debug("[{}]: Connection has no client/server attached to it!", (Object) arg0.getAttachment()); arg0.send(RelayPacket.writePacket(new RelayPacketFFErrorCode(RelayPacketFFErrorCode.TYPE_ILLEGAL_OPERATION, "Internal Server Error"), EaglerSPRelay.logger)); arg0.close(); @@ -406,14 +435,14 @@ public class EaglerSPRelay extends WebSocketServer { } } }catch(Throwable t) { - logger.error("[{}]: Failed to handle binary frame: {}", arg0.getAttachment(), t); + logger.error("[{}]: Failed to handle binary frame: {}", (Object) arg0.getAttachment(), t); arg0.close(); } } @Override public void onMessage(WebSocket arg0, String arg1) { - logger.debug("[{}]: Sent a text frame, disconnecting", arg0.getAttachment()); + logger.debug("[{}]: Sent a text frame, disconnecting", (Object) arg0.getAttachment()); arg0.close(); } @@ -424,7 +453,7 @@ public class EaglerSPRelay extends WebSocketServer { srv = serverConnections.remove(arg0); } if(srv != null) { - logger.debug("[{}]: Server closed, code: {}", arg0.getAttachment(), srv.code); + logger.debug("[{}]: Server closed, code: {}", (Object) arg0.getAttachment(), srv.code); synchronized(serverCodes) { serverCodes.remove(srv.code); } @@ -439,13 +468,13 @@ public class EaglerSPRelay extends WebSocketServer { } ArrayList clientList; synchronized(clientConnections) { - clientList = new ArrayList(clientConnections.values()); + clientList = new ArrayList<>(clientConnections.values()); } Iterator itr = clientList.iterator(); while(itr.hasNext()) { EaglerSPClient cl = itr.next(); if(cl.server == srv) { - logger.debug("[{}]: Disconnecting client: {} (id: {})", cl.socket.getAttachment(), cl.id); + logger.debug("[{}]: Disconnecting client: {} (id: {})", (Object) cl.socket.getAttachment(), cl.id); cl.socket.close(); } } @@ -464,26 +493,26 @@ public class EaglerSPRelay extends WebSocketServer { } } } - logger.debug("[{}]: Client closed, id: {}", arg0.getAttachment(), cl.id); + logger.debug("[{}]: Client closed, id: {}", (Object) arg0.getAttachment(), cl.id); synchronized(clientIds) { clientIds.remove(cl.id); } cl.server.handleClientDisconnect(cl); }else { - logger.debug("[{}]: Connection Closed", arg0.getAttachment()); + logger.debug("[{}]: Connection Closed", (Object) arg0.getAttachment()); } } } @Override public void onError(WebSocket arg0, Exception arg1) { - logger.error("[{}]: Exception thrown: {}", (arg0 == null ? "SERVER" : arg0.getAttachment()), arg1.toString()); + logger.error("[{}]: Exception thrown: {}", (arg0 == null ? "SERVER" : (Object) arg0.getAttachment()), arg1.toString()); logger.debug(arg1); if(arg0 != null) arg0.close(); } private List getLocalWorlds(String addr) { - List lst = new ArrayList(); + List lst = new ArrayList<>(); synchronized(serverAddressSets) { List srvs = serverAddressSets.get(addr); if(srvs != null) { diff --git a/sp-relay/SharedWorldRelay/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/server/EaglerSPRelayConfig.java b/sp-relay/SharedWorldRelay/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/server/EaglerSPRelayConfig.java index ab00e8d..8ad0eb2 100644 --- a/sp-relay/SharedWorldRelay/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/server/EaglerSPRelayConfig.java +++ b/sp-relay/SharedWorldRelay/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/server/EaglerSPRelayConfig.java @@ -295,7 +295,7 @@ public class EaglerSPRelayConfig { save(conf); } String[] splitted = originWhitelist.split(";"); - List splittedList = new ArrayList(); + List splittedList = new ArrayList<>(); for(int i = 0; i < splitted.length; ++i) { splitted[i] = splitted[i].trim().toLowerCase(); if(splitted[i].length() > 0) { diff --git a/sp-relay/SharedWorldRelay/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/server/EaglerSPRelayConfigRelayList.java b/sp-relay/SharedWorldRelay/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/server/EaglerSPRelayConfigRelayList.java index d3c1b0f..09689b1 100644 --- a/sp-relay/SharedWorldRelay/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/server/EaglerSPRelayConfigRelayList.java +++ b/sp-relay/SharedWorldRelay/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/server/EaglerSPRelayConfigRelayList.java @@ -28,10 +28,10 @@ import net.lax1dude.eaglercraft.v1_8.sp.relay.pkt.RelayPacket01ICEServers; */ public class EaglerSPRelayConfigRelayList { - public static final Collection relayServers = new ArrayList(); + public static final Collection relayServers = new ArrayList<>(); public static void loadRelays(File list) throws IOException { - ArrayList loading = new ArrayList(); + ArrayList loading = new ArrayList<>(); if(!list.isFile()) { EaglerSPRelay.logger.info("Creating new {}...", list.getName()); diff --git a/sp-relay/SharedWorldRelay/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/server/EaglerSPServer.java b/sp-relay/SharedWorldRelay/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/server/EaglerSPServer.java index c019b21..75e4fb1 100644 --- a/sp-relay/SharedWorldRelay/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/server/EaglerSPServer.java +++ b/sp-relay/SharedWorldRelay/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/server/EaglerSPServer.java @@ -35,7 +35,7 @@ public class EaglerSPServer { EaglerSPServer(WebSocket sock, String code, String serverName, String serverAddress) { this.socket = sock; this.code = code; - this.clients = new HashMap(); + this.clients = new HashMap<>(); if(serverName.endsWith(";1")) { this.serverHidden = true; @@ -78,7 +78,7 @@ public class EaglerSPServer { if(LoginState.assertEquals(cl, LoginState.SENT_ICE_CANDIDATE)) { cl.state = LoginState.RECIEVED_ICE_CANIDATE; cl.handleServerICECandidate(packet); - EaglerSPRelay.logger.debug("[{}][Server -> Relay -> Client] PKT 0x03: ICECandidate", cl.socket.getAttachment()); + EaglerSPRelay.logger.debug("[{}][Server -> Relay -> Client] PKT 0x03: ICECandidate", (Object) cl.socket.getAttachment()); } }else { socket.send(RelayPacket.writePacket(new RelayPacketFFErrorCode(RelayPacketFFErrorCode.TYPE_UNKNOWN_CLIENT, @@ -92,7 +92,7 @@ public class EaglerSPServer { if(LoginState.assertEquals(cl, LoginState.SENT_DESCRIPTION)) { cl.state = LoginState.RECIEVED_DESCRIPTION; cl.handleServerDescription(packet); - EaglerSPRelay.logger.debug("[{}][Server -> Relay -> Client] PKT 0x04: Description", cl.socket.getAttachment()); + EaglerSPRelay.logger.debug("[{}][Server -> Relay -> Client] PKT 0x04: Description", (Object) cl.socket.getAttachment()); } }else { socket.send(RelayPacket.writePacket(new RelayPacketFFErrorCode(RelayPacketFFErrorCode.TYPE_UNKNOWN_CLIENT, @@ -104,7 +104,7 @@ public class EaglerSPServer { EaglerSPClient cl = clients.get(packet.clientId); if(cl != null) { cl.handleServerDisconnectClient(packet); - EaglerSPRelay.logger.debug("[{}][Server -> Relay -> Client] PKT 0xFE: Disconnect: {}: {}", cl.socket.getAttachment(), + EaglerSPRelay.logger.debug("[{}][Server -> Relay -> Client] PKT 0xFE: Disconnect: {}: {}", (Object) cl.socket.getAttachment(), packet.code, packet.reason); }else { socket.send(RelayPacket.writePacket(new RelayPacketFFErrorCode(RelayPacketFFErrorCode.TYPE_UNKNOWN_CLIENT, @@ -119,9 +119,9 @@ public class EaglerSPServer { public void handleNewClient(EaglerSPClient client) { synchronized(clients) { clients.put(client.id, client); - send(new RelayPacket02NewClient(client.id)); - EaglerSPRelay.logger.debug("[{}][Relay -> Server] PKT 0x02: Notify server of the client, id: {}", serverAddress, client.id); } + send(new RelayPacket02NewClient(client.id)); + EaglerSPRelay.logger.debug("[{}][Relay -> Server] PKT 0x02: Notify server of the client, id: {}", serverAddress, client.id); } public void handleClientDisconnect(EaglerSPClient client) { diff --git a/sp-relay/SharedWorldRelay/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/server/RateLimiter.java b/sp-relay/SharedWorldRelay/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/server/RateLimiter.java index 56ea8ae..fdbede4 100644 --- a/sp-relay/SharedWorldRelay/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/server/RateLimiter.java +++ b/sp-relay/SharedWorldRelay/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/server/RateLimiter.java @@ -34,14 +34,14 @@ public class RateLimiter { protected boolean locked; protected RateLimitEntry() { - timer = System.currentTimeMillis(); + timer = Util.millis(); count = 0; lockedTimer = 0l; locked = false; } protected void update() { - long millis = System.currentTimeMillis(); + long millis = Util.millis(); if(locked) { if(millis - lockedTimer > RateLimiter.this.lockoutDuration) { timer = millis; @@ -70,7 +70,7 @@ public class RateLimiter { NONE, LIMIT, LIMIT_NOW_LOCKOUT, LOCKOUT; } - private final Map limiters = new HashMap(); + private final Map limiters = new HashMap<>(); public RateLimiter(int period, int limit, int lockoutLimit, int lockoutDuration) { this.period = period; @@ -79,50 +79,44 @@ public class RateLimiter { this.lockoutDuration = lockoutDuration; } - public RateLimit limit(String addr) { - synchronized(this) { - RateLimitEntry etr = limiters.get(addr); - - if(etr == null) { - etr = new RateLimitEntry(); - limiters.put(addr, etr); - }else { - etr.update(); - } - - if(etr.locked) { - return RateLimit.LOCKOUT; - } - - ++etr.count; - if(etr.count >= lockoutLimit) { - etr.count = 0; - etr.locked = true; - etr.lockedTimer = System.currentTimeMillis(); - return RateLimit.LIMIT_NOW_LOCKOUT; - }else if(etr.count > limit) { - return RateLimit.LIMIT; - }else { - return RateLimit.NONE; + public synchronized RateLimit limit(String addr) { + RateLimitEntry etr = limiters.get(addr); + + if(etr == null) { + etr = new RateLimitEntry(); + limiters.put(addr, etr); + }else { + etr.update(); + } + + if(etr.locked) { + return RateLimit.LOCKOUT; + } + + ++etr.count; + if(etr.count >= lockoutLimit) { + etr.count = 0; + etr.locked = true; + etr.lockedTimer = Util.millis(); + return RateLimit.LIMIT_NOW_LOCKOUT; + }else if(etr.count > limit) { + return RateLimit.LIMIT; + }else { + return RateLimit.NONE; + } + } + + public synchronized void update() { + Iterator itr = limiters.values().iterator(); + while(itr.hasNext()) { + if(itr.next().count == 0) { + itr.remove(); } } } - public void update() { - synchronized(this) { - Iterator itr = limiters.values().iterator(); - while(itr.hasNext()) { - if(itr.next().count == 0) { - itr.remove(); - } - } - } - } - - public void reset() { - synchronized(this) { - limiters.clear(); - } + public synchronized void reset() { + limiters.clear(); } } diff --git a/sp-relay/SharedWorldRelay/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/server/Util.java b/sp-relay/SharedWorldRelay/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/server/Util.java index 7513712..4abd845 100644 --- a/sp-relay/SharedWorldRelay/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/server/Util.java +++ b/sp-relay/SharedWorldRelay/src/main/java/net/lax1dude/eaglercraft/v1_8/sp/relay/server/Util.java @@ -30,4 +30,7 @@ public class Util { return sock.getAddress().getHostAddress() + ":" + sock.getPort(); } + public static long millis() { + return System.nanoTime() / 1000000l; + } }