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 35package javax.obex; 36 37import android.util.Log; 38 39import java.io.InputStream; 40import java.io.IOException; 41import java.io.OutputStream; 42 43/** 44 * This class in an implementation of the OBEX ServerSession. 45 * @hide 46 */ 47public 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 done = true; 108 break; 109 110 case ObexHelper.OBEX_OPCODE_GET: 111 case ObexHelper.OBEX_OPCODE_GET_FINAL: 112 handleGetRequest(requestType); 113 break; 114 115 case ObexHelper.OBEX_OPCODE_PUT: 116 case ObexHelper.OBEX_OPCODE_PUT_FINAL: 117 handlePutRequest(requestType); 118 break; 119 120 case ObexHelper.OBEX_OPCODE_SETPATH: 121 handleSetPathRequest(); 122 break; 123 case ObexHelper.OBEX_OPCODE_ABORT: 124 handleAbortRequest(); 125 break; 126 127 case -1: 128 done = true; 129 break; 130 131 default: 132 133 /* 134 * Received a request type that is not recognized so I am 135 * just going to read the packet and send a not implemented 136 * to the client 137 */ 138 int length = mInput.read(); 139 length = (length << 8) + mInput.read(); 140 for (int i = 3; i < length; i++) { 141 mInput.read(); 142 } 143 sendResponse(ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED, null); 144 } 145 } 146 147 } catch (NullPointerException e) { 148 Log.d(TAG, "Exception occured - ignoring", e); 149 } catch (Exception e) { 150 Log.d(TAG, "Exception occured - ignoring", e); 151 } 152 close(); 153 } 154 155 /** 156 * Handles a ABORT request from a client. This method will read the rest of 157 * the request from the client. Assuming the request is valid, it will 158 * create a <code>HeaderSet</code> object to pass to the 159 * <code>ServerRequestHandler</code> object. After the handler processes the 160 * request, this method will create a reply message to send to the server. 161 * 162 * @throws IOException if an error occurred at the transport layer 163 */ 164 private void handleAbortRequest() throws IOException { 165 int code = ResponseCodes.OBEX_HTTP_OK; 166 HeaderSet request = new HeaderSet(); 167 HeaderSet reply = new HeaderSet(); 168 169 int length = mInput.read(); 170 length = (length << 8) + mInput.read(); 171 if (length > ObexHelper.getMaxRxPacketSize(mTransport)) { 172 code = ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE; 173 } else { 174 for (int i = 3; i < length; i++) { 175 mInput.read(); 176 } 177 code = mListener.onAbort(request, reply); 178 Log.v(TAG, "onAbort request handler return value- " + code); 179 code = validateResponseCode(code); 180 } 181 sendResponse(code, null); 182 } 183 184 /** 185 * Handles a PUT request from a client. This method will provide a 186 * <code>ServerOperation</code> object to the request handler. The 187 * <code>ServerOperation</code> object will handle the rest of the request. 188 * It will also send replies and receive requests until the final reply 189 * should be sent. When the final reply should be sent, this method will get 190 * the response code to use and send the reply. The 191 * <code>ServerOperation</code> object will always reply with a 192 * OBEX_HTTP_CONTINUE reply. It will only reply if further information is 193 * needed. 194 * @param type the type of request received; either 0x02 or 0x82 195 * @throws IOException if an error occurred at the transport layer 196 */ 197 private void handlePutRequest(int type) throws IOException { 198 ServerOperation op = new ServerOperation(this, mInput, type, mMaxPacketLength, mListener); 199 try { 200 int response = -1; 201 202 if ((op.finalBitSet) && !op.isValidBody()) { 203 response = validateResponseCode(mListener 204 .onDelete(op.requestHeader, op.replyHeader)); 205 } else { 206 response = validateResponseCode(mListener.onPut(op)); 207 } 208 if (response != ResponseCodes.OBEX_HTTP_OK && !op.isAborted) { 209 op.sendReply(response); 210 } else if (!op.isAborted) { 211 // wait for the final bit 212 while (!op.finalBitSet) { 213 op.sendReply(ResponseCodes.OBEX_HTTP_CONTINUE); 214 } 215 op.sendReply(response); 216 } 217 } catch (Exception e) { 218 /*To fix bugs in aborted cases, 219 *(client abort file transfer prior to the last packet which has the end of body header, 220 *internal error should not be sent because server has already replied with 221 *OK response in "sendReply") 222 */ 223 if(V) Log.d(TAG,"Exception occured - sending OBEX_HTTP_INTERNAL_ERROR reply",e); 224 if (!op.isAborted) { 225 sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null); 226 } 227 } 228 } 229 230 /** 231 * Handles a GET request from a client. This method will provide a 232 * <code>ServerOperation</code> object to the request handler. The 233 * <code>ServerOperation</code> object will handle the rest of the request. 234 * It will also send replies and receive requests until the final reply 235 * should be sent. When the final reply should be sent, this method will get 236 * the response code to use and send the reply. The 237 * <code>ServerOperation</code> object will always reply with a 238 * OBEX_HTTP_CONTINUE reply. It will only reply if further information is 239 * needed. 240 * @param type the type of request received; either 0x03 or 0x83 241 * @throws IOException if an error occurred at the transport layer 242 */ 243 private void handleGetRequest(int type) throws IOException { 244 ServerOperation op = new ServerOperation(this, mInput, type, mMaxPacketLength, mListener); 245 try { 246 int response = validateResponseCode(mListener.onGet(op)); 247 248 if (!op.isAborted) { 249 op.sendReply(response); 250 } 251 } catch (Exception e) { 252 if(V) Log.d(TAG,"Exception occured - sending OBEX_HTTP_INTERNAL_ERROR reply",e); 253 sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null); 254 } 255 } 256 257 /** 258 * Send standard response. 259 * @param code the response code to send 260 * @param header the headers to include in the response 261 * @throws IOException if an IO error occurs 262 */ 263 public void sendResponse(int code, byte[] header) throws IOException { 264 int totalLength = 3; 265 byte[] data = null; 266 OutputStream op = mOutput; 267 if (op == null) { 268 return; 269 } 270 271 if (header != null) { 272 totalLength += header.length; 273 data = new byte[totalLength]; 274 data[0] = (byte)code; 275 data[1] = (byte)(totalLength >> 8); 276 data[2] = (byte)totalLength; 277 System.arraycopy(header, 0, data, 3, header.length); 278 } else { 279 data = new byte[totalLength]; 280 data[0] = (byte)code; 281 data[1] = (byte)0x00; 282 data[2] = (byte)totalLength; 283 } 284 op.write(data); 285 op.flush(); // TODO: Do we need to flush? 286 } 287 288 /** 289 * Handles a SETPATH request from a client. This method will read the rest 290 * of the request from the client. Assuming the request is valid, it will 291 * create a <code>HeaderSet</code> object to pass to the 292 * <code>ServerRequestHandler</code> object. After the handler processes the 293 * request, this method will create a reply message to send to the server 294 * with the response code provided. 295 * @throws IOException if an error occurred at the transport layer 296 */ 297 private void handleSetPathRequest() throws IOException { 298 int length; 299 int flags; 300 @SuppressWarnings("unused") 301 int constants; 302 int totalLength = 3; 303 byte[] head = null; 304 int code = -1; 305 int bytesReceived; 306 HeaderSet request = new HeaderSet(); 307 HeaderSet reply = new HeaderSet(); 308 309 length = mInput.read(); 310 length = (length << 8) + mInput.read(); 311 flags = mInput.read(); 312 constants = mInput.read(); 313 314 if (length > ObexHelper.getMaxRxPacketSize(mTransport)) { 315 code = ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE; 316 totalLength = 3; 317 } else { 318 if (length > 5) { 319 byte[] headers = new byte[length - 5]; 320 bytesReceived = mInput.read(headers); 321 322 while (bytesReceived != headers.length) { 323 bytesReceived += mInput.read(headers, bytesReceived, headers.length 324 - bytesReceived); 325 } 326 327 ObexHelper.updateHeaderSet(request, headers); 328 329 if (mListener.getConnectionId() != -1 && request.mConnectionID != null) { 330 mListener.setConnectionId(ObexHelper.convertToLong(request.mConnectionID)); 331 } else { 332 mListener.setConnectionId(1); 333 } 334 // the Auth chan is initiated by the server, client sent back the authResp . 335 if (request.mAuthResp != null) { 336 if (!handleAuthResp(request.mAuthResp)) { 337 code = ResponseCodes.OBEX_HTTP_UNAUTHORIZED; 338 mListener.onAuthenticationFailure(ObexHelper.getTagValue((byte)0x01, 339 request.mAuthResp)); 340 } 341 request.mAuthResp = null; 342 } 343 } 344 345 if (code != ResponseCodes.OBEX_HTTP_UNAUTHORIZED) { 346 // the Auth challenge is initiated by the client 347 // the server will send back the authResp to the client 348 if (request.mAuthChall != null) { 349 handleAuthChall(request); 350 reply.mAuthResp = new byte[request.mAuthResp.length]; 351 System.arraycopy(request.mAuthResp, 0, reply.mAuthResp, 0, 352 reply.mAuthResp.length); 353 request.mAuthChall = null; 354 request.mAuthResp = null; 355 } 356 boolean backup = false; 357 boolean create = true; 358 if (!((flags & 1) == 0)) { 359 backup = true; 360 } 361 if (!((flags & 2) == 0)) { 362 create = false; 363 } 364 365 try { 366 code = mListener.onSetPath(request, reply, backup, create); 367 } catch (Exception e) { 368 if(V) Log.d(TAG,"Exception occured - sending OBEX_HTTP_INTERNAL_ERROR reply",e); 369 sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null); 370 return; 371 } 372 373 code = validateResponseCode(code); 374 375 if (reply.nonce != null) { 376 mChallengeDigest = new byte[16]; 377 System.arraycopy(reply.nonce, 0, mChallengeDigest, 0, 16); 378 } else { 379 mChallengeDigest = null; 380 } 381 382 long id = mListener.getConnectionId(); 383 if (id == -1) { 384 reply.mConnectionID = null; 385 } else { 386 reply.mConnectionID = ObexHelper.convertToByteArray(id); 387 } 388 389 head = ObexHelper.createHeader(reply, false); 390 totalLength += head.length; 391 392 if (totalLength > mMaxPacketLength) { 393 totalLength = 3; 394 head = null; 395 code = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR; 396 } 397 } 398 } 399 400 // Compute Length of OBEX SETPATH packet 401 byte[] replyData = new byte[totalLength]; 402 replyData[0] = (byte)code; 403 replyData[1] = (byte)(totalLength >> 8); 404 replyData[2] = (byte)totalLength; 405 if (head != null) { 406 System.arraycopy(head, 0, replyData, 3, head.length); 407 } 408 /* 409 * Write the OBEX SETPATH packet to the server. Byte 0: response code 410 * Byte 1&2: Connect Packet Length Byte 3 to n: headers 411 */ 412 mOutput.write(replyData); 413 mOutput.flush(); 414 } 415 416 /** 417 * Handles a disconnect request from a client. This method will read the 418 * rest of the request from the client. Assuming the request is valid, it 419 * will create a <code>HeaderSet</code> object to pass to the 420 * <code>ServerRequestHandler</code> object. After the handler processes the 421 * request, this method will create a reply message to send to the server. 422 * @throws IOException if an error occurred at the transport layer 423 */ 424 private void handleDisconnectRequest() throws IOException { 425 int length; 426 int code = ResponseCodes.OBEX_HTTP_OK; 427 int totalLength = 3; 428 byte[] head = null; 429 int bytesReceived; 430 HeaderSet request = new HeaderSet(); 431 HeaderSet reply = new HeaderSet(); 432 433 length = mInput.read(); 434 length = (length << 8) + mInput.read(); 435 436 if (length > ObexHelper.getMaxRxPacketSize(mTransport)) { 437 code = ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE; 438 totalLength = 3; 439 } else { 440 if (length > 3) { 441 byte[] headers = new byte[length - 3]; 442 bytesReceived = mInput.read(headers); 443 444 while (bytesReceived != headers.length) { 445 bytesReceived += mInput.read(headers, bytesReceived, headers.length 446 - bytesReceived); 447 } 448 449 ObexHelper.updateHeaderSet(request, headers); 450 } 451 452 if (mListener.getConnectionId() != -1 && request.mConnectionID != null) { 453 mListener.setConnectionId(ObexHelper.convertToLong(request.mConnectionID)); 454 } else { 455 mListener.setConnectionId(1); 456 } 457 458 if (request.mAuthResp != null) { 459 if (!handleAuthResp(request.mAuthResp)) { 460 code = ResponseCodes.OBEX_HTTP_UNAUTHORIZED; 461 mListener.onAuthenticationFailure(ObexHelper.getTagValue((byte)0x01, 462 request.mAuthResp)); 463 } 464 request.mAuthResp = null; 465 } 466 467 if (code != ResponseCodes.OBEX_HTTP_UNAUTHORIZED) { 468 469 if (request.mAuthChall != null) { 470 handleAuthChall(request); 471 request.mAuthChall = null; 472 } 473 474 try { 475 mListener.onDisconnect(request, reply); 476 } catch (Exception e) { 477 if(V) Log.d(TAG,"Exception occured - sending OBEX_HTTP_INTERNAL_ERROR reply",e); 478 sendResponse(ResponseCodes.OBEX_HTTP_INTERNAL_ERROR, null); 479 return; 480 } 481 482 long id = mListener.getConnectionId(); 483 if (id == -1) { 484 reply.mConnectionID = null; 485 } else { 486 reply.mConnectionID = ObexHelper.convertToByteArray(id); 487 } 488 489 head = ObexHelper.createHeader(reply, false); 490 totalLength += head.length; 491 492 if (totalLength > mMaxPacketLength) { 493 totalLength = 3; 494 head = null; 495 code = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR; 496 } 497 } 498 } 499 500 // Compute Length of OBEX CONNECT packet 501 byte[] replyData; 502 if (head != null) { 503 replyData = new byte[3 + head.length]; 504 } else { 505 replyData = new byte[3]; 506 } 507 replyData[0] = (byte)code; 508 replyData[1] = (byte)(totalLength >> 8); 509 replyData[2] = (byte)totalLength; 510 if (head != null) { 511 System.arraycopy(head, 0, replyData, 3, head.length); 512 } 513 /* 514 * Write the OBEX DISCONNECT packet to the server. Byte 0: response code 515 * Byte 1&2: Connect Packet Length Byte 3 to n: headers 516 */ 517 mOutput.write(replyData); 518 mOutput.flush(); 519 } 520 521 /** 522 * Handles a connect request from a client. This method will read the rest 523 * of the request from the client. Assuming the request is valid, it will 524 * create a <code>HeaderSet</code> object to pass to the 525 * <code>ServerRequestHandler</code> object. After the handler processes the 526 * request, this method will create a reply message to send to the server 527 * with the response code provided. 528 * @throws IOException if an error occurred at the transport layer 529 */ 530 private void handleConnectRequest() throws IOException { 531 int packetLength; 532 @SuppressWarnings("unused") 533 int version; 534 @SuppressWarnings("unused") 535 int flags; 536 int totalLength = 7; 537 byte[] head = null; 538 int code = -1; 539 HeaderSet request = new HeaderSet(); 540 HeaderSet reply = new HeaderSet(); 541 int bytesReceived; 542 543 if(V) Log.v(TAG,"handleConnectRequest()"); 544 545 /* 546 * Read in the length of the OBEX packet, OBEX version, flags, and max 547 * packet length 548 */ 549 packetLength = mInput.read(); 550 packetLength = (packetLength << 8) + mInput.read(); 551 if(V) Log.v(TAG,"handleConnectRequest() - packetLength: " + packetLength); 552 553 version = mInput.read(); 554 flags = mInput.read(); 555 mMaxPacketLength = mInput.read(); 556 mMaxPacketLength = (mMaxPacketLength << 8) + mInput.read(); 557 558 if(V) Log.v(TAG,"handleConnectRequest() - version: " + version 559 + " MaxLength: " + mMaxPacketLength + " flags: " + flags); 560 561 // should we check it? 562 if (mMaxPacketLength > ObexHelper.MAX_PACKET_SIZE_INT) { 563 mMaxPacketLength = ObexHelper.MAX_PACKET_SIZE_INT; 564 } 565 566 if(mMaxPacketLength > ObexHelper.getMaxTxPacketSize(mTransport)) { 567 Log.w(TAG, "Requested MaxObexPacketSize " + mMaxPacketLength 568 + " is larger than the max size supported by the transport: " 569 + ObexHelper.getMaxTxPacketSize(mTransport) 570 + " Reducing to this size."); 571 mMaxPacketLength = ObexHelper.getMaxTxPacketSize(mTransport); 572 } 573 574 if (packetLength > ObexHelper.getMaxRxPacketSize(mTransport)) { 575 code = ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE; 576 totalLength = 7; 577 } else { 578 if (packetLength > 7) { 579 byte[] headers = new byte[packetLength - 7]; 580 bytesReceived = mInput.read(headers); 581 582 while (bytesReceived != headers.length) { 583 bytesReceived += mInput.read(headers, bytesReceived, headers.length 584 - bytesReceived); 585 } 586 587 ObexHelper.updateHeaderSet(request, headers); 588 } 589 590 if (mListener.getConnectionId() != -1 && request.mConnectionID != null) { 591 mListener.setConnectionId(ObexHelper.convertToLong(request.mConnectionID)); 592 } else { 593 mListener.setConnectionId(1); 594 } 595 596 if (request.mAuthResp != null) { 597 if (!handleAuthResp(request.mAuthResp)) { 598 code = ResponseCodes.OBEX_HTTP_UNAUTHORIZED; 599 mListener.onAuthenticationFailure(ObexHelper.getTagValue((byte)0x01, 600 request.mAuthResp)); 601 } 602 request.mAuthResp = null; 603 } 604 605 if (code != ResponseCodes.OBEX_HTTP_UNAUTHORIZED) { 606 if (request.mAuthChall != null) { 607 handleAuthChall(request); 608 reply.mAuthResp = new byte[request.mAuthResp.length]; 609 System.arraycopy(request.mAuthResp, 0, reply.mAuthResp, 0, 610 reply.mAuthResp.length); 611 request.mAuthChall = null; 612 request.mAuthResp = null; 613 } 614 615 try { 616 code = mListener.onConnect(request, reply); 617 code = validateResponseCode(code); 618 619 if (reply.nonce != null) { 620 mChallengeDigest = new byte[16]; 621 System.arraycopy(reply.nonce, 0, mChallengeDigest, 0, 16); 622 } else { 623 mChallengeDigest = null; 624 } 625 long id = mListener.getConnectionId(); 626 if (id == -1) { 627 reply.mConnectionID = null; 628 } else { 629 reply.mConnectionID = ObexHelper.convertToByteArray(id); 630 } 631 632 head = ObexHelper.createHeader(reply, false); 633 totalLength += head.length; 634 635 if (totalLength > mMaxPacketLength) { 636 totalLength = 7; 637 head = null; 638 code = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR; 639 } 640 } catch (Exception e) { 641 if(V) Log.d(TAG,"Exception occured - sending OBEX_HTTP_INTERNAL_ERROR reply",e); 642 totalLength = 7; 643 head = null; 644 code = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR; 645 } 646 647 } 648 } 649 650 // Compute Length of OBEX CONNECT packet 651 byte[] length = ObexHelper.convertToByteArray(totalLength); 652 653 /* 654 * Write the OBEX CONNECT packet to the server. Byte 0: response code 655 * Byte 1&2: Connect Packet Length Byte 3: OBEX Version Number 656 * (Presently, 0x10) Byte 4: Flags (For TCP 0x00) Byte 5&6: Max OBEX 657 * Packet Length (Defined in MAX_PACKET_SIZE) Byte 7 to n: headers 658 */ 659 byte[] sendData = new byte[totalLength]; 660 int maxRxLength = ObexHelper.getMaxRxPacketSize(mTransport); 661 sendData[0] = (byte)code; 662 sendData[1] = length[2]; 663 sendData[2] = length[3]; 664 sendData[3] = (byte)0x10; 665 sendData[4] = (byte)0x00; 666 sendData[5] = (byte)(maxRxLength >> 8); 667 sendData[6] = (byte)(maxRxLength & 0xFF); 668 669 if (head != null) { 670 System.arraycopy(head, 0, sendData, 7, head.length); 671 } 672 673 mOutput.write(sendData); 674 mOutput.flush(); 675 } 676 677 /** 678 * Closes the server session - in detail close I/O streams and the 679 * underlying transport layer. Internal flag is also set so that later 680 * attempt to read/write will throw an exception. 681 */ 682 public synchronized void close() { 683 if (mListener != null) { 684 mListener.onClose(); 685 } 686 try { 687 /* Set state to closed before interrupting the thread by closing the streams */ 688 mClosed = true; 689 if(mInput != null) 690 mInput.close(); 691 if(mOutput != null) 692 mOutput.close(); 693 if(mTransport != null) 694 mTransport.close(); 695 } catch (Exception e) { 696 if(V) Log.d(TAG,"Exception occured during close() - ignore",e); 697 } 698 mTransport = null; 699 mInput = null; 700 mOutput = null; 701 mListener = null; 702 } 703 704 /** 705 * Verifies that the response code is valid. If it is not valid, it will 706 * return the <code>OBEX_HTTP_INTERNAL_ERROR</code> response code. 707 * @param code the response code to check 708 * @return the valid response code or <code>OBEX_HTTP_INTERNAL_ERROR</code> 709 * if <code>code</code> is not valid 710 */ 711 private int validateResponseCode(int code) { 712 713 if ((code >= ResponseCodes.OBEX_HTTP_OK) && (code <= ResponseCodes.OBEX_HTTP_PARTIAL)) { 714 return code; 715 } 716 if ((code >= ResponseCodes.OBEX_HTTP_MULT_CHOICE) 717 && (code <= ResponseCodes.OBEX_HTTP_USE_PROXY)) { 718 return code; 719 } 720 if ((code >= ResponseCodes.OBEX_HTTP_BAD_REQUEST) 721 && (code <= ResponseCodes.OBEX_HTTP_UNSUPPORTED_TYPE)) { 722 return code; 723 } 724 if ((code >= ResponseCodes.OBEX_HTTP_INTERNAL_ERROR) 725 && (code <= ResponseCodes.OBEX_HTTP_VERSION)) { 726 return code; 727 } 728 if ((code >= ResponseCodes.OBEX_DATABASE_FULL) 729 && (code <= ResponseCodes.OBEX_DATABASE_LOCKED)) { 730 return code; 731 } 732 return ResponseCodes.OBEX_HTTP_INTERNAL_ERROR; 733 } 734 735 public ObexTransport getTransport() { 736 return mTransport; 737 } 738} 739