1 /*
2  * Copyright (C) 2017 NXP Semiconductors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.nfc.sneptest;
17 
18 import java.io.IOException;
19 import java.io.UnsupportedEncodingException;
20 
21 import android.content.ComponentName;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.content.ServiceConnection;
25 import android.nfc.NdefMessage;
26 import android.os.IBinder;
27 import android.os.Messenger;
28 import android.util.Log;
29 
30 import com.android.nfc.DeviceHost.LlcpSocket;
31 import com.android.nfc.LlcpException;
32 import com.android.nfc.NfcService;
33 import com.android.nfc.DtaServiceConnector;
34 import com.android.nfc.snep.SnepException;
35 import com.android.nfc.snep.SnepMessage;
36 import com.android.nfc.snep.SnepMessenger;
37 
38 public final class DtaSnepClient {
39     private static final String TAG = "DtaSnepClient";
40     private static final boolean DBG = true;
41     private static final int DEFAULT_ACCEPTABLE_LENGTH = 1024;
42     private static final int DEFAULT_MIU = 128;
43     private static final int DEFAULT_RWSIZE = 1;
44     private static final int DEFAULT_PORT = 63;
45     private static final String SNEP_SERVICE_NAME = "urn:nfc:sn:snep";
46     private static final String DEFAULT_SERVICE_NAME = SNEP_SERVICE_NAME;
47     private final Object mTransmissionLock = new Object();
48 
49     private int mState = DISCONNECTED;
50     private final int mAcceptableLength;
51     private final int mFragmentLength;
52     private final int mMiu;
53     private final int mPort;
54     private final int mRwSize;
55     private final String mServiceName;
56     public static int mTestCaseId;
57 
58     private static final int DISCONNECTED = 0;
59     private static final int CONNECTING = 1;
60     private static final int CONNECTED = 2;
61 
62     SnepMessenger mMessenger = null;
63 
DtaSnepClient()64     public DtaSnepClient() {
65         mServiceName = DEFAULT_SERVICE_NAME;
66         mPort = DEFAULT_PORT;
67         mAcceptableLength = DEFAULT_ACCEPTABLE_LENGTH;
68         mFragmentLength = -1;
69         mMiu = DEFAULT_MIU;
70         mRwSize = DEFAULT_RWSIZE;
71     }
72 
DtaSnepClient(String serviceName, int miu, int rwSize, int testCaseId)73     public DtaSnepClient(String serviceName, int miu, int rwSize, int testCaseId) {
74         mServiceName = serviceName;
75         mPort = -1;
76         mAcceptableLength = DEFAULT_ACCEPTABLE_LENGTH;
77         mFragmentLength = -1;
78         mMiu = miu;
79         mRwSize = rwSize;
80         mTestCaseId = testCaseId;
81     }
82 
DtaClientOperations(Context mContext)83     public void DtaClientOperations(Context mContext) {
84         DtaServiceConnector dtaServiceConnector=new DtaServiceConnector(mContext);
85         dtaServiceConnector.bindService();
86         if (DBG) Log.d(TAG, "Connecting remote server");
87         try {
88             connect();
89         } catch(IOException e) {
90             Log.e(TAG, "Error connecting remote server");
91         }
92         switch(mTestCaseId) {
93            //TC_C_BIT_BV_01
94            case 1:
95            {
96                try {
97                    if (DBG) Log.d(TAG, "PUT Small Ndef Data");
98                    put(SnepMessage.getSmallNdef());
99                    dtaServiceConnector.sendMessage(SnepMessage.getSmallNdef().toString());
100                } catch (UnsupportedEncodingException e) {
101                      e.printStackTrace();
102                } catch (IOException e) {
103                      e.printStackTrace();
104                }
105                close();
106            }
107            break;
108            //TC_C_BIT_BI_01_0
109            case 2:
110            {
111                try {
112                    if (DBG) Log.d(TAG, "PUT Small Ndef Data");
113                    put(SnepMessage.getSmallNdef());
114                    dtaServiceConnector.sendMessage(SnepMessage.getSmallNdef().toString());
115                } catch (UnsupportedEncodingException e) {
116                    e.printStackTrace();
117                } catch (IOException e) {
118                    e.printStackTrace();
119                }
120                close();
121            }
122            break;
123            //TC_C_BIT_BI_01_1
124            case 3:
125            {
126                try {
127                    if (DBG) Log.d(TAG, "PUT Small Ndef Data");
128                    put(SnepMessage.getSmallNdef());
129                    dtaServiceConnector.sendMessage(SnepMessage.getSmallNdef().toString());
130                } catch (UnsupportedEncodingException e) {
131                    e.printStackTrace();
132                } catch (IOException e) {
133                    e.printStackTrace();
134                }
135                close();
136            }
137            break;
138            //TC_C_PUT_BV_01
139            case 4:
140            {
141                try {
142                    if (DBG) Log.d(TAG, "PUT Small Ndef Data");
143                    put(SnepMessage.getSmallNdef());
144                    dtaServiceConnector.sendMessage(SnepMessage.getSmallNdef().toString());
145                } catch (UnsupportedEncodingException e) {
146                    e.printStackTrace();
147                } catch (IOException e) {
148                    e.printStackTrace();
149                }
150                close();
151            }
152            break;
153            //TC_C_PUT_BV_02
154            case 5:
155            {
156                try {
157                    if (DBG) Log.d(TAG, "PUT Large Ndef Data");
158                    put(SnepMessage.getLargeNdef());
159                    dtaServiceConnector.sendMessage(SnepMessage.getLargeNdef().toString());
160                } catch (UnsupportedEncodingException e) {
161                    e.printStackTrace();
162                } catch (IOException e) {
163                    e.printStackTrace();
164                }
165                close();
166            }
167            break;
168            //TC_C_PUT_BI_01
169            case 6:
170            {
171                try {
172                    if (DBG) Log.d(TAG, "PUT Large Ndef Data");
173                    put(SnepMessage.getLargeNdef());
174                    dtaServiceConnector.sendMessage(SnepMessage.getLargeNdef().toString());
175                } catch (UnsupportedEncodingException e) {
176                    e.printStackTrace();
177                } catch (IOException e) {
178                    e.printStackTrace();
179                }
180                close();
181            }
182            break;
183            //TC_C_GET_BV_01
184            case 7:
185            {
186                try {
187                    if (DBG) Log.d(TAG, "GET Ndef Message");
188                    get(SnepMessage.getSmallNdef());
189                    dtaServiceConnector.sendMessage(SnepMessage.getSmallNdef().toString());
190                } catch (UnsupportedEncodingException e) {
191                    e.printStackTrace();
192                } catch (IOException e) {
193                    e.printStackTrace();
194                }
195                close();
196            }
197            break;
198            //TC_C_GET_BV_02
199            case 8:
200            {
201                try {
202                    if (DBG) Log.d(TAG, "GET Ndef Message");
203                    get(SnepMessage.getSmallNdef());
204                    dtaServiceConnector.sendMessage(SnepMessage.getSmallNdef().toString());
205                } catch (UnsupportedEncodingException e) {
206                    e.printStackTrace();
207                } catch (IOException e) {
208                    e.printStackTrace();
209                }
210                close();
211            }
212            break;
213            //TC_C_GET_BV_03
214            case 9:
215            {
216                try {
217                    if (DBG) Log.d(TAG, "GET Ndef Message");
218                    get(SnepMessage.getSmallNdef());
219                    dtaServiceConnector.sendMessage(SnepMessage.getSmallNdef().toString());
220                } catch (UnsupportedEncodingException e) {
221                    e.printStackTrace();
222                } catch (IOException e) {
223                    e.printStackTrace();
224                }
225                close();
226            }
227            break;
228            default:
229                if (DBG) Log.d(TAG, "Unknown test case");
230         }
231     }
232 
put(NdefMessage msg)233     public void put(NdefMessage msg) throws IOException {
234         SnepMessenger messenger;
235         synchronized (this) {
236             if (mState != CONNECTED) {
237                 throw new IOException("Socket not connected.");
238             }
239             messenger = mMessenger;
240         }
241 
242         synchronized (mTransmissionLock) {
243             try {
244                 messenger.sendMessage(SnepMessage.getPutRequest(msg));
245                 messenger.getMessage();
246             } catch (SnepException e) {
247                 throw new IOException(e);
248             }
249         }
250     }
251 
get(NdefMessage msg)252     public SnepMessage get(NdefMessage msg) throws IOException {
253         SnepMessenger messenger;
254         synchronized (this) {
255             if (mState != CONNECTED) {
256                 throw new IOException("Socket not connected.");
257             }
258             messenger = mMessenger;
259         }
260 
261         synchronized (mTransmissionLock) {
262             try {
263                 messenger.sendMessage(SnepMessage.getGetRequest(mAcceptableLength, msg));
264                 return messenger.getMessage();
265             } catch (SnepException e) {
266                 throw new IOException(e);
267             }
268         }
269     }
270 
connect()271     public void connect() throws IOException {
272         synchronized (this) {
273             if (mState != DISCONNECTED) {
274                 throw new IOException("Socket already in use.");
275             }
276             mState = CONNECTING;
277         }
278 
279         LlcpSocket socket = null;
280         SnepMessenger messenger;
281         try {
282             if (DBG) Log.d(TAG, "about to create socket");
283             // Connect to the snep server on the remote side
284             socket = NfcService.getInstance().createLlcpSocket(0, mMiu, mRwSize, 1024);
285             if (socket == null) {
286                 throw new IOException("Could not connect to socket.");
287             }
288             if (mPort == -1) {
289                 if (DBG) Log.d(TAG, "about to connect to service " + mServiceName);
290                 socket.connectToService(mServiceName);
291             } else {
292                 if (DBG) Log.d(TAG, "about to connect to port " + mPort);
293                 socket.connectToSap(mPort);
294             }
295             int miu = socket.getRemoteMiu();
296             int fragmentLength = (mFragmentLength == -1) ?  miu : Math.min(miu, mFragmentLength);
297             messenger = new SnepMessenger(true, socket, fragmentLength);
298         } catch (LlcpException e) {
299             synchronized (this) {
300                 mState = DISCONNECTED;
301             }
302             throw new IOException("Could not connect to socket");
303         } catch (IOException e) {
304             if (socket != null) {
305                 try {
306                     socket.close();
307                 } catch (IOException e2) {}
308             }
309             synchronized (this) {
310                 mState = DISCONNECTED;
311             }
312             throw new IOException("Failed to connect to socket");
313         }
314 
315         synchronized (this) {
316             mMessenger = messenger;
317             mState = CONNECTED;
318         }
319     }
320 
close()321     public void close() {
322         synchronized (this) {
323             if (mMessenger != null) {
324                try {
325                    mMessenger.close();
326                } catch (IOException e) {
327                    // ignore
328                } finally {
329                    mMessenger = null;
330                    mState = DISCONNECTED;
331                }
332             }
333         }
334     }
335 }
336