blob: 27d8976d0702b40653873f32ff6f5d2b456e6b27 [file] [log] [blame]
Nick Pelly9439a7f2009-06-30 12:04:36 -07001/*
2 * Copyright (c) 2008-2009, Motorola, Inc.
3 *
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * - Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
11 *
12 * - Redistributions in binary form must reproduce the above copyright notice,
13 * this list of conditions and the following disclaimer in the documentation
14 * and/or other materials provided with the distribution.
15 *
16 * - Neither the name of the Motorola, Inc. nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33package javax.obex;
34
35import java.io.ByteArrayOutputStream;
36import java.io.IOException;
37import java.io.InputStream;
38import java.io.OutputStream;
39
40/**
Tao Liejun3998bf02009-07-02 19:29:09 +080041 * This class in an implementation of the OBEX ClientSession.
Nick Pelly2e0da962009-06-30 16:28:54 -070042 * @hide
Nick Pelly9439a7f2009-06-30 12:04:36 -070043 */
Tao Liejun3998bf02009-07-02 19:29:09 +080044public final class ClientSession extends ObexSession {
Nick Pelly9439a7f2009-06-30 12:04:36 -070045
Nick Pelly41557e12009-06-30 19:38:30 -070046 private boolean mOpen;
Nick Pelly9439a7f2009-06-30 12:04:36 -070047
Nick Pelly2e0da962009-06-30 16:28:54 -070048 // Determines if an OBEX layer connection has been established
Nick Pelly41557e12009-06-30 19:38:30 -070049 private boolean mObexConnected;
Nick Pelly9439a7f2009-06-30 12:04:36 -070050
Nick Pelly41557e12009-06-30 19:38:30 -070051 private byte[] mConnectionId = null;
Nick Pelly9439a7f2009-06-30 12:04:36 -070052
Nick Pelly9439a7f2009-06-30 12:04:36 -070053 /*
Nick Pelly41557e12009-06-30 19:38:30 -070054 * The max Packet size must be at least 256 according to the OBEX
55 * specification.
56 */
Nick Pelly9439a7f2009-06-30 12:04:36 -070057 private int maxPacketSize = 256;
58
Nick Pelly41557e12009-06-30 19:38:30 -070059 private boolean mRequestActive;
Nick Pelly9439a7f2009-06-30 12:04:36 -070060
Nick Pelly41557e12009-06-30 19:38:30 -070061 private final InputStream mInput;
Nick Pelly9439a7f2009-06-30 12:04:36 -070062
Nick Pelly41557e12009-06-30 19:38:30 -070063 private final OutputStream mOutput;
Nick Pelly9439a7f2009-06-30 12:04:36 -070064
Tao Liejun3998bf02009-07-02 19:29:09 +080065 public ClientSession(final ObexTransport trans) throws IOException {
Nick Pelly41557e12009-06-30 19:38:30 -070066 mInput = trans.openInputStream();
67 mOutput = trans.openOutputStream();
68 mOpen = true;
69 mRequestActive = false;
Nick Pelly9439a7f2009-06-30 12:04:36 -070070 }
71
Tao Liejun3998bf02009-07-02 19:29:09 +080072 public HeaderSet connect(final HeaderSet header) throws IOException {
Nick Pelly9439a7f2009-06-30 12:04:36 -070073 ensureOpen();
Nick Pelly41557e12009-06-30 19:38:30 -070074 if (mObexConnected) {
Nick Pelly9439a7f2009-06-30 12:04:36 -070075 throw new IOException("Already connected to server");
76 }
Nick Pelly41557e12009-06-30 19:38:30 -070077 setRequestActive();
78
Nick Pelly9439a7f2009-06-30 12:04:36 -070079 int totalLength = 4;
80 byte[] head = null;
81
82 // Determine the header byte array
83 if (header != null) {
Nick Pelly41557e12009-06-30 19:38:30 -070084 if (header.nonce != null) {
85 mChallengeDigest = new byte[16];
86 System.arraycopy(header.nonce, 0, mChallengeDigest, 0, 16);
Nick Pelly9439a7f2009-06-30 12:04:36 -070087 }
Nick Pelly2e0da962009-06-30 16:28:54 -070088 head = ObexHelper.createHeader(header, false);
Nick Pelly9439a7f2009-06-30 12:04:36 -070089 totalLength += head.length;
90 }
91 /*
92 * Write the OBEX CONNECT packet to the server.
93 * Byte 0: 0x80
94 * Byte 1&2: Connect Packet Length
95 * Byte 3: OBEX Version Number (Presently, 0x10)
96 * Byte 4: Flags (For TCP 0x00)
97 * Byte 5&6: Max OBEX Packet Length (Defined in MAX_PACKET_SIZE)
98 * Byte 7 to n: headers
99 */
100 byte[] requestPacket = new byte[totalLength];
101 // We just need to start at byte 3 since the sendRequest() method will
102 // handle the length and 0x80.
103 requestPacket[0] = (byte)0x10;
104 requestPacket[1] = (byte)0x00;
Nick Pelly2e0da962009-06-30 16:28:54 -0700105 requestPacket[2] = (byte)(ObexHelper.MAX_PACKET_SIZE_INT >> 8);
106 requestPacket[3] = (byte)(ObexHelper.MAX_PACKET_SIZE_INT & 0xFF);
Nick Pelly9439a7f2009-06-30 12:04:36 -0700107 if (head != null) {
108 System.arraycopy(head, 0, requestPacket, 4, head.length);
109 }
110
111 // check with local max packet size
Nick Pelly2e0da962009-06-30 16:28:54 -0700112 if ((requestPacket.length + 3) > ObexHelper.MAX_PACKET_SIZE_INT) {
Nick Pelly9439a7f2009-06-30 12:04:36 -0700113 throw new IOException("Packet size exceeds max packet size");
114 }
115
116 HeaderSet returnHeaderSet = new HeaderSet();
Tao Liejun3998bf02009-07-02 19:29:09 +0800117 sendRequest(ObexHelper.OBEX_OPCODE_CONNECT, requestPacket, returnHeaderSet, null);
Nick Pelly9439a7f2009-06-30 12:04:36 -0700118
119 /*
120 * Read the response from the OBEX server.
121 * Byte 0: Response Code (If successful then OBEX_HTTP_OK)
122 * Byte 1&2: Packet Length
123 * Byte 3: OBEX Version Number
124 * Byte 4: Flags3
125 * Byte 5&6: Max OBEX packet Length
126 * Byte 7 to n: Optional HeaderSet
127 */
128 if (returnHeaderSet.responseCode == ResponseCodes.OBEX_HTTP_OK) {
Nick Pelly41557e12009-06-30 19:38:30 -0700129 mObexConnected = true;
Nick Pelly9439a7f2009-06-30 12:04:36 -0700130 }
Nick Pelly41557e12009-06-30 19:38:30 -0700131 setRequestInactive();
Nick Pelly9439a7f2009-06-30 12:04:36 -0700132
133 return returnHeaderSet;
134 }
135
Nick Pelly41557e12009-06-30 19:38:30 -0700136 public Operation get(HeaderSet header) throws IOException {
Nick Pelly9439a7f2009-06-30 12:04:36 -0700137
Nick Pelly41557e12009-06-30 19:38:30 -0700138 if (!mObexConnected) {
Nick Pelly9439a7f2009-06-30 12:04:36 -0700139 throw new IOException("Not connected to the server");
140 }
Nick Pelly41557e12009-06-30 19:38:30 -0700141 setRequestActive();
142
Nick Pelly9439a7f2009-06-30 12:04:36 -0700143 ensureOpen();
144
Tao Liejun3998bf02009-07-02 19:29:09 +0800145 HeaderSet head;
Nick Pelly9439a7f2009-06-30 12:04:36 -0700146 if (header == null) {
Tao Liejun3998bf02009-07-02 19:29:09 +0800147 head = new HeaderSet();
Nick Pelly9439a7f2009-06-30 12:04:36 -0700148 } else {
Tao Liejun3998bf02009-07-02 19:29:09 +0800149 head = header;
150 if (head.nonce != null) {
Nick Pelly41557e12009-06-30 19:38:30 -0700151 mChallengeDigest = new byte[16];
Tao Liejun3998bf02009-07-02 19:29:09 +0800152 System.arraycopy(head.nonce, 0, mChallengeDigest, 0, 16);
Nick Pelly9439a7f2009-06-30 12:04:36 -0700153 }
154 }
155 // Add the connection ID if one exists
Nick Pelly41557e12009-06-30 19:38:30 -0700156 if (mConnectionId != null) {
Tao Liejun3998bf02009-07-02 19:29:09 +0800157 head.mConnectionID = new byte[4];
158 System.arraycopy(mConnectionId, 0, head.mConnectionID, 0, 4);
Nick Pelly9439a7f2009-06-30 12:04:36 -0700159 }
160
Tao Liejun3998bf02009-07-02 19:29:09 +0800161 return new ClientOperation(maxPacketSize, this, head, true);
Nick Pelly9439a7f2009-06-30 12:04:36 -0700162 }
163
164 /**
Tao Liejun05ff98bb2009-07-13 15:57:11 -0700165 * 0xCB Connection Id an identifier used for OBEX connection multiplexing
Nick Pelly41557e12009-06-30 19:38:30 -0700166 */
Nick Pelly9439a7f2009-06-30 12:04:36 -0700167 public void setConnectionID(long id) {
168 if ((id < 0) || (id > 0xFFFFFFFFL)) {
169 throw new IllegalArgumentException("Connection ID is not in a valid range");
170 }
Nick Pelly41557e12009-06-30 19:38:30 -0700171 mConnectionId = ObexHelper.convertToByteArray(id);
Nick Pelly9439a7f2009-06-30 12:04:36 -0700172 }
173
Nick Pelly41557e12009-06-30 19:38:30 -0700174 public HeaderSet delete(HeaderSet header) throws IOException {
Nick Pelly9439a7f2009-06-30 12:04:36 -0700175
Nick Pelly41557e12009-06-30 19:38:30 -0700176 Operation op = put(header);
Nick Pelly9439a7f2009-06-30 12:04:36 -0700177 op.getResponseCode();
Tao Liejun3998bf02009-07-02 19:29:09 +0800178 HeaderSet returnValue = op.getReceivedHeader();
Nick Pelly9439a7f2009-06-30 12:04:36 -0700179 op.close();
180
181 return returnValue;
182 }
183
Nick Pelly41557e12009-06-30 19:38:30 -0700184 public HeaderSet disconnect(HeaderSet header) throws IOException {
185 if (!mObexConnected) {
Nick Pelly9439a7f2009-06-30 12:04:36 -0700186 throw new IOException("Not connected to the server");
187 }
Nick Pelly41557e12009-06-30 19:38:30 -0700188 setRequestActive();
189
Nick Pelly9439a7f2009-06-30 12:04:36 -0700190 ensureOpen();
191 // Determine the header byte array
192 byte[] head = null;
193 if (header != null) {
Nick Pelly41557e12009-06-30 19:38:30 -0700194 if (header.nonce != null) {
195 mChallengeDigest = new byte[16];
196 System.arraycopy(header.nonce, 0, mChallengeDigest, 0, 16);
Nick Pelly9439a7f2009-06-30 12:04:36 -0700197 }
198 // Add the connection ID if one exists
Nick Pelly41557e12009-06-30 19:38:30 -0700199 if (mConnectionId != null) {
Tao Liejun3998bf02009-07-02 19:29:09 +0800200 header.mConnectionID = new byte[4];
201 System.arraycopy(mConnectionId, 0, header.mConnectionID, 0, 4);
Nick Pelly9439a7f2009-06-30 12:04:36 -0700202 }
Nick Pelly2e0da962009-06-30 16:28:54 -0700203 head = ObexHelper.createHeader(header, false);
Nick Pelly9439a7f2009-06-30 12:04:36 -0700204
205 if ((head.length + 3) > maxPacketSize) {
206 throw new IOException("Packet size exceeds max packet size");
207 }
208 } else {
209 // Add the connection ID if one exists
Nick Pelly41557e12009-06-30 19:38:30 -0700210 if (mConnectionId != null) {
Nick Pelly9439a7f2009-06-30 12:04:36 -0700211 head = new byte[5];
Tao Liejun3998bf02009-07-02 19:29:09 +0800212 head[0] = (byte)HeaderSet.CONNECTION_ID;
Nick Pelly41557e12009-06-30 19:38:30 -0700213 System.arraycopy(mConnectionId, 0, head, 1, 4);
Nick Pelly9439a7f2009-06-30 12:04:36 -0700214 }
215 }
216
217 HeaderSet returnHeaderSet = new HeaderSet();
Tao Liejun3998bf02009-07-02 19:29:09 +0800218 sendRequest(ObexHelper.OBEX_OPCODE_DISCONNECT, head, returnHeaderSet, null);
Nick Pelly9439a7f2009-06-30 12:04:36 -0700219
220 /*
Nick Pelly41557e12009-06-30 19:38:30 -0700221 * An OBEX DISCONNECT reply from the server:
222 * Byte 1: Response code
223 * Bytes 2 & 3: packet size
224 * Bytes 4 & up: headers
225 */
Nick Pelly9439a7f2009-06-30 12:04:36 -0700226
227 /* response code , and header are ignored
228 * */
229
230 synchronized (this) {
Nick Pelly41557e12009-06-30 19:38:30 -0700231 mObexConnected = false;
232 setRequestInactive();
Nick Pelly9439a7f2009-06-30 12:04:36 -0700233 }
234
235 return returnHeaderSet;
236 }
237
238 public long getConnectionID() {
239
Nick Pelly41557e12009-06-30 19:38:30 -0700240 if (mConnectionId == null) {
Nick Pelly9439a7f2009-06-30 12:04:36 -0700241 return -1;
242 }
Nick Pelly41557e12009-06-30 19:38:30 -0700243 return ObexHelper.convertToLong(mConnectionId);
Nick Pelly9439a7f2009-06-30 12:04:36 -0700244 }
245
Nick Pelly41557e12009-06-30 19:38:30 -0700246 public Operation put(HeaderSet header) throws IOException {
247 if (!mObexConnected) {
Nick Pelly9439a7f2009-06-30 12:04:36 -0700248 throw new IOException("Not connected to the server");
249 }
Nick Pelly41557e12009-06-30 19:38:30 -0700250 setRequestActive();
Nick Pelly9439a7f2009-06-30 12:04:36 -0700251
252 ensureOpen();
Tao Liejun3998bf02009-07-02 19:29:09 +0800253 HeaderSet head;
Nick Pelly9439a7f2009-06-30 12:04:36 -0700254 if (header == null) {
Tao Liejun3998bf02009-07-02 19:29:09 +0800255 head = new HeaderSet();
Nick Pelly9439a7f2009-06-30 12:04:36 -0700256 } else {
Tao Liejun3998bf02009-07-02 19:29:09 +0800257 head = header;
258 // when auth is initiated by client ,save the digest
259 if (head.nonce != null) {
Nick Pelly41557e12009-06-30 19:38:30 -0700260 mChallengeDigest = new byte[16];
Tao Liejun3998bf02009-07-02 19:29:09 +0800261 System.arraycopy(head.nonce, 0, mChallengeDigest, 0, 16);
Nick Pelly9439a7f2009-06-30 12:04:36 -0700262 }
263 }
264
265 // Add the connection ID if one exists
Nick Pelly41557e12009-06-30 19:38:30 -0700266 if (mConnectionId != null) {
Nick Pelly9439a7f2009-06-30 12:04:36 -0700267
Tao Liejun3998bf02009-07-02 19:29:09 +0800268 head.mConnectionID = new byte[4];
269 System.arraycopy(mConnectionId, 0, head.mConnectionID, 0, 4);
Nick Pelly9439a7f2009-06-30 12:04:36 -0700270 }
271
Tao Liejun3998bf02009-07-02 19:29:09 +0800272 return new ClientOperation(maxPacketSize, this, head, false);
Nick Pelly9439a7f2009-06-30 12:04:36 -0700273 }
274
Tao Liejun3998bf02009-07-02 19:29:09 +0800275 public void setAuthenticator(Authenticator auth) throws IOException {
Nick Pelly9439a7f2009-06-30 12:04:36 -0700276 if (auth == null) {
Tao Liejun3998bf02009-07-02 19:29:09 +0800277 throw new IOException("Authenticator may not be null");
Nick Pelly9439a7f2009-06-30 12:04:36 -0700278 }
Nick Pelly41557e12009-06-30 19:38:30 -0700279 mAuthenticator = auth;
Nick Pelly9439a7f2009-06-30 12:04:36 -0700280 }
281
Tao Liejun3998bf02009-07-02 19:29:09 +0800282 public HeaderSet setPath(HeaderSet header, boolean backup, boolean create) throws IOException {
Nick Pelly41557e12009-06-30 19:38:30 -0700283 if (!mObexConnected) {
Nick Pelly9439a7f2009-06-30 12:04:36 -0700284 throw new IOException("Not connected to the server");
285 }
Nick Pelly41557e12009-06-30 19:38:30 -0700286 setRequestActive();
Nick Pelly9439a7f2009-06-30 12:04:36 -0700287 ensureOpen();
288
289 int totalLength = 2;
290 byte[] head = null;
Tao Liejun3998bf02009-07-02 19:29:09 +0800291 HeaderSet headset;
Nick Pelly9439a7f2009-06-30 12:04:36 -0700292 if (header == null) {
Tao Liejun3998bf02009-07-02 19:29:09 +0800293 headset = new HeaderSet();
Nick Pelly9439a7f2009-06-30 12:04:36 -0700294 } else {
Tao Liejun3998bf02009-07-02 19:29:09 +0800295 headset = header;
296 if (headset.nonce != null) {
Nick Pelly41557e12009-06-30 19:38:30 -0700297 mChallengeDigest = new byte[16];
Tao Liejun3998bf02009-07-02 19:29:09 +0800298 System.arraycopy(headset.nonce, 0, mChallengeDigest, 0, 16);
Nick Pelly9439a7f2009-06-30 12:04:36 -0700299 }
300 }
301
302 // when auth is initiated by client ,save the digest
Tao Liejun3998bf02009-07-02 19:29:09 +0800303 if (headset.nonce != null) {
Nick Pelly41557e12009-06-30 19:38:30 -0700304 mChallengeDigest = new byte[16];
Tao Liejun3998bf02009-07-02 19:29:09 +0800305 System.arraycopy(headset.nonce, 0, mChallengeDigest, 0, 16);
Nick Pelly9439a7f2009-06-30 12:04:36 -0700306 }
307
308 // Add the connection ID if one exists
Nick Pelly41557e12009-06-30 19:38:30 -0700309 if (mConnectionId != null) {
Tao Liejun3998bf02009-07-02 19:29:09 +0800310 headset.mConnectionID = new byte[4];
311 System.arraycopy(mConnectionId, 0, headset.mConnectionID, 0, 4);
Nick Pelly9439a7f2009-06-30 12:04:36 -0700312 }
313
Tao Liejun3998bf02009-07-02 19:29:09 +0800314 head = ObexHelper.createHeader(headset, false);
Nick Pelly9439a7f2009-06-30 12:04:36 -0700315 totalLength += head.length;
316
317 if (totalLength > maxPacketSize) {
318 throw new IOException("Packet size exceeds max packet size");
319 }
320
321 int flags = 0;
322 /*
323 * The backup flag bit is bit 0 so if we add 1, this will set that bit
324 */
325 if (backup) {
326 flags++;
327 }
328 /*
329 * The create bit is bit 1 so if we or with 2 the bit will be set.
330 */
331 if (!create) {
332 flags |= 2;
333 }
334
335 /*
336 * An OBEX SETPATH packet to the server:
337 * Byte 1: 0x85
338 * Byte 2 & 3: packet size
339 * Byte 4: flags
340 * Byte 5: constants
341 * Byte 6 & up: headers
342 */
343 byte[] packet = new byte[totalLength];
344 packet[0] = (byte)flags;
345 packet[1] = (byte)0x00;
Tao Liejun3998bf02009-07-02 19:29:09 +0800346 if (headset != null) {
Nick Pelly9439a7f2009-06-30 12:04:36 -0700347 System.arraycopy(head, 0, packet, 2, head.length);
348 }
349
350 HeaderSet returnHeaderSet = new HeaderSet();
Tao Liejun3998bf02009-07-02 19:29:09 +0800351 sendRequest(ObexHelper.OBEX_OPCODE_SETPATH, packet, returnHeaderSet, null);
Nick Pelly9439a7f2009-06-30 12:04:36 -0700352
353 /*
354 * An OBEX SETPATH reply from the server:
355 * Byte 1: Response code
356 * Bytes 2 & 3: packet size
357 * Bytes 4 & up: headers
358 */
359
Nick Pelly41557e12009-06-30 19:38:30 -0700360 setRequestInactive();
Nick Pelly9439a7f2009-06-30 12:04:36 -0700361
362 return returnHeaderSet;
363 }
364
365 /**
366 * Verifies that the connection is open.
Nick Pelly2e0da962009-06-30 16:28:54 -0700367 * @throws IOException if the connection is closed
Nick Pelly9439a7f2009-06-30 12:04:36 -0700368 */
369 public synchronized void ensureOpen() throws IOException {
Nick Pelly41557e12009-06-30 19:38:30 -0700370 if (!mOpen) {
Nick Pelly9439a7f2009-06-30 12:04:36 -0700371 throw new IOException("Connection closed");
372 }
373 }
374
375 /**
Tao Liejun05ff98bb2009-07-13 15:57:11 -0700376 * Set request inactive. Allows Put and get operation objects to tell this
377 * object when they are done.
Nick Pelly9439a7f2009-06-30 12:04:36 -0700378 */
Tao Liejun3998bf02009-07-02 19:29:09 +0800379 /*package*/synchronized void setRequestInactive() {
Nick Pelly41557e12009-06-30 19:38:30 -0700380 mRequestActive = false;
381 }
382
383 /**
384 * Set request to active.
385 * @throws IOException if already active
386 */
387 private synchronized void setRequestActive() throws IOException {
388 if (mRequestActive) {
389 throw new IOException("OBEX request is already being performed");
Nick Pelly9439a7f2009-06-30 12:04:36 -0700390 }
Nick Pelly41557e12009-06-30 19:38:30 -0700391 mRequestActive = true;
Nick Pelly9439a7f2009-06-30 12:04:36 -0700392 }
393
394 /**
Tao Liejun05ff98bb2009-07-13 15:57:11 -0700395 * Sends a standard request to the client. It will then wait for the reply
396 * and update the header set object provided. If any authentication headers
397 * (i.e. authentication challenge or authentication response) are received,
398 * they will be processed.
Tao Liejun3998bf02009-07-02 19:29:09 +0800399 * @param opCode the type of request to send to the client
Tao Liejun05ff98bb2009-07-13 15:57:11 -0700400 * @param head the headers to send to the client
Nick Pelly41557e12009-06-30 19:38:30 -0700401 * @param header the header object to update with the response
Tao Liejun05ff98bb2009-07-13 15:57:11 -0700402 * @param privateInput the input stream used by the Operation object; null
403 * if this is called on a CONNECT, SETPATH or DISCONNECT return
404 * <code>true</code> if the operation completed successfully;
405 * <code>false</code> if an authentication response failed to pass
Nick Pelly2e0da962009-06-30 16:28:54 -0700406 * @throws IOException if an IO error occurs
Nick Pelly9439a7f2009-06-30 12:04:36 -0700407 */
Tao Liejun3998bf02009-07-02 19:29:09 +0800408 public boolean sendRequest(int opCode, byte[] head, HeaderSet header,
Nick Pelly9439a7f2009-06-30 12:04:36 -0700409 PrivateInputStream privateInput) throws IOException {
410 //check header length with local max size
411 if (head != null) {
Nick Pelly2e0da962009-06-30 16:28:54 -0700412 if ((head.length + 3) > ObexHelper.MAX_PACKET_SIZE_INT) {
Nick Pelly9439a7f2009-06-30 12:04:36 -0700413 throw new IOException("header too large ");
414 }
415 }
Tao Liejun3998bf02009-07-02 19:29:09 +0800416
Nick Pelly9439a7f2009-06-30 12:04:36 -0700417 int bytesReceived;
418 ByteArrayOutputStream out = new ByteArrayOutputStream();
Tao Liejun3998bf02009-07-02 19:29:09 +0800419 out.write((byte)opCode);
Nick Pelly9439a7f2009-06-30 12:04:36 -0700420
421 // Determine if there are any headers to send
422 if (head == null) {
423 out.write(0x00);
424 out.write(0x03);
425 } else {
426 out.write((byte)((head.length + 3) >> 8));
427 out.write((byte)(head.length + 3));
428 out.write(head);
429 }
430
431 // Write the request to the output stream and flush the stream
Nick Pelly41557e12009-06-30 19:38:30 -0700432 mOutput.write(out.toByteArray());
433 mOutput.flush();
Nick Pelly9439a7f2009-06-30 12:04:36 -0700434
Nick Pelly41557e12009-06-30 19:38:30 -0700435 header.responseCode = mInput.read();
Nick Pelly9439a7f2009-06-30 12:04:36 -0700436
Nick Pelly41557e12009-06-30 19:38:30 -0700437 int length = ((mInput.read() << 8) | (mInput.read()));
Nick Pelly9439a7f2009-06-30 12:04:36 -0700438
Nick Pelly2e0da962009-06-30 16:28:54 -0700439 if (length > ObexHelper.MAX_PACKET_SIZE_INT) {
Nick Pelly9439a7f2009-06-30 12:04:36 -0700440 throw new IOException("Packet received exceeds packet size limit");
441 }
Tao Liejun3998bf02009-07-02 19:29:09 +0800442 if (length > ObexHelper.BASE_PACKET_LENGTH) {
Nick Pelly9439a7f2009-06-30 12:04:36 -0700443 byte[] data = null;
Tao Liejun3998bf02009-07-02 19:29:09 +0800444 if (opCode == ObexHelper.OBEX_OPCODE_CONNECT) {
445 @SuppressWarnings("unused")
Nick Pelly41557e12009-06-30 19:38:30 -0700446 int version = mInput.read();
Tao Liejun3998bf02009-07-02 19:29:09 +0800447 @SuppressWarnings("unused")
Nick Pelly41557e12009-06-30 19:38:30 -0700448 int flags = mInput.read();
449 maxPacketSize = (mInput.read() << 8) + mInput.read();
Nick Pelly9439a7f2009-06-30 12:04:36 -0700450
451 //check with local max size
Erik Ljungberge83b7442011-03-22 07:58:43 +0100452 if (maxPacketSize > ObexHelper.MAX_CLIENT_PACKET_SIZE) {
453 maxPacketSize = ObexHelper.MAX_CLIENT_PACKET_SIZE;
Nick Pelly9439a7f2009-06-30 12:04:36 -0700454 }
455
456 if (length > 7) {
457 data = new byte[length - 7];
458
Nick Pelly41557e12009-06-30 19:38:30 -0700459 bytesReceived = mInput.read(data);
Nick Pelly9439a7f2009-06-30 12:04:36 -0700460 while (bytesReceived != (length - 7)) {
Nick Pelly41557e12009-06-30 19:38:30 -0700461 bytesReceived += mInput.read(data, bytesReceived, data.length
Nick Pelly9439a7f2009-06-30 12:04:36 -0700462 - bytesReceived);
463 }
464 } else {
465 return true;
466 }
467 } else {
468 data = new byte[length - 3];
Nick Pelly41557e12009-06-30 19:38:30 -0700469 bytesReceived = mInput.read(data);
Nick Pelly9439a7f2009-06-30 12:04:36 -0700470
471 while (bytesReceived != (length - 3)) {
Nick Pelly41557e12009-06-30 19:38:30 -0700472 bytesReceived += mInput.read(data, bytesReceived, data.length - bytesReceived);
Nick Pelly9439a7f2009-06-30 12:04:36 -0700473 }
Tao Liejun3998bf02009-07-02 19:29:09 +0800474 if (opCode == ObexHelper.OBEX_OPCODE_ABORT) {
Nick Pelly9439a7f2009-06-30 12:04:36 -0700475 return true;
476 }
477 }
478
Nick Pelly41557e12009-06-30 19:38:30 -0700479 byte[] body = ObexHelper.updateHeaderSet(header, data);
Nick Pelly9439a7f2009-06-30 12:04:36 -0700480 if ((privateInput != null) && (body != null)) {
481 privateInput.writeBytes(body, 1);
482 }
483
Tao Liejun3998bf02009-07-02 19:29:09 +0800484 if (header.mConnectionID != null) {
Nick Pelly41557e12009-06-30 19:38:30 -0700485 mConnectionId = new byte[4];
Tao Liejun3998bf02009-07-02 19:29:09 +0800486 System.arraycopy(header.mConnectionID, 0, mConnectionId, 0, 4);
Nick Pelly9439a7f2009-06-30 12:04:36 -0700487 }
488
Tao Liejun3998bf02009-07-02 19:29:09 +0800489 if (header.mAuthResp != null) {
490 if (!handleAuthResp(header.mAuthResp)) {
Nick Pelly41557e12009-06-30 19:38:30 -0700491 setRequestInactive();
Nick Pelly9439a7f2009-06-30 12:04:36 -0700492 throw new IOException("Authentication Failed");
493 }
494 }
495
Nick Pelly41557e12009-06-30 19:38:30 -0700496 if ((header.responseCode == ResponseCodes.OBEX_HTTP_UNAUTHORIZED)
Tao Liejun3998bf02009-07-02 19:29:09 +0800497 && (header.mAuthChall != null)) {
Nick Pelly9439a7f2009-06-30 12:04:36 -0700498
Nick Pelly41557e12009-06-30 19:38:30 -0700499 if (handleAuthChall(header)) {
Tao Liejun3998bf02009-07-02 19:29:09 +0800500 out.write((byte)HeaderSet.AUTH_RESPONSE);
501 out.write((byte)((header.mAuthResp.length + 3) >> 8));
502 out.write((byte)(header.mAuthResp.length + 3));
503 out.write(header.mAuthResp);
504 header.mAuthChall = null;
505 header.mAuthResp = null;
Nick Pelly9439a7f2009-06-30 12:04:36 -0700506
507 byte[] sendHeaders = new byte[out.size() - 3];
508 System.arraycopy(out.toByteArray(), 3, sendHeaders, 0, sendHeaders.length);
509
Tao Liejun3998bf02009-07-02 19:29:09 +0800510 return sendRequest(opCode, sendHeaders, header, privateInput);
Nick Pelly9439a7f2009-06-30 12:04:36 -0700511 }
512 }
513 }
514
515 return true;
516 }
517
Nick Pelly9439a7f2009-06-30 12:04:36 -0700518 public void close() throws IOException {
Nick Pelly41557e12009-06-30 19:38:30 -0700519 mOpen = false;
520 mInput.close();
521 mOutput.close();
Nick Pelly9439a7f2009-06-30 12:04:36 -0700522 }
523}