1
1
package com .stealthcopter .networktools ;
2
2
3
3
import android .support .annotation .NonNull ;
4
+ import android .support .annotation .Nullable ;
4
5
5
6
import com .stealthcopter .networktools .portscanning .PortScanTCP ;
6
7
7
8
import java .net .InetAddress ;
8
9
import java .net .UnknownHostException ;
9
10
import java .util .ArrayList ;
11
+ import java .util .Collections ;
12
+ import java .util .concurrent .ExecutorService ;
13
+ import java .util .concurrent .Executors ;
14
+ import java .util .concurrent .TimeUnit ;
10
15
11
16
/**
12
17
* Created by mat on 14/12/15.
13
18
*/
14
19
public class PortScan {
15
20
21
+ private int noThreads = 50 ;
22
+ private InetAddress address ;
23
+ private int timeOutMillis = 1000 ;
24
+ private boolean cancelled = false ;
25
+ private ArrayList <Integer > ports = new ArrayList <>();
26
+ private ArrayList <Integer > openPortsFound = new ArrayList <>();
27
+
28
+ @ Nullable
29
+ private PortListener portListener ;
30
+
16
31
// This class is not to be instantiated
17
32
private PortScan () {
18
33
}
@@ -22,11 +37,6 @@ public interface PortListener{
22
37
void onFinished (ArrayList <Integer > openPorts );
23
38
}
24
39
25
- private InetAddress address ;
26
- private int timeOutMillis = 1000 ;
27
- private boolean cancelled = false ;
28
- private ArrayList <Integer > ports = new ArrayList <>();
29
-
30
40
/**
31
41
* Set the address to ping
32
42
* @param address - Address to be pinged
@@ -54,8 +64,18 @@ public static PortScan onAddress(@NonNull InetAddress ia) {
54
64
}
55
65
56
66
/**
57
- * Set the timeout
67
+ * Sets the timeout for each port scanned
68
+ *
69
+ * If you raise the timeout you may want to consider increasing the thread count {@link #setNoThreads(int)} to compensate.
70
+ * We can afford to have quite a high thread count as most of the time the thread is just sitting
71
+ * idle and waiting for the socket to timeout.
72
+ *
58
73
* @param timeOutMillis - the timeout for each ping in milliseconds
74
+ * Recommendations:
75
+ * Local host: 20 - 500 ms - can be very fast as request doesn't need to go over network
76
+ * Local network 500 - 2500 ms
77
+ * Remote Scan 2500+ ms
78
+ *
59
79
* @return this object to allow chaining
60
80
*/
61
81
public PortScan setTimeOutMillis (int timeOutMillis ){
@@ -172,6 +192,20 @@ private void setAddress(InetAddress address) {
172
192
this .address = address ;
173
193
}
174
194
195
+
196
+ /**
197
+ *
198
+ * @param noThreads set the number of threads to work with, note we default to a large number
199
+ * as these requests are network heavy not cpu heavy.
200
+ * @return self
201
+ * @throws IllegalAccessException - if no threads is less than 1
202
+ */
203
+ public PortScan setNoThreads (int noThreads ) throws IllegalAccessException {
204
+ if (noThreads < 1 ) throw new IllegalArgumentException ("Cannot have less than 1 thread" );
205
+ this .noThreads = noThreads ;
206
+ return this ;
207
+ }
208
+
175
209
/**
176
210
* Cancel a running ping
177
211
*/
@@ -180,23 +214,34 @@ public void cancel() {
180
214
}
181
215
182
216
/**
183
- * Perform a synchrnous port scan and return a list of open ports
217
+ * Perform a synchronous port scan and return a list of open ports
184
218
* @return - ping result
185
219
*/
186
220
public ArrayList <Integer > doScan (){
187
221
188
222
cancelled = false ;
223
+ openPortsFound .clear ();
189
224
190
- ArrayList < Integer > openPorts = new ArrayList <>( );
225
+ ExecutorService executor = Executors . newFixedThreadPool ( noThreads );
191
226
192
227
for (int portNo : ports ) {
193
- if (PortScanTCP .scanAddress (address , portNo , timeOutMillis )){
194
- openPorts .add (portNo );
195
- }
196
- if (cancelled ) break ;
228
+ Runnable worker = new PortScanRunnable (address , portNo , timeOutMillis );
229
+ executor .execute (worker );
230
+ }
231
+
232
+ // This will make the executor accept no new threads
233
+ // and finish all existing threads in the queue
234
+ executor .shutdown ();
235
+ // Wait until all threads are finish
236
+ try {
237
+ executor .awaitTermination (1 , TimeUnit .HOURS );
238
+ } catch (InterruptedException e ) {
239
+ e .printStackTrace ();
197
240
}
198
241
199
- return openPorts ;
242
+ Collections .sort (openPortsFound );
243
+
244
+ return openPortsFound ;
200
245
}
201
246
202
247
/**
@@ -206,23 +251,34 @@ public ArrayList<Integer> doScan(){
206
251
*/
207
252
public PortScan doScan (final PortListener portListener ){
208
253
254
+ this .portListener = portListener ;
255
+ openPortsFound .clear ();
256
+ cancelled = false ;
257
+
209
258
new Thread (new Runnable () {
210
259
@ Override
211
260
public void run () {
212
- cancelled = false ;
213
261
214
- ArrayList <Integer > openPorts = new ArrayList <>();
262
+ ExecutorService executor = Executors .newFixedThreadPool (noThreads );
263
+
215
264
for (int portNo : ports ) {
216
- boolean open = PortScanTCP .scanAddress (address , portNo , 1000 );
217
- if (portListener !=null ){
218
- portListener .onResult (portNo , open );
219
- if (open ) openPorts .add (portNo );
220
- }
221
- if (cancelled ) break ;
265
+ Runnable worker = new PortScanRunnable (address , portNo , timeOutMillis );
266
+ executor .execute (worker );
267
+ }
268
+
269
+ // This will make the executor accept no new threads
270
+ // and finish all existing threads in the queue
271
+ executor .shutdown ();
272
+ // Wait until all threads are finish
273
+ try {
274
+ executor .awaitTermination (1 , TimeUnit .HOURS );
275
+ } catch (InterruptedException e ) {
276
+ e .printStackTrace ();
222
277
}
223
278
224
279
if (portListener !=null ){
225
- portListener .onFinished (openPorts );
280
+ Collections .sort (openPortsFound );
281
+ portListener .onFinished (openPortsFound );
226
282
}
227
283
228
284
}
@@ -231,5 +287,32 @@ public void run() {
231
287
return this ;
232
288
}
233
289
290
+ private synchronized void portScanned (int port , boolean open ){
291
+ if (open ){
292
+ openPortsFound .add (port );
293
+ }
294
+ if (portListener != null ) {
295
+ portListener .onResult (port , open );
296
+ }
297
+ }
298
+
299
+ private class PortScanRunnable implements Runnable {
300
+ private final InetAddress address ;
301
+ private final int portNo ;
302
+ private final int timeOutMillis ;
303
+
304
+ PortScanRunnable (InetAddress address , int portNo , int timeOutMillis ) {
305
+ this .address = address ;
306
+ this .portNo = portNo ;
307
+ this .timeOutMillis = timeOutMillis ;
308
+ }
309
+
310
+ @ Override
311
+ public void run () {
312
+ if (cancelled ) return ;
313
+ portScanned (portNo , PortScanTCP .scanAddress (address , portNo , timeOutMillis ));
314
+ }
315
+ }
316
+
234
317
235
318
}
0 commit comments