From 306bfd36f715837814bec40d8a2cb4bc44f22edf Mon Sep 17 00:00:00 2001 From: Administrator Date: Fri, 8 Aug 2025 17:13:27 +0800 Subject: [PATCH] =?UTF-8?q?UI=E6=94=B9=E8=BF=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .classpath | 6 + klalb-config.json | 1 + klalbconfig.json | 56 - src/assets/ipv6router1.png | Bin 0 -> 21692 bytes src/assets/ipv6router2.png | Bin 0 -> 21867 bytes src/klalb_en_US.properties | 47 + src/klalb_zh_CN.properties | 47 + .../cloud/network/ByteBufferAllocator.java | 37 +- .../cloud/network/IPMulticastDiscovery.java | 2 + .../network/MultipurposeSocketAddress.java | 104 +- src/org/kne/cloud/network/PortRelay.java | 3 +- .../cloud/network/SocketToSocketProxy.java | 13 + .../kne/cloud/network/ipv6/IPv6Packet.java | 3 +- .../ipv6/IPv6TUNLoopbackNetworkLink.java | 2 +- .../klalb/AbstractKLALBPacketLink.java | 8 + .../kne/cloud/network/klalb/KLALBConfig.java | 47 + .../cloud/network/klalb/KLALBConfigItem.java | 103 ++ .../cloud/network/klalb/KLALBController.java | 42 +- .../klalb/KLALBControllerConfigItem.java | 214 +++ .../kne/cloud/network/klalb/KLALBMain.java | 16 +- .../cloud/network/klalb/KLALBProxySystem.java | 356 ++--- .../cloud/network/klalb/KLALBRemoteLine.java | 25 +- .../network/klalb/KLALBRemoteManagement.java | 4 +- .../network/klalb/KLALBVirtualSocketImpl.java | 8 +- .../kne/cloud/network/klalb/PortBinder.java | 6 +- .../network/klalb/SocketBridgeConfigItem.java | 112 ++ .../klalb/StreamChannelKLALBPacketLink.java | 30 +- .../network/klalb/StreamKLALBPacketLink.java | 1 + .../network/klalb/UnknownKLALBConfigItem.java | 9 + .../cloud/network/klalb/ui/GraphPanel.java | 85 +- .../network/klalb/ui/KLALBStateGUI2.java | 2 + .../network/klalb/ui/KLALBStateGUI3.java | 1352 +++++++++++++++++ .../kne/cloud/network/klalb/ui/Language.java | 19 + .../kne/cloud/network/klalb/ui/TPanel2.java | 14 +- src/org/kne/cloud/network/klalb/ui/UIEnv.java | 4 +- .../kne/cloud/network/nathole/Experiment.java | 16 + .../network/srv6/KLALBRoutingProtocol.java | 32 +- .../cloud/network/srv6/SRv6PacketReorder.java | 31 +- .../kne/cloud/network/srv6/SRv6Router.java | 13 +- 39 files changed, 2515 insertions(+), 355 deletions(-) create mode 100644 klalb-config.json delete mode 100644 klalbconfig.json create mode 100644 src/assets/ipv6router1.png create mode 100644 src/assets/ipv6router2.png create mode 100644 src/klalb_en_US.properties create mode 100644 src/klalb_zh_CN.properties create mode 100644 src/org/kne/cloud/network/klalb/KLALBConfig.java create mode 100644 src/org/kne/cloud/network/klalb/KLALBConfigItem.java create mode 100644 src/org/kne/cloud/network/klalb/KLALBControllerConfigItem.java create mode 100644 src/org/kne/cloud/network/klalb/SocketBridgeConfigItem.java create mode 100644 src/org/kne/cloud/network/klalb/UnknownKLALBConfigItem.java create mode 100644 src/org/kne/cloud/network/klalb/ui/KLALBStateGUI3.java create mode 100644 src/org/kne/cloud/network/klalb/ui/Language.java create mode 100644 src/org/kne/cloud/network/nathole/Experiment.java diff --git a/.classpath b/.classpath index ead61f4..5830d28 100644 --- a/.classpath +++ b/.classpath @@ -5,7 +5,13 @@ + + + + + + diff --git a/klalb-config.json b/klalb-config.json new file mode 100644 index 0000000..e1d69a5 --- /dev/null +++ b/klalb-config.json @@ -0,0 +1 @@ +[{"language":"ZH_CN","nogui":false,"VirtualAddress":"2486:1:0:0:0:0:0:8888","DNS":["2486:1:0:0:0:0:0:8888"],"TCPListen":"0.0.0.0:4565","UDPListen":"{UDP}0.0.0.0:4572","VirtualSocketName":"KLALB_Stream","LineTable":["07f4acdef99b.ofalias.net:4565"],"ConnectLineTable":[],"Type":"KLALBController"},{"Listen":"0.0.0.0:4572","Bridge":{"KLALB":"SocketBridge","RDP":"SocketBridge","HTTP":"SocketBridge","HTTPS":"SocketBridge","DEFAULT":"MinecraftSocketBridge23332"},"Connect":{"KLALB":"127.0.0.1:4565","RDP":"127.0.0.1:3389","HTTP":"127.0.0.1:5212","HTTPS":"192.168.1.235:443","DEFAULT":"127.0.0.1:36555"},"Type":"SocketBridge"},{"Listen":"{KLALB_Stream}[::0]:23332","Bridge":{"DEFAULT":"MinecraftSocketBridge23332"},"Connect":{"DEFAULT":"127.0.0.1:36555"},"Type":"SocketBridge"},{"Listen":"{KLALB_Stream}[::0]:23333","Bridge":{"DEFAULT":"SocketBridge"},"Connect":{"DEFAULT":"127.0.0.1:5212"},"Type":"SocketBridge"},{"Listen":"0.0.0.0:25561","Bridge":{"KLALB":"SocketBridge","DEFAULT":"MinecraftSocketBridge23330"},"Connect":{"KLALB":"127.0.0.1:4565","DEFAULT":"127.0.0.1:25562"},"Type":"SocketBridge"},{"Listen":"{KLALB_Stream}[::0]:23330","Bridge":{"DEFAULT":"MinecraftSocketBridge23330"},"Connect":{"DEFAULT":"127.0.0.1:25562"},"Type":"SocketBridge"}] \ No newline at end of file diff --git a/klalbconfig.json b/klalbconfig.json deleted file mode 100644 index 41027f4..0000000 --- a/klalbconfig.json +++ /dev/null @@ -1,56 +0,0 @@ -[ - {"Type":"KLALBController" ,"VirtualAddress":"2486:1:34de:4abd:98c1:abd1:fc7a:401", - "TCPListen" : "0.0.0.0:4565", - "UDPListen" : "{UDP}0.0.0.0:4572", - "VirtualSocketName" : "KLALB_Stream", - "LineTable":["07f4acdef99b.ofalias.net:4572","{UDP}07f4acdef99b.ofalias.net:4572"] - }, - {"Type":"SocketBridge" , - "Listen" : "0.0.0.0:4572", -"Bridge":{ - "KLALB" : "SocketBridge", - "RDP":"SocketBridge", - "HTTP":"SocketBridge", - "HTTPS":"SocketBridge", - "DEFAULT":"MinecraftSocketBridge23332" - } , - "Connect" : { - "KLALB" : "127.0.0.1:4565", - "RDP":"127.0.0.1:3389", - "HTTP":"127.0.0.1:5212", - "HTTPS":"192.168.1.235:443", - "DEFAULT":"127.0.0.1:36555" - } - }, - {"Type":"SocketBridge" , - "Listen" : "{KLALB_Stream}[::0]:23332", -"Bridge":"MinecraftSocketBridge23332", - "Connect" : "127.0.0.1:36555" - }, - { "Type":"SocketBridge" , - "Listen" : "{KLALB_Stream}[::0]:23333", -"Bridge":"SocketBridge", - "Connect" : "127.0.0.1:5212" - }, - - - - - - {"Type":"SocketBridge" , - "Listen" : "0.0.0.0:25561", -"Bridge":{ - "KLALB" : "SocketBridge", - "DEFAULT":"MinecraftSocketBridge23330" - } , - "Connect" : { - "KLALB" : "127.0.0.1:4565", - "DEFAULT":"127.0.0.1:25562" - } - }, - {"Type":"SocketBridge" , - "Listen" : "{KLALB_Stream}[::0]:23330", -"Bridge":"MinecraftSocketBridge23330", - "Connect" : "127.0.0.1:25562" - } -] \ No newline at end of file diff --git a/src/assets/ipv6router1.png b/src/assets/ipv6router1.png new file mode 100644 index 0000000000000000000000000000000000000000..8b6bcab5eaa47baf957ef040426a0d1ddeb32544 GIT binary patch literal 21692 zcmbTd1ymf})*y=0NbukZG){20CO9;%f#5D3ym5DTXxu#nw*bN2Jy?L??hqvC@ZJCZ zcg?&t@6CGCtE%f%)jr$LK4X@{tncF8GST z*4){c(%sg^&PmW+nCf461z+3$JZ7V!{1=F`wJ?>~KLja1E2>aR*h9@J`B*tvOxfAl zDft9gjrsYwI7|eXDLL6WIoQ|*UJn*_c0n#aK`wsEe}AZ6$wAF51l1&^|4r=mPMFHd z+1Wvmjm^!?jn$2d)gEfe#vvf^ihz@ilau8Yg2lpqc4^;2d0_Hvb}S zX3A!6V{U71=j`+f%kdvr2P=DLdnYUV{}R>Ku>})Pf^=dU97IyyELxY`Dkey4Ahl`1wUyz;szd#l3%^(&Y z|2t4l9zpK^74+3-%#59l|Bt|Crh*psP+Q|yfg!fWmgZ~@c9v9>|52l$guRVD^p)@{ zcU=GCLQzpr*3QY<*v`~kR#KSiRc2NQ#7vOif}5R-otK}5--7?u=Qz08S@=!4Oj&p= zxJ)^Wxy`xFEzJMBzofmX%RiR=@BU{0Kl>{~A+JNr*yjHl&p!k1AD0jWL!4fXFQ@@0JaO@?TycXl(kAcMDUQ{$o~iGpc_-hWuY^;J?tiS((2g{r@oce}OsKTR6KJ zL(Ro3U$ymrbSJh~=Gp!khyNu9+y7II=&*0#cUu`C);huHU?v|FV<#YC+ZQbsYx-=_OXd!F&;goZr*=QKqbQTB|r$hp5 zhz`j@XvP8F#M+qJm9FpGtn!*9F(s$Z^NptzN2^@a zOLW`YEw?!jAUEMjq1LhA4?b(xx}7&q$+XcNk1ty<%e{ZKMXaW_w}~+k;Qf(;6Z|EK zapXJ&NAZD0Pl*$_Rn&?Z5Exu`z?PRk-6$7QeC8(K+nyv&<>(Zpvn(S_D_e?UMCq=( z!LN4cXoR6d?}bx&b>rbIMU;uLC|j?r{D&pX#(KsiwtKBrxu~}-bEDQotk1mi6?p~3 zd7bDu^1{x5SuH<5hP6X`Pnv>bRQA*5MHZEYd5D9DIix9rMI$!F8`}pA`LFOB*+i~? z-*5J_k*zs1wzEzO0cWl7)?{Sl zyvRELhSd{&dh9&{9TG82w}IpJr@rugiIEPnTM;`#VsUyPlcs7w*rJNgKIT@&8Ce&^ z>NvwgdT%^T5AcR@YoBU%BzhG4oH)#4yS~gE%G^^TrXdNmp;}H#jnNa^vb#>BN9be? z^+zBe;$uO{+~JlfffCd+n?VTCSK?GRbl)ipeCUs!P(!Zlsj2)22&@D9bMd6vo(;o` zi(%#@3;IoE-`&oh|Ljk*s{Z+QQsPd;{yozLyKr#CDXC&hYOC*B&Bnn2A1ydc2{KZDb6>sdap^eyNoYYzh^ zmfR0ll3h}XSPm56F))M7r9$fk*C@8psEpu3m%yve=a@K*>})li_Ee%4v+q7Wx;zW&V?`#pV_OR z5#6+WD7Kv3q?1ll;?%WN@>ZzP;-uKoq5!E_F)InBSZ>N9eQ$B%&96aQU_C8h@@G95 zUQnS4`6tVhUt-xUjef_NHjlqLu6RE>9MSF89v3KQkoz84FT`e(#x3x6JfbFP*)Oj3 z_YEgv7UGnRqS3?EA2)v7n7(}KObFkm$D1Yy=I$9eArF!);Bd#!A@A6Y8>vZ1mp5EP z*+yZ&Ch~OW(NOy9det_vLGjdj(ECvBb$NhTq3!cQH49fJlo^#4F&;}tB4^JXYg^ji zLF@;Bgc8FiiT+*l!TPT>#MHd$rdW>iu-cV9(xnTCT)SvmkPwQdl8?9!_LRb zNl?8cQtNrDG|(ay+li_>Sfy?8ZYjbl1y}V?_#!oB2m+xM%||r^sCy`mkwqHoy3f9o za{F3LY(%4s@8TSH6jz%Bl}j<~&6hGIBdkz8v% zTG73IW}s~Awl)zhPd?j)&(}}FC<6obm0Aitb!AefuD>Q&5Hgah+FVO1yIq0Yw(L;R11vSDG7UwbcPd* zSlXMEAz_6`vE1MUYT52SK!O@$3pZJPyqk8XF^}(GSZBI{V?X^Vf70H(h{Accq4AfN zZP>Qx1onB5W9X{ty_u2(Hdhh?3EgnY(F9RK(F=y;&%c~hfrNPp&BriyprO}jyQx;^ z&0B3U_vff=9_qo4t7S*io6zAhl9`{hr2 z!sH7$gZ0Fm(XOI@!E(fm7+QVt33XpZFp)2UcOmjvt2Sd7w)~0z_gxAx7a7mP+`1DPuZW zYk#YhKA9AA8VIV)t`&TMVez}2?eyOBAz~T2I1XN3>B4rn9_C2q{7T@I6G!xCPJ)W! zHR@&*<8VRSFHfHYvkA8fP00lxK|NiIi-1a3NgMKbJY&pI@=MI%fww5MVv*$eJTpba zNz@F?hDdUB6(3J};y}0^n_GqtaA9!GX!O6u>JIQr=f8Kj`MGg93=~?XCN0Udo~@)v z<_#rgVc*%aKDk`R#6q`UoilG+n5%cE+S}E7XOhq^+oZ?$R@l(zw4&wW`nvHUF6-0B z?++=%g@X`gZjyKUVly$Xje~Nm*#k5G4}Wwx(DiMDr3JAdIq@`T0w@cg+;g<{>B0+w zJAUDW#gUh4ycb8$g%;-ymqA8$IHeB*MTIx{Q^Iw$S6jxu#tUm9>4)@`S+)ZP=MmhE%@aAu!4D+xs{xDq(#V}dC!p*CIfbISqHwm6SAYEB6;%SKYvG}O zs}y6HhW9ZvboYaXJ0$)aaXuBGzd|o9j8kn}ZfwNh+!MEtw=F^?`h&=b+9_M^FPgn5 z<4AHJ-C^q~$$WI|-PZQ$?}YAt`DHVIC6-VBl^Oj=6Yq+ zzCChS{Rm}YcmQTAp%$Bo4dob`zn~W;h$o@PB%s)OW~IRk^q7Iwl=M3j$$U?lKL8nw z{iMkplG}gh44kkezo$u~jW=iiENtwSJk@P{2(J@Y?U{VFpP2?a^`oJRUhZm ztoh^lzV-ZUJ=@9;f$bR)Z|6fWJgpR**+ANHvDFpc%>+i6blrC3Rifl+Ya|6dxd7A<>}PO{OHbK==+lMxPm62Q6anS3mKsC;jQS7 z#5_{4T&%u6ItDxV_y~$t6fE5?)w)Wn=rltk0gy@w6f;&Ke8VVNrq42Ss0SG`4^1Iy zQQ+W|8YQNtj@M7L$*DmS7cIqDT|E2&;&K+m)g}kl!QdDW-@^N#qeu`}-Y`7$^y)00 zKWE)jw1kpM|ZK-T8kCB)+ ziY}@*`!291lnpi}pL^(U9-p6cSFVb?P*xPWs3}{2`^B-i8|=Fh1`kWD_jN zYl}0bbO{A@5f4?^iX|?3+_r7v|Ehvgi}AZcQA1@M^m6rdFOGKb7BHeP^bt_K9vM`L z3x^zsRQnUhhH+i<^QOT+Y8&;6{lB0|!b8y*<9qtuDwO2vVf>2II)yMQ00I&MZAutw z%6N7S|7zDd!{kS=aK%hs4u1AfB@@_IO-;PRdRO~dv*ciD){f!dwdXxvSB`+)wG9$6 zIylFm%dym}?f$z{OFAkz>kUOer@^LMk?ZaL6EJXIYzO zK8g;_DwdiiyE`DCy}#eAMQkrnp_g9dTHC^c@GD;{l5aY+cv9TFg$_UQK$EQL=itwu zpyWfjK(#mYNkuvVe`?+z;Z@Lj>4i&f#ak2E7ST3LM(#1bz;g681F|DL3~I7?fKjh4xd7aQrO-7 z-4Kos`2#_Sd|^$ei{0(F!hP7MKT`K{gup2RR$E35RBq&WGV3rwn6*TnxS*p_Mu`O)3FEHWbBD#`kJJrgcD$SDbg3i!1y0c>oRg_|3p?PX_BWj!c{Vt<<-h#53 z3BLfhFWc#dkqN`q&o?j4&sxuSfjlpOYD2TC2tRr`p}~kTq?Hao2^XW@=Z1C3H(C!^ z6z$)1RuyiRbgSR>db@p@?M2eHGgiObs$StsYS|uWOev^w0%6@4fECZolk9yO#pm>rGbsDXU+bh$ zr)*=0Q#A{}|6Ri{c!t%NG62h3bMAAeXIlAp{gJAMgHc@YX%Pb5#aA8a_ zt-&J*)|Sl1TK&{@uPV@F*$}{r`Ae5Q;5Z;tuIGBN)3zBHWAmA0CL#lN|K%sjJ-cW- zNx}gppEFv!{}-uzbWsTb1atdr<^l&x^mSb$AFcc;apT}_CTysUYpj|_yiyk4E_e;;HA$YoLql^aa!-Wjw^JRwvhpAQPWnBMZ*~5OG896p zsR^+8lcOu*`+$gDZ?bbhEce+*U9v=KgAEYFQ@}-uoRF7nZbvOP)er8!NGJ4ri11tg z=~8<6t-Q+oDdXdhcSEz$I^$vh*~U(}Eb)x4Z#?Ijofn?2FGgHz9VbdTBATTiE#rG+ zN>M~A)&a6jvu1N6VwW^qC-%$T$d$~zMO{e>s479zP>Wy>gFMfV$IZwW_ zTNW9YAYJ@RlIT;q?(KnqXK_hy@enBqn7*n`+@5H!mPdzw-*y`1=660V89RHd3o^_c< zUZ$uKEx&-uL6U|w?Z-z$yY(=UV~4?Px2wne!u30b!QwfHO0J+>*|Efo$=5^ZbBm?J z4ilU46&*H&^1xqr1k$7n8KCVu9SbjboVv88&jmmI!K9$Qez0RGHSE1 zT;>xB;59V-<(dyqEfVE(B_Y;{(jwi-?exKJ@;>`$;Ilf{cK>VkoXK^jv9_a_H{#KC{c#%xx*nSa51RHKirwGKRS553PW*O8DYYdw&a-$MFh%%vY5*q% z)vAFf76w3GYdxXNeOXZ?_deBr6y@Zti`1rS?$qEL--w*d}w2A)t-x z6wTdE_cAmY*eKKaP&{ZU^as0o=e(ALyi@P9b_lCCE)!(_j z-a987L2*I&r>CHm?+^6eH&JWr3%)1WHXx_)1TiZa#;WMDWDrt@v~}$B2xY1P_rSpH z06;jE;&C0GFvBIVW~^TMWB;vvYe;VEhT!kZk}F3TGKQLsT_jo;OUltcrA@1M7KY&s z;qDRcwM7tjjCQRFEI=$*TuRrPw-lf&rUTIE#JpYO8_#_lrg!&VgP*Vb-4&T^sZ#a> zR&EL~_t9mfsUq^19fA@DwGm?dWTPxOd+39NZiQ}dkFhr3`ld@VS(Lu_d$E6mw8oir z%d!E^`Ds6KwvBItNIo0X?SI!|I~_8~RdbPEYT);R7&mtxriou1sATh16G6cMN#D@y zt@fsl`szAcC`Dz2sbO5Ss0H~hVMYb9p==B1*s*sM_u2Xn>c=I+Cq$xl8)|#^adR7i zN^I0rCGIdz62xTA7`tq>&!)~eRUMn&C2@-Nd)+>1+#CBFvY}yG=R0hxW2ZtLgGUBU z*++&xxK#kFJv8&3gtyJ<&fV(lIO1!fa7gqkim<+T%e$(uast`JnFtY1fLDt!JVo$boE&lFe`;t1J#Nu6guEqZE9y|O z?7deUn|QxDYIx6jd*+d5co)LwczCZGU8ns{Tq4mDT!wDs$rx0fjKBuUdP}t!%P{;>vnxHE%;&GDSCj zdM|R3^voYTKC%_r_Es!a}H6qspkRncoo`myxw+F+LWrC8W$*@~7>z z?SgEpEjyzQiC|d?ZZRfim4&nOJIEnbvBpZXAjMCi97n_ zxb=`(&k2DCXK9pgdHBv5RG3yI=hybX$De}+!xLd0&%h#waLyPU^fH2bq~A5Fgu!oH zvsBvfJH7=$R? zH59_s%8)$N`VKuMVNsF|MQ{1l3Zm(h@n>kLCb?kjfI&)x@JoW?Zw#uyg{tu()p$DF z&4ZGoyk2{VPf zZGj=4nO)ci6r=-`5wj~6Jj|oT2e{Kpb^#-4;ay{DOnZMS{hlWMSU!6lJ>Skq+ceFW z`O#w?#g~4(>T6V&iHmE{MH932|H%-IvfzkAjKR!y*tbL9KxmzzjiV}06dVLaAlF)F z2)M)?cTcGyh__^g;B5)KkL50cM9cR~ON8w+k)V8wj572a51{i6JoHo0$%?ZtMgqqc5caR<*b!= zHh-)mdDwFY>C@AbhWy)-k`njhg!UrGf&G2-5wVErgtu8+^Qa+@tbTXD;VzRsb< zj}$M-hHtUPG7*!$li1^s#oN*#4`pIHU&X^>9RQG?pcpsG6{~e$gMO(-&yzCJ>Xb4- z!~*e!o2e>sL!_r|+(=?>PCgszckm`_m&Wgd7kg(WabRINFX#x{*-kP4mlG{ z5v4Dl$_63vR`w7FuoLFu0HS<$Gx+h5IFZnLaADrEE4Bq&gmZNgkS^1j-OKx**uE;}qX2OUi)H5SLVa|CLljW`W2erzf0?bO}oMo9| z3Yu{;_hQxiu;c3ty(CEvrz;k^xCu4%k+#E(CZmRuRlEG)qFLJwPk8&bQ=Oc2(9njd zI=M)PC;>~nwQL4SAZ1>)rm?SYEJ)dQf2{H|LS#Hm?Y>&EA7HAvNPI9NF`rDg}~5vhByK$*oUX z`a}CT&cAT(aV+Bpkn^zajJy0%Z$%cjcXjPdcQR(b{=7dZK`Y~J&IvnvpyYPs14iQi zpzD>l{qCNE=4|owdGg}ok(2tFy{CxAv2UYShJ>_2wbFeX(pQ{nFm`0nn*5AA)WN>r>^k#rQ@D^nW{*G&9APsElv9|w|` zdD%rM5-eDK-b!VVJc_P|1@eDig0H`tvgxHbe#F=7lyfmk3)oO4%?4!CZi^>vCn#nE z$nOI`hzkLL`z0Jbs?D*YXb_ji3E3;my5Q#k^u~|FKeypQO>u_q%Vf=e66XLA#Mbms zEj{iD?abdJzuUQ1o_gCs9cKWKQ;r#t0q^z@=|Wi8C4ro5!-PtexLllOlSGa+Ina^Z zOL4?;=qigQ#(~_Dgudf7{T2u6rMl7^@2Wv>5YBqEBkAAQ4D*XK)X_*;vKCW{nt%&g z)oxY*na_iqUn@(!omN>A^E@re^~OHWg2@L59mx>}gW7r{H_(?^g>pyPND4I@FO8h1 z^52b9uiz{=rr9?EdVPb--S6@lJN^`(L2ui!H?&Yl-WkeN`h~a0iF6;jl&+^DBr=yQ z+a~Rx$^CF2kpQ4pRuXd!o7%JaU^$~e%~XUIz!%py@m_7?7y0~!a1<*j4vu1 zsD_qL1A%S*1-8JiUg3H%4fqq{$%aCO8zyk1XXU%_dJe&ueU6dbiR6l~L$gH(-UiEx49w1cad>qI2?M-%3|AJN1Z<%c;<6v+yR~C`+M=5WTN9-O$A;jIbAOt@Gvms zB+;5~+|Y-Mo)C!leO}yJv7}Orj-03nh^hbU8U=9d>?bd9Cva`0?*8-^JaQ%u@4#_B0gNmY+~pdL zoG%T|4n=h5`ns+-{UM)|)5vF->u2oJjq8zywFibBrd#sW)M!j^#s}Yrb6U1+D>_Zh z0NK8Uv6HBQgKNtGY8l0Mc=K!x12O#yv)ly)KVWh|!SSKl;IH^e^rVwl2a+z(RbUkL zNPu#&8nDu>`K5bMz~LNcFUv`Ap>tO)6m@;jYx!}`&^K|}zB6+=e@^e}+d?gl8@Q29 zv9$;iY3=RJm#2eqzRC$9G%f-ToBUd3ZJBQN^>;>qR&tbeIf6iwh0AtZhpd?s{2>c% zhny&1aNL0MruV4coTln*dXQ{ct*)my=JN<;-<-3vA8{KAb8XONmu9i#5Q`|+*JMtI zmR_s~Sqv^4!`WhpmN;E^plkPpS++h0`D(WE1+xO9l&gSr3CjqBFDuP7$(*Ezr~iyp z0Ur1VM?@XR2J+{FhfR&TEDoK7<##AxiwYV;jg(*g6*IUwNsmL}F$-7z{ue(RD z$F0+c=pk2d?D3J?>jvaMojA(Y9<5WHyJY%0aWwGA1>(?pE94~6vlLj!QBQ&skva*e z^mPf>1>i@n!CVrh_*-5;4@_|(aJo7xvR;h~29ds=1iT|`M(bkuGMJmsJx96R&gv)f zTJz4s%AXh^e$FK$?|x4up%a^6KzdGDpONg6@uVORX z4NHd!-1*g$=F2xH?!M6!3?s$xdZm&n=%m+JR~T<}vRNOn$@7wE8Va-QG7>EW98>Z& zBIH`I8>kK?_qj`|*DT!^ce0!o0&3L05}=cwyjF&v##ouB*7yci-Jav^SG+B=m)1ze;7Xy?)olVCHxKs%HmD@x9kV7TvB~>>c4`r5?!$KU^MUdCo-lB67zf(9>_$)!8J{U7rgXUMfC2r19t;L(4 zx&n=nbR(ol=3%bCjLfX!J%u;zUv{^)Azemm=<`|MlUpE{hKZ zcf&vE3}Xfi#H%qf5gu}ghgxah1&@X^B-g#wUh2$>VGGWiJ%FpRKT~WdO`ylAo%^zp zqV~AiTaX%PAPH15v(KbAsnrO=5!ka6NMdTz?_08bvmrNRdKAL&rrF^LJ7;IYi=sq7 zPL^6C4*`L#Xzn19mSZPz@;rWWVBET8yY5QBR$@4G2>MmC8z{3MttaoynjpThD5yrD zY1wwU$DfP?un>*l1PJZqm%49l_@@T_7pqg`$Rak8c~b~R0)G=Qt6eA2AcPu zvYNqlY6H^O*c9G`*}1)UD!B16EP2Q1LfzS#BY&m|1Bhk}PwHJT1!-dmzoz&MXlZyn zk$rc3MwXD@6UArHr`h=c(_m0-E*~h6_Q1tZI`bRITb2h*nKL5U2~Fr#7q^aOiOND#SwP4qY+42?X#NP_E<1_w~}gST$MB< z3uU)0f_~MY8FAq#;wIy2+i0xb7-3S*Cs?F}rYs74Kt4Y&#HDy%EbVqV2VpZJNk`(N z8+dJ*>AO?q=daqSqYVFUxA_epJ1~GdiDC(ikgbEQ?9(z!!|CWQ9{2k;r&-BL6F0*U zThe^lxbH$EqZ9MPfMwf}VVw1u?w$gj(JE z`_BrJ#0-~!gZZ8I_4!x;b!~UNdrAjn6%f>g~o`fS~~Y&@PnxMlHBM0>uj^n5%a zfJ?^|n-9sGwptIy&_MaZUnQSnJ_PE$0@Z=)z(*$JwOXn$pkyp8y)v&~sp{X zkw%3v_BfC*O^;(L_bPNjf80EEiR>1XIiG6ERMsW6i3iSH_BbY9ak@1HT@Fz@7xI=5 z$h2(FRK8|yU&x8{WC;JRkw{wyU+iPAClkdwUd(g6_n_ONf4FfPJaMa2$+fhy3P(hZ zJI}{{5`J9`2rae^0}mIEDnHS5(97D+k%*eH z|GJ#7i(P^&ubniM(ii8D9I2cjm5@fAuX(YCj2q1b;Cl9Eaid69d~x09q|kzAtcMPc zsK$UBeBM#%cIs94_!9-%x z63p`4C8^M9Oq}$-$52pYt%2^8naPgiKHe%jZ6K3*EHATK=Fvr{>tYLhz7~DkvLFy0 z+htw7+|#&Vw~-%)<*XM)UGmVu)X{?P{dv{;Pg+a?>Lx) z*V$m0DjEh>t@wUOHGD=laD7G@tt}Fb#>uc)DLTAODy-<>uG#yImHYf>Vex8e3$toP zQl;v338-S+BQ|g9U{9U}N6>n)bhRk`;2}6bvW4(gF)=tjo#fXE zFMTl_fdDV1PyCE3pzw8#e06ojAX2DVrc)%WsH%j0r^%K9y`7aASzdc4U7;-63=xe4 zcE?kLIYh^+XQEBzeAAam?yg?`B6qlqw!?ZpWkE+QF1w5!oP%9kM>onmP#&x`m*cQ zclI1@F4@zfnehRp$FdmA%ld@Y`%C$CLs2K==9A&aB!X3Yn?G2ymBKvRmD&yHV@wek zt>UyTUyywZI0jId8;$LZ;dd-G#OuxS2_UPqe~9r8gWG5=D80_Ngl?79b3>`NJnCw`e&X94pQfj`%k11#6mW4~yA zL=ln{%OM|xaQ|TZuy6TvCr5fMn)hvuEaT8_ddFGZdo*#z8e zQu4URS}Y9}ia}k+;$hInP~61fgDp&K?1a9=`~e)oBQNV?y-u7$I_&es(KCAdL@>cY8REc`}|Tcwx+5Sn3TPLE@yB}w&-O+cSy{gbw)Pt zY&{o^tcf~fa)CP45mSd70`3)Pkiq(r&QYN-zic6+xh`^xpSKxplxk{}b>t7g-Q-s& zj}rlcM5%tMS`{7={QR~f;q~B(cao1XXt?zGxgPZ6Ok1;Jv1^y5d_mV2Gx@&+vSi#K$2btXMiXuwHM{pB^1sP0Rd-o#&Hf zzCiE!zMLE_13m#CGc)VPWBBgJ1_Vt>i? z1Kd_GHGooy3TCKNq49HoaJGxHuqF-IqELX=TgRTm<6FRBVr(2>QQs1N{O1qNE1UGV zs*F+@dz3{xL;Sl#3Dn#A{paWGYH6F>gj{d?&2Mtj4W=37m&}A6^x$@k;EcU9u2~@_ z=RRRwVZ+0`Ymf6yOD+r8{7$pdN^9<{tK6^qx7`Tt#+&@TL@w7JR+J5kn&_L1GIpO8HW_(QS zx<%Y{&Hhp;zCRaE#v)!VP0-@K;k35>(6rlj5mRll{5DmGsL0gmb8?s>7U3_GfnU75 zYQMyO5XR$(NZ2D`R1m||h$}?+xkLsZA3@qF8?uef>~inOCo2s$4lhI?t*o-G zTIj@ENGO6RkkWt6%hjZ(t@t^_?YzZW#4$6>fEoxL-Wa$4fh83^Oy!L#zGISznII;B z(?EuLaK^;Jvt(vfB-fJGS3yKXgfMxHlM^@Gh&&zDvfr0o9KkUo*lNPqkL=l_P*6lO z>hxok^}5BQz!kNaK!=!JAU)txtSytbJH}?fk=}bac$#CMS$=8+Q6^DVHVdsS4?$@{ z`Mr-n7oUBB#)l0dLRmhK(DLZlH4as#*8w`zM#*Zw_H!mGX&FH*9-wL69Ig1{1BhYy z;Zpd#zivk*k3&tgXyc+?c^xc9+}!ZX3Dz6$S}LEiXjEQW0ai}T;+_yqE8rwiGatG_ zV(k7(V2ei%^+we*ZQk60j|Dh{ddXA9F zJX-`&Qb9j()@kmLc}=5-xn?xB-fH?ak=57KbRCb8JMxL64c=g}qs7w8n#dYT52VH(gGB z`!NBBAX)GGb;M5;2qs-n#b<8mMP!B|u?%u*0zsjR9-^lb*=Fo!?#aq+Mj=H5RtJ>`%V1z_bkRLqzMaNz58*Cy|}i@Z@4lz zP=xNg9)`htf8t;@{vMeR=3)c{7*{TY8HyH`mIvHI#HK1U{osfRwcz^T#_yB|)<8EK z;o%yzCx1{9U`O=BRF6)w>+jMH!P>~bDB~+e#C_%2{Ne^NU-xchT}Ef zY*c@WCyN?-4MGrOc!qh#q|YTCSFDvIHpV0m;;UNqwg0tChBugT;mZh$COC$fU$2r zM4hrxT99DmMY7)K;9;iZ@$LA1q@J8;!Vcl5mjOO|`Y543Rg5HhaG9!F{GMk2x;y>$ zDnir&qtRq;QQ2HK@}PS_9DAUru!)iTn;9)iTRq+p&ey3>U0t19_uY{+AoKAUOjINp zRZy7*RaHx(C7pECeqv89&94ng;=gEcDXn?=8)n-)P`%VguSE!znmJiq8G^PT2wLV( z7tKb16QdInfaRIN$|~=q3S?)(?Y@*7glyqiOHHrb8!AiYNBklg0K_UxC(+txr5AQHvmvqE5BNy>Awa*3fMP=<2 z${x+JLDTx=@YE8$8gv&FPaGVhxS8pLU}fQxF`tdN_p2+BKkf{Y?Q-(H*EG-iAPGp! zjzwJnsYIHF)^{bAw2&OGkGz3ufoj7ghoup4B$OZ`;5&tTwp4^R8r&%)U~qs;{Ty&s zh4nU}NI(^@kTGkW2)4>X@x3O`l4ThSmbhZ&Z1<#X3MyBE+4g2)5UOi92Q*uey)kUC z@obS12ShvLEWz)6H}_Gwo6^E-8bk%A4& z*Hm=7l(f!USQpNH$B*PWdmJFpSXURET|&Y8os3=aAi2+*rHxJZ5J6R9iPEJ3vUdXj zR9kMx#Oa71Ry4_SujPIb^S4&P>>+8RsS~tF17K)^cAgG@6ujf|^ddowZNEvz(=gQ> z0bP^Y$PaE#NkLXBd_v?=@`hTRt)4M%b@kbXU+?rpYO))$#1kbM#jRj9!v3%$LO5}y z4BBw!p6VYJdK_a-2s%RZy(#sCj#Sr{2@E^0i?L+6kmp~NjXE*Vef%cfKS*lImS9FzsaRP8sVMyKXA)3{Hx z5yqcM`XjWFMWD=ElxiHzc#adPJ@lXz4vfDEl2&|6b;6P6<(xtE|rDW^={C zkvi=iE^PK%P~TsOb$^GL7~2Va8dC)MlvP{c=fF42NVuT~Ix z`V0Ta^}pB<`70dt7g77O18R^F5mdf+#&Up*r^S;>c+G2Mh=D%~z7l+{sN2*1g_HFe z2_42hZ>245rOuqU`8Fu1x2UXyiSSDeJ@cK>+J30@a>W4Y~t^v>$Fy$Iv&@}FiHi* zzkO@q63Z$H&e`nuto_p$wdL+Q!<9KLZS26Xvk4f#Q;A`((OwtB`COD+Jh$?tk+qCu$%u#ZYLZzz*Tz7kS=n&0&OQS``+V?#c?I6SJKnYO1^uNFk3 z(Pv@1EH{g2(YM*sU+0-b)2O0dIQ^RA&cvF`H0(3lagwizshhpY2n?6X6#^ou5zC93 zUY8#EGlk5>$OfH0!aw&utRui<6utMvhO9?mMa4cp<{kAFSC2T-sx)p%Y&rM3LL`f)} zn3+?=$hl(6^M+s<{qL7DB$i31%bzKwJ5sTywZmJ^Nofp`uf_48O5e*MxH3vP>IdC+ z=P7Yo03!J4h9B>eSps0ITe5@exYA!b+G3flL>~QwwLF!{vdS&gq1T0r{MN4TT#FiJ zX&`?ekPzo)-+8NwHSWd`R|S+srWzM$`PlX0elweDNe1xA%=a_ua>r|)Gn#SIQ{|~F zz%WVs#~ZfC$qNch=s~F}`uv#XQ<=hf23=lJvu-CwMs;B66R)n0`XHJ8p<-BJTk0A& z%EV!~QhRe`M@AVBE~*SyHgPI~x?t$NY*r$qHB2LCugJq--^+68_N0pc$3D0sYARcs z?l&!oIB{J=P$8wmo0DCHP}nExPj>FTH}oGLclqphy!PLr-WW_Vwsr(1u4Sgd` zzl7;~(3Rzxw@c&MZ6}$l`V2Er?hU*_Ej_FR?yIL~&QAX~`ncaWU;`Wz1-q>PRdL-? z@KXO30=W#-8H!Sj)Iot4`mtCoM2(RWAjcnD3lC|nCsqq^e%B`D$OJA3H(*Q~H`S&p zfOoDsDE{^9j2ZW9I6}UQQqJ-lB~KY;dgaOSMC(@fI%aB?W_GslT~yjp?J99Xl?;y1 zhP#+97aM$cAd5~gGTooeN7Zc_$WiWLH1ioduV4>tYR=$FS+yTF(=b2##<6+n^Ch9t zXh)!aW;Ygljo-#{Xd(zcv zB`hDHffc(&6-;^3zp8+1%Hlf75v!P}&uynnj0dq{P>#%TUsyEIW2`D%Y;Z(mnrPXj zHf)>lz%;t*>#$+VOz#v%M_tTi#VYS^~XzUqy3PU2p_rnradG!y=j zM8@w}_!~heqBJmMNcBzD*+e^ zE#5t-d%&f<`E0!WdCxa|?Xj$rROCU+RiVe==A(W}s=gwfYdYDxG$Y+wR#wop#EzMH z=VP3k&({a+u71DEm^JU`bYY68`zBX)(k00v{Av#e8`o(&w_teP0kUxXQlfvp%BM8bB96un6Cz3P%z-%~C>di=a|H(ozI-{H`aBY3{Y(9jT5Q`0n>9r_1`k-|mm5xV- zt`cNf3Np7r)T~2at;*bd-8O#64WnbD=gPCjTB;WtErzZ zcQn#SyANVvx%D1v12qml`y`bK&R0Q?C%#9qAv!*8;PUJ#IfCi$aNhM2|DlMxwh$jo;0b?KF_cJ_J8@z zjhE5prY*2{A77q$aYy}xYudhZH&0CeQTL`Ney6*00=A3Yux%pa#w~io zCkVfP76;FI^?QH$jn{8uVR}Cv9eforJGGy&fij91K~k*79>gSz$av2XUOJYZ>7}Dc zzLG`IcJYy%wA*5Mq@S^&8mq^kzXEwYPix@_0$95eo_?yu{H*QYcGVR%e)ZjNB~RQ{|&^FRL~)gT~hwJ~Xq z>)7i(f!mBe@!DD1zNnzwvcopu3xhI25Rj)`RGv}|Bu?7k`14QT=JWi<2i|wr$A9JG z-}u@lrka=0?fdIrT6^P;ef-h{4vTv5rx0=X?(Iv@cWwuEvTGM?n}Ei%_h=r3KmNI) zueewK#`*7i*ISdJK1HY!Myei%pMMfXj3Pydq|k*ur7xEVx-5vgbjv44183(Q${lnPYUCkaocp366-!GH5gm?|8@0@y6G^hS$I5Jv_TV=bG)SaHL`D`DbzI zMdvX+`7E=OPqS`yKj&^*Psz>r)px&%y^kN|9dEmV_xwVt=_c=IFw_20kt z>KTZcnBc$x!DYYp*~54JCVB=|H7}~g_?i9<$o~WfIt6>e_-_x96mV1?|LIx7 z;;nS@d3*)CZhHu?$hLpk1!r-8_Zdcp$9dJ&o4MxdtGVXde~&hX!1GCTj4mSkFDL>% zK?g1^!X+-WlBC@{Mz!S7Z7mS0oS%E+HONix*!JLCx&Pp6@xQPJwrmD=?ByfBH&mPW z!_DaqBA=T;??SK* zxN8UVK=Q@wUiSN^{O!kAzwWwioU&?=ESg8hbpn-IJ*m4mPDZX{l&5ff2O|we8kDCn zQqhiL96vxP7cCXJkmSn6xIV`9!SV3DGJ#*A6!vrEu%Qxy(GI@Xx3~xPX&bh1`l)@K zdTJlfJr7_1+INT}!>!-@5m5xMd;RsCb=GEb;EwO#W@DJZeS7ZXeeZi8?|kRGn4Ib` zSc9|AK6|lNLx(-GP+o>Z6kgg=v8OGS1!h_I3n}jH8k>_m&YA}85 z3094Hy!U;^f!UcB zqhqU>JTk?;y-zbZbS`U8IfaKGJeFa27*zW(()c3s7fYxm;ut^=3{)@6IQ2)2BA2bN&g|6}it z7iYZ}C*s75{A=fnf8)SR$~yaW7ZXe{!Oq=ek3#pNhbjNzyVn2VMXdkRH-F-^fBNyB zyRLie@h6GXh`6g+o**=+58s`WGSu?OidnQ zY_vkH-*R4*IN-VjAxN*x-p3D9Z$$W|Dn>}c$_QRLC0~OHeN1NJY2PB#CUa zp;8VRs0|Wz8ibBUIp9jWF{YG){(&;1LnXGpamTMdcEuUD{kWe6fQ7lwXE%QO7d70# zmWje_o_mJ@pvOUlq-FES> zu3CNZ_?DT&+x_OFAHH|b1Hr?OJV}y*>$+5`HTugTaVkkNjgW$7W7h5|Y!oPkR4&r> z5Yj;@L4W@MNz}wE`8+=b(t~Pk6wg)6EWq?E2)CcUL5Xw%=9+a}9K0}Oq1oW`U;Pg6 zd+&7!7k2G_05`0$(9HPGcOT@MtG4omFMpZgL8#T>i(h)2M<3gV7y76mWOi`$CPz}+uG)*FG{6IO5b#6xO)qo8P5e z8z9p;?KlEysPvanCP8=WTzB=W=p;F}eSa6qafsuX&@c0{^Uvd&D=+21{{0->f0(^b zKE?E0ol^fW!mW^F=(g(^of3vVeU*SD?$WByAcbbIFJ$`oB$vGWe70V6`JGdzU;Q6% zzm{kB_x8@*4VQoK)72~A_MQ5UEtX0*?Y)VKEjyT)nBbm!qVTrcKH9a!EB=2H9c&x0 ze*+N#m@r&%Cvb%&;5K&JPcP9GA#gTaz13&y2Vv`0%B2nRWv?N75_l4rf%Mv2894vh z``=^gPkwm!-S=|j=rlPlTKaY$4e4W~hg2R~NU~fM&5%-7j16;q>IgbZ81C;Q>U6QY z*Lo-!FgM?1Yr^eJz@zLjv~`p!#7<%py!VyTi?6Cy&KrcjqC<4`uc{Nzc3>2diQnntixd)u*)Xvyzg(h zU^vYHhvNpe`GGV@7n=2XJV#LpLfXv^LMy7J0T3RY zD8utZj?W&a)EAJF;(CBd83=u*CT9rz5yEnnC~aVJNiAGM+HK)Ev*cMsr!GJ#!kR>d zK3bH>k_eT|gKpzFinVLTx%`rsqf1+U@8J#WK6C4t%(D|VpMw5!F<)DD-T<3#T4bR; zAHS%2(H*TOH%>sojW7R`H&Fs11lIE9N^Ne8>tSg z|K!x^TmRzFDNN5FCE0ToP4>d&|DD?3{3q&Ldh@^U2FrOnfYPu}zQH3tr3pJ==L8=c z9`Ii?^PBOO$9AxH3!Js(CU)#yPM{mu%wAw0&|3#DMMQIQh0DYXJ_N9PS z1zzy|-NoY~r|*X0{e*qf$o*Z~Ou(D}JF7Ni-@erI;)@)zUl5Y9`oaRUv$M?3&eE(m z?0&zgE_$BHWzM)>wx^ZGQGl@_F)8hiq+u9R3TybD!;0}Cs-=*jp)su~-;P^;vK7gL z=ofoD`!Ih0Fb>DS8%7>qAelUeY$m14w&MFQL()c{Y(eb68h1Z~+xGwbFvd9lyBxcA z?Rv@AyNq!-`MA+I>{|ASarm?eUh?t9e#01tZT9~=jPWqW>pgCM%y>LzJZ>}|UpC%j z#(3s`!{dLgy5;|-(c{A2*tv7(VkX;mA*|${0Jay8cVcDoPJ3)Kz&pua>Jd?VcYE=@ ziDl34McyQUcOh@uV*j_VkZ7B?z>c2m{NHf=U&lcND^KNh?EnA(07*qoM6N<$f}ZJl A3;+NC literal 0 HcmV?d00001 diff --git a/src/assets/ipv6router2.png b/src/assets/ipv6router2.png new file mode 100644 index 0000000000000000000000000000000000000000..aaa4b0e3b7247dda50deda24d96029c53886b691 GIT binary patch literal 21867 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 literal 0 HcmV?d00001 diff --git a/src/klalb_en_US.properties b/src/klalb_en_US.properties new file mode 100644 index 0000000..f965e39 --- /dev/null +++ b/src/klalb_en_US.properties @@ -0,0 +1,47 @@ +srv6acc=SRv6 network accelerator system +networkgraph=Network graph +language=Language +basicsettings=Basic settings +ipv6addr=IPv6 address +dnsserver=DNS server +asnumber=AS number +tcplistening=TCP listening +udplistening=UDP listening +openlinetable=Open line table +autoconnectlinetable=Auto connect line table +advancedsettings=Advanced settings +congresscontrolalgorithm=Congress control algorithm +savesettings=Save settings +locate=Locate +find=Find +home=Home +uploadspeed=Upload speed +downloadspeed=Download speed +uploadpps=Upload PPS +downloadpps=Download PPS +copy=Copy +onlinedevices=Online devices +monitor=Monitor +showofflines=Show offline remotelines +lineaddressport=Line address:port +addline=Add line +reconnectall=Reconnect All +remotelines=Remote lines +settings=Settings +saveconfigsuccess=Save config success +warning=Warning +invaildipv6addr=IPv6 address:Invaild Input +invailddnsserver=DNS server:Invaild Input +invaildasnumber=AS number:Invaild Input +invaildtcplisten=TCP listen:Invaild Input +invaildudplisten=UDP listen:Invaild Input +invaildopenlinetable=Open line table:Invaild Input +invaildconnectlinetable=Connect line table:Invaild Input +unknown=Unknown +viewlinemonitor=View line monitor +copylineaddress=Copy line address +copyvirtualaddress=Copy virtual address +tryreconnect=Try reconnect +forcedisconnect=Force disconnect +removeline=Remove line + diff --git a/src/klalb_zh_CN.properties b/src/klalb_zh_CN.properties new file mode 100644 index 0000000..6cd332b --- /dev/null +++ b/src/klalb_zh_CN.properties @@ -0,0 +1,47 @@ +srv6acc=SRv6 网络加速系统 +networkgraph=网络拓扑图 +language=语言 +basicsettings=基本设置 +ipv6addr=IPv6地址 +dnsserver=DNS服务器 +asnumber=AS号码 +tcplistening=TCP监听端口 +udplistening=UDP监听端口 +openlinetable=开放线路列表 +autoconnectlinetable=自动连接线路列表 +advancedsettings=高级设置 +congresscontrolalgorithm=拥塞控制算法 +savesettings=保存设置 +locate=定位 +find=查找 +home=本机 +uploadspeed=上传速度 +downloadspeed=下载速度 +uploadpps=上传包转发率 +downloadpps=下载包转发率 +copy=复制 +onlinedevices=在线设备 +monitor=监视器 +showofflines=显示离线远程链路 +lineaddressport=链路地址:端口 +addline=添加链路 +reconnectall=全部重连 +remotelines=远程链路 +settings=设置 +saveconfigsuccess=保存配置成功 +warning=警告 +invaildipv6addr=IPv6地址:非法输入 +invailddnsserver=DNS服务器:非法输入 +invaildasnumber=AS号码:非法输入 +invaildtcplisten=TCP监听端口:非法输入 +invaildudplisten=UDP监听端口:非法输入 +invaildopenlinetable=开放线路列表:非法输入 +invaildconnectlinetable=自动连接线路列表:非法输入 +unknown=未知 +viewlinemonitor=打开链路监视器 +copylineaddress=复制链路地址 +copyvirtualaddress=复制虚拟地址 +tryreconnect=立即尝试重连 +forcedisconnect=强制断开连接 +removeline=强制断开连接并移除 + diff --git a/src/org/kne/cloud/network/ByteBufferAllocator.java b/src/org/kne/cloud/network/ByteBufferAllocator.java index b331444..bdb6017 100644 --- a/src/org/kne/cloud/network/ByteBufferAllocator.java +++ b/src/org/kne/cloud/network/ByteBufferAllocator.java @@ -5,6 +5,8 @@ import java.lang.ref.PhantomReference; import java.lang.ref.Reference; import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; +import java.lang.reflect.Field; +import java.lang.reflect.Method; import java.nio.BufferOverflowException; import java.nio.ByteBuffer; import java.util.ArrayList; @@ -13,6 +15,8 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicReference; import org.kne.debug.TimeDebugger; + +import jdk.internal.misc.Unsafe; public class ByteBufferAllocator { private List bbfps=new ArrayList<>(); @@ -75,9 +79,38 @@ public class ByteBufferAllocator { new ByteBufferPhantomReference(bbfs,refq,bbf,bbfp); return bbfs; } - private static ByteBuffer allocateHeap(int capacity) { - return ByteBuffer.wrap(new byte[capacity]); + private static jdk.internal.misc.Unsafe usf; + private static Method meth; + static { + Class name; + try { + name = Class.forName("jdk.internal.misc.Unsafe"); + Field field = name.getDeclaredField("theUnsafe"); + field.setAccessible(true); + usf= (Unsafe) field.get(null); + meth=name.getMethod("allocateUninitializedArray", Class.class,int.class); + + } catch (java.lang.reflect.InaccessibleObjectException e) { + e.printStackTrace(); + } catch (Exception e) { + e.printStackTrace(); + } } + + private static ByteBuffer allocateHeap(int capacity) { + //return ByteBuffer.wrap((byte[]) usf.allocateUninitializedArray(byte.class, capacity)); + if(usf!=null&&meth!=null) { + try { + return ByteBuffer.wrap((byte[]) usf.allocateUninitializedArray(byte.class, capacity)); + } catch (Exception e) { + return ByteBuffer.wrap(new byte[capacity]); + } + }else { + return ByteBuffer.wrap(new byte[capacity]); + } + } + + private ByteBufferPool getByteBufferPool(int capacity) { int elen=0; for (int i = 0; i < bbfps.size(); i++) { diff --git a/src/org/kne/cloud/network/IPMulticastDiscovery.java b/src/org/kne/cloud/network/IPMulticastDiscovery.java index 9294e3a..a90ec9a 100644 --- a/src/org/kne/cloud/network/IPMulticastDiscovery.java +++ b/src/org/kne/cloud/network/IPMulticastDiscovery.java @@ -81,6 +81,7 @@ public class IPMulticastDiscovery extends Thread implements Closeable, AutoClose try { while (!closed) { HashSet s = new HashSet(); + synchronized (msas) { for (Iterator iterator = msas.iterator(); iterator.hasNext();) { MultipurposeSocketAddress multipurposeSocketAddress = (MultipurposeSocketAddress) iterator .next(); @@ -113,6 +114,7 @@ public class IPMulticastDiscovery extends Thread implements Closeable, AutoClose } catch (NoRouteToHostException|UnknownHostException e) { } + } } Thread.sleep(timeInterval); diff --git a/src/org/kne/cloud/network/MultipurposeSocketAddress.java b/src/org/kne/cloud/network/MultipurposeSocketAddress.java index 1b039fd..5d411d0 100644 --- a/src/org/kne/cloud/network/MultipurposeSocketAddress.java +++ b/src/org/kne/cloud/network/MultipurposeSocketAddress.java @@ -2,6 +2,7 @@ package org.kne.cloud.network; import java.io.IOException; import java.io.Serializable; +import java.lang.reflect.Type; import java.net.DatagramSocket; import java.net.Inet6Address; import java.net.InetAddress; @@ -17,6 +18,16 @@ import java.util.*; import javax.net.ServerSocketFactory; import javax.net.SocketFactory; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonParseException; +import com.google.gson.JsonPrimitive; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; + public class MultipurposeSocketAddress implements Serializable{ /** * @@ -141,8 +152,14 @@ public class MultipurposeSocketAddress implements Serializable{ throw new UnsupportedOperationException("Socket Unsupported"); } Socket s=sf.createSocket(); + try { s.bind(new InetSocketAddress(bindip, bindport)); s.connect(new InetSocketAddress(host, port),timeout); + }catch(Exception e) { + s.close(); + System.gc(); + throw e; + } return s; } public Socket connectSocket(InetAddress bindip,int bindport) throws UnknownHostException, IOException { @@ -151,8 +168,14 @@ public class MultipurposeSocketAddress implements Serializable{ throw new UnsupportedOperationException("Socket Unsupported"); } Socket s=sf.createSocket(); + try { s.bind(new InetSocketAddress(bindip, bindport)); s.connect(new InetSocketAddress(host, port)); + }catch(Exception e) { + s.close(); + System.gc(); + throw e; + } return s; } public Socket connectSocket() throws UnknownHostException, IOException { @@ -161,7 +184,13 @@ public class MultipurposeSocketAddress implements Serializable{ throw new UnsupportedOperationException("Socket Unsupported"); } Socket s=sf.createSocket(); + try { s.connect(new InetSocketAddress(host, port)); + }catch(Exception e) { + s.close(); + System.gc(); + throw e; + } return s; } public Socket connectSocket(int timeout) throws UnknownHostException, IOException { @@ -170,7 +199,13 @@ public class MultipurposeSocketAddress implements Serializable{ throw new UnsupportedOperationException("Socket Unsupported"); } Socket s=sf.createSocket(); + try { s.connect(new InetSocketAddress(host, port),timeout); + }catch(Exception e) { + s.close(); + System.gc(); + throw e; + } return s; } @@ -186,10 +221,16 @@ public class MultipurposeSocketAddress implements Serializable{ throw new UnsupportedOperationException("Socket Unsupported"); } SocketChannel s=sf.createSocketChannel(); - s.bind(new InetSocketAddress(bindip, bindport)); - TimerTask tt=tmoTimer.createTimeOutTask(s, timeout); + TimerTask tt=null; try { + s.bind(new InetSocketAddress(bindip, bindport)); + tt=tmoTimer.createTimeOutTask(s, timeout); + s.connect(new InetSocketAddress(host, port)); + }catch(Exception e) { + s.close(); + System.gc(); + throw e; }finally { if(tt!=null) tt.cancel(); @@ -202,8 +243,14 @@ public class MultipurposeSocketAddress implements Serializable{ throw new UnsupportedOperationException("Socket Unsupported"); } SocketChannel s=sf.createSocketChannel(); + try { s.bind(new InetSocketAddress(bindip, bindport)); s.connect(new InetSocketAddress(host, port)); + }catch(Exception e) { + s.close(); + System.gc(); + throw e; + } return s; } public SocketChannel connectSocketChannel() throws UnknownHostException, IOException { @@ -212,7 +259,13 @@ public class MultipurposeSocketAddress implements Serializable{ throw new UnsupportedOperationException("Socket Unsupported"); } SocketChannel s=sf.createSocketChannel(); + try { s.connect(new InetSocketAddress(host, port)); + }catch(Exception e) { + s.close(); + System.gc(); + throw e; + } return s; } public SocketChannel connectSocketChannel(int timeout) throws UnknownHostException, IOException { @@ -225,6 +278,10 @@ public class MultipurposeSocketAddress implements Serializable{ TimerTask tt=tmoTimer.createTimeOutTask(s, timeout); try { s.connect(new InetSocketAddress(host, port)); + }catch(Exception e) { + s.close(); + System.gc(); + throw e; }finally { if(tt!=null) tt.cancel(); @@ -285,8 +342,14 @@ public class MultipurposeSocketAddress implements Serializable{ throw new UnsupportedOperationException("DatagramSocket Unsupported"); } DatagramSocket dgd=dgs.createSocket(); + try { dgd.bind(new InetSocketAddress(bindip, bindport)); dgd.connect(new InetSocketAddress(host, port)); + }catch(Exception e) { + dgd.close(); + System.gc(); + throw e; + } return dgd; } public DatagramSocket connectDatagramSocket() throws IOException { @@ -295,7 +358,13 @@ public class MultipurposeSocketAddress implements Serializable{ throw new UnsupportedOperationException("DatagramSocket Unsupported"); } DatagramSocket dgd=dgs.createSocket(); + try { dgd.connect(new InetSocketAddress(host, port)); + }catch(Exception e) { + dgd.close(); + System.gc(); + throw e; + } return dgd; } public DatagramServerSocket listenDatagramServerSocket() throws UnknownHostException, IOException { @@ -330,4 +399,35 @@ public class MultipurposeSocketAddress implements Serializable{ return true; } } + + public static JsonDeserializergetDefaultJsonDeserializer(){ + return new JsonDeserializer() { + + @Override + public MultipurposeSocketAddress deserialize(JsonElement arg0, Type arg1, JsonDeserializationContext arg2) + throws JsonParseException { + if(arg0.isJsonPrimitive()) { + JsonPrimitive jp=(JsonPrimitive) arg0; + if(jp.isString()) { + return new MultipurposeSocketAddress(jp.getAsString()); + } + } + throw new JsonParseException("not a string:"+arg0); + } + }; + } + public static JsonSerializergetDefaultJsonSerializer(){ + return new JsonSerializer() { + + @Override + public JsonElement serialize(MultipurposeSocketAddress arg0, Type arg1, JsonSerializationContext arg2) { + return new JsonPrimitive(arg0.toString()); + } + }; + } + + public static void registerToGsonBuilder(GsonBuilder gsonBuilder) { + gsonBuilder.registerTypeAdapter(MultipurposeSocketAddress.class, getDefaultJsonDeserializer()); + gsonBuilder.registerTypeAdapter(MultipurposeSocketAddress.class, getDefaultJsonSerializer()); + } } diff --git a/src/org/kne/cloud/network/PortRelay.java b/src/org/kne/cloud/network/PortRelay.java index 78123b0..cade983 100644 --- a/src/org/kne/cloud/network/PortRelay.java +++ b/src/org/kne/cloud/network/PortRelay.java @@ -36,7 +36,8 @@ public class PortRelay { + "-" + "(" + nx + ")->" + hp.getHost() + ":" + hp.getPort()); try { sl=hp.connectSocket(); - + s.setSoTimeout(120*60*1000); + sl.setSoTimeout(120*60*1000); new SocketBridge(s, sl).run(); } catch (IOException e) { e.printStackTrace(); diff --git a/src/org/kne/cloud/network/SocketToSocketProxy.java b/src/org/kne/cloud/network/SocketToSocketProxy.java index 53c8367..63896ee 100644 --- a/src/org/kne/cloud/network/SocketToSocketProxy.java +++ b/src/org/kne/cloud/network/SocketToSocketProxy.java @@ -20,6 +20,15 @@ public class SocketToSocketProxy extends Proxy { private SocketBridgeFactory defaultFactory; private SocketChannelBridgeFactory defaultChannelFactory; private Map detectedFactory; + private int defaultSoTimeout=120*60*1000; + + public int getDefaultSoTimeout() { + return defaultSoTimeout; + } + + public void setDefaultSoTimeout(int defaultSoTimeout) { + this.defaultSoTimeout = defaultSoTimeout; + } public SocketToSocketProxy(MultipurposeSocketAddress listen, MultipurposeSocketAddress connect) throws IOException { this(listen, new MultipurposeSocketAddress(new InetSocketAddress(0)), connect); @@ -152,6 +161,8 @@ public class SocketToSocketProxy extends Proxy { protected void runBridge(SocketBridgeFactory sbf,Socket sk, Socket sox) throws IOException { + sk.setSoTimeout(defaultSoTimeout); + sox.setSoTimeout(defaultSoTimeout); sk.setTcpNoDelay(true); sox.setTcpNoDelay(true); SocketBridge sb = sbf.createBridge(sk, sox); @@ -159,6 +170,8 @@ public class SocketToSocketProxy extends Proxy { } protected void runChannelBridge(SocketChannelBridgeFactory sbf,SocketChannel sk, SocketChannel sox) throws IOException { + //sk.setSoTimeout(defaultSoTimeout); + //sox.setSoTimeout(defaultSoTimeout); sk.setOption(StandardSocketOptions.TCP_NODELAY, true); sox.setOption(StandardSocketOptions.TCP_NODELAY, true); SocketChannelBridge sb = sbf.createBridge(sk, sox); diff --git a/src/org/kne/cloud/network/ipv6/IPv6Packet.java b/src/org/kne/cloud/network/ipv6/IPv6Packet.java index 6da7cf6..f50b8cc 100644 --- a/src/org/kne/cloud/network/ipv6/IPv6Packet.java +++ b/src/org/kne/cloud/network/ipv6/IPv6Packet.java @@ -15,6 +15,7 @@ import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; +import org.kne.cloud.network.ByteBufferAllocator; import org.kne.cloud.network.NetworkPacket; import org.kne.cloud.network.ipv6.IPv6Packet.IPv6ExtHeader; import org.kne.cloud.network.ipv6.IPv6Packet.IPv6SegmentRoutingHeader; @@ -718,7 +719,7 @@ public class IPv6Packet extends NetworkPacket { //System.out.println("SR length:"+(laste+1)); addresses.clear(); - ByteBuffer bfr=ByteBuffer.allocate(16); + ByteBuffer bfr=NetworkPacket.bufferAllocator.allocate(16); for (int i = 0; i < (laste+1); i++) { bfr.clear(); while (bfr.hasRemaining()) { diff --git a/src/org/kne/cloud/network/ipv6/IPv6TUNLoopbackNetworkLink.java b/src/org/kne/cloud/network/ipv6/IPv6TUNLoopbackNetworkLink.java index ba438e9..5372959 100644 --- a/src/org/kne/cloud/network/ipv6/IPv6TUNLoopbackNetworkLink.java +++ b/src/org/kne/cloud/network/ipv6/IPv6TUNLoopbackNetworkLink.java @@ -141,7 +141,7 @@ public class IPv6TUNLoopbackNetworkLink implements IPv6NetworkLink, Closeable, A e.printStackTrace(); } } - LockSupport.parkNanos(1000000L); + LockSupport.parkNanos(10000000L); } } diff --git a/src/org/kne/cloud/network/klalb/AbstractKLALBPacketLink.java b/src/org/kne/cloud/network/klalb/AbstractKLALBPacketLink.java index 75c59e8..632cec7 100644 --- a/src/org/kne/cloud/network/klalb/AbstractKLALBPacketLink.java +++ b/src/org/kne/cloud/network/klalb/AbstractKLALBPacketLink.java @@ -9,7 +9,15 @@ import org.kne.cloud.network.NetworkPacket; import org.kne.io.KNEChannels; public abstract class AbstractKLALBPacketLink implements KLALBPacketLink { + private static int defaultSoTimeout=60*1000; + + public static int getDefaultSoTimeout() { + return defaultSoTimeout; + } + public static void setDefaultSoTimeout(int defaultSoTimeout) { + AbstractKLALBPacketLink.defaultSoTimeout = defaultSoTimeout; + } private AtomicLong[] inputTrafficCounters; private AtomicLong[] outputTrafficCounters; diff --git a/src/org/kne/cloud/network/klalb/KLALBConfig.java b/src/org/kne/cloud/network/klalb/KLALBConfig.java new file mode 100644 index 0000000..756e059 --- /dev/null +++ b/src/org/kne/cloud/network/klalb/KLALBConfig.java @@ -0,0 +1,47 @@ +package org.kne.cloud.network.klalb; + +import java.io.FileReader; +import java.io.IOException; +import java.lang.reflect.Type; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.ArrayList; + +import javax.annotation.processing.Filer; +import javax.lang.model.element.Element; +import javax.tools.FileObject; +import javax.tools.JavaFileObject; +import javax.tools.JavaFileManager.Location; + +import org.kne.cloud.network.MultipurposeSocketAddress; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonIOException; +import com.google.gson.JsonParseException; +import com.google.gson.JsonPrimitive; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import com.google.gson.JsonSyntaxException; + +import java.io.File; +import java.io.FileNotFoundException; + +public class KLALBConfig extends ArrayList{ + public static void main(String[] args) throws UnknownHostException, JsonSyntaxException, JsonIOException, FileNotFoundException { + GsonBuilder gb=new GsonBuilder(); + MultipurposeSocketAddress.registerToGsonBuilder(gb); + KLALBConfigItem.registerToGsonBuilder(gb); + Gson gson=gb.create(); + KLALBConfig kc=gson.fromJson(new FileReader(new File("klalb-config.json")),KLALBConfig.class); + System.out.println(kc); + String s=gson.toJson(kc); + System.out.println(s); + + } + + +} diff --git a/src/org/kne/cloud/network/klalb/KLALBConfigItem.java b/src/org/kne/cloud/network/klalb/KLALBConfigItem.java new file mode 100644 index 0000000..2ec5b02 --- /dev/null +++ b/src/org/kne/cloud/network/klalb/KLALBConfigItem.java @@ -0,0 +1,103 @@ +package org.kne.cloud.network.klalb; + +import java.lang.reflect.Type; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +import org.kne.cloud.network.MultipurposeSocketAddress; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.JsonPrimitive; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import com.google.gson.reflect.TypeToken; + +public class KLALBConfigItem { + private String Type; + + public String getType() { + return Type; + } + + public void setType(String type) { + Type = type; + } + + @Override + public String toString() { + return "KLALBConfigItem [Type=" + Type + "]"; + } + + public KLALBConfigItem(String type) { + super(); + Type = type; + } + + @Override + public int hashCode() { + return Objects.hash(Type); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + KLALBConfigItem other = (KLALBConfigItem) obj; + return Objects.equals(Type, other.Type); + } + public static JsonDeserializergetDefaultJsonDeserializer(){ + return new JsonDeserializer() { + + @Override + public KLALBConfigItem deserialize(JsonElement arg0, Type arg1, JsonDeserializationContext arg2) + throws JsonParseException { + if(arg0.isJsonObject()) { + JsonObject jobj=(JsonObject) arg0; + String s=jobj.get("Type").getAsString(); + switch(s) { + case "KLALBController": + return arg2.deserialize(arg0, new TypeToken() {}.getType()); + case "SocketBridge": + return arg2.deserialize(arg0, new TypeToken() {}.getType()); + default: + return arg2.deserialize(arg0, new TypeToken() {}.getType()); + } + } + throw new JsonParseException("not a object:"+arg0); + } + }; + } + public static JsonSerializergetDefaultJsonSerializer(){ + return new JsonSerializer() { + + @Override + public JsonElement serialize(KLALBConfigItem arg0, Type arg1, JsonSerializationContext arg2) { + if(arg0 instanceof KLALBControllerConfigItem) { + return arg2.serialize(arg0, new TypeToken() {}.getType()); + } + if(arg0 instanceof SocketBridgeConfigItem) { + return arg2.serialize(arg0, new TypeToken() {}.getType()); + } + return arg2.serialize(arg0, new TypeToken() {}.getType()); + } + }; + } + + public static void registerToGsonBuilder(GsonBuilder gsonBuilder) { + gsonBuilder.registerTypeAdapter(KLALBConfigItem.class, getDefaultJsonDeserializer()); + gsonBuilder.registerTypeAdapter(KLALBConfigItem.class, getDefaultJsonSerializer()); + } +} diff --git a/src/org/kne/cloud/network/klalb/KLALBController.java b/src/org/kne/cloud/network/klalb/KLALBController.java index 4731719..312d9be 100644 --- a/src/org/kne/cloud/network/klalb/KLALBController.java +++ b/src/org/kne/cloud/network/klalb/KLALBController.java @@ -79,7 +79,7 @@ public class KLALBController { private static final boolean showpacket = false; - private static final int PREFIX = 112; + private static final int PREFIX = 128;//112 private static final int DISCOVERY_PORT=4569; private static List ipmd=new ArrayList<>(); @@ -168,25 +168,33 @@ public class KLALBController { for (Iterator iterator = st.iterator(); iterator.hasNext();) { - MultipurposeSocketAddress multipurposeSocketAddress = (MultipurposeSocketAddress) iterator + MultipurposeSocketAddress target = (MultipurposeSocketAddress) iterator .next(); - for (Iterator iterator2 = localaddress.iterator(); iterator2.hasNext();) { + addRemoteLines(target); + /*for (Iterator iterator2 = localaddress.iterator(); iterator2.hasNext();) { MultipurposeSocketAddress bind = (MultipurposeSocketAddress) iterator2 .next(); try { - if(multipurposeSocketAddress.getInetAddress()instanceof Inet4Address&&bind.getInetAddress() instanceof Inet6Address) { + if(target.getInetAddress().isLoopbackAddress() &&(!bind.getInetAddress().isLoopbackAddress())) { continue; } - if(multipurposeSocketAddress.getInetAddress() instanceof Inet6Address &&bind.getInetAddress() instanceof Inet4Address) { + if((!target.getInetAddress().isLoopbackAddress()) &&bind.getInetAddress().isLoopbackAddress()) { + continue; + } + if(target.getInetAddress()instanceof Inet4Address&&bind.getInetAddress() instanceof Inet6Address) { + continue; + } + if(target.getInetAddress() instanceof Inet6Address &&bind.getInetAddress() instanceof Inet4Address) { continue; } } catch (UnknownHostException e) { + if(e.getMessage().toLowerCase().contains("no scope_id found")) } - if(!checkContainsTargetAndBind(multipurposeSocketAddress,bind)) { + if(!checkContainsTargetAndBind(target,bind)) { //System.out.println(target+" "+bind); - addRemoteLine( new KLALBRemoteLine(multipurposeSocketAddress,bind)); + addRemoteLine( new KLALBRemoteLine(target,bind)); } - } + }*/ } for (Iterator iterator = lines.iterator(); iterator.hasNext();) { @@ -404,7 +412,8 @@ public class KLALBController { } - public List addRemoteLines(MultipurposeSocketAddress target) {lineslock.writeLock().lock(); + public List addRemoteLines(MultipurposeSocketAddress target) { + lineslock.writeLock().lock(); try { Listadded=new ArrayList<>(); try { @@ -416,21 +425,36 @@ public class KLALBController { Enumerationei= networkInterface.getInetAddresses(); while (ei.hasMoreElements()) { InetAddress inetAddress = (InetAddress) ei.nextElement(); + try { MultipurposeSocketAddress bind=new MultipurposeSocketAddress(inetAddress.getHostAddress(),0); try { + if(target.getInetAddress().isLoopbackAddress() &&(!bind.getInetAddress().isLoopbackAddress())) { + continue; + } + if((!target.getInetAddress().isLoopbackAddress()) &&bind.getInetAddress().isLoopbackAddress()) { + continue; + } if(target.getInetAddress()instanceof Inet4Address&&bind.getInetAddress() instanceof Inet6Address) { continue; } if(target.getInetAddress() instanceof Inet6Address &&bind.getInetAddress() instanceof Inet4Address) { continue; } + //System.out.println(target+"->"+bind); } catch (UnknownHostException e) { + if(e.getMessage().trim().toLowerCase().contains("no scope_id found")) { + throw e; + } + //e.printStackTrace(); } if(!checkContainsTargetAndBind(target,bind)) { KLALBRemoteLine line=new KLALBRemoteLine(target,bind); addRemoteLine(line ); added.add(line); } + } catch (UnknownHostException e) { + + } } } } diff --git a/src/org/kne/cloud/network/klalb/KLALBControllerConfigItem.java b/src/org/kne/cloud/network/klalb/KLALBControllerConfigItem.java new file mode 100644 index 0000000..eb1199b --- /dev/null +++ b/src/org/kne/cloud/network/klalb/KLALBControllerConfigItem.java @@ -0,0 +1,214 @@ +package org.kne.cloud.network.klalb; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +import org.kne.cloud.network.MultipurposeSocketAddress; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +public class KLALBControllerConfigItem extends KLALBConfigItem { + private String language; + private boolean nogui; + private String VirtualAddress; + private Long VirtualASN; + private List DNS; + private MultipurposeSocketAddress TCPListen; + private MultipurposeSocketAddress UDPListen; + private String VirtualSocketName; + private ListLineTable=new ArrayList<>(); + private ListConnectLineTable=new ArrayList<>(); + + + + + public KLALBControllerConfigItem(String type, boolean nogui, String virtualAddress, Long virtualASN, + List dNS, MultipurposeSocketAddress tCPListen, MultipurposeSocketAddress uDPListen, + String virtualSocketName, List lineTable, + List connectLineTable) { + super(type); + this.nogui = nogui; + VirtualAddress = virtualAddress; + VirtualASN = virtualASN; + DNS = dNS; + TCPListen = tCPListen; + UDPListen = uDPListen; + VirtualSocketName = virtualSocketName; + LineTable = lineTable; + ConnectLineTable = connectLineTable; + } + + + + public void setLanguage(String language) { + this.language = language; + } + + + + public KLALBControllerConfigItem(String type) { + super(type); + } + + + + public String getLanguage() { + return language; + } + + + + public String getVirtualSocketName() { + return VirtualSocketName; + } + + + + public void setVirtualSocketName(String virtualSocketName) { + VirtualSocketName = virtualSocketName; + } + + + + public boolean isNogui() { + return nogui; + } + + + + public void setNogui(boolean nogui) { + this.nogui = nogui; + } + + + + public String getVirtualAddress() { + return VirtualAddress; + } + + + + public void setVirtualAddress(String virtualAddress) { + VirtualAddress = virtualAddress; + } + + + + public Long getVirtualASN() { + return VirtualASN; + } + + + + public void setVirtualASN(Long virtualASN) { + VirtualASN = virtualASN; + } + + + + public List getDNS() { + return DNS; + } + + + + public void setDNS(List dNS) { + DNS = dNS; + } + + + + public MultipurposeSocketAddress getTCPListen() { + return TCPListen; + } + + + + public void setTCPListen(MultipurposeSocketAddress tCPListen) { + TCPListen = tCPListen; + } + + + + public MultipurposeSocketAddress getUDPListen() { + return UDPListen; + } + + + + public void setUDPListen(MultipurposeSocketAddress uDPListen) { + UDPListen = uDPListen; + } + + + + public List getLineTable() { + return LineTable; + } + + + + public void setLineTable(List lineTable) { + LineTable = lineTable; + } + + + + public List getConnectLineTable() { + return ConnectLineTable; + } + + + + public void setConnectLineTable(List connectLineTable) { + ConnectLineTable = connectLineTable; + } + + + + @Override + public String toString() { + return "KLALBControllerConfigItem [language=" + language + ", nogui=" + nogui + ", VirtualAddress=" + + VirtualAddress + ", VirtualASN=" + VirtualASN + ", DNS=" + DNS + ", TCPListen=" + TCPListen + + ", UDPListen=" + UDPListen + ", VirtualSocketName=" + VirtualSocketName + ", LineTable=" + LineTable + + ", ConnectLineTable=" + ConnectLineTable + "]"; + } + + + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + Objects.hash(ConnectLineTable, DNS, LineTable, TCPListen, UDPListen, VirtualASN, + VirtualAddress, VirtualSocketName, language, nogui); + return result; + } + + + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (!super.equals(obj)) + return false; + if (getClass() != obj.getClass()) + return false; + KLALBControllerConfigItem other = (KLALBControllerConfigItem) obj; + return Objects.equals(ConnectLineTable, other.ConnectLineTable) && Objects.equals(DNS, other.DNS) + && Objects.equals(LineTable, other.LineTable) && Objects.equals(TCPListen, other.TCPListen) + && Objects.equals(UDPListen, other.UDPListen) && Objects.equals(VirtualASN, other.VirtualASN) + && Objects.equals(VirtualAddress, other.VirtualAddress) + && Objects.equals(VirtualSocketName, other.VirtualSocketName) + && Objects.equals(language, other.language) && nogui == other.nogui; + } + + + + +} diff --git a/src/org/kne/cloud/network/klalb/KLALBMain.java b/src/org/kne/cloud/network/klalb/KLALBMain.java index 8f610dc..d2f5d49 100644 --- a/src/org/kne/cloud/network/klalb/KLALBMain.java +++ b/src/org/kne/cloud/network/klalb/KLALBMain.java @@ -9,6 +9,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; +import java.util.NoSuchElementException; import java.util.Scanner; import javax.swing.JFrame; @@ -18,6 +19,7 @@ import org.kne.cloud.network.SocketChannelListener; import org.kne.cloud.network.SocketListener; import org.kne.cloud.network.ipv6.RouteItem; import org.kne.cloud.network.klalb.ui.KLALBStateGUI2; +import org.kne.cloud.network.klalb.ui.KLALBStateGUI3; import org.kne.cloud.network.klalb.ui.UIEnv; import org.kne.cloud.network.perf.Kperf; import org.kne.cloud.network.perf.MemcpyBenchmark; @@ -25,7 +27,7 @@ import org.kne.cloud.network.perf.NodeBenchmark; import org.kne.debug.Debuger; public class KLALBMain { - public static KLALBStateGUI2 ksg; + public static KLALBStateGUI3 ksg; public static void main(String[] args) throws IOException { try { UIEnv.inituie(); @@ -35,14 +37,15 @@ public class KLALBMain { System.out.println(CONST.klalb+" V"+CONST.klalbver); Scanner scn=new Scanner(System.in); - File configJson=new File("klalbconfig.json"); + File configJson=new File("klalb-config.json"); KLALBProxySystem kpcje=new KLALBProxySystem(); kpcje.loadConfigJson(configJson); System.out.println("SRv6地址:"+kpcje.getKlalbController().getSelf().getAddress().getHostAddress()); try { + if(!kpcje.getControllerConfig().isNogui()) openGUI(kpcje); - }catch(RuntimeException e) { + }catch(Throwable e) { e.printStackTrace(); } /*MultipurposeSocketAddress mpa=new MultipurposeSocketAddress("127.9.9.9", 49573); @@ -79,7 +82,11 @@ public class KLALBMain { break; case "monitor": + try { openGUI(kpcje); + }catch(Throwable e) { + e.printStackTrace(); + } break; case "lines-state": System.out.println("线路状态:"); @@ -191,6 +198,9 @@ public class KLALBMain { default: System.out.println("未知命令,请输入help以查询命令说明"); } + }catch (NoSuchElementException err) { + System.out.println("已退出程序"); + System.exit(0); }catch(RuntimeException e) { System.out.println("错误!"); e.printStackTrace(); diff --git a/src/org/kne/cloud/network/klalb/KLALBProxySystem.java b/src/org/kne/cloud/network/klalb/KLALBProxySystem.java index 0db0fe4..c55d0b6 100644 --- a/src/org/kne/cloud/network/klalb/KLALBProxySystem.java +++ b/src/org/kne/cloud/network/klalb/KLALBProxySystem.java @@ -2,6 +2,7 @@ package org.kne.cloud.network.klalb; import java.io.File; import java.io.FileReader; +import java.io.FileWriter; import java.io.IOException; import java.io.Reader; import java.net.Inet6Address; @@ -23,10 +24,15 @@ import java.util.Map.Entry; import org.kne.cloud.network.*; import org.kne.cloud.network.klalb.ui.KLALBStateGUI2; +import org.kne.cloud.network.klalb.ui.KLALBStateGUI3; +import org.kne.cloud.network.klalb.ui.Language; +import org.kne.cloud.network.klalb.ui.UIEnv; import org.kne.cloud.network.minecraft.MinecraftSocketBridge; import java.util.Set; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; @@ -37,6 +43,15 @@ public class KLALBProxySystem { private Set proxys=new HashSet<>(); private KLALBController klalbController; private KLALBRemoteManagement krm; + private KLALBConfig config; + private Gson gson; + private File jsonFile; + { + GsonBuilder gb=new GsonBuilder(); + MultipurposeSocketAddress.registerToGsonBuilder(gb); + KLALBConfigItem.registerToGsonBuilder(gb); + gson=gb.create(); + } public Set getProxys() { return proxys; } @@ -87,6 +102,7 @@ public class KLALBProxySystem { } public void loadConfigJson(File jsonFile) throws IOException { + this.jsonFile=jsonFile; FileReader fr = null; try { fr=new FileReader(jsonFile); @@ -104,229 +120,165 @@ public class KLALBProxySystem { loadConfigJson(new JsonParser().parse(json)); } public void loadConfigJson(JsonElement json) { - JsonArray jobj=(JsonArray) json; - jobj.forEach((val)->{ - solveEntry((JsonObject) val); - }); + KLALBConfig config= gson.fromJson(json, KLALBConfig.class); + System.out.println(config); + loadConfig(config); } - protected void solveEntry(JsonObject entry){ - switch (entry.get("Type").getAsString()) { - case "KLALBController": - JsonElement vase= entry.get("VirtualAddress"); - //System.out.println(vase); - Listdaddr=new ArrayList(); - JsonElement vdns= entry.get("DNS"); - if(vdns!=null) { - if(vdns instanceof JsonArray) { - JsonArray arr=(JsonArray) vdns; - for(JsonElement str:arr) { + public void loadConfig(KLALBConfig config) { + this.config=config; + for(KLALBConfigItem item:config) { + if(item instanceof KLALBControllerConfigItem) { + KLALBControllerConfigItem kcci=(KLALBControllerConfigItem) item; + String lstr=kcci.getLanguage(); + if(lstr!=null) { + Language lang=Language.valueOf(lstr); + if(lang!=null) { try { - daddr.add((Inet6Address) InetAddress.getByName(str.getAsString())); - } catch (UnknownHostException e) { + UIEnv.setRsb(lang.getFileName()); + } catch (IOException e) { e.printStackTrace(); } } + } + String vase= kcci.getVirtualAddress(); + //System.out.println(vase); + Listdaddr=new ArrayList(); + List vdns= kcci.getDNS(); + if(vdns!=null) { + for(InetAddress dnsaddr:vdns) { + daddr.add(dnsaddr); + } + + } + if(vase!=null) { + try { + klalbController=new KLALBController((Inet6Address) InetAddress.getByName(vase),daddr); + } catch (UnknownHostException e) { + e.printStackTrace(); + } }else { - try { - daddr.add((Inet6Address) InetAddress.getByName(vdns.getAsString())); - } catch (UnknownHostException e) { - e.printStackTrace(); - } + klalbController=new KLALBController(daddr); } - } - if(vase!=null) { - try { - klalbController=new KLALBController((Inet6Address) InetAddress.getByName(vase.getAsString()),daddr); - } catch (UnknownHostException e) { - e.printStackTrace(); - } - }else { - klalbController=new KLALBController(daddr); - } - - JsonElement vasn= entry.get("VirtualASN"); - if(vasn!=null) { - klalbController.getIpv6Router().setASN (Long.parseLong( vasn.getAsString())); - } - - - JsonElement vsne=entry.get("VirtualSocketName"); - //if(vsne!=null) { - MultipurposeSocketAddress.getSocketTypeRegister().put(vsne.getAsString(), klalbController.getSocketType()); - //} - JsonElement tcple=entry.get("TCPListen"); - if(tcple!=null) { - MultipurposeSocketAddress mpsa=new MultipurposeSocketAddress(tcple.getAsString()); - SocketChannelListener tcpl = null; - try { - tcpl = new SocketChannelListener(mpsa); + Long vasn= kcci.getVirtualASN(); + if(vasn!=null) { + klalbController.getIpv6Router().setASN (vasn); + } - tcpl.setCon((soc)->{ - KLALBRemoteLine krs=null; - try { - krs = new KLALBRemoteLine(new StreamChannelKLALBPacketLink(soc)); - klalbController.addRemoteLine(krs); - } catch (IOException e) { - e.printStackTrace(); - } + String vsne=kcci.getVirtualSocketName(); + //if(vsne!=null) { + MultipurposeSocketAddress.getSocketTypeRegister().put(vsne, klalbController.getSocketType()); + //} + MultipurposeSocketAddress tcple=kcci.getTCPListen(); + if(tcple!=null) { - }); - MultipurposeSocketAddress mpsa2=new MultipurposeSocketAddress(mpsa.getType(), mpsa.getHost(),((InetSocketAddress)tcpl.getServerSocketChannel().getLocalAddress()).getPort()); - klalbController.getListenSocketAddress().add(mpsa2); - } catch (IOException e1) { - e1.printStackTrace(); - } - } - JsonElement udple=entry.get("UDPListen"); - if(udple!=null) { - MultipurposeSocketAddress mpsa=new MultipurposeSocketAddress(udple.getAsString()); - DatagramSocketListener udpl = null; - try { - udpl = new DatagramSocketListener(mpsa); - - udpl.setCon((soc)->{ - - KLALBRemoteLine krs=null; + SocketChannelListener tcpl = null; try { - krs = new KLALBRemoteLine(new SplitedDatagramKLALBPacketLink(soc)); - klalbController.addRemoteLine(krs); - } catch (IOException e) { - e.printStackTrace(); - } + tcpl = new SocketChannelListener(tcple); - }); - MultipurposeSocketAddress mpsau2=new MultipurposeSocketAddress(mpsa.getType(), mpsa.getHost(),((InetSocketAddress)(udpl.getDatagramServerSocket().getLocalSocketAddress())).getPort()); - //klalbController.getListenSocketAddress().add(mpsau2); - } catch (IOException e1) { - e1.printStackTrace(); + tcpl.setCon((soc)->{ + + KLALBRemoteLine krs=null; + try { + krs = new KLALBRemoteLine(new StreamChannelKLALBPacketLink(soc)); + klalbController.addRemoteLine(krs); + } catch (IOException e) { + e.printStackTrace(); + } + + }); + MultipurposeSocketAddress mpsa2=new MultipurposeSocketAddress(tcple.getType(), tcple.getHost(),((InetSocketAddress)tcpl.getServerSocketChannel().getLocalAddress()).getPort()); + klalbController.getListenSocketAddress().add(mpsa2); + } catch (IOException e1) { + e1.printStackTrace(); + } + } + MultipurposeSocketAddress udple=kcci.getUDPListen(); + if(udple!=null) { + DatagramSocketListener udpl = null; + try { + udpl = new DatagramSocketListener(udple); + + udpl.setCon((soc)->{ + + KLALBRemoteLine krs=null; + try { + krs = new KLALBRemoteLine(new SplitedDatagramKLALBPacketLink(soc)); + klalbController.addRemoteLine(krs); + } catch (IOException e) { + e.printStackTrace(); + } + + }); + MultipurposeSocketAddress mpsau2=new MultipurposeSocketAddress(udple.getType(), udple.getHost(),((InetSocketAddress)(udpl.getDatagramServerSocket().getLocalSocketAddress())).getPort()); + //klalbController.getListenSocketAddress().add(mpsau2); + } catch (IOException e1) { + e1.printStackTrace(); + } + } + List linele=kcci.getLineTable(); + if(linele!=null) { + linele.forEach((aline)->{ + klalbController.getSelflineTable().add(aline); + }); + + } + List linetoc=kcci.getConnectLineTable(); + if(linetoc!=null) { + linetoc.forEach((aline)->{ + klalbController.addRemoteLines(aline); + }); + } + }else if(item instanceof SocketBridgeConfigItem) { + SocketBridgeConfigItem scci=(SocketBridgeConfigItem) item; + try { + proxys.add(scci.createProxy(klalbController)); + } catch (IOException e) { + e.printStackTrace(); } } - JsonElement linele=entry.get("LineTable"); - if(linele!=null) { - JsonArray jary=(JsonArray)linele; - jary.forEach((aline)->{ - klalbController.getSelflineTable().add(new MultipurposeSocketAddress(aline.getAsString())); - }); - - } - JsonElement linetoc=entry.get("ConnectLineTable"); - if(linetoc!=null) { - JsonArray jary=(JsonArray)linetoc; - jary.forEach((aline)->{ - klalbController.addRemoteLines(new MultipurposeSocketAddress(aline.getAsString())); - }); - } - break; - case "SocketBridge": - - try { - proxys.add(createProxyByJson(entry)); - } catch (IOException e) { - e.printStackTrace(); - } - break; - default: - break; - } - } - public Proxy createProxyByJson(JsonObject entry) throws IOException { - HostPortMap mapp=new HostPortMap(); - LinkedHashMapmapb=new LinkedHashMap<>(); - MultipurposeSocketAddress l=new MultipurposeSocketAddress(entry.get("Listen").getAsString()); - SocketBridgeFactory bdg=getDefaultBridgeFactory(entry.get("Bridge"),mapb); - MultipurposeSocketAddress r=getDefaultConnect(entry.get("Connect"),mapp); - return new SocketToSocketProxy(l ,new MultipurposeSocketAddress("0.0.0.0:0"), r,mapp,bdg,mapb); - } - public JsonObject createJsonObjectByProxy(Proxy p) { - if(p instanceof SocketToSocketProxy) { - SocketToSocketProxy stsp=(SocketToSocketProxy) p; - JsonObject jobj=new JsonObject(); - jobj.addProperty("Listen", stsp.getListen().toString()); - jobj.add("Bridge", getJsonElementByBridges(stsp)); - jobj.add("Connect", getJsonElementByConnects(stsp)); - return jobj; - }else { - throw new UnsupportedOperationException(); } } - private JsonElement getJsonElementByConnects(SocketToSocketProxy stsp) { - if(stsp.getDetectedConnect()==null||stsp.getDetectedConnect().isEmpty()) { - return new JsonPrimitive(stsp.getDefaultConnect().toString()); - }else { - JsonObject jo=new JsonObject(); - for (Iterator> iterator = stsp.getDetectedConnect().entrySet().iterator(); iterator.hasNext();) { - Entry proxy = (Entry) iterator.next(); - if(!proxy.getKey().equals("DEFAULT")) { - jo.addProperty(proxy.getKey(), proxy.getValue().toString()); - } - } - jo.addProperty("DEFAULT", stsp.getDefaultConnect().toString()); - return jo; - } - } - private JsonElement getJsonElementByBridges(SocketToSocketProxy stsp) { - if(stsp.getDetectedFactory()==null||stsp.getDetectedFactory().isEmpty()) { - return new JsonPrimitive(getJobjByFActory(stsp.getDefaultFactory())); - }else { - JsonObject jo=new JsonObject(); - for (Iterator> iterator = stsp.getDetectedFactory().entrySet().iterator(); iterator.hasNext();) { - Entry proxy = (Entry) iterator.next(); - if(!proxy.getKey().equals("DEFAULT")) { - jo.addProperty(proxy.getKey(), getJobjByFActory(proxy.getValue())); - } - } - jo.addProperty("DEFAULT",getJobjByFActory( stsp.getDefaultFactory())); - return jo; - } - } - private MultipurposeSocketAddress getDefaultConnect(JsonElement jsonElement, LinkedHashMap mapp) { - if(jsonElement instanceof JsonObject) { - JsonObject jobj=(JsonObject) jsonElement; - jobj.entrySet().forEach((en)->{ - mapp.put(en.getKey(), new MultipurposeSocketAddress( en.getValue().getAsString())); - }); - return mapp.get("DEFAULT"); - }else { - return new MultipurposeSocketAddress(jsonElement.getAsString()); - } - } - private SocketBridgeFactory getDefaultBridgeFactory(JsonElement jsonElement, LinkedHashMap mapp) { - if(jsonElement instanceof JsonObject) { - JsonObject jobj=(JsonObject) jsonElement; - jobj.entrySet().forEach((en)->{ - mapp.put(en.getKey(), getFactoryByJobj(en.getValue().getAsString())); - }); - return mapp.get("DEFAULT"); - }else { - return getFactoryByJobj(jsonElement.getAsString()); - } - } - private SocketBridgeFactory getFactoryByJobj(String string) { - if(string.startsWith("SocketBridge")) { - return new DefaultSocketBridgeFactory(); - }else if(string.startsWith("MinecraftSocketBridge")) { - return new DefaultMinecraftSocketBridgeFactory(klalbController.getSelf().getAddress(), Integer.parseInt(string.substring(21))); + private KLALBStateGUI3 kgui; + public KLALBStateGUI3 getKLALBGUI() { + if(kgui==null) { + kgui=new KLALBStateGUI3(klalbController); + kgui.loadConfig(config); + kgui.setSaveComsumer((cfg)->{ + String json=gson.toJson(cfg); + if(jsonFile!=null) { + FileWriter fw = null; + try { + fw=new FileWriter(jsonFile); + fw.write(json); + }catch(IOException e) { + e.printStackTrace(); + }finally { + if(fw!=null) + try { + fw.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + }); } - throw new IllegalArgumentException("unknown SocketBridge type:"+string); - } - private String getJobjByFActory(SocketBridgeFactory sbf) { - if(sbf instanceof DefaultSocketBridgeFactory) { - return "SocketBridge"; - }else if(sbf instanceof DefaultMinecraftSocketBridgeFactory) { - return "MinecraftSocketBridge"+((DefaultMinecraftSocketBridgeFactory)sbf).getVport(); - }else { - throw new UnsupportedOperationException(); - } - } - private KLALBStateGUI2 kgui; - public KLALBStateGUI2 getKLALBGUI() { - if(kgui==null) - kgui=new KLALBStateGUI2(klalbController); return kgui; } + public KLALBConfig getConfig() { + return config; + } + public KLALBControllerConfigItem getControllerConfig() { + for(KLALBConfigItem item:config) { + if(item instanceof KLALBControllerConfigItem) + return (KLALBControllerConfigItem) item; + } + return null; + } } diff --git a/src/org/kne/cloud/network/klalb/KLALBRemoteLine.java b/src/org/kne/cloud/network/klalb/KLALBRemoteLine.java index 954f83b..5bf9f1a 100644 --- a/src/org/kne/cloud/network/klalb/KLALBRemoteLine.java +++ b/src/org/kne/cloud/network/klalb/KLALBRemoteLine.java @@ -369,7 +369,8 @@ public class KLALBRemoteLine implements IPv6NetworkLink,Comparable sendMap= new ConcurrentHashMap<>(); + private Map sendMap= new ConcurrentHashMap<>(1024,0.2f); private AtomicInteger sendmapWindowUsed=new AtomicInteger(0); - private MaprecvedUIDMap=new ConcurrentHashMap(); + private MaprecvedUIDMap=new ConcurrentHashMap(1024,0.2f); private volatile int inputchachesize = 8192 * 4000; private volatile int outputchachesize = 8192 * 240;//500 diff --git a/src/org/kne/cloud/network/klalb/KLALBRemoteManagement.java b/src/org/kne/cloud/network/klalb/KLALBRemoteManagement.java index 483dc0a..6a4e2b9 100644 --- a/src/org/kne/cloud/network/klalb/KLALBRemoteManagement.java +++ b/src/org/kne/cloud/network/klalb/KLALBRemoteManagement.java @@ -144,7 +144,7 @@ public class KLALBRemoteManagement { case "OPENMONITORUI": klalbProxySystem.getKLALBGUI().setVisible(true); break; - case "GETSOCKETBRIDGE": + /*case "GETSOCKETBRIDGE": JsonArray bridges=new JsonArray(); Set pxy=klalbProxySystem.getProxys(); synchronized (pxy) { @@ -165,7 +165,7 @@ public class KLALBRemoteManagement { e.printStackTrace(); } } - break; + break;*/ default: System.out.println("未知请求类型:"+reqt); break; diff --git a/src/org/kne/cloud/network/klalb/KLALBVirtualSocketImpl.java b/src/org/kne/cloud/network/klalb/KLALBVirtualSocketImpl.java index 84965a7..e01ccbc 100644 --- a/src/org/kne/cloud/network/klalb/KLALBVirtualSocketImpl.java +++ b/src/org/kne/cloud/network/klalb/KLALBVirtualSocketImpl.java @@ -94,9 +94,9 @@ public class KLALBVirtualSocketImpl extends VirtualSocketImpl implements Bindabl //60000 30 30 - private final int MTU=10000; + private final int MTU=60000; private final long MIN_RTTVAR=100000000L; - private final long MIN_LIMIT_SPEED=128*1024L; + private final long MIN_LIMIT_SPEED=64*1024L; private final long REACK_INTERVAL = 100000000L; @@ -115,12 +115,12 @@ public class KLALBVirtualSocketImpl extends VirtualSocketImpl implements Bindabl private ReentrantLock backlogQueuelock=new ReentrantLock(); private ThreadParker sendDequeLock=new ThreadParker(); - private Map recvMap = new ConcurrentHashMap(100000); + private Map recvMap = new ConcurrentHashMap(1024,0.2f); private AtomicInteger recvWindowUsed=new AtomicInteger(0); //private AtomicInteger recvCounter=new AtomicInteger(0); - private Map sendmap=new ConcurrentHashMap(100000); + private Map sendmap=new ConcurrentHashMap(1024,0.5f); private AtomicInteger sendmapWindowUsed=new AtomicInteger(0); //private ReentrantReadWriteLock sendmaplock=new ReentrantReadWriteLock(); diff --git a/src/org/kne/cloud/network/klalb/PortBinder.java b/src/org/kne/cloud/network/klalb/PortBinder.java index 8f85c1e..faf7d20 100644 --- a/src/org/kne/cloud/network/klalb/PortBinder.java +++ b/src/org/kne/cloud/network/klalb/PortBinder.java @@ -34,11 +34,11 @@ public class PortBinder { this.controller = controller; } private ReentrantReadWriteLock bindMaplock=new ReentrantReadWriteLock(); - private MapbindMap=new ConcurrentHashMap<>(65536*16); + private MapbindMap=new ConcurrentHashMap<>(1024,0.2f); private ReentrantReadWriteLock listenMaplock=new ReentrantReadWriteLock(); - private MaplistenMap=new ConcurrentHashMap<>(65536*16); + private MaplistenMap=new ConcurrentHashMap<>(1024,0.2f); private ReentrantReadWriteLock connectMaplock=new ReentrantReadWriteLock(); - private Map,BindableKLALBPacketConsumer>connectMap=new ConcurrentHashMap<>(65536*16); + private Map,BindableKLALBPacketConsumer>connectMap=new ConcurrentHashMap<>(1024,0.2f); private volatile int portn=65535; public void bind(BindableKLALBPacketConsumer ks) throws BindException { bindMaplock.writeLock().lock(); diff --git a/src/org/kne/cloud/network/klalb/SocketBridgeConfigItem.java b/src/org/kne/cloud/network/klalb/SocketBridgeConfigItem.java new file mode 100644 index 0000000..def9980 --- /dev/null +++ b/src/org/kne/cloud/network/klalb/SocketBridgeConfigItem.java @@ -0,0 +1,112 @@ +package org.kne.cloud.network.klalb; + +import java.io.IOException; +import java.lang.reflect.Type; +import java.nio.channels.MulticastChannel; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Map.Entry; + +import org.kne.cloud.network.DefaultMinecraftSocketBridgeFactory; +import org.kne.cloud.network.DefaultSocketBridgeFactory; +import org.kne.cloud.network.HostPortMap; +import org.kne.cloud.network.MultipurposeSocketAddress; +import org.kne.cloud.network.Proxy; +import org.kne.cloud.network.SocketBridgeFactory; +import org.kne.cloud.network.SocketToSocketProxy; + +import com.google.gson.GsonBuilder; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.JsonPrimitive; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import com.google.gson.annotations.SerializedName; +import com.google.gson.reflect.TypeToken; + +public class SocketBridgeConfigItem extends KLALBConfigItem { + private MultipurposeSocketAddress Listen; + + private LinkedHashMapBridge=new LinkedHashMap<>(); + private HostPortMap Connect=new HostPortMap(); + + public SocketBridgeConfigItem( MultipurposeSocketAddress listen, + LinkedHashMap bridge, HostPortMap connect) { + super("SocketBridge"); + Listen = listen; + Bridge = bridge; + Connect = connect; + } + + + @Override + public String toString() { + return "SocketBridgeConfigItem [Listen=" + Listen + ", Bridge=" + Bridge + ", Connect=" + Connect + "]"; + } + + + /*public static JsonDeserializer getSocketBridgeConfigItemJsonDeserializer(){ + return new JsonDeserializer() { + + @Override + public SocketBridgeConfigItem deserialize(JsonElement arg0, Type arg1, JsonDeserializationContext arg2) + throws JsonParseException { + if(arg0.isJsonObject()) { + HostPortMap mapp=new HostPortMap(); + LinkedHashMapmapb=new LinkedHashMap<>(); + MultipurposeSocketAddress l=new MultipurposeSocketAddress(((JsonObject) arg0).get("Listen").getAsString()); + SocketBridgeFactory bdg=getDefaultBridgeFactory(((JsonObject)arg0).get("Bridge"),mapb); + MultipurposeSocketAddress r=getDefaultConnect(((JsonObject)arg0).get("Connect"),mapp); + return new SocketBridgeConfigItem(l,mapb,mapp); + }else { + throw new JsonParseException("not a object:"+arg0); + } + } + }; + } + public static JsonSerializer getSocketBridgeConfigItemJsonSerializer(){ + return new JsonSerializer() { + + @Override + public JsonElement serialize(SocketBridgeConfigItem arg0, Type arg1, JsonSerializationContext arg2) { + return null; + + } + }; + } + public static void registerToGsonBuilder(GsonBuilder gsonBuilder) { + gsonBuilder.registerTypeAdapter(SocketBridgeConfigItem.class, getSocketBridgeConfigItemJsonDeserializer()); + gsonBuilder.registerTypeAdapter(SocketBridgeConfigItem.class, getSocketBridgeConfigItemJsonSerializer()); + }*/ + public Proxy createProxy(KLALBController controller) throws IOException { + HostPortMap mapp=new HostPortMap(); + LinkedHashMapmapb=new LinkedHashMap<>(); + MultipurposeSocketAddress l=Listen; + SocketBridgeFactory bdg=getDefaultBridgeFactory(Bridge,mapb,controller); + MultipurposeSocketAddress r=getDefaultConnect(Connect,mapp); + return new SocketToSocketProxy(l ,new MultipurposeSocketAddress("0.0.0.0:0"), r,mapp,bdg,mapb); + } + private MultipurposeSocketAddress getDefaultConnect(HostPortMap connect2, LinkedHashMap mapp) { + connect2.entrySet().forEach((en)->{ + mapp.put(en.getKey(), en.getValue()); + }); + return mapp.get("DEFAULT"); + } + private SocketBridgeFactory getDefaultBridgeFactory(LinkedHashMap bridge2, LinkedHashMap mapp, KLALBController controller) { + bridge2.entrySet().forEach((en)->{ + mapp.put(en.getKey(), getFactoryByJobj(en.getValue(), controller)); + }); + return mapp.get("DEFAULT"); + }private SocketBridgeFactory getFactoryByJobj(String string,KLALBController controller) { + if(string.startsWith("SocketBridge")) { + return new DefaultSocketBridgeFactory(); + }else if(string.startsWith("MinecraftSocketBridge")) { + return new DefaultMinecraftSocketBridgeFactory(controller.getSelf().getAddress(), Integer.parseInt(string.substring(21))); + } + throw new IllegalArgumentException("unknown SocketBridge type:"+string); + } +} diff --git a/src/org/kne/cloud/network/klalb/StreamChannelKLALBPacketLink.java b/src/org/kne/cloud/network/klalb/StreamChannelKLALBPacketLink.java index 8cdde11..138e5d7 100644 --- a/src/org/kne/cloud/network/klalb/StreamChannelKLALBPacketLink.java +++ b/src/org/kne/cloud/network/klalb/StreamChannelKLALBPacketLink.java @@ -61,7 +61,7 @@ public class StreamChannelKLALBPacketLink extends AbstractKLALBPacketLink implem } private SocketChannel connectSocket; - private int sotimeout; + private int sotimeout=getDefaultSoTimeout(); public StreamChannelKLALBPacketLink(SocketChannel connectSocket) throws IOException { this.connectSocket=connectSocket; connectSocket.setOption(StandardSocketOptions.TCP_NODELAY,true); @@ -140,10 +140,15 @@ public class StreamChannelKLALBPacketLink extends AbstractKLALBPacketLink implem } - - + private ByteBuffer[] bbfwx=new ByteBuffer[100<<1]; + { + for(int i=0;i<100;i++) { + bbfwx[i<<1]=NetworkPacket.bufferAllocator.allocate(4); + } + } @Override public void writePackets(ByteBuffer[] kpp,int off,int len) throws IOException { + if(len>100) { ByteBuffer[] bbfw=new ByteBuffer[len<<1]; for(int i=0;ilength) { - Vector2 dicb=sub.normalize().multi((distance-length)/3); + Vector2 dicb=sub.normalize().multi((distance-length)/4); Vector2 dica=dicb.opposite(); na.delta=na.delta.add(dica); nb.delta=nb.delta.add(dicb); @@ -497,15 +544,15 @@ public class GraphPanel extends JPanel { private Random r=new Random(); public Vector2 getRandomPos() { double x,y; - if(xmin>=xmax) { - x=r.nextDouble(); - }else { + if(xmin=ymax) { - y=r.nextDouble(); }else { + x=r.nextDouble(); + } + if(ymin saveComsumer; + + private JComboBox comboLang; + + + public Consumer getSaveComsumer() { + return saveComsumer; + } + + public void setSaveComsumer(Consumer saveComsumer) { + this.saveComsumer = saveComsumer; + } + + /** + * @wbp.parser.constructor + */ + public KLALBStateGUI3(KLALBController kpcje) { + this(kpcje, CONST.klalb + " "+UIEnv.getRsb().getString("srv6acc")+" V" + CONST.klalbver); + } + + public KLALBStateGUI3(KLALBController kc, String title) { + + // setResizable(false); + setIconImage(UIEnv.getIcon()); + // setTitleColor(new Color(255, 255, 255, 250)); + setTitleColor(UIEnv.getDefaultTitleColor()); + getContentPane().setBackground(UIEnv.getDefaultBackgroundColor()); + getTitlelabel().setFont(UIEnv.getFont().deriveFont(17.0f)); + getTitlepanel().setBorder(new LineBorder(Color.LIGHT_GRAY)); + getTitlelabel().setForeground(Color.WHITE); + // getContentPane().setBackground(new Color(0,0,0,0)); + /* + * setTitleColor(new Color(0,0,0,80)); getContentPane().setBackground(new + * Color(0,0,0,80)); getTitlelabel().setForeground(Color.WHITE); + */ + + JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.TOP); + getContentPane().add(tabbedPane, BorderLayout.CENTER); + + JPanel panel_3 = new JPanel(); + panel_3.setBackground(new Color(255, 255, 255)); + tabbedPane.addTab(UIEnv.getRsb().getString("networkgraph"), null, panel_3, null); + panel_3.setLayout(new BorderLayout(0, 0)); + + JPanel panel_4 = new JPanel(); + panel_3.add(panel_4, BorderLayout.NORTH); + panel_4.setLayout(new BorderLayout(0, 0)); + + textFieldLocate = new JTextField(); + panel_4.add(textFieldLocate, BorderLayout.CENTER); + textFieldLocate.setColumns(10); + + graph = new NetworkGraphPanel(kc.getIpv6Router().getKlalbRouteProtol()); + graph.setOpaque(false); + JScrollPane jsp = new JScrollPane(); + jsp.setWheelScrollingEnabled(false); + jsp.setViewportView(graph); + + graph.addMouseWheelListener(new MouseWheelListener() { + private double scaleidx = 1; + + @Override + public void mouseWheelMoved(MouseWheelEvent e) { + int val = e.getWheelRotation(); + double scaleidxold = scaleidx; + scaleidx *= Math.pow(1.1, val); + if (scaleidx > 5) { + scaleidx = 5; + } + if (scaleidx < 0.1) { + scaleidx = 0.1; + } + double pow = scaleidx / scaleidxold; + Point pos = jsp.getViewport().getViewPosition(); + double canvasX = e.getX(); + double canvasY = e.getY(); + double w = graph.getWidth(); + double h = graph.getHeight(); + double percentX = canvasX / w; + double percentY = canvasY / h; + graph.setScale(scaleidx); + graph.updateBounds(); + double newcanvasX = percentX * w * pow; + double newcanvasY = percentY * h * pow; + double dx = newcanvasX - canvasX; + double dy = newcanvasY - canvasY; + // System.out.println(dx+" "+dy); + pos.x += dx; + pos.y += dy; + jsp.getViewport().setViewPosition(pos); + } + }); + + JButton btnLocate = new JButton(UIEnv.getRsb().getString("find")); + btnLocate.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + String text = textFieldLocate.getText(); + try { + Inet6Address addr = (Inet6Address) Inet6Address.getByName(text); + GraphNode node = graph.getNodes().get(addr); + if (node == null) { + JOptionPane.showMessageDialog(KLALBStateGUI3.this, "Address not found", "Warning", + JOptionPane.WARNING_MESSAGE); + } else { + Point pos = new Point(); + graph.updateBounds(); + Dimension dim = jsp.getViewport().getExtentSize(); + // System.out.println(dim); + pos.x = (int) ((node.getX() + graph.getTranslateX()) * graph.getScale() - dim.width / 2); + pos.y = (int) ((node.getY() + graph.getTranslateY()) * graph.getScale() - dim.height / 2); + jsp.getViewport().setViewPosition(pos); + } + } catch (UnknownHostException e1) { + JOptionPane.showMessageDialog(KLALBStateGUI3.this, "Input format error", "Error", + JOptionPane.ERROR_MESSAGE); + e1.printStackTrace(); + } + } + }); + panel_4.add(btnLocate, BorderLayout.EAST); + + JButton btnHome = new JButton(UIEnv.getRsb().getString("home")); + btnHome.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + textFieldLocate.setText(addressField.getText()); + btnLocate.doClick(); + } + }); + panel_4.add(btnHome, BorderLayout.WEST); + panel_3.add(jsp, BorderLayout.CENTER); + + JPanel panel_4_1 = new JPanel(); + panel_3.add(panel_4_1, BorderLayout.SOUTH); + panel_4_1.setLayout(new BorderLayout(0, 0)); + textFieldLocate.addKeyListener(new KeyListener() { + + @Override + public void keyTyped(KeyEvent e) { + } + + @Override + public void keyReleased(KeyEvent e) { + } + + @Override + public void keyPressed(KeyEvent e) { + // TODO 自动生成的方法存根 + + if (e.getKeyCode() == KeyEvent.VK_ENTER) { + btnLocate.doClick(); + } + } + }); + JPanel dashs = new JPanel(); + dashs.setOpaque(false); + // dashboard.add(dashs); + panel_4_1.add(dashs, BorderLayout.EAST); + { + upSpeed = new DefaultValueDataset(0); + upDataSpeed = new DefaultValueDataset(0); + DialPlot dpup = new DialPlot(); + dpup.setDataset(1, upSpeed); + dpup.setDataset(0, upDataSpeed); + StandardDialFrame sdfs = new StandardDialFrame(); + sdfs.setVisible(false); + dpup.setDialFrame(sdfs); + StandardDialScale sds = new StandardDialScale(0, 100, -120, -300, 10, 5); + sds.setTickRadius(0.9); + sds.setTickLabelsVisible(false); + dpup.addScale(0, sds); + + StandardDialRange sdrr = new StandardDialRange(0, 70, Color.GREEN); + sdrr.setInnerRadius(0.92); + sdrr.setOuterRadius(0.93); + dpup.addLayer(sdrr); + + StandardDialRange sdrr2 = new StandardDialRange(70, 90, Color.YELLOW); + sdrr2.setInnerRadius(0.92); + sdrr2.setOuterRadius(0.93); + dpup.addLayer(sdrr2); + + StandardDialRange sdrr3 = new StandardDialRange(90, 100, Color.RED); + sdrr3.setInnerRadius(0.92); + sdrr3.setOuterRadius(0.93); + dpup.addLayer(sdrr3); + + DialPointer.Pointer dpd = new DialPointer.Pointer(); + dpd.setRadius(0.8); + dpd.setFillPaint(new Color(127, 0, 0, 0)); + dpd.setOutlinePaint(new Color(127, 0, 0)); + dpd.setDatasetIndex(0); + dpup.addLayer(dpd); + + DialPointer.Pointer dp = new DialPointer.Pointer(); + dp.setRadius(0.8); + dp.setFillPaint(Color.RED); + dp.setOutlinePaint(Color.RED); + dp.setDatasetIndex(1); + dpup.addLayer(dp); + + upSpeedText = new DialTextAnnotation("0%"); + upSpeedText.setFont(UIEnv.getFont().deriveFont(18.0f)); + dpup.addLayer(upSpeedText); + + JFreeChart jfup = new JFreeChart(dpup); + jfup.setBorderPaint(Color.WHITE); + jfup.setTitle(UIEnv.getRsb().getString("uploadspeed")); + jfup.getTitle().setFont(UIEnv.getFont().deriveFont(20.0f)); + jfup.getTitle().setPosition(RectangleEdge.BOTTOM); + dpup.setView(0, 0, 1, 1); + ChartPanel cpup = new ChartPanel(jfup); + cpup.setPreferredSize(dashSize); + cpup.setSize(cpup.getPreferredSize()); + cpup.setBackground(Color.WHITE); + cpup.setBorder(new LineBorder(Color.LIGHT_GRAY)); + dashs.add(cpup); + + downSpeed = new DefaultValueDataset(0); + downDataSpeed = new DefaultValueDataset(0); + DialPlot dpup1 = new DialPlot(); + dpup1.setDataset(1, downSpeed); + dpup1.setDataset(0, downDataSpeed); + StandardDialFrame sdfs1 = new StandardDialFrame(); + sdfs1.setVisible(false); + dpup1.setDialFrame(sdfs1); + StandardDialScale sds1 = new StandardDialScale(0, 100, -120, -300, 10, 5); + sds1.setTickRadius(0.9); + sds1.setTickLabelsVisible(false); + dpup1.addScale(0, sds1); + + StandardDialRange sdrr1 = new StandardDialRange(0, 70, Color.GREEN); + sdrr1.setInnerRadius(0.92); + sdrr1.setOuterRadius(0.93); + dpup1.addLayer(sdrr1); + + StandardDialRange sdrr21 = new StandardDialRange(70, 90, Color.YELLOW); + sdrr21.setInnerRadius(0.92); + sdrr21.setOuterRadius(0.93); + dpup1.addLayer(sdrr21); + + StandardDialRange sdrr31 = new StandardDialRange(90, 100, Color.RED); + sdrr31.setInnerRadius(0.92); + sdrr31.setOuterRadius(0.93); + dpup1.addLayer(sdrr31); + + DialPointer.Pointer dp11 = new DialPointer.Pointer(); + dp11.setRadius(0.8); + dp11.setFillPaint(new Color(0, 127, 0, 0)); + dp11.setOutlinePaint(new Color(0, 127, 0)); + dp11.setDatasetIndex(0); + dpup1.addLayer(dp11); + + DialPointer.Pointer dp1 = new DialPointer.Pointer(); + dp1.setRadius(0.8); + dp1.setFillPaint(Color.GREEN); + dp1.setOutlinePaint(Color.GREEN); + dp1.setDatasetIndex(1); + dpup1.addLayer(dp1); + + downSpeedText = new DialTextAnnotation("0%"); + downSpeedText.setFont(UIEnv.getFont().deriveFont(18.0f)); + dpup1.addLayer(downSpeedText); + + JFreeChart jfup1 = new JFreeChart(dpup1); + jfup1.setBorderPaint(Color.WHITE); + jfup1.setTitle(UIEnv.getRsb().getString("downloadspeed")); + jfup1.getTitle().setFont(UIEnv.getFont().deriveFont(20.0f)); + jfup1.getTitle().setPosition(RectangleEdge.BOTTOM); + dpup1.setView(0, 0, 1, 1); + ChartPanel cpup1 = new ChartPanel(jfup1); + cpup1.setPreferredSize(dashSize); + cpup1.setSize(cpup1.getPreferredSize()); + cpup1.setBackground(Color.WHITE); + cpup1.setBorder(new LineBorder(Color.LIGHT_GRAY)); + dashs.add(cpup1); + + } + + { + upPPS = new DefaultValueDataset(0); + upDataPPS = new DefaultValueDataset(0); + DialPlot dpup = new DialPlot(); + dpup.setDataset(1, upPPS); + dpup.setDataset(0, upDataPPS); + StandardDialFrame sdfs = new StandardDialFrame(); + sdfs.setVisible(false); + dpup.setDialFrame(sdfs); + StandardDialScale sds = new StandardDialScale(0, 100, -120, -300, 10, 5); + sds.setTickRadius(0.9); + sds.setTickLabelsVisible(false); + dpup.addScale(0, sds); + + StandardDialRange sdrr = new StandardDialRange(0, 70, Color.GREEN); + sdrr.setInnerRadius(0.92); + sdrr.setOuterRadius(0.93); + dpup.addLayer(sdrr); + + StandardDialRange sdrr2 = new StandardDialRange(70, 90, Color.YELLOW); + sdrr2.setInnerRadius(0.92); + sdrr2.setOuterRadius(0.93); + dpup.addLayer(sdrr2); + + StandardDialRange sdrr3 = new StandardDialRange(90, 100, Color.RED); + sdrr3.setInnerRadius(0.92); + sdrr3.setOuterRadius(0.93); + dpup.addLayer(sdrr3); + + DialPointer.Pointer dp1 = new DialPointer.Pointer(); + dp1.setRadius(0.8); + dp1.setFillPaint(new Color(127, 0, 0, 0)); + dp1.setOutlinePaint(new Color(127, 0, 0)); + dp1.setDatasetIndex(0); + dpup.addLayer(dp1); + + DialPointer.Pointer dp = new DialPointer.Pointer(); + dp.setRadius(0.8); + dp.setFillPaint(Color.RED); + dp.setOutlinePaint(Color.RED); + dp.setDatasetIndex(1); + dpup.addLayer(dp); + + upPPSText = new DialTextAnnotation("0PPS"); + upPPSText.setFont(UIEnv.getFont().deriveFont(18.0f)); + dpup.addLayer(upPPSText); + + JFreeChart jfup = new JFreeChart(dpup); + jfup.setBorderPaint(Color.WHITE); + jfup.setTitle(UIEnv.getRsb().getString("uploadpps")); + jfup.getTitle().setFont(UIEnv.getFont().deriveFont(20.0f)); + jfup.getTitle().setPosition(RectangleEdge.BOTTOM); + dpup.setView(0, 0, 1, 1); + ChartPanel cpup = new ChartPanel(jfup); + cpup.setPreferredSize(dashSize); + cpup.setSize(cpup.getPreferredSize()); + cpup.setBackground(Color.WHITE); + cpup.setBorder(new LineBorder(Color.LIGHT_GRAY)); + dashs.add(cpup); + + downPPS = new DefaultValueDataset(0); + downDataPPS = new DefaultValueDataset(0); + DialPlot dpup1 = new DialPlot(); + dpup1.setDataset(1, downPPS); + dpup1.setDataset(0, downDataPPS); + StandardDialFrame sdfs1 = new StandardDialFrame(); + sdfs1.setVisible(false); + dpup1.setDialFrame(sdfs1); + StandardDialScale sds1 = new StandardDialScale(0, 100, -120, -300, 10, 5); + sds1.setTickRadius(0.9); + sds1.setTickLabelsVisible(false); + dpup1.addScale(0, sds1); + + StandardDialRange sdrr1 = new StandardDialRange(0, 70, Color.GREEN); + sdrr1.setInnerRadius(0.92); + sdrr1.setOuterRadius(0.93); + dpup1.addLayer(sdrr1); + + StandardDialRange sdrr21 = new StandardDialRange(70, 90, Color.YELLOW); + sdrr21.setInnerRadius(0.92); + sdrr21.setOuterRadius(0.93); + dpup1.addLayer(sdrr21); + + StandardDialRange sdrr31 = new StandardDialRange(90, 100, Color.RED); + sdrr31.setInnerRadius(0.92); + sdrr31.setOuterRadius(0.93); + dpup1.addLayer(sdrr31); + + DialPointer.Pointer dp111 = new DialPointer.Pointer(); + dp111.setRadius(0.8); + dp111.setFillPaint(new Color(0, 127, 0, 0)); + dp111.setOutlinePaint(new Color(0, 127, 0)); + dp111.setDatasetIndex(0); + dpup1.addLayer(dp111); + DialPointer.Pointer dp11 = new DialPointer.Pointer(); + dp11.setRadius(0.8); + dp11.setFillPaint(Color.GREEN); + dp11.setOutlinePaint(Color.GREEN); + dp11.setDatasetIndex(1); + dpup1.addLayer(dp11); + + downPPSText = new DialTextAnnotation("0PPS"); + downPPSText.setFont(UIEnv.getFont().deriveFont(18.0f)); + dpup1.addLayer(downPPSText); + + JFreeChart jfup1 = new JFreeChart(dpup1); + jfup1.setBorderPaint(Color.WHITE); + jfup1.setTitle(UIEnv.getRsb().getString("downloadpps")); + jfup1.getTitle().setFont(UIEnv.getFont().deriveFont(20.0f)); + jfup1.getTitle().setPosition(RectangleEdge.BOTTOM); + dpup1.setView(0, 0, 1, 1); + ChartPanel cpup1 = new ChartPanel(jfup1); + cpup1.setPreferredSize(dashSize); + cpup1.setSize(cpup1.getPreferredSize()); + cpup1.setBackground(Color.WHITE); + cpup1.setBorder(new LineBorder(Color.LIGHT_GRAY)); + dashs.add(cpup1); + } + JPanel panelp = new JPanel(); + panelp.setOpaque(false); + JPanel panel = new JPanel(); + panel.setOpaque(false); + panel.setBorder(new LineBorder(Color.GRAY)); + panel_4_1.add(panelp, BorderLayout.CENTER); + panelp.setLayout(new GridLayout(3, 1, 0, 0)); + + JPanel panel_2x = new JPanel(); + panel_2x.setOpaque(false); + + JPanel panel_2 = new JPanel(); + panel_2.setOpaque(false); + panelp.add(panel_2x); + panel_2x.setLayout(new BorderLayout(0, 0)); + + JPanel panel_2x_1 = new JPanel(); + panel_2x_1.setOpaque(false); + panelp.add(panel_2x_1); + panel_2x_1.setLayout(new BorderLayout(0, 0)); + + JLabel lblNewLabel_1 = new JLabel(UIEnv.getRsb().getString("asnumber")); + lblNewLabel_1.setFont(new Font("微软雅黑", Font.PLAIN, 20)); + panel_2x_1.add(lblNewLabel_1, BorderLayout.WEST); + + asnField2 = new JTextField(); + asnField2.setFont(new Font("微软雅黑", Font.PLAIN, 20)); + asnField2.setHorizontalAlignment(SwingConstants.CENTER); + asnField2.setEditable(false); + panel_2x_1.add(asnField2, BorderLayout.CENTER); + asnField2.setColumns(10); + + JButton btnNewButton_2 = new JButton(UIEnv.getRsb().getString("copy")); + btnNewButton_2.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + + Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(asnField2.getText()), + null); + } + }); + panel_2x_1.add(btnNewButton_2, BorderLayout.EAST); + + JLabel lblNewLabel = new JLabel(UIEnv.getRsb().getString("ipv6addr")); + lblNewLabel.setFont(UIEnv.getFont().deriveFont(20.0f)); + lblNewLabel.setHorizontalAlignment(SwingConstants.CENTER); + panel_2x.add(lblNewLabel, BorderLayout.WEST); + panel_2x.add(panel_2); + panel_2.setLayout(new BorderLayout(0, 0)); + + addressField = new JTextField(); + addressField.setEditable(false); + addressField.setHorizontalAlignment(SwingConstants.CENTER); + addressField.setOpaque(false); + panel_2.add(addressField); + addressField.setColumns(10); + addressField.setFont(UIEnv.getFont().deriveFont(20.0f)); + + JButton btnNewButton_1 = new JButton(UIEnv.getRsb().getString("copy")); + btnNewButton_1.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + Toolkit.getDefaultToolkit().getSystemClipboard() + .setContents(new StringSelection(addressField.getText()), null); + } + }); + panel_2.add(btnNewButton_1, BorderLayout.EAST); + + panelp.add(panel); + panel.setLayout(new BorderLayout(0, 0)); + + JLabel jlb = new JLabel(UIEnv.getRsb().getString("onlinedevices")); + jlb.setHorizontalAlignment(SwingConstants.CENTER); + jlb.setFont(UIEnv.getFont().deriveFont(20.0f)); + panel.add(jlb, BorderLayout.WEST); + + devicesOnline = new JTextField(); + devicesOnline.setOpaque(false); + devicesOnline.setHorizontalAlignment(SwingConstants.CENTER); + devicesOnline.setFont(UIEnv.getFont().deriveFont(20.0f)); + devicesOnline.setEditable(false); + panel.add(devicesOnline); + devicesOnline.setColumns(10); + + JPanel linesPanel = new JPanel(); + linesPanel.setOpaque(false); + tabbedPane.add(linesPanel); + tabbedPane.setTitleAt(1,UIEnv.getRsb().getString("remotelines")); + linesPanel.setLayout(new BorderLayout()); + + ysp = new YScrollPane(730); + ysp.setOpaque(false); + JPanel wv = ysp.getView(); + linesPanel.add(ysp, BorderLayout.CENTER); + JMenuBar menuBar = new JMenuBar(); + getContentPane().add(menuBar, BorderLayout.NORTH); + + JMenu mnNewMenu = new JMenu(UIEnv.getRsb().getString("monitor")); + menuBar.add(mnNewMenu); + /* + * JMenu mnNewMenu_1 = new JMenu("Update frequency"); + * mnNewMenu.add(mnNewMenu_1); ButtonGroup bg=new ButtonGroup(); + * JRadioButtonMenuItem rdbtnmntmNewRadioItem = new + * JRadioButtonMenuItem("0.5s"); mnNewMenu_1.add(rdbtnmntmNewRadioItem); + * bg.add(rdbtnmntmNewRadioItem); rdbtnmntmNewRadioItem.addActionListener(new + * ActionListener() { + * + * @Override public void actionPerformed(ActionEvent e) { rate=500; + * + * createRefreshTask(kc, ysp); } }); + * + * JRadioButtonMenuItem rdbtnmntmNewRadioItem_1 = new + * JRadioButtonMenuItem("0.2s"); mnNewMenu_1.add(rdbtnmntmNewRadioItem_1); + * bg.add(rdbtnmntmNewRadioItem_1); rdbtnmntmNewRadioItem_1.setSelected(true); + * rdbtnmntmNewRadioItem_1.addActionListener(new ActionListener() { + * + * + * @Override public void actionPerformed(ActionEvent e) { rate=200; + * + * createRefreshTask(kc, ysp); } }); + * + * JRadioButtonMenuItem rdbtnmntmNewRadioItem_2 = new + * JRadioButtonMenuItem("0.1s"); mnNewMenu_1.add(rdbtnmntmNewRadioItem_2); + * bg.add(rdbtnmntmNewRadioItem_2); + * + * rdbtnmntmNewRadioItem_2.addActionListener(new ActionListener() { + * + * @Override public void actionPerformed(ActionEvent e) { rate=100; + * + * createRefreshTask(kc, ysp); } }); + * + * JRadioButtonMenuItem rdbtnmntmNewRadioItem_21 = new + * JRadioButtonMenuItem("0.05s"); mnNewMenu_1.add(rdbtnmntmNewRadioItem_21); + * bg.add(rdbtnmntmNewRadioItem_21); + * rdbtnmntmNewRadioItem_21.addActionListener(new ActionListener() { + * + * @Override public void actionPerformed(ActionEvent e) { rate=50; + * + * createRefreshTask(kc, ysp); } }); + */ + + showoffline = new JCheckBoxMenuItem(UIEnv.getRsb().getString("showofflines")); + mnNewMenu.add(showoffline); + /* + * JProgressBar progressBar = new JProgressBar(); + * progressBar.setIndeterminate(true); progressBar.setForeground(Color.YELLOW); + * progressBar.setBorder(null); progressBar.setPreferredSize(new Dimension(100, + * 4)); ysp.add(progressBar, BorderLayout.NORTH); + */ + wv.addComponentListener(new ComponentListener() { + + @Override + public void componentShown(ComponentEvent e) { + // TODO 自动生成的方法存根 + + } + + @Override + public void componentResized(ComponentEvent e) { + // TODO 自动生成的方法存根 + + } + + @Override + public void componentMoved(ComponentEvent e) { + repaint(); + } + + @Override + public void componentHidden(ComponentEvent e) { + // TODO 自动生成的方法存根 + + } + }); + setTitle(title); + setSize(1200, 780); + setLocationRelativeTo(null); + + // setVisible(true); + if (SystemTray.isSupported()) { + st = SystemTray.getSystemTray(); + ti = new TrayIcon(UIEnv.getIcon()); + ti.setImageAutoSize(true); + PopupMenu jpm = new PopupMenu(); + MenuItem mix = new MenuItem("open"); + mix.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + setVisible(true); + } + }); + jpm.add(mix); + MenuItem mi = new MenuItem("exit"); + mi.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + close(); + } + }); + jpm.add(mi); + ti.setPopupMenu(jpm); + try { + st.add(ti); + } catch (AWTException e1) { + e1.printStackTrace(); + } + ti.addActionListener((x) -> { + setVisible(true); + }); + } + + // repaint(); + + t3 = new Timer("监视器刷新线程", true); + t2 = new Timer("仪表盘刷新线程", true); + t = new Timer("状态刷新线程", true); + createRefreshTask(kc, ysp); + + JPanel panel_1 = new JPanel(); + panel_1.setOpaque(false); + linesPanel.add(panel_1, BorderLayout.NORTH); + panel_1.setLayout(new BorderLayout(0, 0)); + + textField = new JTextField(); + panel_1.add(textField); + textField.setColumns(10); + textField.setToolTipText(UIEnv.getRsb().getString("lineaddressport")); + + JButton btnNewButton = new JButton(UIEnv.getRsb().getString("addline")); + btnNewButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + try { + kc.addRemoteLines(new MultipurposeSocketAddress(textField.getText())); + } catch (RuntimeException ex) { + JOptionPane.showMessageDialog(KLALBStateGUI3.this, "Input format error", "Error", + JOptionPane.ERROR_MESSAGE); + ex.printStackTrace(); + } + } + }); + panel_1.add(btnNewButton, BorderLayout.EAST); + + JButton btnReconnect = new JButton(UIEnv.getRsb().getString("reconnectall")); + btnReconnect.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + kc.reconnectImmediately(); + } + }); + panel_1.add(btnReconnect, BorderLayout.WEST); + MouseAdapter ma = new MouseAdapter() { + + private Point origin; + + @Override + public void mousePressed(MouseEvent e) { + origin = new Point(e.getPoint()); + // System.out.println(e); + } + + @Override + public void mouseReleased(MouseEvent e) { + } + + @Override + public void mouseDragged(MouseEvent e) { + if (origin != null) { + // System.out.println(e); + // JViewport viewPort = (JViewport) + // SwingUtilities.getAncestorOfClass(JViewport.class, jsp); + // if (viewPort != null) { + int deltaX = origin.x - e.getX(); + int deltaY = origin.y - e.getY(); + + Rectangle view = jsp.getViewport().getVisibleRect(); + view.x += deltaX; + view.y += deltaY; + + jsp.getViewport().scrollRectToVisible(view); + // } + } + } + + }; + yspc = new YScrollPane(730); + yspc.setOpaque(false); + JPanel configsPanel = new JPanel(); + configsPanel.setLayout(new BorderLayout(0, 0)); + configsPanel.add(yspc); + addSettingItems(yspc); + JButton btnSave = new JButton(UIEnv.getRsb().getString("savesettings")); + btnSave.addActionListener(new ActionListener() { + + public void actionPerformed(ActionEvent e) { + saveConfig(); + } + }); + yspc.add(btnSave, BorderLayout.SOUTH); + tabbedPane.addTab(UIEnv.getRsb().getString("settings"), null, configsPanel, null); + configsPanel.setOpaque(false); + textField.addKeyListener(new KeyListener() { + + @Override + public void keyTyped(KeyEvent e) { + } + + @Override + public void keyReleased(KeyEvent e) { + } + + @Override + public void keyPressed(KeyEvent e) { + // TODO 自动生成的方法存根 + + if (e.getKeyCode() == KeyEvent.VK_ENTER) { + btnNewButton.doClick(); + } + } + }); + graph.addMouseListener(ma); + graph.addMouseMotionListener(ma); + } + private void saveConfig() { + if(config==null) { + config=new KLALBConfig(); + config.add(new KLALBControllerConfigItem("KLALBController")); + } + for (KLALBConfigItem item : config) { + if (item instanceof KLALBControllerConfigItem) { + KLALBControllerConfigItem kck = (KLALBControllerConfigItem) item; + + kck.setLanguage(((Language)comboLang.getSelectedItem()).name()); + + String ttext=addressFieldSet.getText().trim(); + if(ttext.equals("")) { + kck.setVirtualAddress(null); + }else { + try { + kck.setVirtualAddress(Inet6Address.getByName(ttext).getHostAddress()); + } catch (UnknownHostException e1) { + e1.printStackTrace(); + JOptionPane.showMessageDialog(this,UIEnv.getRsb().getString("invaildipv6addr") , UIEnv.getRsb().getString("warning"), JOptionPane.WARNING_MESSAGE); + } + } + String[]splt=dnsAreaSet.getText().split("\n"); + Listiaddr=new ArrayList(); + boolean show=true; + for (int i = 0; i < splt.length; i++) { + try { + String str=splt[i].trim(); + if(!str.isEmpty()) + iaddr.add( Inet6Address.getByName(str)); + } catch (UnknownHostException e) { + e.printStackTrace(); + if(show) { + show=false; + JOptionPane.showMessageDialog(this,UIEnv.getRsb().getString("invailddnsserver") , UIEnv.getRsb().getString("warning"), JOptionPane.WARNING_MESSAGE); + } + } + } + kck.setDNS(iaddr); + + String asntext=asnFieldSet.getText(); + if(asntext.equals("")) { + kck.setVirtualASN(null); + }else { + try { + kck.setVirtualASN(Long.parseLong(asntext)); + }catch (NumberFormatException e) { + e.printStackTrace(); + JOptionPane.showMessageDialog(this,UIEnv.getRsb().getString("invaildasnumber") , UIEnv.getRsb().getString("warning"), JOptionPane.WARNING_MESSAGE); + } + } + + String tcptext=tcpListeningSet.getText(); + if(tcptext.equals("")) { + kck.setTCPListen(null); + }else { + try { + kck.setTCPListen(new MultipurposeSocketAddress(tcptext)); + }catch (RuntimeException e) { + e.printStackTrace(); + JOptionPane.showMessageDialog(this,UIEnv.getRsb().getString("invaildtcplisten") , UIEnv.getRsb().getString("warning"), JOptionPane.WARNING_MESSAGE); + } + } + + String udptext=udpListeningSet.getText(); + if(udptext.equals("")) { + kck.setUDPListen(null); + }else { + try { + kck.setUDPListen(new MultipurposeSocketAddress(udptext)); + }catch (RuntimeException e) { + e.printStackTrace(); + JOptionPane.showMessageDialog(this,UIEnv.getRsb().getString("invaildudplisten") , UIEnv.getRsb().getString("warning"), JOptionPane.WARNING_MESSAGE); + } + } + + String[]splt1=openLineTabelSet.getText().split("\n"); + Listiaddr1=new ArrayList(); + boolean show1=true; + for (int i = 0; i < splt1.length; i++) { + try { + String str=splt1[i].trim(); + if(!str.isEmpty()) + iaddr1.add( new MultipurposeSocketAddress(str)); + } catch (RuntimeException e) { + e.printStackTrace(); + if(show1) { + show1=false; + JOptionPane.showMessageDialog(this,UIEnv.getRsb().getString("invaildopenlinetable") , UIEnv.getRsb().getString("warning"), JOptionPane.WARNING_MESSAGE); + } + } + } + kck.setLineTable(iaddr1); + + String[]splt11=connectLineTabelSet.getText().split("\n"); + Listiaddr11=new ArrayList(); + boolean show11=true; + for (int i = 0; i < splt11.length; i++) { + try { + String str=splt11[i].trim(); + if(!str.isEmpty()) + iaddr11.add( new MultipurposeSocketAddress(str)); + } catch (RuntimeException e) { + e.printStackTrace(); + if(show11) { + show11=false; + JOptionPane.showMessageDialog(this,UIEnv.getRsb().getString("invaildconnectlinetable") , UIEnv.getRsb().getString("warning"), JOptionPane.WARNING_MESSAGE); + } + } + } + kck.setConnectLineTable(iaddr11); + } + } + if(saveComsumer!=null) { + saveComsumer.accept(config); + JOptionPane.showMessageDialog(this,UIEnv.getRsb().getString("saveconfigsuccess")); + } + } + + private void addSettingItems(YScrollPane settings) { + + ComboSettingItem lang = new ComboSettingItem(UIEnv.getRsb().getString("language"), CONST.itemwidth, CONST.settingheight); + comboLang = lang.getComboBox(); + comboLang.addItem(Language.EN_US); + comboLang.addItem(Language.ZH_CN); + settings.getView().add(lang); + settings.updateScrool(); + + SettingItem si = new SettingItem(UIEnv.getRsb().getString("basicsettings"), UIEnv.getFont().deriveFont(20.0f).deriveFont(Font.BOLD), + CONST.itemwidth, CONST.settingheight); + settings.getView().add(si); + + TextSettingItem addr6 = new TextSettingItem(UIEnv.getRsb().getString("ipv6addr"), CONST.itemwidth, CONST.settingheight); + addressFieldSet = addr6.getTextField(); + settings.getView().add(addr6); + + TextAreaSettingItem dns = new TextAreaSettingItem(UIEnv.getRsb().getString("dnsserver"), CONST.itemwidth, CONST.settingheight * 5); + dnsAreaSet = dns.getTextArea(); + settings.getView().add(dns); + + TextSettingItem asn = new TextSettingItem(UIEnv.getRsb().getString("asnumber"), CONST.itemwidth, CONST.settingheight); + asnFieldSet = asn.getTextField(); + settings.getView().add(asn); + + TextSettingItem tcpl = new TextSettingItem(UIEnv.getRsb().getString("tcplistening"), CONST.itemwidth, CONST.settingheight); + tcpListeningSet = tcpl.getTextField(); + settings.getView().add(tcpl); + + TextSettingItem udpl = new TextSettingItem(UIEnv.getRsb().getString("udplistening"), CONST.itemwidth, CONST.settingheight); + udpListeningSet = udpl.getTextField(); + settings.getView().add(udpl); + + TextAreaSettingItem olinet = new TextAreaSettingItem(UIEnv.getRsb().getString("openlinetable"), CONST.itemwidth, + CONST.settingheight * 5); + openLineTabelSet = olinet.getTextArea(); + settings.getView().add(olinet); + + TextAreaSettingItem clinet = new TextAreaSettingItem(UIEnv.getRsb().getString("autoconnectlinetable"), CONST.itemwidth, + CONST.settingheight * 5); + connectLineTabelSet = clinet.getTextArea(); + settings.getView().add(clinet); + + SettingItem hi = new SettingItem(UIEnv.getRsb().getString("advancedsettings"), UIEnv.getFont().deriveFont(20.0f).deriveFont(Font.BOLD), + CONST.itemwidth, CONST.settingheight); + settings.getView().add(hi); + + ComboSettingItem congress = new ComboSettingItem(UIEnv.getRsb().getString("congresscontrolalgorithm"), CONST.itemwidth, CONST.settingheight); + comboCongress = congress.getComboBox(); + comboCongress.addItem("BBR"); + comboCongress.addItem("Vegas"); + comboCongress.addItem("BBR-Vegas"); + settings.getView().add(congress); + settings.updateScrool(); + + + } + + private void createRefreshTask(KLALBController kc, YScrollPane ysp) { + if (tsk != null) { + tsk.cancel(); + } + tsk = new TimerTask() { + + @Override + public void run() { + Object[] kll; + kll = kc.getLines().toArray(); + + loop: for (int ix = 0; ix < kll.length; ix++) { + KLALBRemoteLine ent = (KLALBRemoteLine) kll[ix]; + /* + * if(ent.getMonitor().getState()!=MonitorData.ONLINE) { continue loop; } + */ + Component[] count = ysp.getView().getComponents(); + for (int i = 0; i < count.length; i++) { + Component tp = count[i]; + if (tp instanceof TPanel2) { + if (((TPanel2) tp).getTunnel().equals(ent)) { + tp.setVisible( + showoffline.isSelected() || ent.getMonitor().getState() == MonitorData.ONLINE); + continue loop; + } + } + } + TPanel2 tp = new TPanel2(ent, kc); + tp.setVisible(showoffline.isSelected() || ent.getMonitor().getState() == MonitorData.ONLINE); + ysp.getView().add(tp); + } + Component[] count = ysp.getView().getComponents(); + for (int i = 0; i < count.length; i++) { + Component tp = count[i]; + if (tp instanceof TPanel2) { + /* + * if((((TPanel2) tp).getTunnel().getMonitor().getState())!=MonitorData.ONLINE) + * { ysp.getView().remove(tp); continue; } + */ + if (kc.getLines().contains(((TPanel2) tp).getTunnel())) { + try { + if (tp.isVisible()) + ((TPanel2) tp).updateTraffic(); + } catch (RuntimeException e) { + e.printStackTrace(); + } + } else { + ysp.getView().remove(tp); + } + } + } + ysp.updateScrool(); + // repaint(); + } + }; + t.scheduleAtFixedRate(tsk, 200, 500); + if (tsk2 != null) { + tsk2.cancel(); + } + tsk2 = new TimerTask() { + + @Override + public void run() { + double outload = kc.getLinkMonitor().getOutSpeed() * 100.0 / kc.getLinkMonitor().getOutSpeedMax2(); + if (Double.isFinite(outload)) { + upSpeedText.setLabel(KLALBUtils.bytesUnit(kc.getLinkMonitor().getOutSpeedAvg()) + "/s"); + upSpeed.setValue(Math.min(upSpeed.getValue().doubleValue() * 0.98 + outload * 0.02, 101.0)); + } + + double inload = kc.getLinkMonitor().getInSpeed() * 100.0 / kc.getLinkMonitor().getInSpeedMax2(); + if (Double.isFinite(inload)) { + downSpeedText.setLabel(KLALBUtils.bytesUnit(kc.getLinkMonitor().getInSpeedAvg()) + "/s"); + downSpeed.setValue(Math.min(downSpeed.getValue().doubleValue() * 0.98 + inload * 0.02, 101.0)); + } + + double outPPSload = kc.getLinkMonitor().getOutPPS() * 100.0 / kc.getLinkMonitor().getOutPPSMax2(); + if (Double.isFinite(outPPSload)) { + upPPSText.setLabel(KLALBUtils.defaultUnit(kc.getLinkMonitor().getOutPPSAvg()) + "PPS"); + upPPS.setValue(Math.min(upPPS.getValue().doubleValue() * 0.98 + outPPSload * 0.02, 101.0)); + } + + double inPPSload = kc.getLinkMonitor().getInPPS() * 100.0 / kc.getLinkMonitor().getInPPSMax2(); + if (Double.isFinite(inPPSload)) { + downPPSText.setLabel(KLALBUtils.defaultUnit(kc.getLinkMonitor().getInPPSAvg()) + "PPS"); + downPPS.setValue(Math.min(downPPS.getValue().doubleValue() * 0.98 + inPPSload * 0.02, 101.0)); + } + + double outload1 = kc.getDatatMonitor().getOutSpeed() * 100.0 / kc.getLinkMonitor().getOutSpeedMax2(); + if (Double.isFinite(outload1)) { + upDataSpeed + .setValue(Math.min(upDataSpeed.getValue().doubleValue() * 0.98 + outload1 * 0.02, 101.0)); + } + + double inload1 = kc.getDatatMonitor().getInSpeed() * 100.0 / kc.getLinkMonitor().getInSpeedMax2(); + if (Double.isFinite(inload1)) { + downDataSpeed + .setValue(Math.min(downDataSpeed.getValue().doubleValue() * 0.98 + inload1 * 0.02, 101.0)); + } + + double outPPSload1 = kc.getDatatMonitor().getOutPPS() * 100.0 / kc.getLinkMonitor().getOutPPSMax2(); + if (Double.isFinite(outPPSload1)) { + upDataPPS.setValue(Math.min(upDataPPS.getValue().doubleValue() * 0.98 + outPPSload1 * 0.02, 101.0)); + } + + double inPPSload1 = kc.getDatatMonitor().getInPPS() * 100.0 / kc.getLinkMonitor().getInPPSMax2(); + if (Double.isFinite(inPPSload1)) { + downDataPPS + .setValue(Math.min(downDataPPS.getValue().doubleValue() * 0.98 + inPPSload1 * 0.02, 101.0)); + } + + /* + * double + * outefi=kc.getDatatMonitor().getOutSpeedAvg2()*100.0D/kc.getLinkMonitor(). + * getOutSpeedAvg2(); if(Double.isFinite(outefi)) { + * upEfficiency.setValue(upEfficiency.getValue().doubleValue()*0.95+ + * outefi*0.05); upEfficiencyText.setLabel(String.format("%.1f", + * upEfficiency.getValue().doubleValue())+"%"); } + * + * double + * inefi=kc.getDatatMonitor().getInSpeedAvg2()*100.0D/kc.getLinkMonitor(). + * getInSpeedAvg2(); if(Double.isFinite(inefi)) { + * downEfficiency.setValue(downEfficiency.getValue().doubleValue()*0.95+ + * inefi*0.05); downEfficiencyText.setLabel(String.format("%.1f", + * downEfficiency.getValue().doubleValue())+"%"); } + */ + String contt = Long.toString(kc.getIpv6Router().getKlalbRouteProtol().getDevicesFound()); + if (!contt.equals(devicesOnline.getText())) { + devicesOnline.setText(contt); + } + String address = kc.getSelf().getAddress().getHostAddress(); + if (!address.equals(addressField.getText())) { + addressField.setText(address); + } + + String asnstr = Long.toString(kc.getIpv6Router().getASN()); + + if (!asnstr.equals(asnField2.getText())) { + asnField2.setText(asnstr); + } + + } + }; + t2.scheduleAtFixedRate(tsk2, 200, 100); + + if (tsk3 != null) { + tsk3.cancel(); + } + tsk3 = new TimerTask() { + + @Override + public void run() { + Component[] count = ysp.getView().getComponents(); + for (int i = 0; i < count.length; i++) { + Component tp = count[i]; + if (tp instanceof TPanel2) { + try { + ((TPanel2) tp).getMdg().updateTraffic(); + } catch (RuntimeException e) { + e.printStackTrace(); + } + } + } + } + }; + t3.scheduleAtFixedRate(tsk3, 200, 200); + + if (tsk4 != null) { + tsk4.cancel(); + } + tsk4 = new TimerTask() { + + @Override + public void run() { + Component[] count = ysp.getView().getComponents(); + for (int i = 0; i < count.length; i++) { + Component tp = count[i]; + if (tp instanceof TPanel2) { + try { + ((TPanel2) tp).getMdg().recordData(); + } catch (RuntimeException e) { + e.printStackTrace(); + } + } + } + } + }; + t3.scheduleAtFixedRate(tsk4, 200, 20); + if (tsk5 != null) { + tsk5.cancel(); + } + tsk5 = new TimerTask() { + + @Override + public void run() { + graph.loadNodes(); + for (int i = 0; i < 5; i++) { + graph.runPhy(); + } + if (graph.isVisible()) { + graph.repaint(); + graph.revalidate(); + } + } + }; + t.scheduleAtFixedRate(tsk5, 200, 100); + // setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + } + + public void loadConfig(KLALBConfig config) { + this.config = config; + for (KLALBConfigItem item : config) { + if (item instanceof KLALBControllerConfigItem) { + KLALBControllerConfigItem kck = (KLALBControllerConfigItem) item; + + String lg=kck.getLanguage(); + if(lg!=null) { + Language l=Language.valueOf( lg); + if(l!=null) { + comboLang.setSelectedItem(l); + } + } + String vaddr = kck.getVirtualAddress(); + if (vaddr != null) { + addressFieldSet.setText(vaddr); + } else { + addressFieldSet.setText(""); + } + + List dns = kck.getDNS(); + String str=listToStr(dns); + + dnsAreaSet.setText(str); + Long vasn = kck.getVirtualASN(); + if (vasn != null) { + asnFieldSet.setText(vasn.toString()); + } else { + asnFieldSet.setText(""); + } + + MultipurposeSocketAddress mpat= kck.getTCPListen(); + if(mpat!=null) { + tcpListeningSet.setText(mpat.toString()); + }else { + tcpListeningSet.setText(""); + } + + MultipurposeSocketAddress mpau= kck.getUDPListen(); + if(mpau!=null) { + udpListeningSet.setText(mpau.toString()); + }else { + udpListeningSet.setText(""); + } + + List linet =kck.getLineTable(); + String str1=listToStr2(linet); + openLineTabelSet.setText(str1); + + List clinet =kck.getConnectLineTable(); + String str2=listToStr2(clinet); + connectLineTabelSet.setText(str2); + } + } + } + + private String listToStr(List dns) { + StringBuilder sbdr = new StringBuilder(); + if (dns != null) + for (InetAddress addrdns : dns) { + sbdr.append(addrdns.getHostAddress()); + sbdr.append('\n'); + } + return sbdr.toString(); + } + + private String listToStr2(List objs) { + StringBuilder sbdr = new StringBuilder(); + if (objs != null) + for (Object addrdns : objs) { + sbdr.append(addrdns); + sbdr.append('\n'); + } + return sbdr.toString(); + } + + public void close() { + setVisible(false); + if (tsk != null) { + tsk.cancel(); + } + st.remove(ti); + } + + public static void main(String[] args) throws IOException, InterruptedException {// ,new + // MultipurposeSocketAddress("frp-mom.top:22226"),new + // MultipurposeSocketAddress("0.0.0.0:26468") + KLALBStateGUI3 kcg = new KLALBStateGUI3(new KLALBController()); + kcg.setVisible(true); + // Thread.sleep(10000); + // kcg.close(); + } +} diff --git a/src/org/kne/cloud/network/klalb/ui/Language.java b/src/org/kne/cloud/network/klalb/ui/Language.java new file mode 100644 index 0000000..0cae394 --- /dev/null +++ b/src/org/kne/cloud/network/klalb/ui/Language.java @@ -0,0 +1,19 @@ +package org.kne.cloud.network.klalb.ui; + +import java.util.HashMap; +import java.util.Map; + +public enum Language { + ZH_CN("简体中文","zh_CN"),EN_US("English","en_US"); + private String string,filename; + private Language(String string, String filename) { + this.string=string; + this.filename=filename; + } + public String toString() { + return string; + } + public String getFileName() { + return filename; + } +} diff --git a/src/org/kne/cloud/network/klalb/ui/TPanel2.java b/src/org/kne/cloud/network/klalb/ui/TPanel2.java index 3371571..120badb 100644 --- a/src/org/kne/cloud/network/klalb/ui/TPanel2.java +++ b/src/org/kne/cloud/network/klalb/ui/TPanel2.java @@ -103,7 +103,7 @@ public class TPanel2 extends JPanel { panel.setLayout(new BorderLayout(0, 0)); panel.add(tname); - vaddr = new JLabel("unknown"); + vaddr = new JLabel(UIEnv.getRsb().getString("unknown")); panel.add(vaddr, BorderLayout.SOUTH); vaddr.setForeground(Color.DARK_GRAY); @@ -157,7 +157,7 @@ public class TPanel2 extends JPanel { popupMenu = new JPopupMenu(); - mntmNewMenuItem = new JMenuItem("View line monitor"); + mntmNewMenuItem = new JMenuItem(UIEnv.getRsb().getString("viewlinemonitor")); popupMenu.add(mntmNewMenuItem); mntmNewMenuItem.addActionListener(new ActionListener() { @@ -168,7 +168,7 @@ public class TPanel2 extends JPanel { } }); - JMenuItem mntmNewMenuItemz = new JMenuItem("Copy line address"); + JMenuItem mntmNewMenuItemz = new JMenuItem(UIEnv.getRsb().getString("copylineaddress")); popupMenu.add(mntmNewMenuItemz); mntmNewMenuItemz.addActionListener(new ActionListener() { @@ -178,7 +178,7 @@ public class TPanel2 extends JPanel { } }); - JMenuItem mntmNewMenuItemx = new JMenuItem("Copy virtual address"); + JMenuItem mntmNewMenuItemx = new JMenuItem(UIEnv.getRsb().getString("copyvirtualaddress")); popupMenu.add(mntmNewMenuItemx); mntmNewMenuItemx.addActionListener(new ActionListener() { @@ -191,7 +191,7 @@ public class TPanel2 extends JPanel { - mntmNewMenuItem3 = new JMenuItem("Try reconnect"); + mntmNewMenuItem3 = new JMenuItem(UIEnv.getRsb().getString("tryreconnect")); popupMenu.add(mntmNewMenuItem3); mntmNewMenuItem3.addActionListener(new ActionListener() { @@ -202,7 +202,7 @@ public class TPanel2 extends JPanel { } }); mntmNewMenuItem3.setForeground(Color.GREEN); - mntmNewMenuItem2 = new JMenuItem("Force disconnect"); + mntmNewMenuItem2 = new JMenuItem(UIEnv.getRsb().getString("forcedisconnect")); popupMenu.add(mntmNewMenuItem2); mntmNewMenuItem2.addActionListener(new ActionListener() { @@ -213,7 +213,7 @@ public class TPanel2 extends JPanel { }); mntmNewMenuItem2.setForeground(Color.RED); - JMenuItem mi=new JMenuItem("Remove line"); + JMenuItem mi=new JMenuItem(UIEnv.getRsb().getString("removeline")); popupMenu.add(mi); mi.addActionListener(new ActionListener() { diff --git a/src/org/kne/cloud/network/klalb/ui/UIEnv.java b/src/org/kne/cloud/network/klalb/ui/UIEnv.java index 59830ab..bd79d47 100644 --- a/src/org/kne/cloud/network/klalb/ui/UIEnv.java +++ b/src/org/kne/cloud/network/klalb/ui/UIEnv.java @@ -29,7 +29,7 @@ public class UIEnv { private static ResourceBundle rsb; public static void setRsb(String xrsb) throws IOException { - rsb=new PropertyResourceBundle(UIEnv.class.getResourceAsStream("/knemcl_"+xrsb+".properties")); + rsb=new PropertyResourceBundle(UIEnv.class.getResourceAsStream("/klalb_"+xrsb+".properties")); } public static void setRsb(ResourceBundle xrsb) { @@ -38,7 +38,7 @@ public class UIEnv { public static ResourceBundle getRsb() { if(rsb==null) { try { - rsb=new PropertyResourceBundle(UIEnv.class.getResourceAsStream("/knemcl_en_US.properties")); + rsb=new PropertyResourceBundle(UIEnv.class.getResourceAsStream("/klalb_en_US.properties")); } catch (IOException e) { e.printStackTrace(); } diff --git a/src/org/kne/cloud/network/nathole/Experiment.java b/src/org/kne/cloud/network/nathole/Experiment.java new file mode 100644 index 0000000..42bae28 --- /dev/null +++ b/src/org/kne/cloud/network/nathole/Experiment.java @@ -0,0 +1,16 @@ +package org.kne.cloud.network.nathole; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.Socket; + +public class Experiment { + + public static void main(String[] args) throws IOException { + Socket soc=new Socket(); + soc.bind(new InetSocketAddress("kne02.yoyo250.fun", 1234)); + soc.connect(new InetSocketAddress("kne04.yoyo250.fun", 1234)); + System.out.println("连接成功"); + } + +} diff --git a/src/org/kne/cloud/network/srv6/KLALBRoutingProtocol.java b/src/org/kne/cloud/network/srv6/KLALBRoutingProtocol.java index 7328c6f..c401711 100644 --- a/src/org/kne/cloud/network/srv6/KLALBRoutingProtocol.java +++ b/src/org/kne/cloud/network/srv6/KLALBRoutingProtocol.java @@ -69,7 +69,7 @@ public class KLALBRoutingProtocol extends Thread{ public static final long HOTSOPT_TIMEOUT = 1000000000; - public static final int HOTSOPT_REPORT_INTERVAL = 100000000; + public static final int HOTSOPT_REPORT_INTERVAL = 50000000; private SRv6Router router; public SRv6Router getRouter() { return router; @@ -83,14 +83,13 @@ public class KLALBRoutingProtocol extends Thread{ private long floodTimer=System.nanoTime(); private long floodTimer2=System.nanoTime(); private long requestTimer=System.nanoTime(); + KLALBVirtualRawSocket ds = null; @Override public void run() { Thread.currentThread().setName("KLALB路由协议接收线程"); getSelfRouterInfo(); - KLALBVirtualRawSocket ds = null; try{ ds=new KLALBVirtualRawSocket(router,router.getLocator().getAddress(), DEFAULT_PROTOCOL_NUMBER); - KLALBVirtualRawSocket ds2=ds; new Thread(()->{ Thread.currentThread().setName("KLALB路由协议接收线程"); @@ -120,14 +119,14 @@ public class KLALBRoutingProtocol extends Thread{ if(debug) System.out.println("update60"); floodTimer=cur; - floodPacket(ds2, null, new RouterInfoPacket(selfRouterInfo,true,-1)); + floodPacket(ds, null, new RouterInfoPacket(selfRouterInfo,true,-1)); } if(cur-floodTimer2>1000000000L) { if(debug) System.out.println("update1"); floodTimer2=cur; - floodPacket(ds2, null, new RouterInfoPacket(selfRouterInfo,true,router.getASN())); + floodPacket(ds, null, new RouterInfoPacket(selfRouterInfo,true,router.getASN())); } //Set requestSet=new HashSet<>(); @@ -174,10 +173,10 @@ public class KLALBRoutingProtocol extends Thread{ for (Iterator> iterator = hotspots.entrySet().iterator(); iterator.hasNext();) { Entry type = (Entry) iterator.next(); - if(type.getValue().checkReportTime()) { + //if(type.getValue().checkReportTime()) { //System.out.println("hotspot address:"+type.getKey()); - writePacket(ds2, new RouterInfoPacket( netmap.get(router.getLocator().getAddress()),false,-1), new InetSocketAddress(type.getKey(), DEFAULT_PORT)); - } + //writePacket(ds2, new RouterInfoPacket( netmap.get(router.getLocator().getAddress()),false,-1), new InetSocketAddress(type.getKey(), DEFAULT_PORT)); + //} if(type.getValue().checkTimeOut()) { iterator.remove(); } @@ -358,7 +357,7 @@ public class KLALBRoutingProtocol extends Thread{ return; } Set> s=netmap.entrySet(); - Mapairs=new HashMap<>(netmap.size()+1); + Mapairs=new HashMap<>(netmap.size()*2,0.4f); Listrias=new ArrayList<>(netmap.size()+1); @@ -620,10 +619,18 @@ public class KLALBRoutingProtocol extends Thread{ if(true) { HotspotAddressTimer hat=hotspots.get(sourceAddress); if(hat==null) { - hotspots.put(sourceAddress, new HotspotAddressTimer()); + hotspots.put(sourceAddress,hat= new HotspotAddressTimer()); }else { hat.refreshTimeout(); } + if(hat.checkReportTime()) { + System.out.println("hotspot address:"+sourceAddress); + try { + writePacket(ds, new RouterInfoPacket( netmap.get(router.getLocator().getAddress()),false,-1), new InetSocketAddress(sourceAddress, DEFAULT_PORT)); + } catch (IOException e) { + e.printStackTrace(); + } + } } } private Map toIpBandwidth=new ConcurrentHashMap(); @@ -646,7 +653,10 @@ public class KLALBRoutingProtocol extends Thread{ NetmapDirections directionsx=directions; if(directionsx==null) return null; - long number= directionsx.getDirection_airs().get(text); + Long l=directionsx.getDirection_airs().get(text); + if(l==null) + return null; + long number= l; long prev= directionsx.getDirection()[(int)number]; if(prev==-1) { return null; diff --git a/src/org/kne/cloud/network/srv6/SRv6PacketReorder.java b/src/org/kne/cloud/network/srv6/SRv6PacketReorder.java index b40d9e4..c46f395 100644 --- a/src/org/kne/cloud/network/srv6/SRv6PacketReorder.java +++ b/src/org/kne/cloud/network/srv6/SRv6PacketReorder.java @@ -1,6 +1,7 @@ package org.kne.cloud.network.srv6; import java.io.IOException; +import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; @@ -17,9 +18,23 @@ public class SRv6PacketReorder { this.packetConsumer=packetConsumer; } - private long jumpTime=500000000L; + private long jumpTime=400000000L; - private Mapmap=new ConcurrentHashMap<>(); + + private long maxCacheingTime=5000000000L; + + private class PacketTimeEntry{ + private IPv6Packet packet; + private long addTime; + public PacketTimeEntry(IPv6Packet packet) { + super(); + this.packet = packet; + this.addTime = System.nanoTime(); + } + + } + + private Mapmap=new ConcurrentHashMap<>(); private long orderTime=System.nanoTime(); @@ -27,7 +42,7 @@ public class SRv6PacketReorder { public void put(IPv6Packet pack, long sequence) throws IOException { //System.out.println(pack.getFlowLabel()+" "+sequence); - map.put(sequence,pack); + map.put(sequence,new PacketTimeEntry(pack)); runOrdering(); } private ReentrantLock orderLock=new ReentrantLock(); @@ -39,13 +54,13 @@ public class SRv6PacketReorder { whi=false; while(true) { - IPv6Packet i6p=map.remove(seqptr.get()); + PacketTimeEntry i6p=map.remove(seqptr.get()); if(i6p!=null) { //System.out.println("Ord:"+i6p.getFlowLabel()+" "+seqptr.get()); seqptr.getAndIncrement(); orderTime=System.nanoTime(); if(packetConsumer!=null) { - packetConsumer.accept(i6p); + packetConsumer.accept(i6p.packet); } }else { break; @@ -69,6 +84,12 @@ public class SRv6PacketReorder { }finally { orderLock.unlock(); } + for (Iterator iterator = map.values().iterator(); iterator.hasNext();) { + PacketTimeEntry type = (PacketTimeEntry) iterator.next(); + if(System.nanoTime()-type.addTime>maxCacheingTime) { + iterator.remove(); + } + } } } diff --git a/src/org/kne/cloud/network/srv6/SRv6Router.java b/src/org/kne/cloud/network/srv6/SRv6Router.java index a85f083..0118131 100644 --- a/src/org/kne/cloud/network/srv6/SRv6Router.java +++ b/src/org/kne/cloud/network/srv6/SRv6Router.java @@ -76,7 +76,7 @@ import com.google.gson.internal.Pair; public class SRv6Router { private static final boolean debug = false; - public static final int MTU = 8192; + public static final int MTU = 16384; public static final int MAX_REROUTE_COUNT=2;//1 @@ -417,7 +417,7 @@ public class SRv6Router { segmentsLeft--; } List repairSegments= klalbRouteProtol.createSegmentList(srh.getAddresses().get(segmentsLeft)); - if(repairSegments ==null) { + if(repairSegments ==null||repairSegments.isEmpty()) { System.out.println("FRR保护失败"); return; } @@ -589,15 +589,15 @@ public class SRv6Router { } if(retry) { - if(System.nanoTime()-start>200000000L) { + if(System.nanoTime()-start>1000000L) { break; } - try { + /*try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); - } - //Thread.yield(); + }*/ + Thread.yield(); //短暂挂起当前线程,待链路速度未超限时重试发送数据包 } }while((!routes.isEmpty())&&retry); @@ -713,6 +713,7 @@ public class SRv6Router { srhh.setSegmentsLeft(newSL); iPv6Packet.setDestinationAddress(srhh.getAddresses().get(newSL)); } + if(iPv6Packet.getPayload().getProtocolNumber()!=KLALBRoutingProtocol.DEFAULT_PROTOCOL_NUMBER) klalbRouteProtol.putHotspotAddress(iPv6Packet.getSourceAddress()); routePacket(iPv6Packet,reroute); }