• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 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.ndefpush;
18 
19 import com.android.internal.nfc.LlcpException;
20 import com.android.internal.nfc.LlcpServiceSocket;
21 import com.android.internal.nfc.LlcpSocket;
22 import com.android.nfc.NfcService;
23 
24 import android.nfc.FormatException;
25 import android.nfc.NfcAdapter;
26 import android.util.Log;
27 
28 import java.io.ByteArrayOutputStream;
29 import java.io.IOException;
30 
31 /**
32  * A simple server that accepts NDEF messages pushed to it over an LLCP connection. Those messages
33  * are typically set on the client side by using {@link NfcAdapter#setLocalNdefMessage}.
34  */
35 public class NdefPushServer {
36     private static final String TAG = "NdefPushServer";
37     private static final boolean DBG = true;
38 
39     private static final int SERVICE_SAP = 0x10;
40     private static final int MIU = 248;
41 
42     static final String SERVICE_NAME = "com.android.npp";
43 
44     NfcService mService = NfcService.getInstance();
45 
46     /** Protected by 'this', null when stopped, non-null when running */
47     ServerThread mServerThread = null;
48 
49     /** Connection class, used to handle incoming connections */
50     private class ConnectionThread extends Thread {
51         private LlcpSocket mSock;
52 
ConnectionThread(LlcpSocket sock)53         ConnectionThread(LlcpSocket sock) {
54             super(TAG);
55             mSock = sock;
56         }
57 
58         @Override
run()59         public void run() {
60             if (DBG) Log.d(TAG, "starting connection thread");
61             try {
62                 ByteArrayOutputStream buffer = new ByteArrayOutputStream(1024);
63                 byte[] partial = new byte[1024];
64                 int size;
65                 boolean connectionBroken = false;
66 
67                 // Get raw data from remote server
68                 while(!connectionBroken) {
69                     try {
70                         size = mSock.receive(partial);
71                         if (DBG) Log.d(TAG, "read " + size + " bytes");
72                         if (size < 0) {
73                             connectionBroken = true;
74                             break;
75                         } else {
76                             buffer.write(partial, 0, size);
77                         }
78                     } catch (IOException e) {
79                         // Connection broken
80                         connectionBroken = true;
81                         if (DBG) Log.d(TAG, "connection broken by IOException", e);
82                     }
83                 }
84 
85                 // Build NDEF message set from the stream
86                 NdefPushProtocol msg = new NdefPushProtocol(buffer.toByteArray());
87                 if (DBG) Log.d(TAG, "got message " + msg.toString());
88 
89                 // Send the intent for the fake tag
90                 mService.sendMockNdefTag(msg.getImmediate());
91             } catch (FormatException e) {
92                 Log.e(TAG, "badly formatted NDEF message, ignoring", e);
93             } finally {
94                 try {
95                     if (DBG) Log.d(TAG, "about to close");
96                     mSock.close();
97                 } catch (IOException e) {
98                     // ignore
99                 }
100             }
101             if (DBG) Log.d(TAG, "finished connection thread");
102         }
103     };
104 
105     /** Server class, used to listen for incoming connection request */
106     class ServerThread extends Thread {
107         boolean mRunning = true;
108         LlcpServiceSocket mServerSocket;
109 
110         @Override
run()111         public void run() {
112             while (mRunning) {
113                 if (DBG) Log.d(TAG, "about create LLCP service socket");
114                 mServerSocket = mService.createLlcpServiceSocket(SERVICE_SAP, SERVICE_NAME,
115                         MIU, 1, 1024);
116                 if (mServerSocket == null) {
117                     if (DBG) Log.d(TAG, "failed to create LLCP service socket");
118                     return;
119                 }
120                 if (DBG) Log.d(TAG, "created LLCP service socket");
121                 try {
122                     while (mRunning) {
123                         if (DBG) Log.d(TAG, "about to accept");
124                         LlcpSocket communicationSocket = mServerSocket.accept();
125                         if (DBG) Log.d(TAG, "accept returned " + communicationSocket);
126                         if (communicationSocket != null) {
127                             new ConnectionThread(communicationSocket).start();
128                         }
129                     }
130                     if (DBG) Log.d(TAG, "stop running");
131                 } catch (LlcpException e) {
132                     Log.e(TAG, "llcp error", e);
133                 } catch (IOException e) {
134                     Log.e(TAG, "IO error", e);
135                 } finally {
136                     if (mServerSocket != null) {
137                         if (DBG) Log.d(TAG, "about to close");
138                         mServerSocket.close();
139                         mServerSocket = null;
140                     }
141                 }
142             }
143         }
144 
shutdown()145         public void shutdown() {
146             mRunning = false;
147             if (mServerSocket != null) {
148                 mServerSocket.close();
149                 mServerSocket = null;
150             }
151         }
152     };
153 
start()154     public void start() {
155         synchronized (this) {
156             if (DBG) Log.d(TAG, "start, thread = " + mServerThread);
157             if (mServerThread == null) {
158                 if (DBG) Log.d(TAG, "starting new server thread");
159                 mServerThread = new ServerThread();
160                 mServerThread.start();
161             }
162         }
163     }
164 
stop()165     public void stop() {
166         synchronized (this) {
167             if (DBG) Log.d(TAG, "stop, thread = " + mServerThread);
168             if (mServerThread != null) {
169                 if (DBG) Log.d(TAG, "shuting down server thread");
170                 mServerThread.shutdown();
171                 mServerThread = null;
172             }
173         }
174     }
175 }
176