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 // added for TC_S_BIT_B1_01_X 206 if (!mIsClient && (requestField == SnepMessage.RESPONSE_CONTINUE || 207 requestField == SnepMessage.RESPONSE_SUCCESS || 208 requestField == SnepMessage.RESPONSE_NOT_FOUND)) { 209 if (DBG) Log.d(TAG, "errorneous response received, disconnecting client"); 210 close(); 211 } 212 if (!mIsClient && requestField == SnepMessage.REQUEST_RFU) { 213 if (DBG) Log.d(TAG, "unknown request received, disconnecting client"); 214 sendMessage(SnepMessage.getMessage(SnepMessage.RESPONSE_BAD_REQUEST)); 215 close(); 216 } 217 // added for TC_C_BIT_BI_01_0 218 if (mIsClient && requestField == SnepMessage.REQUEST_PUT) { 219 if (DBG) Log.d(TAG, "errorneous PUT request received, disconnecting from server"); 220 close(); 221 } 222 // added for TC_C_GET_BV_03 223 if (mIsClient && (requestSize > SnepMessage.MAL_IUT)) { 224 if (DBG) Log.d(TAG, "responding reject"); 225 return new SnepMessage(requestVersion, requestField, requestSize, 0, null); 226 } 227 //added for TC_S_ACC_BV_05_0&1 and TC_S_ACC_BV_06_0&1 228 if (!mIsClient && ((requestSize > SnepMessage.MAL_IUT) || 229 requestSize == SnepMessage.MAL)) { 230 if (DBG) Log.d(TAG, "responding reject"); 231 return new SnepMessage(requestVersion, requestField, requestSize, 0, null); 232 } 233 } 234 235 if (requestSize > readSize) { 236 if (DBG) Log.d(TAG, "requesting continuation"); 237 mSocket.send(SnepMessage.getMessage(fieldContinue).toByteArray()); 238 } else { 239 doneReading = true; 240 } 241 242 // Remaining fragments 243 while (!doneReading) { 244 try { 245 size = mSocket.receive(partial); 246 if (DBG) Log.d(TAG, "read " + size + " bytes"); 247 if (size < 0) { 248 try { 249 mSocket.send(SnepMessage.getMessage(fieldReject).toByteArray()); 250 } catch (IOException e) { 251 // Ignore 252 } 253 throw new IOException(); 254 } else { 255 readSize += size; 256 buffer.write(partial, 0, size); 257 if (readSize == requestSize) { 258 doneReading = true; 259 } 260 } 261 } catch (IOException e) { 262 try { 263 mSocket.send(SnepMessage.getMessage(fieldReject).toByteArray()); 264 } catch (IOException e2) { 265 // Ignore 266 } 267 throw e; 268 } 269 } 270 271 // Build NDEF message set from the stream 272 try { 273 return SnepMessage.fromByteArray(buffer.toByteArray()); 274 } catch (FormatException e) { 275 Log.e(TAG, "Badly formatted NDEF message, ignoring", e); 276 throw new SnepException(e); 277 } 278 } 279 close()280 public void close() throws IOException { 281 mSocket.close(); 282 } 283 } 284