| /* |
| * Copyright (C) 2017 NXP Semiconductors |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package com.android.nfc.sneptest; |
| |
| import java.io.IOException; |
| |
| import android.content.Context; |
| import android.nfc.NdefMessage; |
| import android.util.Log; |
| |
| import com.android.nfc.DtaServiceConnector; |
| import com.android.nfc.DeviceHost.LlcpServerSocket; |
| import com.android.nfc.DeviceHost.LlcpSocket; |
| import com.android.nfc.LlcpException; |
| import com.android.nfc.NfcService; |
| import com.android.nfc.snep.SnepException; |
| import com.android.nfc.snep.SnepMessage; |
| import com.android.nfc.snep.SnepMessenger; |
| |
| public final class ExtDtaSnepServer { |
| private static final String TAG = "ExtDtaSnepServer"; |
| private static final boolean DBG = true; |
| public static final int DEFAULT_PORT = 5; |
| public static final String EXTENDED_SNEP_DTA_SERVICE_NAME = "urn:nfc:sn:sneptest"; |
| public static final String DEFAULT_SERVICE_NAME = EXTENDED_SNEP_DTA_SERVICE_NAME; |
| |
| final Callback mExtDtaSnepServerCallback; |
| final String mDtaServiceName; |
| final int mDtaServiceSap; |
| final int mDtaFragmentLength; |
| final int mDtaMiu; |
| final int mDtaRwSize; |
| public static Context mContext; |
| public static int mTestCaseId; |
| |
| /** Protected by 'this', null when stopped, non-null when running */ |
| ServerThread mServerThread = null; |
| boolean mServerRunning = false; |
| static DtaServiceConnector dtaServiceConnector; |
| |
| public interface Callback { |
| public SnepMessage doPut(NdefMessage msg); |
| public SnepMessage doGet(int acceptableLength, NdefMessage msg); |
| } |
| |
| // for NFC Forum SNEP DTA |
| public ExtDtaSnepServer(String serviceName, int serviceSap, int miu, int rwSize, |
| Callback callback,Context mContext,int testCaseId) { |
| mExtDtaSnepServerCallback = callback; |
| mDtaServiceName = serviceName; |
| mDtaServiceSap = serviceSap; |
| mDtaFragmentLength = -1; // to get remote MIU |
| mDtaMiu = miu; |
| mDtaRwSize = rwSize; |
| mTestCaseId = testCaseId; |
| dtaServiceConnector=new DtaServiceConnector(mContext); |
| dtaServiceConnector.bindService(); |
| } |
| |
| /** Connection class, used to handle incoming connections */ |
| private class ConnectionThread extends Thread { |
| private final LlcpSocket mSock; |
| private final SnepMessenger mMessager; |
| |
| ConnectionThread(LlcpSocket socket, int fragmentLength) { |
| super(TAG); |
| mSock = socket; |
| mMessager = new SnepMessenger(false, socket, fragmentLength); |
| } |
| |
| @Override |
| public void run() { |
| if (DBG) Log.d(TAG, "starting connection thread"); |
| try { |
| boolean running; |
| synchronized (ExtDtaSnepServer.this) { |
| running = mServerRunning; |
| } |
| |
| while (running) { |
| if (!handleRequest(mMessager, mExtDtaSnepServerCallback)) |
| break; |
| |
| synchronized (ExtDtaSnepServer.this) { |
| running = mServerRunning; |
| } |
| } |
| } catch (IOException e) { |
| if (DBG) Log.e(TAG, "Closing from IOException"); |
| } finally { |
| try { |
| if (DBG) Log.d(TAG, "about to close"); |
| mSock.close(); |
| } catch (IOException e) {} |
| } |
| if (DBG) Log.d(TAG, "finished connection thread"); |
| } |
| } |
| |
| static boolean handleRequest(SnepMessenger messenger, Callback callback) throws IOException { |
| SnepMessage request; |
| try { |
| request = messenger.getMessage(); |
| } catch (SnepException e) { |
| if (DBG) Log.w(TAG, "Bad snep message", e); |
| try { |
| messenger.sendMessage(SnepMessage.getMessage( |
| SnepMessage.RESPONSE_BAD_REQUEST)); |
| } catch (IOException e2) {} |
| return false; |
| } |
| |
| if (((request.getVersion() & 0xF0) >> 4) != SnepMessage.VERSION_MAJOR) { |
| messenger.sendMessage(SnepMessage.getMessage( |
| SnepMessage.RESPONSE_UNSUPPORTED_VERSION)); |
| } else if ((request.getLength() > SnepMessage.MAL_IUT) || request.getLength() == SnepMessage.MAL) { |
| if (DBG) Log.d(TAG, "Bad requested length"); |
| messenger.sendMessage(SnepMessage.getMessage(SnepMessage.RESPONSE_REJECT)); |
| } else if (request.getField() == SnepMessage.REQUEST_GET) { |
| if (DBG) Log.d(TAG, "getting message " + request.toString()); |
| messenger.sendMessage(callback.doGet(request.getAcceptableLength(), request.getNdefMessage())); |
| if (request.getNdefMessage() != null) |
| dtaServiceConnector.sendMessage(request.getNdefMessage().toString()); |
| } else if (request.getField() == SnepMessage.REQUEST_PUT) { |
| if (DBG) Log.d(TAG, "putting message " + request.toString()); |
| messenger.sendMessage(callback.doPut(request.getNdefMessage())); |
| if (request.getNdefMessage() != null) |
| dtaServiceConnector.sendMessage(request.getNdefMessage().toString()); |
| } else { |
| if (DBG) Log.d(TAG, "Unknown request (" + request.getField() +")"); |
| messenger.sendMessage(SnepMessage.getMessage(SnepMessage.RESPONSE_BAD_REQUEST)); |
| } |
| return true; |
| } |
| |
| /** Server class, used to listen for incoming connection request */ |
| class ServerThread extends Thread { |
| private boolean mThreadRunning = true; |
| LlcpServerSocket mServerSocket; |
| |
| @Override |
| public void run() { |
| boolean threadRunning; |
| synchronized (ExtDtaSnepServer.this) { |
| threadRunning = mThreadRunning; |
| } |
| |
| while (threadRunning) { |
| if (DBG) Log.d(TAG, "about create LLCP service socket"); |
| try { |
| synchronized (ExtDtaSnepServer.this) { |
| mServerSocket = NfcService.getInstance().createLlcpServerSocket(mDtaServiceSap, |
| mDtaServiceName, mDtaMiu, mDtaRwSize, 1024); |
| } |
| if (mServerSocket == null) { |
| if (DBG) Log.d(TAG, "failed to create LLCP service socket"); |
| return; |
| } |
| if (DBG) Log.d(TAG, "created LLCP service socket"); |
| synchronized (ExtDtaSnepServer.this) { |
| threadRunning = mThreadRunning; |
| } |
| |
| while (threadRunning) { |
| LlcpServerSocket serverSocket; |
| synchronized (ExtDtaSnepServer.this) { |
| serverSocket = mServerSocket; |
| } |
| |
| if (serverSocket == null) { |
| if (DBG) Log.d(TAG, "Server socket shut down."); |
| return; |
| } |
| if (DBG) Log.d(TAG, "about to accept"); |
| LlcpSocket communicationSocket = serverSocket.accept(); |
| if (DBG) Log.d(TAG, "accept returned " + communicationSocket); |
| if (communicationSocket != null) { |
| int miu = communicationSocket.getRemoteMiu(); |
| int fragmentLength = (mDtaFragmentLength == -1) ? miu : Math.min(miu, mDtaFragmentLength); |
| new ConnectionThread(communicationSocket, fragmentLength).start(); |
| } |
| |
| synchronized (ExtDtaSnepServer.this) { |
| threadRunning = mThreadRunning; |
| } |
| } |
| if (DBG) Log.d(TAG, "stop running"); |
| } catch (LlcpException e) { |
| Log.e(TAG, "llcp error", e); |
| } catch (IOException e) { |
| Log.e(TAG, "IO error", e); |
| } finally { |
| synchronized (ExtDtaSnepServer.this) { |
| if (mServerSocket != null) { |
| if (DBG) Log.d(TAG, "about to close"); |
| try { |
| mServerSocket.close(); |
| } catch (IOException e) {} |
| mServerSocket = null; |
| } |
| } |
| } |
| |
| synchronized (ExtDtaSnepServer.this) { |
| threadRunning = mThreadRunning; |
| } |
| } |
| } |
| |
| public void shutdown() { |
| synchronized (ExtDtaSnepServer.this) { |
| mThreadRunning = false; |
| if (mServerSocket != null) { |
| try { |
| mServerSocket.close(); |
| } catch (IOException e) {} |
| mServerSocket = null; |
| } |
| } |
| } |
| } |
| |
| public void start() { |
| synchronized (ExtDtaSnepServer.this) { |
| if (DBG) Log.d(TAG, "start, thread = " + mServerThread); |
| if (mServerThread == null) { |
| if (DBG) Log.d(TAG, "starting new server thread"); |
| mServerThread = new ServerThread(); |
| mServerThread.start(); |
| mServerRunning = true; |
| } |
| } |
| } |
| |
| public void stop() { |
| synchronized (ExtDtaSnepServer.this) { |
| if (DBG) Log.d(TAG, "stop, thread = " + mServerThread); |
| if (mServerThread != null) { |
| if (DBG) Log.d(TAG, "shuting down server thread"); |
| mServerThread.shutdown(); |
| mServerThread = null; |
| mServerRunning = false; |
| } |
| } |
| } |
| } |