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 */
16package com.android.nfc.sneptest;
17
18import java.io.IOException;
19import java.io.UnsupportedEncodingException;
20
21import android.content.ComponentName;
22import android.content.Context;
23import android.content.Intent;
24import android.content.ServiceConnection;
25import android.nfc.NdefMessage;
26import android.os.IBinder;
27import android.os.Messenger;
28import android.util.Log;
29
30import com.android.nfc.DeviceHost.LlcpSocket;
31import com.android.nfc.LlcpException;
32import com.android.nfc.NfcService;
33import com.android.nfc.DtaServiceConnector;
34import com.android.nfc.snep.SnepException;
35import com.android.nfc.snep.SnepMessage;
36import com.android.nfc.snep.SnepMessenger;
37
38public 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
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
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
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
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
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
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
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