12ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson/* 22ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson * Copyright (C) 2011 The Android Open Source Project 32ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson * 42ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson * Licensed under the Apache License, Version 2.0 (the "License"); 52ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson * you may not use this file except in compliance with the License. 62ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson * You may obtain a copy of the License at 72ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson * 82ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson * http://www.apache.org/licenses/LICENSE-2.0 92ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson * 102ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson * Unless required by applicable law or agreed to in writing, software 112ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson * distributed under the License is distributed on an "AS IS" BASIS, 122ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 132ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson * See the License for the specific language governing permissions and 142ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson * limitations under the License. 152ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson */ 162ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson 172ef360deaff9f17aa72d5749ceee283cc80897afBen Dodsonpackage com.android.nfc.snep; 182ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson 194a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamiltonimport com.android.nfc.DeviceHost.LlcpSocket; 204a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamiltonimport com.android.nfc.LlcpException; 212ef360deaff9f17aa72d5749ceee283cc80897afBen Dodsonimport com.android.nfc.NfcService; 222ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson 232ef360deaff9f17aa72d5749ceee283cc80897afBen Dodsonimport android.nfc.NdefMessage; 242ef360deaff9f17aa72d5749ceee283cc80897afBen Dodsonimport android.util.Log; 252ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson 264a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamiltonimport java.io.IOException; 274a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton 282ef360deaff9f17aa72d5749ceee283cc80897afBen Dodsonpublic final class SnepClient { 292ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson private static final String TAG = "SnepClient"; 302ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson private static final boolean DBG = false; 312ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson private static final int DEFAULT_ACCEPTABLE_LENGTH = 100*1024; 32525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project private static final int DEFAULT_MIU = 128; 33525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project private static final int DEFAULT_RWSIZE = 1; 342ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson SnepMessenger mMessenger = null; 35154fcb2b2bca5dfb27bb251efee8f13f1ebe56f8Ben Dodson private final Object mTransmissionLock = new Object(); 362ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson 372ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson private final String mServiceName; 382ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson private final int mPort; 39154fcb2b2bca5dfb27bb251efee8f13f1ebe56f8Ben Dodson private int mState = DISCONNECTED; 402ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson private final int mAcceptableLength; 412ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson private final int mFragmentLength; 42525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project private final int mMiu; 43525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project private final int mRwSize; 442ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson 45154fcb2b2bca5dfb27bb251efee8f13f1ebe56f8Ben Dodson private static final int DISCONNECTED = 0; 46154fcb2b2bca5dfb27bb251efee8f13f1ebe56f8Ben Dodson private static final int CONNECTING = 1; 47154fcb2b2bca5dfb27bb251efee8f13f1ebe56f8Ben Dodson private static final int CONNECTED = 2; 48154fcb2b2bca5dfb27bb251efee8f13f1ebe56f8Ben Dodson 492ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson public SnepClient() { 502ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson mServiceName = SnepServer.DEFAULT_SERVICE_NAME; 512ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson mPort = SnepServer.DEFAULT_PORT; 522ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson mAcceptableLength = DEFAULT_ACCEPTABLE_LENGTH; 532ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson mFragmentLength = -1; 54525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project mMiu = DEFAULT_MIU; 55525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project mRwSize = DEFAULT_RWSIZE; 562ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson } 572ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson 582ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson public SnepClient(String serviceName) { 592ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson mServiceName = serviceName; 602ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson mPort = -1; 612ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson mAcceptableLength = DEFAULT_ACCEPTABLE_LENGTH; 622ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson mFragmentLength = -1; 63525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project mMiu = DEFAULT_MIU; 64525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project mRwSize = DEFAULT_RWSIZE; 65525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project } 66525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project 67525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project public SnepClient(int miu, int rwSize) { 68525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project mServiceName = SnepServer.DEFAULT_SERVICE_NAME; 69525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project mPort = SnepServer.DEFAULT_PORT; 70525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project mAcceptableLength = DEFAULT_ACCEPTABLE_LENGTH; 71525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project mFragmentLength = -1; 72525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project mMiu = miu; 73525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project mRwSize = rwSize; 742ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson } 752ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson 762ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson SnepClient(String serviceName, int fragmentLength) { 772ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson mServiceName = serviceName; 782ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson mPort = -1; 792ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson mAcceptableLength = DEFAULT_ACCEPTABLE_LENGTH; 802ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson mFragmentLength = fragmentLength; 81525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project mMiu = DEFAULT_MIU; 82525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project mRwSize = DEFAULT_RWSIZE; 832ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson } 842ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson 852ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson SnepClient(String serviceName, int acceptableLength, int fragmentLength) { 862ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson mServiceName = serviceName; 872ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson mPort = -1; 882ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson mAcceptableLength = acceptableLength; 892ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson mFragmentLength = fragmentLength; 90525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project mMiu = DEFAULT_MIU; 91525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project mRwSize = DEFAULT_RWSIZE; 922ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson } 932ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson 942ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson public void put(NdefMessage msg) throws IOException { 95154fcb2b2bca5dfb27bb251efee8f13f1ebe56f8Ben Dodson SnepMessenger messenger; 962ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson synchronized (this) { 97154fcb2b2bca5dfb27bb251efee8f13f1ebe56f8Ben Dodson if (mState != CONNECTED) { 982ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson throw new IOException("Socket not connected."); 992ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson } 100154fcb2b2bca5dfb27bb251efee8f13f1ebe56f8Ben Dodson messenger = mMessenger; 101154fcb2b2bca5dfb27bb251efee8f13f1ebe56f8Ben Dodson } 1022ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson 103154fcb2b2bca5dfb27bb251efee8f13f1ebe56f8Ben Dodson synchronized (mTransmissionLock) { 1042ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson try { 105154fcb2b2bca5dfb27bb251efee8f13f1ebe56f8Ben Dodson messenger.sendMessage(SnepMessage.getPutRequest(msg)); 106154fcb2b2bca5dfb27bb251efee8f13f1ebe56f8Ben Dodson messenger.getMessage(); 1072ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson } catch (SnepException e) { 1082ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson throw new IOException(e); 1092ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson } 1102ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson } 1112ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson } 1122ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson 1132ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson public SnepMessage get(NdefMessage msg) throws IOException { 114154fcb2b2bca5dfb27bb251efee8f13f1ebe56f8Ben Dodson SnepMessenger messenger; 1152ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson synchronized (this) { 116154fcb2b2bca5dfb27bb251efee8f13f1ebe56f8Ben Dodson if (mState != CONNECTED) { 1172ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson throw new IOException("Socket not connected."); 1182ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson } 119154fcb2b2bca5dfb27bb251efee8f13f1ebe56f8Ben Dodson messenger = mMessenger; 120154fcb2b2bca5dfb27bb251efee8f13f1ebe56f8Ben Dodson } 1212ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson 122154fcb2b2bca5dfb27bb251efee8f13f1ebe56f8Ben Dodson synchronized (mTransmissionLock) { 1232ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson try { 124154fcb2b2bca5dfb27bb251efee8f13f1ebe56f8Ben Dodson messenger.sendMessage(SnepMessage.getGetRequest(mAcceptableLength, msg)); 125154fcb2b2bca5dfb27bb251efee8f13f1ebe56f8Ben Dodson return messenger.getMessage(); 1262ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson } catch (SnepException e) { 1272ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson throw new IOException(e); 1282ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson } 1292ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson } 1302ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson } 1312ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson 1322ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson public void connect() throws IOException { 1332ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson synchronized (this) { 134154fcb2b2bca5dfb27bb251efee8f13f1ebe56f8Ben Dodson if (mState != DISCONNECTED) { 135154fcb2b2bca5dfb27bb251efee8f13f1ebe56f8Ben Dodson throw new IOException("Socket already in use."); 136154fcb2b2bca5dfb27bb251efee8f13f1ebe56f8Ben Dodson } 137154fcb2b2bca5dfb27bb251efee8f13f1ebe56f8Ben Dodson mState = CONNECTING; 138154fcb2b2bca5dfb27bb251efee8f13f1ebe56f8Ben Dodson } 139154fcb2b2bca5dfb27bb251efee8f13f1ebe56f8Ben Dodson 140d1246caeb5eb22aeb7e411e357e89ec945be1d87Ben Dodson LlcpSocket socket = null; 141154fcb2b2bca5dfb27bb251efee8f13f1ebe56f8Ben Dodson SnepMessenger messenger; 142154fcb2b2bca5dfb27bb251efee8f13f1ebe56f8Ben Dodson try { 143154fcb2b2bca5dfb27bb251efee8f13f1ebe56f8Ben Dodson if (DBG) Log.d(TAG, "about to create socket"); 144154fcb2b2bca5dfb27bb251efee8f13f1ebe56f8Ben Dodson // Connect to the snep server on the remote side 145525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project socket = NfcService.getInstance().createLlcpSocket(0, mMiu, mRwSize, 1024); 146154fcb2b2bca5dfb27bb251efee8f13f1ebe56f8Ben Dodson if (socket == null) { 147154fcb2b2bca5dfb27bb251efee8f13f1ebe56f8Ben Dodson throw new IOException("Could not connect to socket."); 148154fcb2b2bca5dfb27bb251efee8f13f1ebe56f8Ben Dodson } 149154fcb2b2bca5dfb27bb251efee8f13f1ebe56f8Ben Dodson if (mPort == -1) { 150154fcb2b2bca5dfb27bb251efee8f13f1ebe56f8Ben Dodson if (DBG) Log.d(TAG, "about to connect to service " + mServiceName); 1514a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton socket.connectToService(mServiceName); 152154fcb2b2bca5dfb27bb251efee8f13f1ebe56f8Ben Dodson } else { 153154fcb2b2bca5dfb27bb251efee8f13f1ebe56f8Ben Dodson if (DBG) Log.d(TAG, "about to connect to port " + mPort); 1544a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton socket.connectToSap(mPort); 1552ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson } 1564a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton int miu = socket.getRemoteMiu(); 157154fcb2b2bca5dfb27bb251efee8f13f1ebe56f8Ben Dodson int fragmentLength = (mFragmentLength == -1) ? miu : Math.min(miu, mFragmentLength); 158154fcb2b2bca5dfb27bb251efee8f13f1ebe56f8Ben Dodson messenger = new SnepMessenger(true, socket, fragmentLength); 159154fcb2b2bca5dfb27bb251efee8f13f1ebe56f8Ben Dodson } catch (LlcpException e) { 1603329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen synchronized (this) { 1613329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen mState = DISCONNECTED; 1623329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen } 163154fcb2b2bca5dfb27bb251efee8f13f1ebe56f8Ben Dodson throw new IOException("Could not connect to socket"); 1640a0a2428190767616e00435930a566d7cb76888fMartijn Coenen } catch (IOException e) { 1650a0a2428190767616e00435930a566d7cb76888fMartijn Coenen if (socket != null) { 1660a0a2428190767616e00435930a566d7cb76888fMartijn Coenen try { 1670a0a2428190767616e00435930a566d7cb76888fMartijn Coenen socket.close(); 1680a0a2428190767616e00435930a566d7cb76888fMartijn Coenen } catch (IOException e2) { 1690a0a2428190767616e00435930a566d7cb76888fMartijn Coenen } 1700a0a2428190767616e00435930a566d7cb76888fMartijn Coenen } 1713329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen synchronized (this) { 1723329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen mState = DISCONNECTED; 1733329e45c618c5896cb662f686930a75eb2ee5bbcMartijn Coenen } 1740a0a2428190767616e00435930a566d7cb76888fMartijn Coenen throw new IOException("Failed to connect to socket"); 175154fcb2b2bca5dfb27bb251efee8f13f1ebe56f8Ben Dodson } 176154fcb2b2bca5dfb27bb251efee8f13f1ebe56f8Ben Dodson 177154fcb2b2bca5dfb27bb251efee8f13f1ebe56f8Ben Dodson synchronized (this) { 178154fcb2b2bca5dfb27bb251efee8f13f1ebe56f8Ben Dodson mMessenger = messenger; 179154fcb2b2bca5dfb27bb251efee8f13f1ebe56f8Ben Dodson mState = CONNECTED; 1802ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson } 1812ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson } 1822ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson 1832ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson public void close() { 1842ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson synchronized (this) { 185154fcb2b2bca5dfb27bb251efee8f13f1ebe56f8Ben Dodson if (mMessenger != null) { 1862ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson try { 187154fcb2b2bca5dfb27bb251efee8f13f1ebe56f8Ben Dodson mMessenger.close(); 1882ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson } catch (IOException e) { 1892ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson // ignore 1902ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson } finally { 1912ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson mMessenger = null; 192154fcb2b2bca5dfb27bb251efee8f13f1ebe56f8Ben Dodson mState = DISCONNECTED; 1932ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson } 1942ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson } 1952ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson } 1962ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson } 1972ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson} 198