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