3749ac02c21a2f753080c0f72eabacade2a720c8
[strongswan.git] / src / frontends / android / app / src / main / java / org / strongswan / android / utils / IPRangeSet.java
1 /*
2 * Copyright (C) 2012-2017 Tobias Brunner
3 * HSR Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 package org.strongswan.android.utils;
17
18 import java.util.ArrayList;
19 import java.util.Enumeration;
20 import java.util.Iterator;
21 import java.util.List;
22 import java.util.TreeSet;
23
24 /**
25 * Class that represents a set of IP address ranges (not necessarily proper subnets) and allows
26 * modifying the set and enumerating the resulting subnets.
27 */
28 public class IPRangeSet
29 {
30 private TreeSet<IPRange> mRanges = new TreeSet<>();
31
32 /**
33 * Parse the given string (space separated ranges in CIDR or range notation) and return the
34 * resulting set or {@code null} if the string was invalid. An empty set is returned if the given string
35 * is {@code null}.
36 */
37 public static IPRangeSet fromString(String ranges)
38 {
39 IPRangeSet set = new IPRangeSet();
40 if (ranges != null)
41 {
42 for (String range : ranges.split("\\s+"))
43 {
44 try
45 {
46 set.add(new IPRange(range));
47 }
48 catch (Exception unused)
49 { /* besides due to invalid strings exceptions might get thrown if the string
50 * contains a hostname (NetworkOnMainThreadException) */
51 return null;
52 }
53 }
54 }
55 return set;
56 }
57
58 /**
59 * Add a range to this set. Automatically gets merged with existing ranges.
60 */
61 public void add(IPRange range)
62 {
63 if (mRanges.contains(range))
64 {
65 return;
66 }
67 reinsert:
68 while (true)
69 {
70 Iterator<IPRange> iterator = mRanges.iterator();
71 while (iterator.hasNext())
72 {
73 IPRange existing = iterator.next();
74 IPRange replacement = existing.merge(range);
75 if (replacement != null)
76 {
77 iterator.remove();
78 range = replacement;
79 continue reinsert;
80 }
81 }
82 mRanges.add(range);
83 break;
84 }
85 }
86
87 /**
88 * Remove the given range from this set. Existing ranges are automatically adjusted.
89 */
90 public void remove(IPRange range)
91 {
92 ArrayList <IPRange> additions = new ArrayList<>();
93 Iterator<IPRange> iterator = mRanges.iterator();
94 while (iterator.hasNext())
95 {
96 IPRange existing = iterator.next();
97 List<IPRange> result = existing.remove(range);
98 if (result.size() == 0)
99 {
100 iterator.remove();
101 }
102 else if (!result.get(0).equals(existing))
103 {
104 iterator.remove();
105 additions.addAll(result);
106 }
107 }
108 mRanges.addAll(additions);
109 }
110
111 /**
112 * Remove the given ranges from ranges in this set.
113 */
114 public void remove(IPRangeSet ranges)
115 {
116 if (ranges == this)
117 {
118 mRanges.clear();
119 return;
120 }
121 for (IPRange range : ranges.mRanges)
122 {
123 remove(range);
124 }
125 }
126
127 /**
128 * Returns the subnets derived from all the ranges in this set.
129 */
130 public Enumeration<IPRange> getSubnets()
131 {
132 return new Enumeration<IPRange>()
133 {
134 private Iterator<IPRange> mIterator = mRanges.iterator();
135 private List<IPRange> mSubnets;
136
137 @Override
138 public boolean hasMoreElements()
139 {
140 return (mSubnets != null && mSubnets.size() > 0) || mIterator.hasNext();
141 }
142
143 @Override
144 public IPRange nextElement()
145 {
146 if (mSubnets == null || mSubnets.size() == 0)
147 {
148 IPRange range = mIterator.next();
149 mSubnets = range.toSubnets();
150 }
151 return mSubnets.remove(0);
152 }
153 };
154 }
155
156 /**
157 * Returns the number of ranges, not subnets.
158 */
159 public int size()
160 {
161 return mRanges.size();
162 }
163 }