19439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly/*
2238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde * Copyright (C) 2015 The Android Open Source Project
3238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde * Copyright (c) 2015 Samsung LSI
49439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * Copyright (c) 2008-2009, Motorola, Inc.
59439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly *
69439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * All rights reserved.
79439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly *
89439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * Redistribution and use in source and binary forms, with or without
99439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * modification, are permitted provided that the following conditions are met:
109439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly *
119439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * - Redistributions of source code must retain the above copyright notice,
129439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * this list of conditions and the following disclaimer.
139439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly *
149439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * - Redistributions in binary form must reproduce the above copyright notice,
159439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * this list of conditions and the following disclaimer in the documentation
169439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * and/or other materials provided with the distribution.
179439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly *
189439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * - Neither the name of the Motorola, Inc. nor the names of its contributors
199439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * may be used to endorse or promote products derived from this software
209439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * without specific prior written permission.
219439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly *
229439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
239439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
249439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
259439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
269439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
279439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
289439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
299439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
309439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
319439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
329439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * POSSIBILITY OF SUCH DAMAGE.
339439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly */
349439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
359439a7fe517b858bc5e5c654b459315e4722feb2Nick Pellypackage javax.obex;
369439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
373998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejunimport android.util.Log;
383998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun
392e0da96e757a977154063f980d3f4e1abd41cf09Nick Pellyimport java.io.InputStream;
402e0da96e757a977154063f980d3f4e1abd41cf09Nick Pellyimport java.io.IOException;
412e0da96e757a977154063f980d3f4e1abd41cf09Nick Pellyimport java.io.OutputStream;
429439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
439439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly/**
443998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun * This class in an implementation of the OBEX ServerSession.
452e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly * @hide
469439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly */
473998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejunpublic final class ServerSession extends ObexSession implements Runnable {
489439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
493998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    private static final String TAG = "Obex ServerSession";
50238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde    private static final boolean V = ObexHelper.VDBG;
519439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
523998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    private ObexTransport mTransport;
539439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
543998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    private InputStream mInput;
559439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
563998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    private OutputStream mOutput;
579439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
583998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    private ServerRequestHandler mListener;
599439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
603998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    private Thread mProcessThread;
619439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
623998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    private int mMaxPacketLength;
639439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
643998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    private boolean mClosed;
659439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
669439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
679439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Creates new ServerSession.
6805ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * @param trans the connection to the client
6905ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * @param handler the event listener that will process requests
7005ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * @param auth the authenticator to use with this connection
7105ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * @throws IOException if an error occurred while opening the input and
7205ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     *         output streams
739439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
743998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    public ServerSession(ObexTransport trans, ServerRequestHandler handler, Authenticator auth)
759439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            throws IOException {
763998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        mAuthenticator = auth;
773998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        mTransport = trans;
783998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        mInput = mTransport.openInputStream();
793998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        mOutput = mTransport.openOutputStream();
803998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        mListener = handler;
813998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        mMaxPacketLength = 256;
823998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun
833998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        mClosed = false;
843998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        mProcessThread = new Thread(this);
853998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        mProcessThread.start();
869439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
879439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
889439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
899439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Processes requests made to the server and forwards them to the
909439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * appropriate event listener.
919439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
929439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public void run() {
939439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        try {
949439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
959439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            boolean done = false;
963998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun            while (!done && !mClosed) {
97238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                if(V) Log.v(TAG, "Waiting for incoming request...");
983998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                int requestType = mInput.read();
99238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                if(V) Log.v(TAG, "Read request: " + requestType);
1009439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                switch (requestType) {
1013998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                    case ObexHelper.OBEX_OPCODE_CONNECT:
1029439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        handleConnectRequest();
1039439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        break;
1049439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
1053998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                    case ObexHelper.OBEX_OPCODE_DISCONNECT:
1069439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        handleDisconnectRequest();
1079439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        break;
1089439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
1093998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                    case ObexHelper.OBEX_OPCODE_GET:
1103998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                    case ObexHelper.OBEX_OPCODE_GET_FINAL:
1119439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        handleGetRequest(requestType);
1129439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        break;
1139439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
1143998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                    case ObexHelper.OBEX_OPCODE_PUT:
1153998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                    case ObexHelper.OBEX_OPCODE_PUT_FINAL:
1169439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        handlePutRequest(requestType);
1179439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        break;
1189439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
1193998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                    case ObexHelper.OBEX_OPCODE_SETPATH:
1209439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        handleSetPathRequest();
1219439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        break;
1228258ebdf128ef70a96fcaaa294167e39f1b5e94eLixin Yue                    case ObexHelper.OBEX_OPCODE_ABORT:
1238258ebdf128ef70a96fcaaa294167e39f1b5e94eLixin Yue                        handleAbortRequest();
1248258ebdf128ef70a96fcaaa294167e39f1b5e94eLixin Yue                        break;
1259439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
1269439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    case -1:
1279439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        done = true;
1289439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        break;
1299439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
1309439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    default:
1319439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
1329439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        /*
1339439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                         * Received a request type that is not recognized so I am
1349439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                         * just going to read the packet and send a not implemented
1359439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                         * to the client
1369439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                         */
1373998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                        int length = mInput.read();
1383998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                        length = (length << 8) + mInput.read();
1399439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        for (int i = 3; i < length; i++) {
1403998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                            mInput.read();
1419439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        }
1429439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        sendResponse(ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED, null);
1439439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
1449439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
1459439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
1469439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        } catch (NullPointerException e) {
147238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde            Log.d(TAG, "Exception occured - ignoring", e);
1489439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        } catch (Exception e) {
149238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde            Log.d(TAG, "Exception occured - ignoring", e);
1509439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
1519439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        close();
1529439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
1539439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
1549439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
1558258ebdf128ef70a96fcaaa294167e39f1b5e94eLixin Yue     * Handles a ABORT request from a client. This method will read the rest of
1568258ebdf128ef70a96fcaaa294167e39f1b5e94eLixin Yue     * the request from the client. Assuming the request is valid, it will
1578258ebdf128ef70a96fcaaa294167e39f1b5e94eLixin Yue     * create a <code>HeaderSet</code> object to pass to the
1588258ebdf128ef70a96fcaaa294167e39f1b5e94eLixin Yue     * <code>ServerRequestHandler</code> object. After the handler processes the
1598258ebdf128ef70a96fcaaa294167e39f1b5e94eLixin Yue     * request, this method will create a reply message to send to the server.
1608258ebdf128ef70a96fcaaa294167e39f1b5e94eLixin Yue     *
1618258ebdf128ef70a96fcaaa294167e39f1b5e94eLixin Yue     * @throws IOException if an error occurred at the transport layer
1628258ebdf128ef70a96fcaaa294167e39f1b5e94eLixin Yue     */
1638258ebdf128ef70a96fcaaa294167e39f1b5e94eLixin Yue    private void handleAbortRequest() throws IOException {
1648258ebdf128ef70a96fcaaa294167e39f1b5e94eLixin Yue        int code = ResponseCodes.OBEX_HTTP_OK;
1658258ebdf128ef70a96fcaaa294167e39f1b5e94eLixin Yue        HeaderSet request = new HeaderSet();
1668258ebdf128ef70a96fcaaa294167e39f1b5e94eLixin Yue        HeaderSet reply = new HeaderSet();
1678258ebdf128ef70a96fcaaa294167e39f1b5e94eLixin Yue
1688258ebdf128ef70a96fcaaa294167e39f1b5e94eLixin Yue        int length = mInput.read();
1698258ebdf128ef70a96fcaaa294167e39f1b5e94eLixin Yue        length = (length << 8) + mInput.read();
170238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        if (length > ObexHelper.getMaxRxPacketSize(mTransport)) {
1718258ebdf128ef70a96fcaaa294167e39f1b5e94eLixin Yue            code = ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE;
1728258ebdf128ef70a96fcaaa294167e39f1b5e94eLixin Yue        } else {
1738258ebdf128ef70a96fcaaa294167e39f1b5e94eLixin Yue            for (int i = 3; i < length; i++) {
1748258ebdf128ef70a96fcaaa294167e39f1b5e94eLixin Yue                mInput.read();
1758258ebdf128ef70a96fcaaa294167e39f1b5e94eLixin Yue            }
1768258ebdf128ef70a96fcaaa294167e39f1b5e94eLixin Yue            code = mListener.onAbort(request, reply);
1778258ebdf128ef70a96fcaaa294167e39f1b5e94eLixin Yue            Log.v(TAG, "onAbort request handler return value- " + code);
1788258ebdf128ef70a96fcaaa294167e39f1b5e94eLixin Yue            code = validateResponseCode(code);
1798258ebdf128ef70a96fcaaa294167e39f1b5e94eLixin Yue        }
1808258ebdf128ef70a96fcaaa294167e39f1b5e94eLixin Yue        sendResponse(code, null);
1818258ebdf128ef70a96fcaaa294167e39f1b5e94eLixin Yue    }
1828258ebdf128ef70a96fcaaa294167e39f1b5e94eLixin Yue
1838258ebdf128ef70a96fcaaa294167e39f1b5e94eLixin Yue    /**
1849439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Handles a PUT request from a client. This method will provide a
1859439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * <code>ServerOperation</code> object to the request handler. The
1869439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * <code>ServerOperation</code> object will handle the rest of the request.
1879439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * It will also send replies and receive requests until the final reply
1889439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * should be sent. When the final reply should be sent, this method will get
1899439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * the response code to use and send the reply. The
1909439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * <code>ServerOperation</code> object will always reply with a
1919439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * OBEX_HTTP_CONTINUE reply. It will only reply if further information is
1929439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * needed.
19305ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * @param type the type of request received; either 0x02 or 0x82
19405ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * @throws IOException if an error occurred at the transport layer
1959439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
1969439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    private void handlePutRequest(int type) throws IOException {
1973998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        ServerOperation op = new ServerOperation(this, mInput, type, mMaxPacketLength, mListener);
1989439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        try {
1999439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            int response = -1;
2009439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
2013998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun            if ((op.finalBitSet) && !op.isValidBody()) {
2023998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                response = validateResponseCode(mListener
2033998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                        .onDelete(op.requestHeader, op.replyHeader));
2049439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            } else {
2053998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                response = validateResponseCode(mListener.onPut(op));
2069439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
2070b309d6ee433d55b7499d7bbd447494366ef1316Jackson Fan            if (response != ResponseCodes.OBEX_HTTP_OK && !op.isAborted) {
2083998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                op.sendReply(response);
2093998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun            } else if (!op.isAborted) {
2109439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                // wait for the final bit
2113998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                while (!op.finalBitSet) {
2123998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                    op.sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
2139439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
2143998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                op.sendReply(response);
2159439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
2169439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        } catch (Exception e) {
21705ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun            /*To fix bugs in aborted cases,
21805ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun             *(client abort file transfer prior to the last packet which has the end of body header,
21905ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun             *internal error should not be sent because server has already replied with
22005ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun             *OK response in "sendReply")
22105ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun             */
222238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde            if(V) Log.d(TAG,"Exception occured - sending OBEX_HTTP_INTERNAL_ERROR reply",e);
22305ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun            if (!op.isAborted) {
22405ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun                sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null);
22505ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun            }
2269439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
2279439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
2289439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
2299439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
2309439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Handles a GET request from a client. This method will provide a
2319439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * <code>ServerOperation</code> object to the request handler. The
2329439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * <code>ServerOperation</code> object will handle the rest of the request.
2339439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * It will also send replies and receive requests until the final reply
2349439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * should be sent. When the final reply should be sent, this method will get
2359439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * the response code to use and send the reply. The
2369439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * <code>ServerOperation</code> object will always reply with a
2379439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * OBEX_HTTP_CONTINUE reply. It will only reply if further information is
2389439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * needed.
23905ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * @param type the type of request received; either 0x03 or 0x83
24005ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * @throws IOException if an error occurred at the transport layer
2419439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
2429439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    private void handleGetRequest(int type) throws IOException {
2433998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        ServerOperation op = new ServerOperation(this, mInput, type, mMaxPacketLength, mListener);
2449439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        try {
2453998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun            int response = validateResponseCode(mListener.onGet(op));
2469439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
2473998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun            if (!op.isAborted) {
2483998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                op.sendReply(response);
2499439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
2509439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        } catch (Exception e) {
251238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde            if(V) Log.d(TAG,"Exception occured - sending OBEX_HTTP_INTERNAL_ERROR reply",e);
2529439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null);
2539439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
2549439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
2559439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
2569439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
2579439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Send standard response.
25805ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * @param code the response code to send
25905ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * @param header the headers to include in the response
26005ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * @throws IOException if an IO error occurs
2619439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
2623998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun    public void sendResponse(int code, byte[] header) throws IOException {
2639439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int totalLength = 3;
2649439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        byte[] data = null;
2650d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        OutputStream op = mOutput;
2660d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        if (op == null) {
2670d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz            return;
2680d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        }
2699439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
2709439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if (header != null) {
2719439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            totalLength += header.length;
2729439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            data = new byte[totalLength];
2739439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            data[0] = (byte)code;
2749439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            data[1] = (byte)(totalLength >> 8);
2759439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            data[2] = (byte)totalLength;
2769439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            System.arraycopy(header, 0, data, 3, header.length);
2779439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        } else {
2789439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            data = new byte[totalLength];
2799439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            data[0] = (byte)code;
2809439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            data[1] = (byte)0x00;
2819439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            data[2] = (byte)totalLength;
2829439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
2830d376053747615ac7c4b45ab7810329ffbdf80d1Kim Schulz        op.write(data);
284238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        op.flush(); // TODO: Do we need to flush?
2859439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
2869439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
2879439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
2889439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Handles a SETPATH request from a client. This method will read the rest
2899439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * of the request from the client. Assuming the request is valid, it will
2909439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * create a <code>HeaderSet</code> object to pass to the
2919439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * <code>ServerRequestHandler</code> object. After the handler processes the
2929439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * request, this method will create a reply message to send to the server
2939439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * with the response code provided.
29405ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * @throws IOException if an error occurred at the transport layer
2959439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
2969439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    private void handleSetPathRequest() throws IOException {
2979439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int length;
2989439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int flags;
2993998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        @SuppressWarnings("unused")
3009439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int constants;
3019439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int totalLength = 3;
3029439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        byte[] head = null;
3039439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int code = -1;
3049439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int bytesReceived;
3059439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        HeaderSet request = new HeaderSet();
3069439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        HeaderSet reply = new HeaderSet();
3079439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
3083998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        length = mInput.read();
3093998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        length = (length << 8) + mInput.read();
3103998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        flags = mInput.read();
3113998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        constants = mInput.read();
3129439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
313238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        if (length > ObexHelper.getMaxRxPacketSize(mTransport)) {
3149439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            code = ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE;
3159439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            totalLength = 3;
3169439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        } else {
3179439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if (length > 5) {
3189439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                byte[] headers = new byte[length - 5];
3193998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                bytesReceived = mInput.read(headers);
3209439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
3219439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                while (bytesReceived != headers.length) {
3223998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                    bytesReceived += mInput.read(headers, bytesReceived, headers.length
3239439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                            - bytesReceived);
3249439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
3259439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
3262e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly                ObexHelper.updateHeaderSet(request, headers);
3279439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
328e80534ff59b2e62a0ddf4359147b81f5ba10de86Tao Liejun                if (mListener.getConnectionId() != -1 && request.mConnectionID != null) {
3293998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                    mListener.setConnectionId(ObexHelper.convertToLong(request.mConnectionID));
3309439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                } else {
331e80534ff59b2e62a0ddf4359147b81f5ba10de86Tao Liejun                    mListener.setConnectionId(1);
3329439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
3333998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                // the Auth chan is initiated by the server, client sent back the authResp .
3343998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                if (request.mAuthResp != null) {
3353998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                    if (!handleAuthResp(request.mAuthResp)) {
3369439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        code = ResponseCodes.OBEX_HTTP_UNAUTHORIZED;
3373998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                        mListener.onAuthenticationFailure(ObexHelper.getTagValue((byte)0x01,
3383998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                                request.mAuthResp));
3399439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    }
3403998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                    request.mAuthResp = null;
3419439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
3429439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
3439439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
3449439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if (code != ResponseCodes.OBEX_HTTP_UNAUTHORIZED) {
3453998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                // the Auth challenge is initiated by the client
3469439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                // the server will send back the authResp to the client
3473998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                if (request.mAuthChall != null) {
3489439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    handleAuthChall(request);
3493998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                    reply.mAuthResp = new byte[request.mAuthResp.length];
3503998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                    System.arraycopy(request.mAuthResp, 0, reply.mAuthResp, 0,
3513998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                            reply.mAuthResp.length);
3523998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                    request.mAuthChall = null;
3533998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                    request.mAuthResp = null;
3549439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
3559439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                boolean backup = false;
3569439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                boolean create = true;
3579439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (!((flags & 1) == 0)) {
3589439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    backup = true;
3599439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
36069f72c00a12933f0fde049e8465257745f373d21Lixin Yue                if (!((flags & 2) == 0)) {
3619439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    create = false;
3629439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
3639439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
3649439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                try {
3653998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                    code = mListener.onSetPath(request, reply, backup, create);
3669439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                } catch (Exception e) {
367238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                    if(V) Log.d(TAG,"Exception occured - sending OBEX_HTTP_INTERNAL_ERROR reply",e);
3689439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null);
3699439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    return;
3709439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
3719439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
3729439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                code = validateResponseCode(code);
3739439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
3749439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (reply.nonce != null) {
3753998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                    mChallengeDigest = new byte[16];
3763998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                    System.arraycopy(reply.nonce, 0, mChallengeDigest, 0, 16);
3779439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                } else {
3783998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                    mChallengeDigest = null;
3799439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
3809439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
3813998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                long id = mListener.getConnectionId();
3829439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (id == -1) {
3833998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                    reply.mConnectionID = null;
3849439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                } else {
3853998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                    reply.mConnectionID = ObexHelper.convertToByteArray(id);
3869439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
3879439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
3882e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly                head = ObexHelper.createHeader(reply, false);
3899439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                totalLength += head.length;
3909439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
3913998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                if (totalLength > mMaxPacketLength) {
3929439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    totalLength = 3;
3939439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    head = null;
3949439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    code = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
3959439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
3969439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
3979439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
3989439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
3999439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        // Compute Length of OBEX SETPATH packet
4009439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        byte[] replyData = new byte[totalLength];
4019439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        replyData[0] = (byte)code;
4029439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        replyData[1] = (byte)(totalLength >> 8);
4039439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        replyData[2] = (byte)totalLength;
4049439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if (head != null) {
4059439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            System.arraycopy(head, 0, replyData, 3, head.length);
4069439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
4079439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        /*
4089439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * Write the OBEX SETPATH packet to the server. Byte 0: response code
4099439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * Byte 1&2: Connect Packet Length Byte 3 to n: headers
4109439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         */
4113998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        mOutput.write(replyData);
4123998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        mOutput.flush();
4139439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
4149439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
4159439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
4169439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Handles a disconnect request from a client. This method will read the
4179439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * rest of the request from the client. Assuming the request is valid, it
4189439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * will create a <code>HeaderSet</code> object to pass to the
4199439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * <code>ServerRequestHandler</code> object. After the handler processes the
4209439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * request, this method will create a reply message to send to the server.
42105ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * @throws IOException if an error occurred at the transport layer
4229439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
4239439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    private void handleDisconnectRequest() throws IOException {
4249439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int length;
4259439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int code = ResponseCodes.OBEX_HTTP_OK;
4269439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int totalLength = 3;
4279439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        byte[] head = null;
4289439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int bytesReceived;
4299439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        HeaderSet request = new HeaderSet();
4309439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        HeaderSet reply = new HeaderSet();
4319439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
4323998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        length = mInput.read();
4333998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        length = (length << 8) + mInput.read();
4349439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
435238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        if (length > ObexHelper.getMaxRxPacketSize(mTransport)) {
4369439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            code = ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE;
4379439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            totalLength = 3;
4389439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        } else {
4399439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if (length > 3) {
4409439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                byte[] headers = new byte[length - 3];
4413998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                bytesReceived = mInput.read(headers);
4429439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
4439439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                while (bytesReceived != headers.length) {
4443998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                    bytesReceived += mInput.read(headers, bytesReceived, headers.length
4459439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                            - bytesReceived);
4469439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
4479439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
4482e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly                ObexHelper.updateHeaderSet(request, headers);
4499439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
4509439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
451e80534ff59b2e62a0ddf4359147b81f5ba10de86Tao Liejun            if (mListener.getConnectionId() != -1 && request.mConnectionID != null) {
4523998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                mListener.setConnectionId(ObexHelper.convertToLong(request.mConnectionID));
4539439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            } else {
4543998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                mListener.setConnectionId(1);
4559439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
4569439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
4573998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun            if (request.mAuthResp != null) {
4583998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                if (!handleAuthResp(request.mAuthResp)) {
4599439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    code = ResponseCodes.OBEX_HTTP_UNAUTHORIZED;
4603998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                    mListener.onAuthenticationFailure(ObexHelper.getTagValue((byte)0x01,
4613998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                            request.mAuthResp));
4629439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
4633998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                request.mAuthResp = null;
4649439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
4659439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
4669439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if (code != ResponseCodes.OBEX_HTTP_UNAUTHORIZED) {
4679439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
4683998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                if (request.mAuthChall != null) {
4699439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    handleAuthChall(request);
4703998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                    request.mAuthChall = null;
4719439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
4729439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
4739439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                try {
4743998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                    mListener.onDisconnect(request, reply);
4759439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                } catch (Exception e) {
476238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                    if(V) Log.d(TAG,"Exception occured - sending OBEX_HTTP_INTERNAL_ERROR reply",e);
4779439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null);
4789439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    return;
4799439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
4809439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
4813998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                long id = mListener.getConnectionId();
4829439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                if (id == -1) {
4833998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                    reply.mConnectionID = null;
4849439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                } else {
4853998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                    reply.mConnectionID = ObexHelper.convertToByteArray(id);
4869439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
4879439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
4882e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly                head = ObexHelper.createHeader(reply, false);
4899439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                totalLength += head.length;
4909439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
4913998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                if (totalLength > mMaxPacketLength) {
4929439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    totalLength = 3;
4939439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    head = null;
4949439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    code = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
4959439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
4969439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
4979439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
4989439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
4999439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        // Compute Length of OBEX CONNECT packet
5009439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        byte[] replyData;
5019439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if (head != null) {
5029439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            replyData = new byte[3 + head.length];
5039439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        } else {
5049439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            replyData = new byte[3];
5059439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
5069439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        replyData[0] = (byte)code;
5079439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        replyData[1] = (byte)(totalLength >> 8);
5089439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        replyData[2] = (byte)totalLength;
5099439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if (head != null) {
5109439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            System.arraycopy(head, 0, replyData, 3, head.length);
5119439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
5129439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        /*
5139439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * Write the OBEX DISCONNECT packet to the server. Byte 0: response code
5149439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * Byte 1&2: Connect Packet Length Byte 3 to n: headers
5159439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         */
5163998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        mOutput.write(replyData);
5173998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        mOutput.flush();
5189439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
5199439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
5209439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
5219439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Handles a connect request from a client. This method will read the rest
5229439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * of the request from the client. Assuming the request is valid, it will
5239439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * create a <code>HeaderSet</code> object to pass to the
5249439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * <code>ServerRequestHandler</code> object. After the handler processes the
5259439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * request, this method will create a reply message to send to the server
5269439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * with the response code provided.
52705ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * @throws IOException if an error occurred at the transport layer
5289439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
5299439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    private void handleConnectRequest() throws IOException {
5309439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int packetLength;
5313998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        @SuppressWarnings("unused")
5329439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int version;
5333998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        @SuppressWarnings("unused")
5349439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int flags;
5359439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int totalLength = 7;
5369439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        byte[] head = null;
5379439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int code = -1;
5389439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        HeaderSet request = new HeaderSet();
5399439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        HeaderSet reply = new HeaderSet();
5409439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        int bytesReceived;
5419439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
542238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        if(V) Log.v(TAG,"handleConnectRequest()");
543238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde
5449439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        /*
5459439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * Read in the length of the OBEX packet, OBEX version, flags, and max
5469439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * packet length
5479439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         */
5483998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        packetLength = mInput.read();
5493998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        packetLength = (packetLength << 8) + mInput.read();
550238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        if(V) Log.v(TAG,"handleConnectRequest() - packetLength: " + packetLength);
551238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde
5523998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        version = mInput.read();
5533998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        flags = mInput.read();
5543998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        mMaxPacketLength = mInput.read();
5553998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        mMaxPacketLength = (mMaxPacketLength << 8) + mInput.read();
5569439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
557238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        if(V) Log.v(TAG,"handleConnectRequest() - version: " + version
558238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                + " MaxLength: " + mMaxPacketLength + " flags: " + flags);
559238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde
5609439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        // should we check it?
5613998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        if (mMaxPacketLength > ObexHelper.MAX_PACKET_SIZE_INT) {
5623998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun            mMaxPacketLength = ObexHelper.MAX_PACKET_SIZE_INT;
5639439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
5649439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
565238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        if(mMaxPacketLength > ObexHelper.getMaxTxPacketSize(mTransport)) {
566238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde            Log.w(TAG, "Requested MaxObexPacketSize " + mMaxPacketLength
567238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                    + " is larger than the max size supported by the transport: "
568238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                    + ObexHelper.getMaxTxPacketSize(mTransport)
569238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                    + " Reducing to this size.");
570238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde            mMaxPacketLength = ObexHelper.getMaxTxPacketSize(mTransport);
571238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        }
572238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde
573238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        if (packetLength > ObexHelper.getMaxRxPacketSize(mTransport)) {
5749439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            code = ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE;
5759439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            totalLength = 7;
5769439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        } else {
5779439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if (packetLength > 7) {
5789439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                byte[] headers = new byte[packetLength - 7];
5793998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                bytesReceived = mInput.read(headers);
5809439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
5819439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                while (bytesReceived != headers.length) {
5823998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                    bytesReceived += mInput.read(headers, bytesReceived, headers.length
5839439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                            - bytesReceived);
5849439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
5859439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
5862e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly                ObexHelper.updateHeaderSet(request, headers);
5879439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
5889439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
589e80534ff59b2e62a0ddf4359147b81f5ba10de86Tao Liejun            if (mListener.getConnectionId() != -1 && request.mConnectionID != null) {
5903998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                mListener.setConnectionId(ObexHelper.convertToLong(request.mConnectionID));
5919439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            } else {
5923998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                mListener.setConnectionId(1);
5939439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
5949439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
5953998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun            if (request.mAuthResp != null) {
5963998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                if (!handleAuthResp(request.mAuthResp)) {
5979439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    code = ResponseCodes.OBEX_HTTP_UNAUTHORIZED;
5983998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                    mListener.onAuthenticationFailure(ObexHelper.getTagValue((byte)0x01,
5993998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                            request.mAuthResp));
6009439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
6013998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                request.mAuthResp = null;
6029439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
6039439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
6049439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            if (code != ResponseCodes.OBEX_HTTP_UNAUTHORIZED) {
6053998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                if (request.mAuthChall != null) {
6069439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    handleAuthChall(request);
6073998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                    reply.mAuthResp = new byte[request.mAuthResp.length];
6083998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                    System.arraycopy(request.mAuthResp, 0, reply.mAuthResp, 0,
6093998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                            reply.mAuthResp.length);
6103998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                    request.mAuthChall = null;
6113998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                    request.mAuthResp = null;
6129439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
6139439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
6149439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                try {
6153998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                    code = mListener.onConnect(request, reply);
6169439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    code = validateResponseCode(code);
6179439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
6189439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    if (reply.nonce != null) {
6193998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                        mChallengeDigest = new byte[16];
6203998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                        System.arraycopy(reply.nonce, 0, mChallengeDigest, 0, 16);
6219439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    } else {
6223998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                        mChallengeDigest = null;
6239439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    }
6243998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                    long id = mListener.getConnectionId();
6259439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    if (id == -1) {
6263998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                        reply.mConnectionID = null;
6279439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    } else {
6283998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                        reply.mConnectionID = ObexHelper.convertToByteArray(id);
6299439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    }
6309439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
6312e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly                    head = ObexHelper.createHeader(reply, false);
6329439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    totalLength += head.length;
6339439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
6343998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun                    if (totalLength > mMaxPacketLength) {
6359439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        totalLength = 7;
6369439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        head = null;
6379439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                        code = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
6389439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    }
6399439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                } catch (Exception e) {
640238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                    if(V) Log.d(TAG,"Exception occured - sending OBEX_HTTP_INTERNAL_ERROR reply",e);
6419439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    totalLength = 7;
6429439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    head = null;
6439439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                    code = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
6449439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                }
6459439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
6469439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            }
6479439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
6489439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
6499439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        // Compute Length of OBEX CONNECT packet
6502e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly        byte[] length = ObexHelper.convertToByteArray(totalLength);
6519439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
6529439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        /*
6539439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * Write the OBEX CONNECT packet to the server. Byte 0: response code
6549439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * Byte 1&2: Connect Packet Length Byte 3: OBEX Version Number
6559439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * (Presently, 0x10) Byte 4: Flags (For TCP 0x00) Byte 5&6: Max OBEX
6569439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         * Packet Length (Defined in MAX_PACKET_SIZE) Byte 7 to n: headers
6579439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly         */
6589439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        byte[] sendData = new byte[totalLength];
659238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        int maxRxLength = ObexHelper.getMaxRxPacketSize(mTransport);
6603fba4935a7d2353f6f3ec1091729e3509ba73d41Hemant Gupta        if (maxRxLength > mMaxPacketLength) {
6613fba4935a7d2353f6f3ec1091729e3509ba73d41Hemant Gupta            if(V) Log.v(TAG,"Set maxRxLength to min of maxRxServrLen:" + maxRxLength +
6623fba4935a7d2353f6f3ec1091729e3509ba73d41Hemant Gupta                    " and MaxNegotiated from Client: " + mMaxPacketLength);
6633fba4935a7d2353f6f3ec1091729e3509ba73d41Hemant Gupta            maxRxLength = mMaxPacketLength;
6643fba4935a7d2353f6f3ec1091729e3509ba73d41Hemant Gupta        }
6659439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        sendData[0] = (byte)code;
6669439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        sendData[1] = length[2];
6679439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        sendData[2] = length[3];
6689439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        sendData[3] = (byte)0x10;
6699439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        sendData[4] = (byte)0x00;
670238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        sendData[5] = (byte)(maxRxLength >> 8);
671238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        sendData[6] = (byte)(maxRxLength & 0xFF);
6729439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
6739439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if (head != null) {
6749439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            System.arraycopy(head, 0, sendData, 7, head.length);
6759439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
6769439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
6773998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        mOutput.write(sendData);
6783998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        mOutput.flush();
6799439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
6809439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
6819439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
6829439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Closes the server session - in detail close I/O streams and the
6839439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * underlying transport layer. Internal flag is also set so that later
6849439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * attempt to read/write will throw an exception.
6859439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
6869439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    public synchronized void close() {
6873998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        if (mListener != null) {
6883998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun            mListener.onClose();
6899439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
6909439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        try {
691238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde            /* Set state to closed before interrupting the thread by closing the streams */
6923998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun            mClosed = true;
693238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde            if(mInput != null)
694238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                mInput.close();
695238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde            if(mOutput != null)
696238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                mOutput.close();
697238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde            if(mTransport != null)
698238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde                mTransport.close();
6999439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        } catch (Exception e) {
700238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde            if(V) Log.d(TAG,"Exception occured during close() - ignore",e);
7019439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
7023998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        mTransport = null;
7033998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        mInput = null;
7043998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        mOutput = null;
7053998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun        mListener = null;
7069439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
7079439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
7089439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    /**
7099439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * Verifies that the response code is valid. If it is not valid, it will
7109439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * return the <code>OBEX_HTTP_INTERNAL_ERROR</code> response code.
71105ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun     * @param code the response code to check
7129439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     * @return the valid response code or <code>OBEX_HTTP_INTERNAL_ERROR</code>
7139439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     *         if <code>code</code> is not valid
7149439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly     */
7159439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    private int validateResponseCode(int code) {
7169439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
7179439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if ((code >= ResponseCodes.OBEX_HTTP_OK) && (code <= ResponseCodes.OBEX_HTTP_PARTIAL)) {
7189439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            return code;
7199439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
7209439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if ((code >= ResponseCodes.OBEX_HTTP_MULT_CHOICE)
7219439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                && (code <= ResponseCodes.OBEX_HTTP_USE_PROXY)) {
7229439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            return code;
7239439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
7249439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if ((code >= ResponseCodes.OBEX_HTTP_BAD_REQUEST)
7259439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                && (code <= ResponseCodes.OBEX_HTTP_UNSUPPORTED_TYPE)) {
7269439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            return code;
7279439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
7289439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if ((code >= ResponseCodes.OBEX_HTTP_INTERNAL_ERROR)
7299439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                && (code <= ResponseCodes.OBEX_HTTP_VERSION)) {
7309439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            return code;
7319439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
7329439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        if ((code >= ResponseCodes.OBEX_DATABASE_FULL)
7339439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly                && (code <= ResponseCodes.OBEX_DATABASE_LOCKED)) {
7349439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly            return code;
7359439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        }
7369439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly        return ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
7379439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly    }
7389439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly
739238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde    public ObexTransport getTransport() {
740238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde        return mTransport;
741238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde    }
7429439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly}
743