1/*
2 * Conditions Of Use
3 *
4 * This software was developed by employees of the National Institute of
5 * Standards and Technology (NIST), an agency of the Federal Government.
6 * Pursuant to title 15 Untied States Code Section 105, works of NIST
7 * employees are not subject to copyright protection in the United States
8 * and are considered to be in the public domain.  As a result, a formal
9 * license is not needed to use the software.
10 *
11 * This software is provided by NIST as a service and is expressly
12 * provided "AS IS."  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED
13 * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF
14 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT
15 * AND DATA ACCURACY.  NIST does not warrant or make any representations
16 * regarding the use of the software or the results thereof, including but
17 * not limited to the correctness, accuracy, reliability or usefulness of
18 * the software.
19 *
20 * Permission to use this software is contingent upon your acceptance
21 * of the terms of this agreement
22 *
23 * .
24 *
25 */
26/*******************************************************************************
27 * Product of NIST/ITL Advanced Networking Technologies Division (ANTD).       *
28 *******************************************************************************/
29package gov.nist.javax.sip;
30
31import gov.nist.javax.sip.header.Via;
32import gov.nist.javax.sip.message.SIPResponse;
33
34import java.security.MessageDigest;
35import java.util.HashSet;
36
37/**
38 * A few utilities that are used in various places by the stack. This is used to
39 * convert byte arrays to hex strings etc. Generate tags and branch identifiers
40 * and odds and ends.
41 *
42 * @author mranga
43 * @version 1.2 $Revision: 1.21 $ $Date: 2009/10/18 13:46:37 $
44 */
45public class Utils implements UtilsExt {
46
47    private static MessageDigest digester;
48
49    private static java.util.Random rand;
50
51    private static long counter = 0;
52
53    private static int callIDCounter;
54
55    private static String signature ;
56
57    private static Utils instance = new Utils();
58
59
60    /**
61     * to hex converter
62     */
63    private static final char[] toHex = { '0', '1', '2', '3', '4', '5', '6',
64            '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
65
66    static {
67        try {
68            digester = MessageDigest.getInstance("MD5");
69        } catch (Exception ex) {
70            throw new RuntimeException("Could not intialize Digester ", ex);
71        }
72        rand = new java.util.Random();
73        signature = toHexString(Integer.toString(Math.abs( rand.nextInt() % 1000 )).getBytes());
74    }
75
76
77    public static Utils getInstance() {
78        return instance;
79    }
80
81    /**
82     * convert an array of bytes to an hexadecimal string
83     *
84     * @return a string
85     * @param b
86     *            bytes array to convert to a hexadecimal string
87     */
88
89    public static String toHexString(byte b[]) {
90        int pos = 0;
91        char[] c = new char[b.length * 2];
92        for (int i = 0; i < b.length; i++) {
93            c[pos++] = toHex[(b[i] >> 4) & 0x0F];
94            c[pos++] = toHex[b[i] & 0x0f];
95        }
96        return new String(c);
97    }
98
99    /**
100     * Put quotes around a string and return it.
101     * Any " characters appearing in str are escaped
102     *
103     * @return a quoted string
104     * @param str
105     *            string to be quoted
106     */
107    public static String getQuotedString(String str) {
108        return '"' + str.replace( "\"", "\\\"" ) + '"';
109    }
110
111    /**
112     * Squeeze out all white space from a string and return the reduced string.
113     *
114     * @param input
115     *            input string to sqeeze.
116     * @return String a reduced string.
117     */
118    protected static String reduceString(String input) {
119        String newString = input.toLowerCase();
120        int len = newString.length();
121        String retval = "";
122        for (int i = 0; i < len; i++) {
123            if (newString.charAt(i) == ' ' || newString.charAt(i) == '\t')
124                continue;
125            else
126                retval += newString.charAt(i);
127        }
128        return retval;
129    }
130
131    /**
132     * Generate a call identifier. This is useful when we want to generate a
133     * call identifier in advance of generating a message.
134     */
135    public synchronized String generateCallIdentifier(String address) {
136
137            String date = Long.toString(System.currentTimeMillis() + callIDCounter++
138                    + rand.nextLong());
139            byte cid[] = digester.digest(date.getBytes());
140
141            String cidString = Utils.toHexString(cid);
142            return cidString + "@" + address;
143
144    }
145
146    /**
147     * Generate a tag for a FROM header or TO header. Just return a random 4
148     * digit integer (should be enough to avoid any clashes!) Tags only need to
149     * be unique within a call.
150     *
151     * @return a string that can be used as a tag parameter.
152     *
153     * synchronized: needed for access to 'rand', else risk to generate same tag
154     * twice
155     */
156    public synchronized String generateTag() {
157
158            return Integer.toHexString(rand.nextInt());
159
160    }
161
162    /**
163     * Generate a cryptographically random identifier that can be used to
164     * generate a branch identifier.
165     *
166     * @return a cryptographically random gloablly unique string that can be
167     *         used as a branch identifier.
168     */
169    public synchronized String generateBranchId() {
170        //
171
172
173            long num = rand.nextLong() + Utils.counter++  + System.currentTimeMillis();
174
175            byte bid[] = digester.digest(Long.toString(num).getBytes());
176            // prepend with a magic cookie to indicate we are bis09 compatible.
177            return SIPConstants.BRANCH_MAGIC_COOKIE + Utils.toHexString(bid) + this.signature;
178
179
180    }
181
182    public boolean responseBelongsToUs(SIPResponse response) {
183        Via topmostVia = response.getTopmostVia();
184        String branch = topmostVia.getBranch();
185        return branch != null && branch.endsWith(this.signature);
186    }
187
188    public static String getSignature() {
189        return signature;
190    }
191
192    public static void main(String[] args) {
193        HashSet branchIds = new HashSet();
194        for (int b = 0; b < 100000; b++) {
195            String bid = Utils.getInstance().generateBranchId();
196            if (branchIds.contains(bid)) {
197                throw new RuntimeException("Duplicate Branch ID");
198            } else {
199                branchIds.add(bid);
200            }
201        }
202        System.out.println("Done!!");
203
204    }
205
206
207
208}
209