20
20
package com .vsmartcard .remotesmartcardreader .app ;
21
21
22
22
import android .os .AsyncTask ;
23
- import android .support .annotation .Nullable ;
23
+
24
+ import androidx .annotation .Nullable ;
24
25
25
26
import com .example .android .common .logger .Log ;
26
27
import com .vsmartcard .remotesmartcardreader .app .screaders .SCReader ;
27
28
28
29
import java .io .IOException ;
29
30
import java .io .InputStream ;
30
31
import java .io .OutputStream ;
32
+ import java .net .Inet4Address ;
31
33
import java .net .InetAddress ;
34
+ import java .net .InterfaceAddress ;
35
+ import java .net .NetworkInterface ;
36
+ import java .net .ServerSocket ;
32
37
import java .net .Socket ;
38
+ import java .net .SocketTimeoutException ;
39
+ import java .util .Enumeration ;
40
+ import java .util .LinkedList ;
41
+ import java .util .List ;
42
+ import java .util .concurrent .TimeUnit ;
33
43
34
44
class VPCDWorker extends AsyncTask <VPCDWorker .VPCDWorkerParams , Void , Void > {
35
45
36
46
public static class VPCDWorkerParams {
37
47
final String hostname ;
38
48
final int port ;
39
49
final SCReader reader ;
40
- VPCDWorkerParams (String hostname , int port , SCReader reader ) {
50
+ final boolean listen ;
51
+ VPCDWorkerParams (String hostname , int port , SCReader reader , boolean listen ) {
41
52
this .hostname = hostname ;
42
53
this .port = port ;
43
54
this .reader = reader ;
55
+ this .listen = listen ;
44
56
}
45
57
}
46
58
47
59
public static final int DEFAULT_PORT = 35963 ;
48
60
// default URI when used in emulator
49
61
public static final String DEFAULT_HOSTNAME = "10.0.2.2" ;
62
+ public static final boolean DEFAULT_LISTEN = false ;
50
63
51
64
private SCReader reader ;
65
+ private ServerSocket listenSocket ;
52
66
private Socket socket ;
53
67
private InputStream inputStream ;
54
68
private OutputStream outputStream ;
@@ -74,15 +88,22 @@ protected void onCancelled () {
74
88
public Void doInBackground (VPCDWorkerParams ... params ) {
75
89
try {
76
90
reader = params [0 ].reader ;
77
- Log .i (this .getClass ().getName (), "Connecting to " + params [0 ].hostname + ":" + Integer .toString (params [0 ].port ) + "..." );
78
- vpcdConnect (params [0 ].hostname , params [0 ].port );
79
- Log .i (this .getClass ().getName (), "Connected to VPCD" );
91
+ vpcdConnection (params [0 ]);
80
92
81
93
while (!isCancelled ()) {
94
+ vpcdAccept ();
82
95
byte [] out = null ;
83
96
byte [] in = receiveFromVPCD ();
84
- if (in == null )
85
- break ;
97
+ if (in == null ) {
98
+ if (listenSocket == null ) {
99
+ Log .i (this .getClass ().getName (), "End of stream, finishing" );
100
+ break ;
101
+ } else {
102
+ Log .i (this .getClass ().getName (), "End of stream, closing connection" );
103
+ vpcdCloseClient ();
104
+ continue ; // back to accept
105
+ }
106
+ }
86
107
87
108
if (in .length == VPCD_CTRL_LEN ) {
88
109
switch (in [0 ]) {
@@ -168,7 +189,79 @@ private void sendToVPCD(byte[] data) throws IOException {
168
189
outputStream .flush ();
169
190
}
170
191
192
+ private void vpcdConnection (VPCDWorkerParams params ) throws IOException {
193
+ if (params .listen ){
194
+ vpcdListen (params .port );
195
+ return ;
196
+ }
197
+
198
+ Log .i (this .getClass ().getName (), "Connecting to " + params .hostname + ":" + Integer .toString (params .port ) + "..." );
199
+ vpcdConnect (params .hostname , params .port );
200
+ Log .i (this .getClass ().getName (), "Connected to VPCD" );
201
+ }
202
+
203
+ private void vpcdListen (int port ) throws IOException {
204
+ listenSocket = new ServerSocket (port );
205
+
206
+ final List <String > ifaceAddresses = new LinkedList <>();
207
+ final Enumeration <NetworkInterface > ifaces = NetworkInterface .getNetworkInterfaces ();
208
+ while (ifaces .hasMoreElements ()){
209
+ final NetworkInterface iface = ifaces .nextElement ();
210
+ if (!iface .isUp () || iface .isLoopback () || iface .isVirtual ()) {
211
+ continue ;
212
+ }
213
+ for (InterfaceAddress addr : iface .getInterfaceAddresses ()){
214
+ final InetAddress inetAddr = addr .getAddress ();
215
+ ifaceAddresses .add (inetAddr .getHostAddress ());
216
+ }
217
+ }
218
+
219
+ Log .i (this .getClass ().getName (), "Listening on port " + port + ". Local addresses: " + join (", " , ifaceAddresses ));
220
+ }
221
+
222
+ private void vpcdAccept () throws IOException {
223
+ if (listenSocket == null ){
224
+ return ;
225
+ }
226
+
227
+ if (socket != null ){
228
+ return ; // Already accepted, only one client allowed
229
+ }
230
+
231
+ Log .i (this .getClass ().getName (),"Waiting for connections..." );
232
+ while (!isCancelled ()) {
233
+ listenSocket .setSoTimeout (1000 );
234
+ try {
235
+ socket = listenSocket .accept ();
236
+ } catch (SocketTimeoutException ignored ){}
237
+ if (socket != null ){
238
+ break ;
239
+ }
240
+ }
241
+
242
+ Log .i (this .getClass ().getName (),"Connected, " + socket .getInetAddress ());
243
+ listenSocket .setSoTimeout (0 );
244
+ outputStream = socket .getOutputStream ();
245
+ inputStream = socket .getInputStream ();
246
+ }
247
+
248
+ private void vpcdCloseClient (){
249
+ try {
250
+ outputStream .close ();
251
+ } catch (IOException ignored ) { }
252
+ try {
253
+ inputStream .close ();
254
+ } catch (IOException ignored ) { }
255
+ try {
256
+ socket .close ();
257
+ } catch (IOException ignored ) { }
258
+ outputStream = null ;
259
+ inputStream = null ;
260
+ socket = null ;
261
+ }
262
+
171
263
private void vpcdConnect (String hostname , int port ) throws IOException {
264
+ listenSocket = null ;
172
265
socket = new Socket (InetAddress .getByName (hostname ), port );
173
266
outputStream = socket .getOutputStream ();
174
267
inputStream = socket .getInputStream ();
@@ -182,5 +275,25 @@ private void vpcdDisconnect() throws IOException {
182
275
socket .close ();
183
276
Log .i (this .getClass ().getName (), "Disconnected from VPCD" );
184
277
}
278
+ if (listenSocket != null ) {
279
+ Log .i (this .getClass ().getName (), "Closing listening socket" );
280
+ listenSocket .close ();
281
+ }
282
+ }
283
+
284
+ /**
285
+ * Usage of API level 24+ would allow streams(), join can be removed.
286
+ */
287
+ private static String join (String separator , List <String > input ) {
288
+ if (input == null || input .size () <= 0 ) return "" ;
289
+ StringBuilder sb = new StringBuilder ();
290
+ for (int i = 0 ; i < input .size (); i ++) {
291
+ sb .append (input .get (i ));
292
+ if (i != input .size () - 1 ) {
293
+ sb .append (separator );
294
+ }
295
+ }
296
+ return sb .toString ();
297
+
185
298
}
186
299
}
0 commit comments