Home | History | Annotate | Download | only in sneptest
      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  */
     16 package com.android.nfc.sneptest;
     17 
     18 import java.io.IOException;
     19 
     20 import android.content.Context;
     21 import android.nfc.NdefMessage;
     22 import android.util.Log;
     23 
     24 import com.android.nfc.DtaServiceConnector;
     25 import com.android.nfc.DeviceHost.LlcpServerSocket;
     26 import com.android.nfc.DeviceHost.LlcpSocket;
     27 import com.android.nfc.LlcpException;
     28 import com.android.nfc.NfcService;
     29 import com.android.nfc.snep.SnepException;
     30 import com.android.nfc.snep.SnepMessage;
     31 import com.android.nfc.snep.SnepMessenger;
     32 
     33 public final class ExtDtaSnepServer {
     34     private static final String TAG = "ExtDtaSnepServer";
     35     private static final boolean DBG = true;
     36     public static final int DEFAULT_PORT = 5;
     37     public static final String EXTENDED_SNEP_DTA_SERVICE_NAME = "urn:nfc:sn:sneptest";
     38     public static final String DEFAULT_SERVICE_NAME = EXTENDED_SNEP_DTA_SERVICE_NAME;
     39 
     40     final Callback mExtDtaSnepServerCallback;
     41     final String mDtaServiceName;
     42     final int mDtaServiceSap;
     43     final int mDtaFragmentLength;
     44     final int mDtaMiu;
     45     final int mDtaRwSize;
     46     public static Context mContext;
     47     public static int mTestCaseId;
     48 
     49     /** Protected by 'this', null when stopped, non-null when running */
     50     ServerThread mServerThread = null;
     51     boolean mServerRunning = false;
     52     static DtaServiceConnector dtaServiceConnector;
     53 
     54     public interface Callback {
     55         public SnepMessage doPut(NdefMessage msg);
     56         public SnepMessage doGet(int acceptableLength, NdefMessage msg);
     57     }
     58 
     59     // for NFC Forum SNEP DTA
     60     public ExtDtaSnepServer(String serviceName, int serviceSap, int miu, int rwSize,
     61                             Callback callback,Context mContext,int testCaseId) {
     62         mExtDtaSnepServerCallback = callback;
     63         mDtaServiceName = serviceName;
     64         mDtaServiceSap = serviceSap;
     65         mDtaFragmentLength = -1; // to get remote MIU
     66         mDtaMiu = miu;
     67         mDtaRwSize = rwSize;
     68         mTestCaseId = testCaseId;
     69         dtaServiceConnector=new DtaServiceConnector(mContext);
     70         dtaServiceConnector.bindService();
     71     }
     72 
     73     /** Connection class, used to handle incoming connections */
     74     private class ConnectionThread extends Thread {
     75         private final LlcpSocket mSock;
     76         private final SnepMessenger mMessager;
     77 
     78         ConnectionThread(LlcpSocket socket, int fragmentLength) {
     79             super(TAG);
     80             mSock = socket;
     81             mMessager = new SnepMessenger(false, socket, fragmentLength);
     82         }
     83 
     84         @Override
     85         public void run() {
     86             if (DBG) Log.d(TAG, "starting connection thread");
     87             try {
     88                 boolean running;
     89                 synchronized (ExtDtaSnepServer.this) {
     90                     running = mServerRunning;
     91                 }
     92 
     93                 while (running) {
     94                     if (!handleRequest(mMessager, mExtDtaSnepServerCallback))
     95                         break;
     96 
     97                     synchronized (ExtDtaSnepServer.this) {
     98                         running = mServerRunning;
     99                     }
    100                 }
    101             } catch (IOException e) {
    102                 if (DBG) Log.e(TAG, "Closing from IOException");
    103             } finally {
    104                 try {
    105                     if (DBG) Log.d(TAG, "about to close");
    106                     mSock.close();
    107                 } catch (IOException e) {}
    108             }
    109             if (DBG) Log.d(TAG, "finished connection thread");
    110         }
    111     }
    112 
    113     static boolean handleRequest(SnepMessenger messenger, Callback callback) throws IOException {
    114         SnepMessage request;
    115         try {
    116             request = messenger.getMessage();
    117         } catch (SnepException e) {
    118             if (DBG) Log.w(TAG, "Bad snep message", e);
    119             try {
    120                 messenger.sendMessage(SnepMessage.getMessage(
    121                     SnepMessage.RESPONSE_BAD_REQUEST));
    122             } catch (IOException e2) {}
    123             return false;
    124         }
    125 
    126         if (((request.getVersion() & 0xF0) >> 4) != SnepMessage.VERSION_MAJOR) {
    127             messenger.sendMessage(SnepMessage.getMessage(
    128                     SnepMessage.RESPONSE_UNSUPPORTED_VERSION));
    129         } else if ((request.getLength() > SnepMessage.MAL_IUT) || request.getLength() == SnepMessage.MAL) {
    130             if (DBG) Log.d(TAG, "Bad requested length");
    131             messenger.sendMessage(SnepMessage.getMessage(SnepMessage.RESPONSE_REJECT));
    132         } else if (request.getField() == SnepMessage.REQUEST_GET) {
    133             if (DBG) Log.d(TAG, "getting message " + request.toString());
    134             messenger.sendMessage(callback.doGet(request.getAcceptableLength(), request.getNdefMessage()));
    135             if (request.getNdefMessage() != null)
    136                 dtaServiceConnector.sendMessage(request.getNdefMessage().toString());
    137         } else if (request.getField() == SnepMessage.REQUEST_PUT) {
    138             if (DBG) Log.d(TAG, "putting message " + request.toString());
    139             messenger.sendMessage(callback.doPut(request.getNdefMessage()));
    140             if (request.getNdefMessage() != null)
    141                 dtaServiceConnector.sendMessage(request.getNdefMessage().toString());
    142         } else {
    143             if (DBG) Log.d(TAG, "Unknown request (" + request.getField() +")");
    144             messenger.sendMessage(SnepMessage.getMessage(SnepMessage.RESPONSE_BAD_REQUEST));
    145         }
    146         return true;
    147     }
    148 
    149     /** Server class, used to listen for incoming connection request */
    150     class ServerThread extends Thread {
    151         private boolean mThreadRunning = true;
    152         LlcpServerSocket mServerSocket;
    153 
    154         @Override
    155         public void run() {
    156             boolean threadRunning;
    157             synchronized (ExtDtaSnepServer.this) {
    158                 threadRunning = mThreadRunning;
    159             }
    160 
    161             while (threadRunning) {
    162                 if (DBG) Log.d(TAG, "about create LLCP service socket");
    163                 try {
    164                     synchronized (ExtDtaSnepServer.this) {
    165                         mServerSocket = NfcService.getInstance().createLlcpServerSocket(mDtaServiceSap,
    166                                 mDtaServiceName, mDtaMiu, mDtaRwSize, 1024);
    167                     }
    168                     if (mServerSocket == null) {
    169                         if (DBG) Log.d(TAG, "failed to create LLCP service socket");
    170                         return;
    171                     }
    172                     if (DBG) Log.d(TAG, "created LLCP service socket");
    173                     synchronized (ExtDtaSnepServer.this) {
    174                         threadRunning = mThreadRunning;
    175                     }
    176 
    177                     while (threadRunning) {
    178                         LlcpServerSocket serverSocket;
    179                         synchronized (ExtDtaSnepServer.this) {
    180                             serverSocket = mServerSocket;
    181                         }
    182 
    183                         if (serverSocket == null) {
    184                             if (DBG) Log.d(TAG, "Server socket shut down.");
    185                             return;
    186                         }
    187                         if (DBG) Log.d(TAG, "about to accept");
    188                         LlcpSocket communicationSocket = serverSocket.accept();
    189                         if (DBG) Log.d(TAG, "accept returned " + communicationSocket);
    190                         if (communicationSocket != null) {
    191                             int miu = communicationSocket.getRemoteMiu();
    192                             int fragmentLength = (mDtaFragmentLength == -1) ? miu : Math.min(miu, mDtaFragmentLength);
    193                             new ConnectionThread(communicationSocket, fragmentLength).start();
    194                         }
    195 
    196                         synchronized (ExtDtaSnepServer.this) {
    197                             threadRunning = mThreadRunning;
    198                         }
    199                     }
    200                     if (DBG) Log.d(TAG, "stop running");
    201                 } catch (LlcpException e) {
    202                     Log.e(TAG, "llcp error", e);
    203                 } catch (IOException e) {
    204                     Log.e(TAG, "IO error", e);
    205                 } finally {
    206                     synchronized (ExtDtaSnepServer.this) {
    207                         if (mServerSocket != null) {
    208                             if (DBG) Log.d(TAG, "about to close");
    209                             try {
    210                                 mServerSocket.close();
    211                             } catch (IOException e) {}
    212                             mServerSocket = null;
    213                         }
    214                     }
    215                 }
    216 
    217                 synchronized (ExtDtaSnepServer.this) {
    218                     threadRunning = mThreadRunning;
    219                 }
    220             }
    221         }
    222 
    223         public void shutdown() {
    224             synchronized (ExtDtaSnepServer.this) {
    225                 mThreadRunning = false;
    226                 if (mServerSocket != null) {
    227                     try {
    228                         mServerSocket.close();
    229                     } catch (IOException e) {}
    230                     mServerSocket = null;
    231                 }
    232             }
    233         }
    234     }
    235 
    236     public void start() {
    237         synchronized (ExtDtaSnepServer.this) {
    238             if (DBG) Log.d(TAG, "start, thread = " + mServerThread);
    239             if (mServerThread == null) {
    240                 if (DBG) Log.d(TAG, "starting new server thread");
    241                 mServerThread = new ServerThread();
    242                 mServerThread.start();
    243                 mServerRunning = true;
    244             }
    245         }
    246     }
    247 
    248     public void stop() {
    249         synchronized (ExtDtaSnepServer.this) {
    250             if (DBG) Log.d(TAG, "stop, thread = " + mServerThread);
    251             if (mServerThread != null) {
    252                 if (DBG) Log.d(TAG, "shuting down server thread");
    253                 mServerThread.shutdown();
    254                 mServerThread = null;
    255                 mServerRunning = false;
    256             }
    257         }
    258     }
    259 }
    260