PageRenderTime 79ms CodeModel.GetById 35ms RepoModel.GetById 1ms app.codeStats 0ms

/projects/azureus-4.7.0.2/org/gudy/azureus2/core3/ipfilter/impl/IPAddressRangeManager.java

https://gitlab.com/essere.lab.public/qualitas.class-corpus
Java | 587 lines | 298 code | 174 blank | 115 comment | 46 complexity | de7f4e02fc35316d3e8135ffb0d46337 MD5 | raw file
  1. /*
  2. * Created on 05-Jul-2004
  3. * Created by Paul Gardner
  4. * Copyright (C) 2004, 2005, 2006 Aelitis, All Rights Reserved.
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation; either version 2
  9. * of the License, or (at your option) any later version.
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17. *
  18. * AELITIS, SAS au capital de 46,603.30 euros
  19. * 8 Allee Lenotre, La Grille Royale, 78600 Le Mesnil le Roi, France.
  20. *
  21. */
  22. package org.gudy.azureus2.core3.ipfilter.impl;
  23. /**
  24. * @author parg
  25. *
  26. */
  27. import java.util.*;
  28. import java.net.InetAddress;
  29. import java.net.UnknownHostException;
  30. import org.gudy.azureus2.core3.ipfilter.IpFilterManagerFactory;
  31. import org.gudy.azureus2.core3.ipfilter.IpRange;
  32. import org.gudy.azureus2.core3.logging.*;
  33. import org.gudy.azureus2.core3.util.*;
  34. import org.gudy.azureus2.core3.tracker.protocol.PRHelpers;
  35. public class
  36. IPAddressRangeManager
  37. {
  38. private static final LogIDs LOGID = LogIDs.CORE;
  39. protected ArrayList entries = new ArrayList();
  40. protected long total_span;
  41. protected boolean rebuild_required;
  42. protected long last_rebuild_time;
  43. protected IpRange[] mergedRanges = new IpRange[0];
  44. protected AEMonitor this_mon = new AEMonitor( "IPAddressRangeManager" );
  45. protected
  46. IPAddressRangeManager()
  47. {
  48. }
  49. public void
  50. addRange(IpRange range)
  51. {
  52. try{
  53. this_mon.enter();
  54. // checking for existing (either by entries.contains, or by
  55. // rebuilding and searching ips) is slow. Skip check, merge will take
  56. // care of it
  57. entries.add( range);
  58. rebuild_required = true;
  59. }finally{
  60. this_mon.exit();
  61. }
  62. }
  63. public void removeRange(IpRange range) {
  64. try{
  65. this_mon.enter();
  66. entries.remove( range );
  67. rebuild_required = true;
  68. }finally{
  69. this_mon.exit();
  70. }
  71. }
  72. public Object
  73. isInRange(
  74. String ip )
  75. {
  76. // optimise for pretty normal case where there are no ranges
  77. if ( entries.size() == 0 ){
  78. return( null );
  79. }
  80. try{
  81. this_mon.enter();
  82. long address_long = addressToInt( ip );
  83. if ( address_long < 0 ){
  84. address_long += 0x100000000L;
  85. }
  86. Object res = isInRange( address_long );
  87. // LGLogger.log( "IPAddressRangeManager: checking '" + ip + "' against " + entries.size() + "/" + merged_entries.length + " -> " + res );
  88. return( res );
  89. }finally{
  90. this_mon.exit();
  91. }
  92. }
  93. public Object
  94. isInRange(
  95. InetAddress ip )
  96. {
  97. // optimise for pretty normal case where there are no ranges
  98. if ( entries.size() == 0 ){
  99. return( null );
  100. }
  101. try{
  102. this_mon.enter();
  103. long address_long = addressToInt( ip );
  104. if ( address_long < 0 ){
  105. address_long += 0x100000000L;
  106. }
  107. Object res = isInRange( address_long );
  108. // LGLogger.log( "IPAddressRangeManager: checking '" + ip + "' against " + entries.size() + "/" + merged_entries.length + " -> " + res );
  109. return( res );
  110. }finally{
  111. this_mon.exit();
  112. }
  113. }
  114. protected Object
  115. isInRange(
  116. long address_long )
  117. {
  118. try{
  119. this_mon.enter();
  120. checkRebuild();
  121. if ( mergedRanges.length == 0 ){
  122. return( null );
  123. }
  124. // assisted binary chop
  125. int bottom = 0;
  126. int top = mergedRanges.length-1;
  127. int current = -1;
  128. while( top >= 0 && bottom < mergedRanges.length && bottom <= top){
  129. current = (bottom+top)/2;
  130. IpRange e = mergedRanges[current];
  131. long this_start = e.getStartIpLong();
  132. long this_end = e.getMergedEndLong();
  133. if ( address_long == this_start ){
  134. break;
  135. }else if ( address_long > this_start ){
  136. if ( address_long <= this_end ){
  137. break;
  138. }
  139. // lies to the right of this entry
  140. bottom = current + 1;
  141. }else if ( address_long == this_end ){
  142. break;
  143. }else{
  144. // < this_end
  145. if ( address_long >= this_start ){
  146. break;
  147. }
  148. top = current - 1;
  149. }
  150. }
  151. if ( top >= 0 && bottom < mergedRanges.length && bottom <= top ){
  152. IpRange e = mergedRanges[current];
  153. if ( address_long <= e.getEndIpLong()){
  154. return( e );
  155. }
  156. IpRange[] merged = e.getMergedEntries();
  157. if ( merged == null ){
  158. Debug.out( "IPAddressRangeManager: inconsistent merged details - no entries" );
  159. return( null );
  160. }
  161. for (int i=0;i<merged.length;i++){
  162. IpRange me = merged[i];
  163. if ( me.getStartIpLong() <= address_long && me.getEndIpLong() >= address_long ){
  164. return( me );
  165. }
  166. }
  167. Debug.out( "IPAddressRangeManager: inconsistent merged details - entry not found" );
  168. }
  169. return( null );
  170. }finally{
  171. this_mon.exit();
  172. }
  173. }
  174. protected int
  175. addressToInt(
  176. String address )
  177. {
  178. try{
  179. return( PRHelpers.addressToInt( address ));
  180. }catch( UnknownHostException e ){
  181. return( UnresolvableHostManager.getPseudoAddress( address ));
  182. }
  183. }
  184. protected int
  185. addressToInt(
  186. InetAddress address )
  187. {
  188. return( PRHelpers.addressToInt( address ));
  189. }
  190. protected void
  191. checkRebuild()
  192. {
  193. try{
  194. this_mon.enter();
  195. if ( rebuild_required ){
  196. // with substantial numbers of filters (e.g. 80,000) rebuilding
  197. // is a slow process. Therefore prevent frequent rebuilds at the
  198. // cost of delaying the effect of the change
  199. long now = SystemTime.getCurrentTime();
  200. long secs_since_last_build = (now - last_rebuild_time)/1000;
  201. // allow one second per 2000 entries
  202. if ( secs_since_last_build > entries.size()/2000 ){
  203. last_rebuild_time = now;
  204. rebuild_required = false;
  205. rebuild();
  206. }
  207. }
  208. }finally{
  209. this_mon.exit();
  210. }
  211. }
  212. protected void
  213. rebuild()
  214. {
  215. if (Logger.isEnabled())
  216. Logger.log(new LogEvent(LOGID, "IPAddressRangeManager: rebuilding "
  217. + entries.size() + " entries starts"));
  218. IpRange[] ents = new IpRange[entries.size()];
  219. entries.toArray(ents);
  220. for (int i=0;i<ents.length;i++){
  221. ents[i].resetMergeInfo();
  222. }
  223. // sort based on start address
  224. Arrays.sort(
  225. ents,
  226. new Comparator()
  227. {
  228. public int
  229. compare(
  230. Object o1,
  231. Object o2 )
  232. {
  233. IpRange e1 = (IpRange)o1;
  234. IpRange e2 = (IpRange)o2;
  235. long diff = e1.getStartIpLong() - e2.getStartIpLong();
  236. if (diff == 0) {
  237. diff = e2.getEndIpLong() - e1.getEndIpLong();
  238. }
  239. return signum(diff);
  240. }
  241. public boolean
  242. equals(Object obj)
  243. {
  244. return( false );
  245. }
  246. });
  247. // now merge overlapping ranges
  248. List me = new ArrayList( ents.length );
  249. for (int i=0;i<ents.length;i++){
  250. IpRange entry = ents[i];
  251. if ( entry.getMerged()){
  252. continue;
  253. }
  254. me.add( entry );
  255. int pos = i+1;
  256. while( pos < ents.length ){
  257. long end_pos = entry.getMergedEndLong();
  258. IpRange e2 = ents[pos++];
  259. if (!e2.getMerged()){
  260. if ( end_pos >= e2.getStartIpLong()){
  261. e2.setMerged();
  262. if ( e2.getEndIpLong() > end_pos ){
  263. entry.setMergedEnd( e2.getEndIpLong() );
  264. entry.addMergedEntry( e2 );
  265. }
  266. }else{
  267. break;
  268. }
  269. }
  270. }
  271. }
  272. /*
  273. for (int i=0;i<ents.length;i++){
  274. entry e = ents[i];
  275. System.out.println( Long.toHexString(e.getStart()) + " - " + Long.toHexString(e.getEnd()) + ": " + e.getMerged() + "/" + Long.toHexString(e.getMergedEnd()));
  276. }
  277. */
  278. mergedRanges = new IpRange[me.size()];
  279. me.toArray( mergedRanges );
  280. total_span = 0;
  281. for (int i=0;i<mergedRanges.length;i++){
  282. IpRange e = mergedRanges[i];
  283. // span is inclusive
  284. long span = ( e.getMergedEndLong() - e.getStartIpLong()) + 1;
  285. total_span += span;
  286. }
  287. // System.out.println( "non_merged = " + merged_entries.length );
  288. if (Logger.isEnabled())
  289. Logger.log(new LogEvent(LOGID, "IPAddressRangeManager: rebuilding "
  290. + entries.size() + " entries ends"));
  291. }
  292. /**
  293. * @param diff
  294. * @return
  295. */
  296. protected int signum(long diff) {
  297. if (diff > 0) {
  298. return 1;
  299. }
  300. if (diff < 0) {
  301. return -1;
  302. }
  303. return 0;
  304. }
  305. protected long
  306. getTotalSpan()
  307. {
  308. checkRebuild();
  309. return( total_span );
  310. }
  311. public static void
  312. main(
  313. String[] args )
  314. {
  315. IPAddressRangeManager manager = new IPAddressRangeManager();
  316. /*
  317. Object[] testBlockIPs1 = {
  318. new String[] { "1", "3.1.1.1", "3.1.1.2" },
  319. new String[] { "2", "3.1.1.1", "3.1.1.3" },
  320. new String[] { "3", "1.1.1.1", "2.2.2.2", "2" },
  321. new String[] { "4", "0.1.1.1", "2.2.2.2", "3" },
  322. new String[] { "5", "1.1.1.1", "1.2.2.2" },
  323. new String[] { "6", "7.7.7.7", "7.7.8.7" },
  324. new String[] { "7", "8.8.8.8", "8.8.8.8" },
  325. //new String[] {"8","0.0.0.0", "255.255.255.255"},
  326. new String[] { "9", "5.5.5.5", "6.6.6.9" },
  327. new String[] { "10", "6.6.6.6", "7.7.0.0" },
  328. new String[] { "11", "254.6.6.6", "254.7.0.0" } };
  329. Object[] testBlockIPs2 = {
  330. new String[] { "1", "0.0.0.1", "60.0.0.0" },
  331. new String[] { "2", "60.0.0.2", "119.255.255.255" },
  332. new String[] { "2a", "60.0.0.2", "119.255.255.255" },
  333. new String[] { "3", "120.0.0.1", "180.0.0.0" },
  334. new String[] { "4", "180.0.0.0", "255.255.255.255" }
  335. };
  336. Object[] testBlockIPs = testBlockIPs2;
  337. for (int i = 0; i < testBlockIPs.length; i++) {
  338. String[] ip = (String[]) testBlockIPs[i];
  339. if (ip == null)
  340. continue;
  341. manager.addRange(new IpRangeImpl(ip[0], ip[1], ip[2], true));
  342. }
  343. System.out.println( "inRange -> " + manager.isInRange( "254.6.6.8" ));
  344. String [] testIPs = { "60.0.0.0", "60.0.0.1", "60.0.0.2", "60.0.0.3",
  345. "119.255.255.254", "119.255.255.255", "120.0.0.0", "120.0.0.1",
  346. "120.0.0.2", "179.255.255.255", "180.0.0.0", "180.0.0.1"
  347. };
  348. for (int i = 0; i < testIPs.length; i++) {
  349. String string = testIPs[i];
  350. System.out.println(string + " InRange? " + manager.isInRange(string));
  351. }
  352. System.out.println( "Total span = " + manager.getTotalSpan());
  353. */
  354. Random r = new Random();
  355. for (int i=0;i<1000000;i++){
  356. int ip1 = r.nextInt( 0x0fffffff );
  357. int ip2 = ip1 + r.nextInt( 255 );
  358. String start = PRHelpers.intToAddress( ip1 );
  359. String end = PRHelpers.intToAddress( ip2 );
  360. manager.addRange( new IpRangeImpl("test_" + i, start, end, true ));
  361. }
  362. /*
  363. for (int i=0;i<100000;i++){
  364. int start = (int)(Math.random() * 0xfffff000);
  365. int end = start + (int)(Math.random()*5000);
  366. manager.addRange( start, end, new Object());
  367. }
  368. */
  369. int num = 0;
  370. int hits = 0;
  371. while(true){
  372. if ( num % 1000 == 0 ){
  373. System.out.println( num + "/" + hits );
  374. }
  375. num++;
  376. int ip = r.nextInt();
  377. Object res = manager.isInRange( ip );
  378. if ( res != null ){
  379. hits++;
  380. }
  381. }
  382. }
  383. public ArrayList getEntries() {
  384. return entries;
  385. }
  386. public void clearAllEntries() {
  387. try{
  388. this_mon.enter();
  389. entries.clear();
  390. IpFilterManagerFactory.getSingleton().deleteAllDescriptions();
  391. rebuild_required = true;
  392. }finally{
  393. this_mon.exit();
  394. }
  395. }
  396. }