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 379439a7fe517b858bc5e5c654b459315e4722feb2Nick Pellyimport java.io.ByteArrayOutputStream; 389439a7fe517b858bc5e5c654b459315e4722feb2Nick Pellyimport java.io.IOException; 399439a7fe517b858bc5e5c654b459315e4722feb2Nick Pellyimport java.io.InputStream; 409439a7fe517b858bc5e5c654b459315e4722feb2Nick Pellyimport java.io.OutputStream; 419439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 42238e0f934f1f47263b384bc745ae0678c777130dCasper Bondeimport android.util.Log; 43238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde 449439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly/** 453998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun * This class in an implementation of the OBEX ClientSession. 462e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly * @hide 479439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly */ 483998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejunpublic final class ClientSession extends ObexSession { 499439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 50238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde private static final String TAG = "ClientSession"; 51238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde 5241557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly private boolean mOpen; 539439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 542e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly // Determines if an OBEX layer connection has been established 5541557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly private boolean mObexConnected; 569439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 5741557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly private byte[] mConnectionId = null; 589439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 599439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly /* 60238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde * The max Packet size must be at least 255 according to the OBEX 6141557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly * specification. 6241557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly */ 63238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde private int mMaxTxPacketSize = ObexHelper.LOWER_LIMIT_MAX_PACKET_SIZE; 649439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 6541557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly private boolean mRequestActive; 669439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 6741557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly private final InputStream mInput; 689439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 6941557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly private final OutputStream mOutput; 709439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 71238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde private final boolean mLocalSrmSupported; 72238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde 73238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde private final ObexTransport mTransport; 74238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde 753998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun public ClientSession(final ObexTransport trans) throws IOException { 7641557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly mInput = trans.openInputStream(); 7741557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly mOutput = trans.openOutputStream(); 7841557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly mOpen = true; 7941557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly mRequestActive = false; 80238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde mLocalSrmSupported = trans.isSrmSupported(); 81238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde mTransport = trans; 82238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde } 83238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde 84238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde /** 85238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde * Create a ClientSession 86238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde * @param trans The transport to use for OBEX transactions 87238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde * @param supportsSrm True if Single Response Mode should be used e.g. if the 88238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde * supplied transport is a TCP or l2cap channel. 89238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde * @throws IOException if it occurs while opening the transport streams. 90238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde */ 91238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde public ClientSession(final ObexTransport trans, final boolean supportsSrm) throws IOException { 92238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde mInput = trans.openInputStream(); 93238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde mOutput = trans.openOutputStream(); 94238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde mOpen = true; 95238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde mRequestActive = false; 96238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde mLocalSrmSupported = supportsSrm; 97238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde mTransport = trans; 989439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 999439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 1003998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun public HeaderSet connect(final HeaderSet header) throws IOException { 1019439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly ensureOpen(); 10241557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly if (mObexConnected) { 1039439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly throw new IOException("Already connected to server"); 1049439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 10541557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly setRequestActive(); 10641557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly 1079439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly int totalLength = 4; 1089439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly byte[] head = null; 1099439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 1109439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly // Determine the header byte array 1119439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly if (header != null) { 11241557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly if (header.nonce != null) { 11341557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly mChallengeDigest = new byte[16]; 11441557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly System.arraycopy(header.nonce, 0, mChallengeDigest, 0, 16); 1159439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 1162e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly head = ObexHelper.createHeader(header, false); 1179439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly totalLength += head.length; 1189439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 1199439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly /* 1209439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * Write the OBEX CONNECT packet to the server. 1219439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * Byte 0: 0x80 1229439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * Byte 1&2: Connect Packet Length 1239439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * Byte 3: OBEX Version Number (Presently, 0x10) 1249439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * Byte 4: Flags (For TCP 0x00) 1259439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * Byte 5&6: Max OBEX Packet Length (Defined in MAX_PACKET_SIZE) 1269439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * Byte 7 to n: headers 1279439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly */ 1289439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly byte[] requestPacket = new byte[totalLength]; 129238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde int maxRxPacketSize = ObexHelper.getMaxRxPacketSize(mTransport); 1309439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly // We just need to start at byte 3 since the sendRequest() method will 1319439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly // handle the length and 0x80. 1329439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly requestPacket[0] = (byte)0x10; 1339439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly requestPacket[1] = (byte)0x00; 134238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde requestPacket[2] = (byte)(maxRxPacketSize >> 8); 135238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde requestPacket[3] = (byte)(maxRxPacketSize & 0xFF); 1369439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly if (head != null) { 1379439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly System.arraycopy(head, 0, requestPacket, 4, head.length); 1389439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 1399439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 140238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde // Since we are not yet connected, the peer max packet size is unknown, 141238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde // hence we are only guaranteed the server will use the first 7 bytes. 1422e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly if ((requestPacket.length + 3) > ObexHelper.MAX_PACKET_SIZE_INT) { 143238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde throw new IOException("Packet size exceeds max packet size for connect"); 1449439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 1459439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 1469439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly HeaderSet returnHeaderSet = new HeaderSet(); 147238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde sendRequest(ObexHelper.OBEX_OPCODE_CONNECT, requestPacket, returnHeaderSet, null, false); 1489439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 1499439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly /* 1509439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * Read the response from the OBEX server. 1519439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * Byte 0: Response Code (If successful then OBEX_HTTP_OK) 1529439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * Byte 1&2: Packet Length 1539439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * Byte 3: OBEX Version Number 1549439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * Byte 4: Flags3 1559439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * Byte 5&6: Max OBEX packet Length 1569439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * Byte 7 to n: Optional HeaderSet 1579439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly */ 1589439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly if (returnHeaderSet.responseCode == ResponseCodes.OBEX_HTTP_OK) { 15941557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly mObexConnected = true; 1609439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 16141557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly setRequestInactive(); 1629439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 1639439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly return returnHeaderSet; 1649439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 1659439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 16641557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly public Operation get(HeaderSet header) throws IOException { 1679439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 16841557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly if (!mObexConnected) { 1699439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly throw new IOException("Not connected to the server"); 1709439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 17141557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly setRequestActive(); 17241557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly 1739439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly ensureOpen(); 1749439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 1753998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun HeaderSet head; 1769439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly if (header == null) { 1773998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun head = new HeaderSet(); 1789439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } else { 1793998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun head = header; 1803998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun if (head.nonce != null) { 18141557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly mChallengeDigest = new byte[16]; 1823998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun System.arraycopy(head.nonce, 0, mChallengeDigest, 0, 16); 1839439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 1849439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 1859439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly // Add the connection ID if one exists 18641557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly if (mConnectionId != null) { 1873998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun head.mConnectionID = new byte[4]; 1883998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun System.arraycopy(mConnectionId, 0, head.mConnectionID, 0, 4); 1899439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 1909439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 191238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if(mLocalSrmSupported) { 192238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde head.setHeader(HeaderSet.SINGLE_RESPONSE_MODE, ObexHelper.OBEX_SRM_ENABLE); 193238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde /* TODO: Consider creating an interface to get the wait state. 194238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde * On an android system, I cannot see when this is to be used. 195238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde * except perhaps if we are to wait for user accept on a push message. 196238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if(getLocalWaitState()) { 197238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde head.setHeader(HeaderSet.SINGLE_RESPONSE_MODE_PARAMETER, ObexHelper.OBEX_SRMP_WAIT); 198238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde } 199238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde */ 200238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde } 201238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde 202238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde return new ClientOperation(mMaxTxPacketSize, this, head, true); 2039439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 2049439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 2059439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly /** 20605ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * 0xCB Connection Id an identifier used for OBEX connection multiplexing 20741557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly */ 2089439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly public void setConnectionID(long id) { 2099439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly if ((id < 0) || (id > 0xFFFFFFFFL)) { 2109439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly throw new IllegalArgumentException("Connection ID is not in a valid range"); 2119439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 21241557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly mConnectionId = ObexHelper.convertToByteArray(id); 2139439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 2149439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 21541557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly public HeaderSet delete(HeaderSet header) throws IOException { 2169439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 21741557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly Operation op = put(header); 2189439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly op.getResponseCode(); 2193998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun HeaderSet returnValue = op.getReceivedHeader(); 2209439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly op.close(); 2219439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 2229439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly return returnValue; 2239439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 2249439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 22541557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly public HeaderSet disconnect(HeaderSet header) throws IOException { 22641557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly if (!mObexConnected) { 2279439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly throw new IOException("Not connected to the server"); 2289439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 22941557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly setRequestActive(); 23041557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly 2319439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly ensureOpen(); 2329439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly // Determine the header byte array 2339439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly byte[] head = null; 2349439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly if (header != null) { 23541557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly if (header.nonce != null) { 23641557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly mChallengeDigest = new byte[16]; 23741557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly System.arraycopy(header.nonce, 0, mChallengeDigest, 0, 16); 2389439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 2399439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly // Add the connection ID if one exists 24041557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly if (mConnectionId != null) { 2413998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun header.mConnectionID = new byte[4]; 2423998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun System.arraycopy(mConnectionId, 0, header.mConnectionID, 0, 4); 2439439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 2442e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly head = ObexHelper.createHeader(header, false); 2459439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 246238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if ((head.length + 3) > mMaxTxPacketSize) { 2479439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly throw new IOException("Packet size exceeds max packet size"); 2489439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 2499439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } else { 2509439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly // Add the connection ID if one exists 25141557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly if (mConnectionId != null) { 2529439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly head = new byte[5]; 2533998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun head[0] = (byte)HeaderSet.CONNECTION_ID; 25441557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly System.arraycopy(mConnectionId, 0, head, 1, 4); 2559439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 2569439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 2579439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 2589439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly HeaderSet returnHeaderSet = new HeaderSet(); 259238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde sendRequest(ObexHelper.OBEX_OPCODE_DISCONNECT, head, returnHeaderSet, null, false); 2609439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 2619439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly /* 26241557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly * An OBEX DISCONNECT reply from the server: 26341557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly * Byte 1: Response code 26441557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly * Bytes 2 & 3: packet size 26541557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly * Bytes 4 & up: headers 26641557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly */ 2679439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 2689439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly /* response code , and header are ignored 2699439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * */ 2709439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 2719439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly synchronized (this) { 27241557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly mObexConnected = false; 27341557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly setRequestInactive(); 2749439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 2759439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 2769439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly return returnHeaderSet; 2779439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 2789439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 2799439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly public long getConnectionID() { 2809439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 28141557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly if (mConnectionId == null) { 2829439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly return -1; 2839439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 28441557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly return ObexHelper.convertToLong(mConnectionId); 2859439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 2869439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 28741557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly public Operation put(HeaderSet header) throws IOException { 28841557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly if (!mObexConnected) { 2899439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly throw new IOException("Not connected to the server"); 2909439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 29141557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly setRequestActive(); 2929439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 2939439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly ensureOpen(); 2943998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun HeaderSet head; 2959439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly if (header == null) { 2963998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun head = new HeaderSet(); 2979439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } else { 2983998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun head = header; 2993998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun // when auth is initiated by client ,save the digest 3003998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun if (head.nonce != null) { 30141557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly mChallengeDigest = new byte[16]; 3023998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun System.arraycopy(head.nonce, 0, mChallengeDigest, 0, 16); 3039439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 3049439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 3059439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 3069439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly // Add the connection ID if one exists 30741557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly if (mConnectionId != null) { 3089439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 3093998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun head.mConnectionID = new byte[4]; 3103998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun System.arraycopy(mConnectionId, 0, head.mConnectionID, 0, 4); 3119439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 3129439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 313238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if(mLocalSrmSupported) { 314238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde head.setHeader(HeaderSet.SINGLE_RESPONSE_MODE, ObexHelper.OBEX_SRM_ENABLE); 315238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde /* TODO: Consider creating an interface to get the wait state. 316238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde * On an android system, I cannot see when this is to be used. 317238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if(getLocalWaitState()) { 318238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde head.setHeader(HeaderSet.SINGLE_RESPONSE_MODE_PARAMETER, ObexHelper.OBEX_SRMP_WAIT); 319238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde } 320238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde */ 321238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde } 322238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde return new ClientOperation(mMaxTxPacketSize, this, head, false); 3239439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 3249439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 3253998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun public void setAuthenticator(Authenticator auth) throws IOException { 3269439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly if (auth == null) { 3273998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun throw new IOException("Authenticator may not be null"); 3289439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 32941557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly mAuthenticator = auth; 3309439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 3319439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 3323998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun public HeaderSet setPath(HeaderSet header, boolean backup, boolean create) throws IOException { 33341557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly if (!mObexConnected) { 3349439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly throw new IOException("Not connected to the server"); 3359439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 33641557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly setRequestActive(); 3379439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly ensureOpen(); 3389439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 3399439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly int totalLength = 2; 3409439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly byte[] head = null; 3413998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun HeaderSet headset; 3429439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly if (header == null) { 3433998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun headset = new HeaderSet(); 3449439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } else { 3453998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun headset = header; 3463998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun if (headset.nonce != null) { 34741557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly mChallengeDigest = new byte[16]; 3483998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun System.arraycopy(headset.nonce, 0, mChallengeDigest, 0, 16); 3499439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 3509439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 3519439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 3529439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly // when auth is initiated by client ,save the digest 3533998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun if (headset.nonce != null) { 35441557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly mChallengeDigest = new byte[16]; 3553998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun System.arraycopy(headset.nonce, 0, mChallengeDigest, 0, 16); 3569439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 3579439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 3589439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly // Add the connection ID if one exists 35941557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly if (mConnectionId != null) { 3603998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun headset.mConnectionID = new byte[4]; 3613998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun System.arraycopy(mConnectionId, 0, headset.mConnectionID, 0, 4); 3629439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 3639439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 3643998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun head = ObexHelper.createHeader(headset, false); 3659439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly totalLength += head.length; 3669439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 367238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if (totalLength > mMaxTxPacketSize) { 3689439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly throw new IOException("Packet size exceeds max packet size"); 3699439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 3709439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 3719439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly int flags = 0; 3729439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly /* 3739439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * The backup flag bit is bit 0 so if we add 1, this will set that bit 3749439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly */ 3759439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly if (backup) { 3769439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly flags++; 3779439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 3789439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly /* 3799439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * The create bit is bit 1 so if we or with 2 the bit will be set. 3809439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly */ 3819439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly if (!create) { 3829439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly flags |= 2; 3839439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 3849439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 3859439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly /* 3869439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * An OBEX SETPATH packet to the server: 3879439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * Byte 1: 0x85 3889439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * Byte 2 & 3: packet size 3899439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * Byte 4: flags 3909439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * Byte 5: constants 3919439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * Byte 6 & up: headers 3929439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly */ 3939439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly byte[] packet = new byte[totalLength]; 3949439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly packet[0] = (byte)flags; 3959439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly packet[1] = (byte)0x00; 3963998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun if (headset != null) { 3979439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly System.arraycopy(head, 0, packet, 2, head.length); 3989439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 3999439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 4009439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly HeaderSet returnHeaderSet = new HeaderSet(); 401238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde sendRequest(ObexHelper.OBEX_OPCODE_SETPATH, packet, returnHeaderSet, null, false); 4029439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 4039439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly /* 4049439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * An OBEX SETPATH reply from the server: 4059439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * Byte 1: Response code 4069439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * Bytes 2 & 3: packet size 4079439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * Bytes 4 & up: headers 4089439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly */ 4099439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 41041557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly setRequestInactive(); 4119439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 4129439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly return returnHeaderSet; 4139439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 4149439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 4159439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly /** 4169439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly * Verifies that the connection is open. 4172e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly * @throws IOException if the connection is closed 4189439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly */ 4199439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly public synchronized void ensureOpen() throws IOException { 42041557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly if (!mOpen) { 4219439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly throw new IOException("Connection closed"); 4229439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 4239439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 4249439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 4259439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly /** 42605ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * Set request inactive. Allows Put and get operation objects to tell this 42705ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * object when they are done. 4289439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly */ 4293998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun /*package*/synchronized void setRequestInactive() { 43041557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly mRequestActive = false; 43141557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly } 43241557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly 43341557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly /** 43441557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly * Set request to active. 43541557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly * @throws IOException if already active 43641557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly */ 43741557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly private synchronized void setRequestActive() throws IOException { 43841557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly if (mRequestActive) { 43941557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly throw new IOException("OBEX request is already being performed"); 4409439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 44141557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly mRequestActive = true; 4429439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 4439439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 4449439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly /** 44505ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * Sends a standard request to the client. It will then wait for the reply 44605ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * and update the header set object provided. If any authentication headers 44705ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * (i.e. authentication challenge or authentication response) are received, 44805ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * they will be processed. 4493998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun * @param opCode the type of request to send to the client 45005ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * @param head the headers to send to the client 45141557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly * @param header the header object to update with the response 45205ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * @param privateInput the input stream used by the Operation object; null 453238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde * if this is called on a CONNECT, SETPATH or DISCONNECT 454238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde * @return 45505ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * <code>true</code> if the operation completed successfully; 45605ff98bbefda39b9ff26f8bca132cfd0248745c6Tao Liejun * <code>false</code> if an authentication response failed to pass 4572e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly * @throws IOException if an IO error occurs 4589439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly */ 4593998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun public boolean sendRequest(int opCode, byte[] head, HeaderSet header, 460238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde PrivateInputStream privateInput, boolean srmActive) throws IOException { 4619439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly //check header length with local max size 4629439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly if (head != null) { 4632e0da96e757a977154063f980d3f4e1abd41cf09Nick Pelly if ((head.length + 3) > ObexHelper.MAX_PACKET_SIZE_INT) { 464238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde // TODO: This is an implementation limit - not a specification requirement. 4659439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly throw new IOException("header too large "); 4669439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 4679439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 4683998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun 469238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde boolean skipSend = false; 470238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde boolean skipReceive = false; 471238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if (srmActive == true) { 472238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if (opCode == ObexHelper.OBEX_OPCODE_PUT) { 473238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde // we are in the middle of a SRM PUT operation, don't expect a continue. 474238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde skipReceive = true; 475238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde } else if (opCode == ObexHelper.OBEX_OPCODE_GET) { 476238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde // We are still sending the get request, send, but don't expect continue 477238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde // until the request is transfered (the final bit is set) 478238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde skipReceive = true; 479238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde } else if (opCode == ObexHelper.OBEX_OPCODE_GET_FINAL) { 480238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde // All done sending the request, expect data from the server, without 481238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde // sending continue. 482238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde skipSend = true; 483238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde } 484238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde 485238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde } 486238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde 4879439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly int bytesReceived; 4889439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly ByteArrayOutputStream out = new ByteArrayOutputStream(); 4893998bf009acaf8cde4d7f837f8b8e41ae0a65141Tao Liejun out.write((byte)opCode); 4909439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 4919439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly // Determine if there are any headers to send 4929439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly if (head == null) { 4939439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly out.write(0x00); 4949439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly out.write(0x03); 4959439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } else { 4969439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly out.write((byte)((head.length + 3) >> 8)); 4979439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly out.write((byte)(head.length + 3)); 4989439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly out.write(head); 4999439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 5009439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 501238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if (!skipSend) { 502238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde // Write the request to the output stream and flush the stream 503238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde mOutput.write(out.toByteArray()); 504238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde // TODO: is this really needed? if this flush is implemented 505238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde // correctly, we will get a gap between each obex packet. 506238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde // which is kind of the idea behind SRM to avoid. 507238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde // Consider offloading to another thread (async action) 508238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde mOutput.flush(); 509238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde } 5109439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 511238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if (!skipReceive) { 512238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde header.responseCode = mInput.read(); 5139439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 514238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde int length = ((mInput.read() << 8) | (mInput.read())); 5159439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 516238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if (length > ObexHelper.getMaxRxPacketSize(mTransport)) { 517238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde throw new IOException("Packet received exceeds packet size limit"); 518238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde } 519238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if (length > ObexHelper.BASE_PACKET_LENGTH) { 520238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde byte[] data = null; 521238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if (opCode == ObexHelper.OBEX_OPCODE_CONNECT) { 522238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde @SuppressWarnings("unused") 523238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde int version = mInput.read(); 524238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde @SuppressWarnings("unused") 525238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde int flags = mInput.read(); 526238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde mMaxTxPacketSize = (mInput.read() << 8) + mInput.read(); 527238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde 528238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde //check with local max size 529238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if (mMaxTxPacketSize > ObexHelper.MAX_CLIENT_PACKET_SIZE) { 530238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde mMaxTxPacketSize = ObexHelper.MAX_CLIENT_PACKET_SIZE; 531238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde } 5329439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 533238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde // check with transport maximum size 534238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if(mMaxTxPacketSize > ObexHelper.getMaxTxPacketSize(mTransport)) { 535238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde // To increase this size, increase the buffer size in L2CAP layer 536238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde // in Bluedroid. 537238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde Log.w(TAG, "An OBEX packet size of " + mMaxTxPacketSize + "was" 538238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde + " requested. Transport only allows: " 539238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde + ObexHelper.getMaxTxPacketSize(mTransport) 540238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde + " Lowering limit to this value."); 541238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde mMaxTxPacketSize = ObexHelper.getMaxTxPacketSize(mTransport); 542238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde } 5439439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 544238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if (length > 7) { 545238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde data = new byte[length - 7]; 5469439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 547238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde bytesReceived = mInput.read(data); 548238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde while (bytesReceived != (length - 7)) { 549238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde bytesReceived += mInput.read(data, bytesReceived, data.length 550238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde - bytesReceived); 551238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde } 552238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde } else { 553238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde return true; 5549439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 5559439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } else { 556238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde data = new byte[length - 3]; 557238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde bytesReceived = mInput.read(data); 5589439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 559238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde while (bytesReceived != (length - 3)) { 560238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde bytesReceived += mInput.read(data, bytesReceived, data.length - bytesReceived); 561238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde } 562238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if (opCode == ObexHelper.OBEX_OPCODE_ABORT) { 563238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde return true; 564238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde } 5659439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 5669439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 567238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde byte[] body = ObexHelper.updateHeaderSet(header, data); 568238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if ((privateInput != null) && (body != null)) { 569238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde privateInput.writeBytes(body, 1); 570238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde } 5719439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 572238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if (header.mConnectionID != null) { 573238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde mConnectionId = new byte[4]; 574238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde System.arraycopy(header.mConnectionID, 0, mConnectionId, 0, 4); 575238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde } 5769439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 577238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if (header.mAuthResp != null) { 578238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if (!handleAuthResp(header.mAuthResp)) { 579238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde setRequestInactive(); 580238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde throw new IOException("Authentication Failed"); 581238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde } 5829439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 5839439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 584238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if ((header.responseCode == ResponseCodes.OBEX_HTTP_UNAUTHORIZED) 585238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde && (header.mAuthChall != null)) { 5869439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 587238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde if (handleAuthChall(header)) { 588238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde out.write((byte)HeaderSet.AUTH_RESPONSE); 589238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde out.write((byte)((header.mAuthResp.length + 3) >> 8)); 590238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde out.write((byte)(header.mAuthResp.length + 3)); 591238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde out.write(header.mAuthResp); 592238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde header.mAuthChall = null; 593238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde header.mAuthResp = null; 5949439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 595238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde byte[] sendHeaders = new byte[out.size() - 3]; 596238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde System.arraycopy(out.toByteArray(), 3, sendHeaders, 0, sendHeaders.length); 5979439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 598238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde return sendRequest(opCode, sendHeaders, header, privateInput, false); 599238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde } 6009439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 6019439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 6029439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 6039439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 6049439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly return true; 6059439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 6069439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly 6079439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly public void close() throws IOException { 60841557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly mOpen = false; 60941557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly mInput.close(); 61041557e18fa3fc5791a5a1c7f0051ae3385608bc4Nick Pelly mOutput.close(); 6119439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly } 612238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde 613238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde public boolean isSrmSupported() { 614238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde return mLocalSrmSupported; 615238e0f934f1f47263b384bc745ae0678c777130dCasper Bonde } 6169439a7fe517b858bc5e5c654b459315e4722feb2Nick Pelly} 617