1 /* 2 * Copyright (c) 2014 The Android Open Source Project 3 * Copyright (c) 2008-2009, Motorola, Inc. 4 * 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions are met: 9 * 10 * - Redistributions of source code must retain the above copyright notice, 11 * this list of conditions and the following disclaimer. 12 * 13 * - Redistributions in binary form must reproduce the above copyright notice, 14 * this list of conditions and the following disclaimer in the documentation 15 * and/or other materials provided with the distribution. 16 * 17 * - Neither the name of the Motorola, Inc. nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 * POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 package com.android.obex; 35 36 import java.io.ByteArrayOutputStream; 37 import java.io.IOException; 38 import java.security.SecureRandom; 39 import java.util.Calendar; 40 41 /** 42 * This class implements the com.android.obex.HeaderSet interface for OBEX over 43 * RFCOMM or OBEX over l2cap. 44 */ 45 public final class HeaderSet { 46 47 /** 48 * Represents the OBEX Count header. This allows the connection statement to 49 * tell the server how many objects it plans to send or retrieve. 50 * <P> 51 * The value of <code>COUNT</code> is 0xC0 (192). 52 */ 53 public static final int COUNT = 0xC0; 54 55 /** 56 * Represents the OBEX Name header. This specifies the name of the object. 57 * <P> 58 * The value of <code>NAME</code> is 0x01 (1). 59 */ 60 public static final int NAME = 0x01; 61 62 /** 63 * Represents the OBEX Type header. This allows a request to specify the 64 * type of the object (e.g. text, html, binary, etc.). 65 * <P> 66 * The value of <code>TYPE</code> is 0x42 (66). 67 */ 68 public static final int TYPE = 0x42; 69 70 /** 71 * Represents the OBEX Length header. This is the length of the object in 72 * bytes. 73 * <P> 74 * The value of <code>LENGTH</code> is 0xC3 (195). 75 */ 76 public static final int LENGTH = 0xC3; 77 78 /** 79 * Represents the OBEX Time header using the ISO 8601 standards. This is the 80 * preferred time header. 81 * <P> 82 * The value of <code>TIME_ISO_8601</code> is 0x44 (68). 83 */ 84 public static final int TIME_ISO_8601 = 0x44; 85 86 /** 87 * Represents the OBEX Time header using the 4 byte representation. This is 88 * only included for backwards compatibility. It represents the number of 89 * seconds since January 1, 1970. 90 * <P> 91 * The value of <code>TIME_4_BYTE</code> is 0xC4 (196). 92 */ 93 public static final int TIME_4_BYTE = 0xC4; 94 95 /** 96 * Represents the OBEX Description header. This is a text description of the 97 * object. 98 * <P> 99 * The value of <code>DESCRIPTION</code> is 0x05 (5). 100 */ 101 public static final int DESCRIPTION = 0x05; 102 103 /** 104 * Represents the OBEX Target header. This is the name of the service an 105 * operation is targeted to. 106 * <P> 107 * The value of <code>TARGET</code> is 0x46 (70). 108 */ 109 public static final int TARGET = 0x46; 110 111 /** 112 * Represents the OBEX HTTP header. This allows an HTTP 1.X header to be 113 * included in a request or reply. 114 * <P> 115 * The value of <code>HTTP</code> is 0x47 (71). 116 */ 117 public static final int HTTP = 0x47; 118 119 /** 120 * Represents the OBEX BODY header. 121 * <P> 122 * The value of <code>BODY</code> is 0x48 (72). 123 * 124 * @hide 125 */ 126 public static final int BODY = 0x48; 127 128 /** 129 * Represents the OBEX End of BODY header. 130 * <P> 131 * The value of <code>BODY</code> is 0x49 (73). 132 * 133 * @hide 134 */ 135 public static final int END_OF_BODY = 0x49; 136 137 /** 138 * Represents the OBEX Who header. Identifies the OBEX application to 139 * determine if the two peers are talking to each other. 140 * <P> 141 * The value of <code>WHO</code> is 0x4A (74). 142 */ 143 public static final int WHO = 0x4A; 144 145 /** 146 * Represents the OBEX Connection ID header. Identifies used for OBEX 147 * connection multiplexing. 148 * <P> 149 * The value of <code>CONNECTION_ID</code> is 0xCB (203). 150 * 151 * @hide 152 */ 153 public static final int CONNECTION_ID = 0xCB; 154 155 /** 156 * Represents the OBEX Application Parameter header. This header specifies 157 * additional application request and response information. 158 * <P> 159 * The value of <code>APPLICATION_PARAMETER</code> is 0x4C (76). 160 */ 161 public static final int APPLICATION_PARAMETER = 0x4C; 162 163 /** 164 * Represents the OBEX authentication digest-challenge. 165 * <P> 166 * The value of <code>AUTH_CHALLENGE</code> is 0x4D (77). 167 * 168 * @hide 169 */ 170 public static final int AUTH_CHALLENGE = 0x4D; 171 172 /** 173 * Represents the OBEX authentication digest-response. 174 * <P> 175 * The value of <code>AUTH_RESPONSE</code> is 0x4E (78). 176 * 177 * @hide 178 */ 179 public static final int AUTH_RESPONSE = 0x4E; 180 181 /** 182 * Represents the OBEX Object Class header. This header specifies the OBEX 183 * object class of the object. 184 * <P> 185 * The value of <code>OBJECT_CLASS</code> is 0x4F (79). 186 */ 187 public static final int OBJECT_CLASS = 0x4F; 188 189 /** 190 * Represents the OBEX Single Response Mode (SRM). This header is used 191 * for Single response mode, introduced in OBEX 1.5. 192 * <P> 193 * The value of <code>SINGLE_RESPONSE_MODE</code> is 0x97 (151). 194 * 195 * @hide 196 */ 197 public static final int SINGLE_RESPONSE_MODE = 0x97; 198 199 /** 200 * Represents the OBEX Single Response Mode Parameters. This header is used 201 * for Single response mode, introduced in OBEX 1.5. 202 * <P> 203 * The value of <code>SINGLE_RESPONSE_MODE_PARAMETER</code> is 0x98 (152). 204 * 205 * @hide 206 */ 207 public static final int SINGLE_RESPONSE_MODE_PARAMETER = 0x98; 208 209 private Long mCount; // 4 byte unsigned integer 210 211 private String mName; // null terminated Unicode text string 212 213 private boolean mEmptyName; 214 215 private String mType; // null terminated ASCII text string 216 217 private Long mLength; // 4 byte unsigend integer 218 219 private Calendar mIsoTime; // String of the form YYYYMMDDTHHMMSSZ 220 221 private Calendar mByteTime; // 4 byte unsigned integer 222 223 private String mDescription; // null terminated Unicode text String 224 225 private byte[] mTarget; // byte sequence 226 227 private byte[] mHttpHeader; // byte sequence 228 229 private byte[] mWho; // length prefixed byte sequence 230 231 private byte[] mAppParam; // byte sequence of the form tag length value 232 233 private byte[] mObjectClass; // byte sequence 234 235 private String[] mUnicodeUserDefined; // null terminated unicode string 236 237 private byte[][] mSequenceUserDefined; // byte sequence user defined 238 239 private Byte[] mByteUserDefined; // 1 byte 240 241 private Long[] mIntegerUserDefined; // 4 byte unsigned integer 242 243 private SecureRandom mRandom = null; 244 245 private Byte mSingleResponseMode; // byte to indicate enable/disable/support for SRM 246 247 private Byte mSrmParam; // byte representing the SRM parameters - only "wait" 248 // is supported by Bluetooth 249 250 /*package*/ byte[] nonce; 251 252 public byte[] mAuthChall; // The authentication challenge header 253 254 public byte[] mAuthResp; // The authentication response header 255 256 public byte[] mConnectionID; // THe connection ID 257 258 public int responseCode; 259 260 /** 261 * Creates new <code>HeaderSet</code> object. 262 */ HeaderSet()263 public HeaderSet() { 264 mUnicodeUserDefined = new String[16]; 265 mSequenceUserDefined = new byte[16][]; 266 mByteUserDefined = new Byte[16]; 267 mIntegerUserDefined = new Long[16]; 268 responseCode = -1; 269 } 270 271 /** 272 * Sets flag for special "value" of NAME header which should be empty. This 273 * is not the same as NAME header with empty string in which case it will 274 * have length of 5 bytes. It should be 3 bytes with only header id and 275 * length field. 276 */ setEmptyNameHeader()277 public void setEmptyNameHeader() { 278 mName = null; 279 mEmptyName = true; 280 } 281 282 /** 283 * Gets flag for special "value" of NAME header which should be empty. See 284 * above. 285 * 286 * @hide 287 */ getEmptyNameHeader()288 public boolean getEmptyNameHeader() { 289 return mEmptyName; 290 } 291 292 /** 293 * Sets the value of the header identifier to the value provided. The type 294 * of object must correspond to the Java type defined in the description of 295 * this interface. If <code>null</code> is passed as the 296 * <code>headerValue</code> then the header will be removed from the set of 297 * headers to include in the next request. 298 * @param headerID the identifier to include in the message 299 * @param headerValue the value of the header identifier 300 * @throws IllegalArgumentException if the header identifier provided is not 301 * one defined in this interface or a user-defined header; if the 302 * type of <code>headerValue</code> is not the correct Java type as 303 * defined in the description of this interface\ 304 */ setHeader(int headerID, Object headerValue)305 public void setHeader(int headerID, Object headerValue) { 306 long temp = -1; 307 308 switch (headerID) { 309 case COUNT: 310 if (!(headerValue instanceof Long)) { 311 if (headerValue == null) { 312 mCount = null; 313 break; 314 } 315 throw new IllegalArgumentException("Count must be a Long"); 316 } 317 temp = ((Long)headerValue).longValue(); 318 if ((temp < 0L) || (temp > 0xFFFFFFFFL)) { 319 throw new IllegalArgumentException("Count must be between 0 and 0xFFFFFFFF"); 320 } 321 mCount = (Long)headerValue; 322 break; 323 case NAME: 324 if ((headerValue != null) && (!(headerValue instanceof String))) { 325 throw new IllegalArgumentException("Name must be a String"); 326 } 327 mEmptyName = false; 328 mName = (String)headerValue; 329 break; 330 case TYPE: 331 if ((headerValue != null) && (!(headerValue instanceof String))) { 332 throw new IllegalArgumentException("Type must be a String"); 333 } 334 mType = (String)headerValue; 335 break; 336 case LENGTH: 337 if (!(headerValue instanceof Long)) { 338 if (headerValue == null) { 339 mLength = null; 340 break; 341 } 342 throw new IllegalArgumentException("Length must be a Long"); 343 } 344 temp = ((Long)headerValue).longValue(); 345 if ((temp < 0L) || (temp > 0xFFFFFFFFL)) { 346 throw new IllegalArgumentException("Length must be between 0 and 0xFFFFFFFF"); 347 } 348 mLength = (Long)headerValue; 349 break; 350 case TIME_ISO_8601: 351 if ((headerValue != null) && (!(headerValue instanceof Calendar))) { 352 throw new IllegalArgumentException("Time ISO 8601 must be a Calendar"); 353 } 354 mIsoTime = (Calendar)headerValue; 355 break; 356 case TIME_4_BYTE: 357 if ((headerValue != null) && (!(headerValue instanceof Calendar))) { 358 throw new IllegalArgumentException("Time 4 Byte must be a Calendar"); 359 } 360 mByteTime = (Calendar)headerValue; 361 break; 362 case DESCRIPTION: 363 if ((headerValue != null) && (!(headerValue instanceof String))) { 364 throw new IllegalArgumentException("Description must be a String"); 365 } 366 mDescription = (String)headerValue; 367 break; 368 case TARGET: 369 if (headerValue == null) { 370 mTarget = null; 371 } else { 372 if (!(headerValue instanceof byte[])) { 373 throw new IllegalArgumentException("Target must be a byte array"); 374 } else { 375 mTarget = new byte[((byte[])headerValue).length]; 376 System.arraycopy(headerValue, 0, mTarget, 0, mTarget.length); 377 } 378 } 379 break; 380 case HTTP: 381 if (headerValue == null) { 382 mHttpHeader = null; 383 } else { 384 if (!(headerValue instanceof byte[])) { 385 throw new IllegalArgumentException("HTTP must be a byte array"); 386 } else { 387 mHttpHeader = new byte[((byte[])headerValue).length]; 388 System.arraycopy(headerValue, 0, mHttpHeader, 0, mHttpHeader.length); 389 } 390 } 391 break; 392 case WHO: 393 if (headerValue == null) { 394 mWho = null; 395 } else { 396 if (!(headerValue instanceof byte[])) { 397 throw new IllegalArgumentException("WHO must be a byte array"); 398 } else { 399 mWho = new byte[((byte[])headerValue).length]; 400 System.arraycopy(headerValue, 0, mWho, 0, mWho.length); 401 } 402 } 403 break; 404 case OBJECT_CLASS: 405 if (headerValue == null) { 406 mObjectClass = null; 407 } else { 408 if (!(headerValue instanceof byte[])) { 409 throw new IllegalArgumentException("Object Class must be a byte array"); 410 } else { 411 mObjectClass = new byte[((byte[])headerValue).length]; 412 System.arraycopy(headerValue, 0, mObjectClass, 0, mObjectClass.length); 413 } 414 } 415 break; 416 case APPLICATION_PARAMETER: 417 if (headerValue == null) { 418 mAppParam = null; 419 } else { 420 if (!(headerValue instanceof byte[])) { 421 throw new IllegalArgumentException( 422 "Application Parameter must be a byte array"); 423 } else { 424 mAppParam = new byte[((byte[])headerValue).length]; 425 System.arraycopy(headerValue, 0, mAppParam, 0, mAppParam.length); 426 } 427 } 428 break; 429 case SINGLE_RESPONSE_MODE: 430 if (headerValue == null) { 431 mSingleResponseMode = null; 432 } else { 433 if (!(headerValue instanceof Byte)) { 434 throw new IllegalArgumentException( 435 "Single Response Mode must be a Byte"); 436 } else { 437 mSingleResponseMode = (Byte)headerValue; 438 } 439 } 440 break; 441 case SINGLE_RESPONSE_MODE_PARAMETER: 442 if (headerValue == null) { 443 mSrmParam = null; 444 } else { 445 if (!(headerValue instanceof Byte)) { 446 throw new IllegalArgumentException( 447 "Single Response Mode Parameter must be a Byte"); 448 } else { 449 mSrmParam = (Byte)headerValue; 450 } 451 } 452 break; 453 default: 454 // Verify that it was not a Unicode String user Defined 455 if ((headerID >= 0x30) && (headerID <= 0x3F)) { 456 if ((headerValue != null) && (!(headerValue instanceof String))) { 457 throw new IllegalArgumentException( 458 "Unicode String User Defined must be a String"); 459 } 460 mUnicodeUserDefined[headerID - 0x30] = (String)headerValue; 461 462 break; 463 } 464 // Verify that it was not a byte sequence user defined value 465 if ((headerID >= 0x70) && (headerID <= 0x7F)) { 466 467 if (headerValue == null) { 468 mSequenceUserDefined[headerID - 0x70] = null; 469 } else { 470 if (!(headerValue instanceof byte[])) { 471 throw new IllegalArgumentException( 472 "Byte Sequence User Defined must be a byte array"); 473 } else { 474 mSequenceUserDefined[headerID - 0x70] 475 = new byte[((byte[])headerValue).length]; 476 System.arraycopy(headerValue, 0, mSequenceUserDefined[headerID - 0x70], 477 0, mSequenceUserDefined[headerID - 0x70].length); 478 } 479 } 480 break; 481 } 482 // Verify that it was not a Byte user Defined 483 if ((headerID >= 0xB0) && (headerID <= 0xBF)) { 484 if ((headerValue != null) && (!(headerValue instanceof Byte))) { 485 throw new IllegalArgumentException("ByteUser Defined must be a Byte"); 486 } 487 mByteUserDefined[headerID - 0xB0] = (Byte)headerValue; 488 489 break; 490 } 491 // Verify that is was not the 4 byte unsigned integer user 492 // defined header 493 if ((headerID >= 0xF0) && (headerID <= 0xFF)) { 494 if (!(headerValue instanceof Long)) { 495 if (headerValue == null) { 496 mIntegerUserDefined[headerID - 0xF0] = null; 497 break; 498 } 499 throw new IllegalArgumentException("Integer User Defined must be a Long"); 500 } 501 temp = ((Long)headerValue).longValue(); 502 if ((temp < 0L) || (temp > 0xFFFFFFFFL)) { 503 throw new IllegalArgumentException( 504 "Integer User Defined must be between 0 and 0xFFFFFFFF"); 505 } 506 mIntegerUserDefined[headerID - 0xF0] = (Long)headerValue; 507 break; 508 } 509 throw new IllegalArgumentException("Invalid Header Identifier"); 510 } 511 } 512 513 /** 514 * Retrieves the value of the header identifier provided. The type of the 515 * Object returned is defined in the description of this interface. 516 * @param headerID the header identifier whose value is to be returned 517 * @return the value of the header provided or <code>null</code> if the 518 * header identifier specified is not part of this 519 * <code>HeaderSet</code> object 520 * @throws IllegalArgumentException if the <code>headerID</code> is not one 521 * defined in this interface or any of the user-defined headers 522 * @throws IOException if an error occurred in the transport layer during 523 * the operation or if the connection has been closed 524 */ getHeader(int headerID)525 public Object getHeader(int headerID) throws IOException { 526 527 switch (headerID) { 528 case COUNT: 529 return mCount; 530 case NAME: 531 return mName; 532 case TYPE: 533 return mType; 534 case LENGTH: 535 return mLength; 536 case TIME_ISO_8601: 537 return mIsoTime; 538 case TIME_4_BYTE: 539 return mByteTime; 540 case DESCRIPTION: 541 return mDescription; 542 case TARGET: 543 return mTarget; 544 case HTTP: 545 return mHttpHeader; 546 case WHO: 547 return mWho; 548 case CONNECTION_ID: 549 return mConnectionID; 550 case OBJECT_CLASS: 551 return mObjectClass; 552 case APPLICATION_PARAMETER: 553 return mAppParam; 554 case SINGLE_RESPONSE_MODE: 555 return mSingleResponseMode; 556 case SINGLE_RESPONSE_MODE_PARAMETER: 557 return mSrmParam; 558 default: 559 // Verify that it was not a Unicode String user Defined 560 if ((headerID >= 0x30) && (headerID <= 0x3F)) { 561 return mUnicodeUserDefined[headerID - 0x30]; 562 } 563 // Verify that it was not a byte sequence user defined header 564 if ((headerID >= 0x70) && (headerID <= 0x7F)) { 565 return mSequenceUserDefined[headerID - 0x70]; 566 } 567 // Verify that it was not a byte user defined header 568 if ((headerID >= 0xB0) && (headerID <= 0xBF)) { 569 return mByteUserDefined[headerID - 0xB0]; 570 } 571 // Verify that it was not a integer user defined header 572 if ((headerID >= 0xF0) && (headerID <= 0xFF)) { 573 return mIntegerUserDefined[headerID - 0xF0]; 574 } 575 throw new IllegalArgumentException("Invalid Header Identifier"); 576 } 577 } 578 579 /** 580 * Retrieves the list of headers that may be retrieved via the 581 * <code>getHeader</code> method that will not return <code>null</code>. In 582 * other words, this method returns all the headers that are available in 583 * this object. 584 * @see #getHeader 585 * @return the array of headers that are set in this object or 586 * <code>null</code> if no headers are available 587 * @throws IOException if an error occurred in the transport layer during 588 * the operation or the connection has been closed 589 * 590 * @hide 591 */ getHeaderList()592 public int[] getHeaderList() throws IOException { 593 ByteArrayOutputStream out = new ByteArrayOutputStream(); 594 595 if (mCount != null) { 596 out.write(COUNT); 597 } 598 if (mName != null) { 599 out.write(NAME); 600 } 601 if (mType != null) { 602 out.write(TYPE); 603 } 604 if (mLength != null) { 605 out.write(LENGTH); 606 } 607 if (mIsoTime != null) { 608 out.write(TIME_ISO_8601); 609 } 610 if (mByteTime != null) { 611 out.write(TIME_4_BYTE); 612 } 613 if (mDescription != null) { 614 out.write(DESCRIPTION); 615 } 616 if (mTarget != null) { 617 out.write(TARGET); 618 } 619 if (mHttpHeader != null) { 620 out.write(HTTP); 621 } 622 if (mWho != null) { 623 out.write(WHO); 624 } 625 if (mAppParam != null) { 626 out.write(APPLICATION_PARAMETER); 627 } 628 if (mObjectClass != null) { 629 out.write(OBJECT_CLASS); 630 } 631 if(mSingleResponseMode != null) { 632 out.write(SINGLE_RESPONSE_MODE); 633 } 634 if(mSrmParam != null) { 635 out.write(SINGLE_RESPONSE_MODE_PARAMETER); 636 } 637 638 for (int i = 0x30; i < 0x40; i++) { 639 if (mUnicodeUserDefined[i - 0x30] != null) { 640 out.write(i); 641 } 642 } 643 644 for (int i = 0x70; i < 0x80; i++) { 645 if (mSequenceUserDefined[i - 0x70] != null) { 646 out.write(i); 647 } 648 } 649 650 for (int i = 0xB0; i < 0xC0; i++) { 651 if (mByteUserDefined[i - 0xB0] != null) { 652 out.write(i); 653 } 654 } 655 656 for (int i = 0xF0; i < 0x100; i++) { 657 if (mIntegerUserDefined[i - 0xF0] != null) { 658 out.write(i); 659 } 660 } 661 662 byte[] headers = out.toByteArray(); 663 out.close(); 664 665 if ((headers == null) || (headers.length == 0)) { 666 return null; 667 } 668 669 int[] result = new int[headers.length]; 670 for (int i = 0; i < headers.length; i++) { 671 // Convert the byte to a positive integer. That is, an integer 672 // between 0 and 256. 673 result[i] = headers[i] & 0xFF; 674 } 675 676 return result; 677 } 678 679 /** 680 * Sets the authentication challenge header. The <code>realm</code> will be 681 * encoded based upon the default encoding scheme used by the implementation 682 * to encode strings. Therefore, the encoding scheme used to encode the 683 * <code>realm</code> is application dependent. 684 * @param realm a short description that describes what password to use; if 685 * <code>null</code> no realm will be sent in the authentication 686 * challenge header 687 * @param userID if <code>true</code>, a user ID is required in the reply; 688 * if <code>false</code>, no user ID is required 689 * @param access if <code>true</code> then full access will be granted if 690 * successful; if <code>false</code> then read-only access will be 691 * granted if successful 692 * @throws IOException 693 * 694 * @hide 695 */ createAuthenticationChallenge(String realm, boolean userID, boolean access)696 public void createAuthenticationChallenge(String realm, boolean userID, boolean access) 697 throws IOException { 698 699 nonce = new byte[16]; 700 if(mRandom == null) { 701 mRandom = new SecureRandom(); 702 } 703 for (int i = 0; i < 16; i++) { 704 nonce[i] = (byte)mRandom.nextInt(); 705 } 706 707 mAuthChall = ObexHelper.computeAuthenticationChallenge(nonce, realm, access, userID); 708 } 709 710 /** 711 * Returns the response code received from the server. Response codes are 712 * defined in the <code>ResponseCodes</code> class. 713 * @see ResponseCodes 714 * @return the response code retrieved from the server 715 * @throws IOException if an error occurred in the transport layer during 716 * the transaction; if this method is called on a 717 * <code>HeaderSet</code> object created by calling 718 * <code>createHeaderSet()</code> in a <code>ClientSession</code> 719 * object; if this object was created by an OBEX server 720 */ getResponseCode()721 public int getResponseCode() throws IOException { 722 if (responseCode == -1) { 723 throw new IOException("May not be called on a server"); 724 } else { 725 return responseCode; 726 } 727 } 728 } 729