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