Home | History | Annotate | Download | only in snep
      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.LlcpException;
     21 import com.android.nfc.NfcService;
     22 
     23 import android.nfc.NdefMessage;
     24 import android.util.Log;
     25 
     26 import java.io.IOException;
     27 
     28 public final class SnepClient {
     29     private static final String TAG = "SnepClient";
     30     private static final boolean DBG = false;
     31     private static final int DEFAULT_ACCEPTABLE_LENGTH = 100*1024;
     32     private static final int DEFAULT_MIU = 128;
     33     private static final int DEFAULT_RWSIZE = 1;
     34     SnepMessenger mMessenger = null;
     35     private final Object mTransmissionLock = new Object();
     36 
     37     private final String mServiceName;
     38     private final int mPort;
     39     private int  mState = DISCONNECTED;
     40     private final int mAcceptableLength;
     41     private final int mFragmentLength;
     42     private final int mMiu;
     43     private final int mRwSize;
     44 
     45     private static final int DISCONNECTED = 0;
     46     private static final int CONNECTING = 1;
     47     private static final int CONNECTED = 2;
     48 
     49     public SnepClient() {
     50         mServiceName = SnepServer.DEFAULT_SERVICE_NAME;
     51         mPort = SnepServer.DEFAULT_PORT;
     52         mAcceptableLength = DEFAULT_ACCEPTABLE_LENGTH;
     53         mFragmentLength = -1;
     54         mMiu = DEFAULT_MIU;
     55         mRwSize = DEFAULT_RWSIZE;
     56     }
     57 
     58     public SnepClient(String serviceName) {
     59         mServiceName = serviceName;
     60         mPort = -1;
     61         mAcceptableLength = DEFAULT_ACCEPTABLE_LENGTH;
     62         mFragmentLength = -1;
     63         mMiu = DEFAULT_MIU;
     64         mRwSize = DEFAULT_RWSIZE;
     65     }
     66 
     67     public SnepClient(int miu, int rwSize) {
     68         mServiceName = SnepServer.DEFAULT_SERVICE_NAME;
     69         mPort = SnepServer.DEFAULT_PORT;
     70         mAcceptableLength = DEFAULT_ACCEPTABLE_LENGTH;
     71         mFragmentLength = -1;
     72         mMiu = miu;
     73         mRwSize = rwSize;
     74     }
     75 
     76     SnepClient(String serviceName, int fragmentLength) {
     77         mServiceName = serviceName;
     78         mPort = -1;
     79         mAcceptableLength = DEFAULT_ACCEPTABLE_LENGTH;
     80         mFragmentLength = fragmentLength;
     81         mMiu = DEFAULT_MIU;
     82         mRwSize = DEFAULT_RWSIZE;
     83     }
     84 
     85     SnepClient(String serviceName, int acceptableLength, int fragmentLength) {
     86         mServiceName = serviceName;
     87         mPort = -1;
     88         mAcceptableLength = acceptableLength;
     89         mFragmentLength = fragmentLength;
     90         mMiu = DEFAULT_MIU;
     91         mRwSize = DEFAULT_RWSIZE;
     92     }
     93 
     94     public void put(NdefMessage msg) throws IOException {
     95         SnepMessenger messenger;
     96         synchronized (this) {
     97             if (mState != CONNECTED) {
     98                 throw new IOException("Socket not connected.");
     99             }
    100             messenger = mMessenger;
    101         }
    102 
    103         synchronized (mTransmissionLock) {
    104             try {
    105                 messenger.sendMessage(SnepMessage.getPutRequest(msg));
    106                 messenger.getMessage();
    107             } catch (SnepException e) {
    108                 throw new IOException(e);
    109             }
    110         }
    111     }
    112 
    113     public SnepMessage get(NdefMessage msg) throws IOException {
    114         SnepMessenger messenger;
    115         synchronized (this) {
    116             if (mState != CONNECTED) {
    117                 throw new IOException("Socket not connected.");
    118             }
    119             messenger = mMessenger;
    120         }
    121 
    122         synchronized (mTransmissionLock) {
    123             try {
    124                 messenger.sendMessage(SnepMessage.getGetRequest(mAcceptableLength, msg));
    125                 return messenger.getMessage();
    126             } catch (SnepException e) {
    127                 throw new IOException(e);
    128             }
    129         }
    130     }
    131 
    132     public void connect() throws IOException {
    133         synchronized (this) {
    134             if (mState != DISCONNECTED) {
    135                 throw new IOException("Socket already in use.");
    136             }
    137             mState = CONNECTING;
    138         }
    139 
    140         LlcpSocket socket = null;
    141         SnepMessenger messenger;
    142         try {
    143             if (DBG) Log.d(TAG, "about to create socket");
    144             // Connect to the snep server on the remote side
    145             socket = NfcService.getInstance().createLlcpSocket(0, mMiu, mRwSize, 1024);
    146             if (socket == null) {
    147                 throw new IOException("Could not connect to socket.");
    148             }
    149             if (mPort == -1) {
    150                 if (DBG) Log.d(TAG, "about to connect to service " + mServiceName);
    151                 socket.connectToService(mServiceName);
    152             } else {
    153                 if (DBG) Log.d(TAG, "about to connect to port " + mPort);
    154                 socket.connectToSap(mPort);
    155             }
    156             int miu = socket.getRemoteMiu();
    157             int fragmentLength = (mFragmentLength == -1) ?  miu : Math.min(miu, mFragmentLength);
    158             messenger = new SnepMessenger(true, socket, fragmentLength);
    159         } catch (LlcpException e) {
    160             synchronized (this) {
    161                 mState = DISCONNECTED;
    162             }
    163             throw new IOException("Could not connect to socket");
    164         } catch (IOException e) {
    165             if (socket != null) {
    166                 try {
    167                     socket.close();
    168                 } catch (IOException e2) {
    169                 }
    170             }
    171             synchronized (this) {
    172                 mState = DISCONNECTED;
    173             }
    174             throw new IOException("Failed to connect to socket");
    175         }
    176 
    177         synchronized (this) {
    178             mMessenger = messenger;
    179             mState = CONNECTED;
    180         }
    181     }
    182 
    183     public void close() {
    184         synchronized (this) {
    185             if (mMessenger != null) {
    186                try {
    187                    mMessenger.close();
    188                } catch (IOException e) {
    189                    // ignore
    190                } finally {
    191                    mMessenger = null;
    192                    mState = DISCONNECTED;
    193                }
    194             }
    195         }
    196     }
    197 }
    198