1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * Copyright (c) 2015 Samsung LSI 4 * Copyright (c) 2008-2009, Motorola, Inc. 5 * 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions are met: 10 * 11 * - Redistributions of source code must retain the above copyright notice, 12 * this list of conditions and the following disclaimer. 13 * 14 * - Redistributions in binary form must reproduce the above copyright notice, 15 * this list of conditions and the following disclaimer in the documentation 16 * and/or other materials provided with the distribution. 17 * 18 * - Neither the name of the Motorola, Inc. nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 26 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 * POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35 package javax.obex; 36 37 import android.util.Log; 38 39 import java.io.InputStream; 40 import java.io.IOException; 41 import java.io.OutputStream; 42 43 /** 44 * This class in an implementation of the OBEX ServerSession. 45 * @hide 46 */ 47 public final class ServerSession extends ObexSession implements Runnable { 48 49 private static final String TAG = "Obex ServerSession"; 50 private static final boolean V = ObexHelper.VDBG; 51 52 private ObexTransport mTransport; 53 54 private InputStream mInput; 55 56 private OutputStream mOutput; 57 58 private ServerRequestHandler mListener; 59 60 private Thread mProcessThread; 61 62 private int mMaxPacketLength; 63 64 private boolean mClosed; 65 66 /** 67 * Creates new ServerSession. 68 * @param trans the connection to the client 69 * @param handler the event listener that will process requests 70 * @param auth the authenticator to use with this connection 71 * @throws IOException if an error occurred while opening the input and 72 * output streams 73 */ 74 public ServerSession(ObexTransport trans, ServerRequestHandler handler, Authenticator auth) 75 throws IOException { 76 mAuthenticator = auth; 77 mTransport = trans; 78 mInput = mTransport.openInputStream(); 79 mOutput = mTransport.openOutputStream(); 80 mListener = handler; 81 mMaxPacketLength = 256; 82 83 mClosed = false; 84 mProcessThread = new Thread(this); 85 mProcessThread.start(); 86 } 87 88 /** 89 * Processes requests made to the server and forwards them to the 90 * appropriate event listener. 91 */ 92 public void run() { 93 try { 94 95 boolean done = false; 96 while (!done && !mClosed) { 97 if(V) Log.v(TAG, "Waiting for incoming request..."); 98 int requestType = mInput.read(); 99 if(V) Log.v(TAG, "Read request: " + requestType); 100 switch (requestType) { 101 case ObexHelper.OBEX_OPCODE_CONNECT: 102 handleConnectRequest(); 103 break; 104 105 case ObexHelper.OBEX_OPCODE_DISCONNECT: 106 handleDisconnectRequest(); 107 break; 108 109 case ObexHelper.OBEX_OPCODE_GET: 110 case ObexHelper.OBEX_OPCODE_GET_FINAL: 111 handleGetRequest(requestType); 112 break; 113 114 case ObexHelper.OBEX_OPCODE_PUT: 115 case ObexHelper.OBEX_OPCODE_PUT_FINAL: 116 handlePutRequest(requestType); 117 break; 118 119 case ObexHelper.OBEX_OPCODE_SETPATH: 120 handleSetPathRequest(); 121 break; 122 case ObexHelper.OBEX_OPCODE_ABORT: 123 handleAbortRequest(); 124 break; 125 126 case -1: 127 done = true; 128 break; 129 130 default: 131 132 /* 133 * Received a request type that is not recognized so I am 134 * just going to read the packet and send a not implemented 135 * to the client 136 */ 137 int length = mInput.read(); 138 length = (length << 8) + mInput.read(); 139 for (int i = 3; i < length; i++) { 140 mInput.read(); 141 } 142 sendResponse(ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED, null); 143 } 144 } 145 146 } catch (NullPointerException e) { 147 Log.d(TAG, "Exception occured - ignoring", e); 148 } catch (Exception e) { 149 Log.d(TAG, "Exception occured - ignoring", e); 150 } 151 close(); 152 } 153 154 /** 155 * Handles a ABORT request from a client. This method will read the rest of 156 * the request from the client. Assuming the request is valid, it will 157 * create a <code>HeaderSet</code> object to pass to the 158 * <code>ServerRequestHandler</code> object. After the handler processes the 159 * request, this method will create a reply message to send to the server. 160 * 161 * @throws IOException if an error occurred at the transport layer 162 */ 163 private void handleAbortRequest() throws IOException { 164 int code = ResponseCodes.OBEX_HTTP_OK; 165 HeaderSet request = new HeaderSet(); 166 HeaderSet reply = new HeaderSet(); 167 168 int length = mInput.read(); 169 length = (length << 8) + mInput.read(); 170 if (length > ObexHelper.getMaxRxPacketSize(mTransport)) { 171 code = ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE; 172 } else { 173 for (int i = 3; i < length; i++) { 174 mInput.read(); 175 } 176 code = mListener.onAbort(request, reply); 177 Log.v(TAG, "onAbort request handler return value- " + code); 178 code = validateResponseCode(code); 179 } 180 sendResponse(code, null); 181 } 182 183 /** 184 * Handles a PUT request from a client. This method will provide a 185 * <code>ServerOperation</code> object to the request handler. The 186 * <code>ServerOperation</code> object will handle the rest of the request. 187 * It will also send replies and receive requests until the final reply 188 * should be sent. When the final reply should be sent, this method will get 189 * the response code to use and send the reply. The 190 * <code>ServerOperation</code> object will always reply with a 191 * OBEX_HTTP_CONTINUE reply. It will only reply if further information is 192 * needed. 193 * @param type the type of request received; either 0x02 or 0x82 194 * @throws IOException if an error occurred at the transport layer 195 */ 196 private void handlePutRequest(int type) throws IOException { 197 ServerOperation op = new ServerOperation(this, mInput, type, mMaxPacketLength, mListener); 198 try { 199 int response = -1; 200 201 if ((op.finalBitSet) && !op.isValidBody()) { 202 response = validateResponseCode(mListener 203 .onDelete(op.requestHeader, op.replyHeader)); 204 } else { 205 response = validateResponseCode(mListener.onPut(op)); 206 } 207 if (response != ResponseCodes.OBEX_HTTP_OK && !op.isAborted) { 208 op.sendReply(response); 209 } else if (!op.isAborted) { 210 // wait for the final bit 211 while (!op.finalBitSet) { 212 op.sendReply(ResponseCodes.OBEX_HTTP_CONTINUE); 213 } 214 op.sendReply(response); 215 } 216 } catch (Exception e) { 217 /*To fix bugs in aborted cases, 218 *(client abort file transfer prior to the last packet which has the end of body header, 219 *internal error should not be sent because server has already replied with 220 *OK response in "sendReply") 221 */ 222 if(V) Log.d(TAG,"Exception occured - sending OBEX_HTTP_INTERNAL_ERROR reply",e); 223 if (!op.isAborted) { 224 sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null); 225 } 226 } 227 } 228 229 /** 230 * Handles a GET request from a client. This method will provide a 231 * <code>ServerOperation</code> object to the request handler. The 232 * <code>ServerOperation</code> object will handle the rest of the request. 233 * It will also send replies and receive requests until the final reply 234 * should be sent. When the final reply should be sent, this method will get 235 * the response code to use and send the reply. The 236 * <code>ServerOperation</code> object will always reply with a 237 * OBEX_HTTP_CONTINUE reply. It will only reply if further information is 238 * needed. 239 * @param type the type of request received; either 0x03 or 0x83 240 * @throws IOException if an error occurred at the transport layer 241 */ 242 private void handleGetRequest(int type) throws IOException { 243 ServerOperation op = new ServerOperation(this, mInput, type, mMaxPacketLength, mListener); 244 try { 245 int response = validateResponseCode(mListener.onGet(op)); 246 247 if (!op.isAborted) { 248 op.sendReply(response); 249 } 250 } catch (Exception e) { 251 if(V) Log.d(TAG,"Exception occured - sending OBEX_HTTP_INTERNAL_ERROR reply",e); 252 sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null); 253 } 254 } 255 256 /** 257 * Send standard response. 258 * @param code the response code to send 259 * @param header the headers to include in the response 260 * @throws IOException if an IO error occurs 261 */ 262 public void sendResponse(int code, byte[] header) throws IOException { 263 int totalLength = 3; 264 byte[] data = null; 265 OutputStream op = mOutput; 266 if (op == null) { 267 return; 268 } 269 270 if (header != null) { 271 totalLength += header.length; 272 data = new byte[totalLength]; 273 data[0] = (byte)code; 274 data[1] = (byte)(totalLength >> 8); 275 data[2] = (byte)totalLength; 276 System.arraycopy(header, 0, data, 3, header.length); 277 } else { 278 data = new byte[totalLength]; 279 data[0] = (byte)code; 280 data[1] = (byte)0x00; 281 data[2] = (byte)totalLength; 282 } 283 op.write(data); 284 op.flush(); // TODO: Do we need to flush? 285 } 286 287 /** 288 * Handles a SETPATH request from a client. This method will read the rest 289 * of the request from the client. Assuming the request is valid, it will 290 * create a <code>HeaderSet</code> object to pass to the 291 * <code>ServerRequestHandler</code> object. After the handler processes the 292 * request, this method will create a reply message to send to the server 293 * with the response code provided. 294 * @throws IOException if an error occurred at the transport layer 295 */ 296 private void handleSetPathRequest() throws IOException { 297 int length; 298 int flags; 299 @SuppressWarnings("unused") 300 int constants; 301 int totalLength = 3; 302 byte[] head = null; 303 int code = -1; 304 int bytesReceived; 305 HeaderSet request = new HeaderSet(); 306 HeaderSet reply = new HeaderSet(); 307 308 length = mInput.read(); 309 length = (length << 8) + mInput.read(); 310 flags = mInput.read(); 311 constants = mInput.read(); 312 313 if (length > ObexHelper.getMaxRxPacketSize(mTransport)) { 314 code = ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE; 315 totalLength = 3; 316 } else { 317 if (length > 5) { 318 byte[] headers = new byte[length - 5]; 319 bytesReceived = mInput.read(headers); 320 321 while (bytesReceived != headers.length) { 322 bytesReceived += mInput.read(headers, bytesReceived, headers.length 323 - bytesReceived); 324 } 325 326 ObexHelper.updateHeaderSet(request, headers); 327 328 if (mListener.getConnectionId() != -1 && request.mConnectionID != null) { 329 mListener.setConnectionId(ObexHelper.convertToLong(request.mConnectionID)); 330 } else { 331 mListener.setConnectionId(1); 332 } 333 // the Auth chan is initiated by the server, client sent back the authResp . 334 if (request.mAuthResp != null) { 335 if (!handleAuthResp(request.mAuthResp)) { 336 code = ResponseCodes.OBEX_HTTP_UNAUTHORIZED; 337 mListener.onAuthenticationFailure(ObexHelper.getTagValue((byte)0x01, 338 request.mAuthResp)); 339 } 340 request.mAuthResp = null; 341 } 342 } 343 344 if (code != ResponseCodes.OBEX_HTTP_UNAUTHORIZED) { 345 // the Auth challenge is initiated by the client 346 // the server will send back the authResp to the client 347 if (request.mAuthChall != null) { 348 handleAuthChall(request); 349 reply.mAuthResp = new byte[request.mAuthResp.length]; 350 System.arraycopy(request.mAuthResp, 0, reply.mAuthResp, 0, 351 reply.mAuthResp.length); 352 request.mAuthChall = null; 353 request.mAuthResp = null; 354 } 355 boolean backup = false; 356 boolean create = true; 357 if (!((flags & 1) == 0)) { 358 backup = true; 359 } 360 if (!((flags & 2) == 0)) { 361 create = false; 362 } 363 364 try { 365 code = mListener.onSetPath(request, reply, backup, create); 366 } catch (Exception e) { 367 if(V) Log.d(TAG,"Exception occured - sending OBEX_HTTP_INTERNAL_ERROR reply",e); 368 sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null); 369 return; 370 } 371 372 code = validateResponseCode(code); 373 374 if (reply.nonce != null) { 375 mChallengeDigest = new byte[16]; 376 System.arraycopy(reply.nonce, 0, mChallengeDigest, 0, 16); 377 } else { 378 mChallengeDigest = null; 379 } 380 381 long id = mListener.getConnectionId(); 382 if (id == -1) { 383 reply.mConnectionID = null; 384 } else { 385 reply.mConnectionID = ObexHelper.convertToByteArray(id); 386 } 387 388 head = ObexHelper.createHeader(reply, false); 389 totalLength += head.length; 390 391 if (totalLength > mMaxPacketLength) { 392 totalLength = 3; 393 head = null; 394 code = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR; 395 } 396 } 397 } 398 399 // Compute Length of OBEX SETPATH packet 400 byte[] replyData = new byte[totalLength]; 401 replyData[0] = (byte)code; 402 replyData[1] = (byte)(totalLength >> 8); 403 replyData[2] = (byte)totalLength; 404 if (head != null) { 405 System.arraycopy(head, 0, replyData, 3, head.length); 406 } 407 /* 408 * Write the OBEX SETPATH packet to the server. Byte 0: response code 409 * Byte 1&2: Connect Packet Length Byte 3 to n: headers 410 */ 411 mOutput.write(replyData); 412 mOutput.flush(); 413 } 414 415 /** 416 * Handles a disconnect request from a client. This method will read the 417 * rest of the request from the client. Assuming the request is valid, it 418 * will create a <code>HeaderSet</code> object to pass to the 419 * <code>ServerRequestHandler</code> object. After the handler processes the 420 * request, this method will create a reply message to send to the server. 421 * @throws IOException if an error occurred at the transport layer 422 */ 423 private void handleDisconnectRequest() throws IOException { 424 int length; 425 int code = ResponseCodes.OBEX_HTTP_OK; 426 int totalLength = 3; 427 byte[] head = null; 428 int bytesReceived; 429 HeaderSet request = new HeaderSet(); 430 HeaderSet reply = new HeaderSet(); 431 432 length = mInput.read(); 433 length = (length << 8) + mInput.read(); 434 435 if (length > ObexHelper.getMaxRxPacketSize(mTransport)) { 436 code = ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE; 437 totalLength = 3; 438 } else { 439 if (length > 3) { 440 byte[] headers = new byte[length - 3]; 441 bytesReceived = mInput.read(headers); 442 443 while (bytesReceived != headers.length) { 444 bytesReceived += mInput.read(headers, bytesReceived, headers.length 445 - bytesReceived); 446 } 447 448 ObexHelper.updateHeaderSet(request, headers); 449 } 450 451 if (mListener.getConnectionId() != -1 && request.mConnectionID != null) { 452 mListener.setConnectionId(ObexHelper.convertToLong(request.mConnectionID)); 453 } else { 454 mListener.setConnectionId(1); 455 } 456 457 if (request.mAuthResp != null) { 458 if (!handleAuthResp(request.mAuthResp)) { 459 code = ResponseCodes.OBEX_HTTP_UNAUTHORIZED; 460 mListener.onAuthenticationFailure(ObexHelper.getTagValue((byte)0x01, 461 request.mAuthResp)); 462 } 463 request.mAuthResp = null; 464 } 465 466 if (code != ResponseCodes.OBEX_HTTP_UNAUTHORIZED) { 467 468 if (request.mAuthChall != null) { 469 handleAuthChall(request); 470 request.mAuthChall = null; 471 } 472 473 try { 474 mListener.onDisconnect(request, reply); 475 } catch (Exception e) { 476 if(V) Log.d(TAG,"Exception occured - sending OBEX_HTTP_INTERNAL_ERROR reply",e); 477 sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null); 478 return; 479 } 480 481 long id = mListener.getConnectionId(); 482 if (id == -1) { 483 reply.mConnectionID = null; 484 } else { 485 reply.mConnectionID = ObexHelper.convertToByteArray(id); 486 } 487 488 head = ObexHelper.createHeader(reply, false); 489 totalLength += head.length; 490 491 if (totalLength > mMaxPacketLength) { 492 totalLength = 3; 493 head = null; 494 code = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR; 495 } 496 } 497 } 498 499 // Compute Length of OBEX CONNECT packet 500 byte[] replyData; 501 if (head != null) { 502 replyData = new byte[3 + head.length]; 503 } else { 504 replyData = new byte[3]; 505 } 506 replyData[0] = (byte)code; 507 replyData[1] = (byte)(totalLength >> 8); 508 replyData[2] = (byte)totalLength; 509 if (head != null) { 510 System.arraycopy(head, 0, replyData, 3, head.length); 511 } 512 /* 513 * Write the OBEX DISCONNECT packet to the server. Byte 0: response code 514 * Byte 1&2: Connect Packet Length Byte 3 to n: headers 515 */ 516 mOutput.write(replyData); 517 mOutput.flush(); 518 } 519 520 /** 521 * Handles a connect request from a client. This method will read the rest 522 * of the request from the client. Assuming the request is valid, it will 523 * create a <code>HeaderSet</code> object to pass to the 524 * <code>ServerRequestHandler</code> object. After the handler processes the 525 * request, this method will create a reply message to send to the server 526 * with the response code provided. 527 * @throws IOException if an error occurred at the transport layer 528 */ 529 private void handleConnectRequest() throws IOException { 530 int packetLength; 531 @SuppressWarnings("unused") 532 int version; 533 @SuppressWarnings("unused") 534 int flags; 535 int totalLength = 7; 536 byte[] head = null; 537 int code = -1; 538 HeaderSet request = new HeaderSet(); 539 HeaderSet reply = new HeaderSet(); 540 int bytesReceived; 541 542 if(V) Log.v(TAG,"handleConnectRequest()"); 543 544 /* 545 * Read in the length of the OBEX packet, OBEX version, flags, and max 546 * packet length 547 */ 548 packetLength = mInput.read(); 549 packetLength = (packetLength << 8) + mInput.read(); 550 if(V) Log.v(TAG,"handleConnectRequest() - packetLength: " + packetLength); 551 552 version = mInput.read(); 553 flags = mInput.read(); 554 mMaxPacketLength = mInput.read(); 555 mMaxPacketLength = (mMaxPacketLength << 8) + mInput.read(); 556 557 if(V) Log.v(TAG,"handleConnectRequest() - version: " + version 558 + " MaxLength: " + mMaxPacketLength + " flags: " + flags); 559 560 // should we check it? 561 if (mMaxPacketLength > ObexHelper.MAX_PACKET_SIZE_INT) { 562 mMaxPacketLength = ObexHelper.MAX_PACKET_SIZE_INT; 563 } 564 565 if(mMaxPacketLength > ObexHelper.getMaxTxPacketSize(mTransport)) { 566 Log.w(TAG, "Requested MaxObexPacketSize " + mMaxPacketLength 567 + " is larger than the max size supported by the transport: " 568 + ObexHelper.getMaxTxPacketSize(mTransport) 569 + " Reducing to this size."); 570 mMaxPacketLength = ObexHelper.getMaxTxPacketSize(mTransport); 571 } 572 573 if (packetLength > ObexHelper.getMaxRxPacketSize(mTransport)) { 574 code = ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE; 575 totalLength = 7; 576 } else { 577 if (packetLength > 7) { 578 byte[] headers = new byte[packetLength - 7]; 579 bytesReceived = mInput.read(headers); 580 581 while (bytesReceived != headers.length) { 582 bytesReceived += mInput.read(headers, bytesReceived, headers.length 583 - bytesReceived); 584 } 585 586 ObexHelper.updateHeaderSet(request, headers); 587 } 588 589 if (mListener.getConnectionId() != -1 && request.mConnectionID != null) { 590 mListener.setConnectionId(ObexHelper.convertToLong(request.mConnectionID)); 591 } else { 592 mListener.setConnectionId(1); 593 } 594 595 if (request.mAuthResp != null) { 596 if (!handleAuthResp(request.mAuthResp)) { 597 code = ResponseCodes.OBEX_HTTP_UNAUTHORIZED; 598 mListener.onAuthenticationFailure(ObexHelper.getTagValue((byte)0x01, 599 request.mAuthResp)); 600 } 601 request.mAuthResp = null; 602 } 603 604 if (code != ResponseCodes.OBEX_HTTP_UNAUTHORIZED) { 605 if (request.mAuthChall != null) { 606 handleAuthChall(request); 607 reply.mAuthResp = new byte[request.mAuthResp.length]; 608 System.arraycopy(request.mAuthResp, 0, reply.mAuthResp, 0, 609 reply.mAuthResp.length); 610 request.mAuthChall = null; 611 request.mAuthResp = null; 612 } 613 614 try { 615 code = mListener.onConnect(request, reply); 616 code = validateResponseCode(code); 617 618 if (reply.nonce != null) { 619 mChallengeDigest = new byte[16]; 620 System.arraycopy(reply.nonce, 0, mChallengeDigest, 0, 16); 621 } else { 622 mChallengeDigest = null; 623 } 624 long id = mListener.getConnectionId(); 625 if (id == -1) { 626 reply.mConnectionID = null; 627 } else { 628 reply.mConnectionID = ObexHelper.convertToByteArray(id); 629 } 630 631 head = ObexHelper.createHeader(reply, false); 632 totalLength += head.length; 633 634 if (totalLength > mMaxPacketLength) { 635 totalLength = 7; 636 head = null; 637 code = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR; 638 } 639 } catch (Exception e) { 640 if(V) Log.d(TAG,"Exception occured - sending OBEX_HTTP_INTERNAL_ERROR reply",e); 641 totalLength = 7; 642 head = null; 643 code = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR; 644 } 645 646 } 647 } 648 649 // Compute Length of OBEX CONNECT packet 650 byte[] length = ObexHelper.convertToByteArray(totalLength); 651 652 /* 653 * Write the OBEX CONNECT packet to the server. Byte 0: response code 654 * Byte 1&2: Connect Packet Length Byte 3: OBEX Version Number 655 * (Presently, 0x10) Byte 4: Flags (For TCP 0x00) Byte 5&6: Max OBEX 656 * Packet Length (Defined in MAX_PACKET_SIZE) Byte 7 to n: headers 657 */ 658 byte[] sendData = new byte[totalLength]; 659 int maxRxLength = ObexHelper.getMaxRxPacketSize(mTransport); 660 if (maxRxLength > mMaxPacketLength) { 661 if(V) Log.v(TAG,"Set maxRxLength to min of maxRxServrLen:" + maxRxLength + 662 " and MaxNegotiated from Client: " + mMaxPacketLength); 663 maxRxLength = mMaxPacketLength; 664 } 665 sendData[0] = (byte)code; 666 sendData[1] = length[2]; 667 sendData[2] = length[3]; 668 sendData[3] = (byte)0x10; 669 sendData[4] = (byte)0x00; 670 sendData[5] = (byte)(maxRxLength >> 8); 671 sendData[6] = (byte)(maxRxLength & 0xFF); 672 673 if (head != null) { 674 System.arraycopy(head, 0, sendData, 7, head.length); 675 } 676 677 mOutput.write(sendData); 678 mOutput.flush(); 679 } 680 681 /** 682 * Closes the server session - in detail close I/O streams and the 683 * underlying transport layer. Internal flag is also set so that later 684 * attempt to read/write will throw an exception. 685 */ 686 public synchronized void close() { 687 if (mListener != null) { 688 mListener.onClose(); 689 } 690 try { 691 /* Set state to closed before interrupting the thread by closing the streams */ 692 mClosed = true; 693 if(mInput != null) 694 mInput.close(); 695 if(mOutput != null) 696 mOutput.close(); 697 if(mTransport != null) 698 mTransport.close(); 699 } catch (Exception e) { 700 if(V) Log.d(TAG,"Exception occured during close() - ignore",e); 701 } 702 mTransport = null; 703 mInput = null; 704 mOutput = null; 705 mListener = null; 706 } 707 708 /** 709 * Verifies that the response code is valid. If it is not valid, it will 710 * return the <code>OBEX_HTTP_INTERNAL_ERROR</code> response code. 711 * @param code the response code to check 712 * @return the valid response code or <code>OBEX_HTTP_INTERNAL_ERROR</code> 713 * if <code>code</code> is not valid 714 */ 715 private int validateResponseCode(int code) { 716 717 if ((code >= ResponseCodes.OBEX_HTTP_OK) && (code <= ResponseCodes.OBEX_HTTP_PARTIAL)) { 718 return code; 719 } 720 if ((code >= ResponseCodes.OBEX_HTTP_MULT_CHOICE) 721 && (code <= ResponseCodes.OBEX_HTTP_USE_PROXY)) { 722 return code; 723 } 724 if ((code >= ResponseCodes.OBEX_HTTP_BAD_REQUEST) 725 && (code <= ResponseCodes.OBEX_HTTP_UNSUPPORTED_TYPE)) { 726 return code; 727 } 728 if ((code >= ResponseCodes.OBEX_HTTP_INTERNAL_ERROR) 729 && (code <= ResponseCodes.OBEX_HTTP_VERSION)) { 730 return code; 731 } 732 if ((code >= ResponseCodes.OBEX_DATABASE_FULL) 733 && (code <= ResponseCodes.OBEX_DATABASE_LOCKED)) { 734 return code; 735 } 736 return ResponseCodes.OBEX_HTTP_INTERNAL_ERROR; 737 } 738 739 public ObexTransport getTransport() { 740 return mTransport; 741 } 742 } 743