1f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen/*
2f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen * Copyright (C) 2012 The Android Open Source Project
3f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen *
4f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen * Licensed under the Apache License, Version 2.0 (the "License");
5f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen * you may not use this file except in compliance with the License.
6f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen * You may obtain a copy of the License at
7f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen *
8f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen *      http://www.apache.org/licenses/LICENSE-2.0
9f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen *
10f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen * Unless required by applicable law or agreed to in writing, software
11f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen * distributed under the License is distributed on an "AS IS" BASIS,
12f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen * See the License for the specific language governing permissions and
14f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen * limitations under the License.
15f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen */
16f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenenpackage com.android.nfc.handover;
17f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen
18f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenenimport android.nfc.FormatException;
19f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenenimport android.nfc.NdefMessage;
20f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenenimport android.util.Log;
21f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen
22f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenenimport com.android.nfc.LlcpException;
23f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenenimport com.android.nfc.NfcService;
24f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenenimport com.android.nfc.DeviceHost.LlcpServerSocket;
25f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenenimport com.android.nfc.DeviceHost.LlcpSocket;
26f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen
27f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenenimport java.io.ByteArrayOutputStream;
28f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenenimport java.io.IOException;
29f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenenimport java.util.Arrays;
30f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen
31f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenenpublic final class HandoverServer {
32f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen    public static final String HANDOVER_SERVICE_NAME = "urn:nfc:sn:handover";
33f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen    public static final String TAG = "HandoverServer";
34f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen    public static final Boolean DBG = false;
35f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen
36f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen    public static final int MIU = 128;
37f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen
38f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen    final HandoverManager mHandoverManager;
39f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen    final int mSap;
40f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen    final Callback mCallback;
41f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen
42f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen    ServerThread mServerThread = null;
43f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen    boolean mServerRunning = false;
44f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen
45f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen    public interface Callback {
46f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen        void onHandoverRequestReceived();
47f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen    }
48f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen
49f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen    public HandoverServer(int sap, HandoverManager manager, Callback callback) {
50f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen        mSap = sap;
51f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen        mHandoverManager = manager;
52f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen        mCallback = callback;
53f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen    }
54f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen
55f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen    public synchronized void start() {
56f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen        if (mServerThread == null) {
57f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen            mServerThread = new ServerThread();
58f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen            mServerThread.start();
59f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen            mServerRunning = true;
60f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen        }
61f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen    }
62f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen
63f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen    public synchronized void stop() {
64f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen        if (mServerThread != null) {
65f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen            mServerThread.shutdown();
66f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen            mServerThread = null;
67f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen            mServerRunning = false;
68f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen        }
69f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen    }
70f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen
71f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen    private class ServerThread extends Thread {
72f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen        private boolean mThreadRunning = true;
73f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen        LlcpServerSocket mServerSocket;
74f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen
75f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen        @Override
76f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen        public void run() {
77f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen            boolean threadRunning;
78f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen            synchronized (HandoverServer.this) {
79f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                threadRunning = mThreadRunning;
80f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen            }
81f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen
82f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen            while (threadRunning) {
83f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                try {
84f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                    synchronized (HandoverServer.this) {
85f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                        mServerSocket = NfcService.getInstance().createLlcpServerSocket(mSap,
86f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                                HANDOVER_SERVICE_NAME, MIU, 1, 1024);
87f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                    }
88f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                    if (mServerSocket == null) {
89f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                        if (DBG) Log.d(TAG, "failed to create LLCP service socket");
90f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                        return;
91f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                    }
92f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                    if (DBG) Log.d(TAG, "created LLCP service socket");
93f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                    synchronized (HandoverServer.this) {
94f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                        threadRunning = mThreadRunning;
95f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                    }
96f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen
97f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                    while (threadRunning) {
98f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                        LlcpServerSocket serverSocket;
99f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                        synchronized (HandoverServer.this) {
100f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                            serverSocket = mServerSocket;
101f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                        }
102f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen
103f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                        if (serverSocket == null) {
104f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                            if (DBG) Log.d(TAG, "Server socket shut down.");
105f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                            return;
106f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                        }
107f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                        if (DBG) Log.d(TAG, "about to accept");
108f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                        LlcpSocket communicationSocket = serverSocket.accept();
109f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                        if (DBG) Log.d(TAG, "accept returned " + communicationSocket);
110f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                        if (communicationSocket != null) {
111f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                            new ConnectionThread(communicationSocket).start();
112f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                        }
113f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen
114f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                        synchronized (HandoverServer.this) {
115f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                            threadRunning = mThreadRunning;
116f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                        }
117f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                    }
118f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                    if (DBG) Log.d(TAG, "stop running");
119f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                } catch (LlcpException e) {
120f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                    Log.e(TAG, "llcp error", e);
121f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                } catch (IOException e) {
122f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                    Log.e(TAG, "IO error", e);
123f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                } finally {
124f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                    synchronized (HandoverServer.this) {
125f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                        if (mServerSocket != null) {
126f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                            if (DBG) Log.d(TAG, "about to close");
127f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                            try {
128f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                                mServerSocket.close();
129f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                            } catch (IOException e) {
130f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                                // ignore
131f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                            }
132f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                            mServerSocket = null;
133f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                        }
134f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                    }
135f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                }
136f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen
137f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                synchronized (HandoverServer.this) {
138f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                    threadRunning = mThreadRunning;
139f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                }
140f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen            }
141f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen        }
142f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen
143f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen        public void shutdown() {
144f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen            synchronized (HandoverServer.this) {
145f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                mThreadRunning = false;
146f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                if (mServerSocket != null) {
147f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                    try {
148f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                        mServerSocket.close();
149f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                    } catch (IOException e) {
150f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                        // ignore
151f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                    }
152f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                    mServerSocket = null;
153f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                }
154f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen            }
155f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen        }
156f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen    }
157f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen
158f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen    private class ConnectionThread extends Thread {
159f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen        private final LlcpSocket mSock;
160f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen
161f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen        ConnectionThread(LlcpSocket socket) {
162f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen            super(TAG);
163f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen            mSock = socket;
164f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen        }
165f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen
166f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen        @Override
167f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen        public void run() {
168f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen            if (DBG) Log.d(TAG, "starting connection thread");
169f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen            ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
170f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen
171f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen            try {
172f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                boolean running;
173f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                synchronized (HandoverServer.this) {
174f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                    running = mServerRunning;
175f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                }
176f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen
177f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                byte[] partial = new byte[mSock.getLocalMiu()];
178f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen
179f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                NdefMessage handoverRequestMsg = null;
180f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                while (running) {
181f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                    int size = mSock.receive(partial);
182f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                    if (size < 0) {
183f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                        break;
184f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                    }
185f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                    byteStream.write(partial, 0, size);
186f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                    // 1) Try to parse a handover request message from bytes received so far
187f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                    try {
188f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                        handoverRequestMsg = new NdefMessage(byteStream.toByteArray());
189f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                    } catch (FormatException e) {
190f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                        // Ignore, and try to fetch more bytes
191f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                    }
192f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen
193f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                    if (handoverRequestMsg != null) {
194f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                        // 2) convert to handover response
195f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                        NdefMessage resp = mHandoverManager.tryHandoverRequest(handoverRequestMsg);
196f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                        if (resp == null) {
197f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                            Log.e(TAG, "Failed to create handover response");
198f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                            break;
199f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                        }
200f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen
201f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                        // 3) send handover response
202f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                        int offset = 0;
203f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                        byte[] buffer = resp.toByteArray();
204f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                        int remoteMiu = mSock.getRemoteMiu();
205f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                        while (offset < buffer.length) {
206f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                            int length = Math.min(buffer.length - offset, remoteMiu);
207f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                            byte[] tmpBuffer = Arrays.copyOfRange(buffer, offset, offset+length);
208f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                            mSock.send(tmpBuffer);
209f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                            offset += length;
210f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                        }
211f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                        // We're done
212f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                        mCallback.onHandoverRequestReceived();
213be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project                        // We can process another handover transfer
214be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project                        byteStream = new ByteArrayOutputStream();
215f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                    }
216f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen
217f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                    synchronized (HandoverServer.this) {
218f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                        running = mServerRunning;
219f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                    }
220f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                }
221f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen
222f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen            } catch (IOException e) {
223f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                if (DBG) Log.d(TAG, "IOException");
224f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen            } finally {
225f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                try {
226f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                    if (DBG) Log.d(TAG, "about to close");
227f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                    mSock.close();
228f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                } catch (IOException e) {
229f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                    // ignore
230f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                }
231f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                try {
232f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                    byteStream.close();
233f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                } catch (IOException e) {
234f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                    // ignore
235f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen                }
236f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen            }
237f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen            if (DBG) Log.d(TAG, "finished connection thread");
238f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen        }
239f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen    }
240f5a196b643c654c7ea98a5e2935e3bff6683399bMartijn Coenen}
241