• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 The Android Open Source Project
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 
17 package com.android.nfc.snep;
18 
19 import com.android.nfc.DeviceHost.LlcpSocket;
20 import com.android.nfc.NfcService;
21 import com.android.nfc.sneptest.DtaSnepClient;
22 import com.android.nfc.sneptest.ExtDtaSnepServer;
23 
24 import android.nfc.FormatException;
25 import android.util.Log;
26 
27 import java.io.ByteArrayInputStream;
28 import java.io.ByteArrayOutputStream;
29 import java.io.DataInputStream;
30 import java.io.IOException;
31 import java.util.Arrays;
32 
33 public class SnepMessenger {
34     private static final String TAG = "SnepMessager";
35     private static final boolean DBG = false;
36     private static final int HEADER_LENGTH = 6;
37     final LlcpSocket mSocket;
38     final int mFragmentLength;
39     final boolean mIsClient;
40 
SnepMessenger(boolean isClient, LlcpSocket socket, int fragmentLength)41     public SnepMessenger(boolean isClient, LlcpSocket socket, int fragmentLength) {
42         mSocket = socket;
43         mFragmentLength = fragmentLength;
44         mIsClient = isClient;
45     }
46 
sendMessage(SnepMessage msg)47     public void sendMessage(SnepMessage msg) throws IOException {
48         byte[] buffer = msg.toByteArray();
49         byte remoteContinue;
50         if (mIsClient) {
51             remoteContinue = SnepMessage.RESPONSE_CONTINUE;
52         } else {
53             remoteContinue = SnepMessage.REQUEST_CONTINUE;
54         }
55         if (DBG) Log.d(TAG, "about to send a " + buffer.length + " byte message");
56 
57         // Send first fragment
58         int length = Math.min(buffer.length, mFragmentLength);
59         byte[] tmpBuffer = Arrays.copyOfRange(buffer, 0, length);
60         if (DBG) Log.d(TAG, "about to send a " + length + " byte fragment");
61         mSocket.send(tmpBuffer);
62 
63         if (length == buffer.length) {
64             return;
65         }
66 
67         // Look for Continue or Reject from peer.
68         int offset = length;
69         byte[] responseBytes = new byte[HEADER_LENGTH];
70         mSocket.receive(responseBytes);
71         SnepMessage snepResponse;
72         try {
73             snepResponse = SnepMessage.fromByteArray(responseBytes);
74         } catch (FormatException e) {
75             throw new IOException("Invalid SNEP message", e);
76         }
77 
78         if (DBG) Log.d(TAG, "Got response from first fragment: " + snepResponse.getField());
79         if (snepResponse.getField() != remoteContinue) {
80             throw new IOException("Invalid response from server (" +
81                     snepResponse.getField() + ")");
82         }
83         // Look for wrong/invalid request or response from peer
84        if (NfcService.sIsDtaMode) {
85             if (mIsClient && (DtaSnepClient.mTestCaseId == 6)) {
86                 length = Math.min(buffer.length - offset, mFragmentLength);
87                 tmpBuffer = Arrays.copyOfRange(buffer, offset, offset + length);
88                 if (DBG) Log.d(TAG, "about to send a " + length + " byte fragment");
89                 mSocket.send(tmpBuffer);
90                 offset += length;
91 
92                 mSocket.receive(responseBytes);
93 
94                 try {
95                     snepResponse = SnepMessage.fromByteArray(responseBytes);
96                 } catch (FormatException e) {
97                     throw new IOException("Invalid SNEP message", e);
98                 }
99                 if (DBG) Log.d(TAG, "Got response from second fragment: " + snepResponse.getField());
100                 if (snepResponse.getField() == remoteContinue) {
101                     close();
102                     return;
103                 }
104             }
105         }
106 
107         // Send remaining fragments.
108         while (offset < buffer.length) {
109             length = Math.min(buffer.length - offset, mFragmentLength);
110             tmpBuffer = Arrays.copyOfRange(buffer, offset, offset + length);
111             if (DBG) Log.d(TAG, "about to send a " + length + " byte fragment");
112             mSocket.send(tmpBuffer);
113 
114             if (NfcService.sIsDtaMode) {
115                 if (!mIsClient && ExtDtaSnepServer.mTestCaseId == 0x01) {
116                     mSocket.receive(responseBytes);
117                     try {
118                         snepResponse = SnepMessage.fromByteArray(responseBytes);
119                     } catch (FormatException e) {
120                         throw new IOException("Invalid SNEP message", e);
121                     }
122                     if (DBG) Log.d(TAG, "Got continue response after second fragment: and now disconnecting..." + snepResponse.getField());
123                     if (snepResponse.getField() == remoteContinue) {
124                         close();
125                         return;
126                     }
127                 }
128             }
129 
130             offset += length;
131         }
132     }
133 
getMessage()134     public SnepMessage getMessage() throws IOException, SnepException {
135         ByteArrayOutputStream buffer = new ByteArrayOutputStream(mFragmentLength);
136         byte[] partial = new byte[mFragmentLength];
137         int size;
138         int requestSize = 0;
139         int readSize = 0;
140         byte requestVersion = 0;
141         byte requestField = 0; // for DTA Mode
142         boolean doneReading = false;
143         byte fieldContinue;
144         byte fieldReject;
145         if (mIsClient) {
146             fieldContinue = SnepMessage.REQUEST_CONTINUE;
147             fieldReject = SnepMessage.REQUEST_REJECT;
148         } else {
149             fieldContinue = SnepMessage.RESPONSE_CONTINUE;
150             fieldReject = SnepMessage.RESPONSE_REJECT;
151         }
152 
153         size = mSocket.receive(partial);
154         if (DBG) Log.d(TAG, "read " + size + " bytes");
155         if (size < 0) {
156             try {
157                 mSocket.send(SnepMessage.getMessage(fieldReject).toByteArray());
158             } catch (IOException e) {
159                 // Ignore
160             }
161             throw new IOException("Error reading SNEP message.");
162         } else if (size < HEADER_LENGTH) {
163             try {
164                 if (NfcService.sIsDtaMode && mIsClient) {
165                     if (DBG) Log.d(TAG, "Invalid header length");
166                     close();
167                 } else {
168                     mSocket.send(SnepMessage.getMessage(fieldReject).toByteArray());
169 
170                 }
171                 mSocket.send(SnepMessage.getMessage(fieldReject).toByteArray());
172             } catch (IOException e) {
173                 // Ignore
174             }
175             throw new IOException("Invalid fragment from sender.");
176         } else {
177             readSize = size - HEADER_LENGTH;
178             buffer.write(partial, 0, size);
179         }
180 
181         DataInputStream dataIn = new DataInputStream(new ByteArrayInputStream(partial));
182         requestVersion = dataIn.readByte();
183         requestField = dataIn.readByte();
184         requestSize = dataIn.readInt();
185 
186         if (DBG) Log.d(TAG, "read " + readSize + " of " + requestSize);
187 
188         if (((requestVersion & 0xF0) >> 4) != SnepMessage.VERSION_MAJOR) {
189             if (NfcService.sIsDtaMode) {
190                 sendMessage(SnepMessage.getMessage(SnepMessage.RESPONSE_UNSUPPORTED_VERSION));
191                 close();
192             } else {
193             if (NfcService.sIsDtaMode) {
194                 sendMessage(SnepMessage.getMessage(SnepMessage.RESPONSE_UNSUPPORTED_VERSION));
195                 close();
196             } else {
197                 // Invalid protocol version; treat message as complete.
198                 return new SnepMessage(requestVersion, requestField, 0, 0, null);
199             }
200             }
201 
202         }
203 
204         if (NfcService.sIsDtaMode) {
205             if (!mIsClient && (requestField == SnepMessage.RESPONSE_CONTINUE)||  // added for TC_S_BIT_B1_01_X
206                               requestField == SnepMessage.RESPONSE_SUCCESS ||
207                               requestField == SnepMessage.RESPONSE_NOT_FOUND) {
208                 if (DBG) Log.d(TAG, "errorneous response received, disconnecting client");
209                 close();
210             }
211             if (!mIsClient && requestField == SnepMessage.REQUEST_RFU) {
212                 if (DBG) Log.d(TAG, "unknown request received, disconnecting client");
213                 sendMessage(SnepMessage.getMessage(SnepMessage.RESPONSE_BAD_REQUEST));
214                 close();
215             }
216             // added for TC_C_BIT_BI_01_0
217             if (mIsClient && requestField == SnepMessage.REQUEST_PUT) {
218                 if (DBG) Log.d(TAG, "errorneous PUT request received, disconnecting from server");
219                     close();
220             }
221             // added for TC_C_GET_BV_03
222             if (mIsClient && (requestSize > SnepMessage.MAL_IUT)) {
223                 if (DBG) Log.d(TAG, "responding reject");
224                     return new SnepMessage(requestVersion, requestField, requestSize, 0, null);
225             }
226             //added for TC_S_ACC_BV_05_0&1 and TC_S_ACC_BV_06_0&1
227             if (!mIsClient && ((requestSize > SnepMessage.MAL_IUT) ||
228                                 requestSize == SnepMessage.MAL)) {
229                 if (DBG) Log.d(TAG, "responding reject");
230                     return new SnepMessage(requestVersion, requestField, requestSize, 0, null);
231             }
232         }
233 
234         if (requestSize > readSize) {
235             if (DBG) Log.d(TAG, "requesting continuation");
236             mSocket.send(SnepMessage.getMessage(fieldContinue).toByteArray());
237         } else {
238             doneReading = true;
239         }
240 
241         // Remaining fragments
242         while (!doneReading) {
243             try {
244                 size = mSocket.receive(partial);
245                 if (DBG) Log.d(TAG, "read " + size + " bytes");
246                 if (size < 0) {
247                     try {
248                         mSocket.send(SnepMessage.getMessage(fieldReject).toByteArray());
249                     } catch (IOException e) {
250                         // Ignore
251                     }
252                     throw new IOException();
253                 } else {
254                     readSize += size;
255                     buffer.write(partial, 0, size);
256                     if (readSize == requestSize) {
257                         doneReading = true;
258                     }
259                 }
260             } catch (IOException e) {
261                 try {
262                     mSocket.send(SnepMessage.getMessage(fieldReject).toByteArray());
263                 } catch (IOException e2) {
264                     // Ignore
265                 }
266                 throw e;
267             }
268         }
269 
270         // Build NDEF message set from the stream
271         try {
272             return SnepMessage.fromByteArray(buffer.toByteArray());
273         } catch (FormatException e) {
274             Log.e(TAG, "Badly formatted NDEF message, ignoring", e);
275             throw new SnepException(e);
276         }
277     }
278 
close()279     public void close() throws IOException {
280         mSocket.close();
281     }
282 }
283