1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.telephony.ims.cts;
18 
19 import android.telephony.ims.SipMessage;
20 
21 import java.util.Set;
22 
23 
24 public class SipMessageUtils {
25 
26     public static final String INVITE_SIP_METHOD = "INVITE";
27     public static final String CANCEL_SIP_METHOD = "CANCEL";
28     public static final String BYE_SIP_METHOD = "BYE";
29     public static final String ACK_SIP_METHOD = "ACK";
30     public static final String MESSAGE_SIP_METHOD = "MESSAGE";
31     public static final String BASE_ADDRESS = "client.example.com";
32 
33     private static final String PARAM_SEPARATOR = ";";
34     private static final String PARAM_KEY_VALUE_SEPARATOR = "=";
35     private static final String BASE_VIA_HEADER_VALUE = "SIP/2.0/TCP " + BASE_ADDRESS + ":5060";
36 
37     public static final SipMessage TEST_SIP_MESSAGE = generateSipRequest(MESSAGE_SIP_METHOD,
38             new SipDialogAttributes());
39 
40     // Example from RFC 3665
41     public static final SipMessage TEST_INVALID_SIP_REGISTER = new SipMessage(
42             "REGISTER sips:ss2.biloxi.example.com SIP/2.0",
43             "Via: SIP/2.0/TLS client.biloxi.example.com:5061;branch=z9hG4bKnashds7\n"
44                     + "Max-Forwards: 70\n"
45                     + "From: Bob <sips:bob@biloxi.example.com>;tag=a73kszlfl\n"
46                     + "To: Bob <sips:bob@biloxi.example.com>\n"
47                     + "Call-ID: 1j9FpLxk3uxtm8tn@biloxi.example.com\n"
48                     + "CSeq: 1 REGISTER\n"
49                     + "Contact: <sips:bob@client.biloxi.example.com>\n"
50                     + "Content-Length: 0",
51             new byte[0]);
52 
53     //Example from RFC3903, but does not include PIDF document. PUBLISH is not allowed.
54     public static final SipMessage TEST_INVALID_SIP_PUBLISH = new SipMessage(
55             "PUBLISH sip:presentity@example.com SIP/2.0",
56             "Via: SIP/2.0/UDP pua.example.com;branch=z9hG4bKcdad2\n"
57                     + "To: <sip:presentity@example.com>\n"
58                     + "From: <sip:presentity@example.com>;tag=54321mm\n"
59                     + "Call-ID: 5566778@pua.example.com\n"
60                     + "CSeq: 1 PUBLISH\n"
61                     + "Max-Forwards: 70\n"
62                     + "Expires: 3600\n"
63                     + "Event: presence\n"
64                     + "Content-Type: application/pidf+xml",
65             new byte[0]);
66 
67     //Example from RFC3856 - SUBSCRIBE with event presence is not allowed
68     public static final SipMessage TEST_INVALID_SIP_SUBSCRIBE_PRESENCE = new SipMessage(
69             "SUBSCRIBE sip:resource@example.com SIP/2.0",
70             "Via: SIP/2.0/TCP watcherhost.example.com;branch=z9hG4bKnashds7\n"
71                     + "To: <sip:resource@example.com>\n"
72                     + "From: <sip:user@example.com>;tag=xfg9\n"
73                     + "Call-ID: 2010@watcherhost.example.com\n"
74                     + "CSeq: 17766 SUBSCRIBE\n"
75                     + "Max-Forwards: 70\n"
76                     + "Event: presence\n"
77                     + "Accept: application/pidf+xml\n"
78                     + "Contact: <sip:user@watcherhost.example.com>\n"
79                     + "Expires: 600\n"
80                     + "Content-Length: 0",
81             new byte[0]);
82 
83     //Example from RFC3261, OPTIONS not allowed from app
84     public static final SipMessage TEST_INVALID_SIP_OPTIONS = new SipMessage(
85             "OPTIONS sip:carol@chicago.com SIP/2.0",
86             "Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKhjhs8ass877\n"
87                     + "Max-Forwards: 70\n"
88                     + "To: <sip:carol@chicago.com>\n"
89                     + "From: Alice <sip:alice@atlanta.com>;tag=1928301774\n"
90                     + "Call-ID: a84b4c76e66710\n"
91                     + "CSeq: 63104 OPTIONS\n"
92                     + "Contact: <sip:alice@pc33.atlanta.com>\n"
93                     + "Accept: application/sdp\n"
94                     + "Content-Length: 0",
95             new byte[0]);
96 
97     // Sample message from RFC 3261, malformed request start line
98     public static final SipMessage TEST_SIP_MESSAGE_INVALID_REQUEST = new SipMessage(
99             "INVITE sip:bob@biloxi.comSIP/2.0",
100             // Typical Via
101             "Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bK.TeSt\n"
102                     + "Max-Forwards: 70\n"
103                     + "To: Bob <sip:bob@biloxi.com>\n"
104                     + "From: Alice <sip:alice@atlanta.com>;tag=1928301774\n"
105                     + "Call-ID: a84b4c76e66710@pc33.atlanta.com\n"
106                     + "CSeq: 314159 INVITE\n"
107                     + "Contact: <sip:alice@pc33.atlanta.com>\n"
108                     + "Content-Type: application/sdp\n"
109                     + "Content-Length: 142",
110             new byte[0]);
111 
112     // Sample message from RFC 3261, malformed response start line
113     public static final SipMessage TEST_SIP_MESSAGE_INVALID_RESPONSE = new SipMessage(
114             "SIP/2.0 200OK",
115             "Via: SIP/2.0/TCP terminal.vancouver.example.com;"
116                     + "branch=z9hG4bKwYb6QREiCL\n"
117                     + "To: <sip:adam-buddies@pres.vancouver.example.com>;tag=zpNctbZq\n"
118                     + "From: <sip:adam@vancouver.example.com>;tag=ie4hbb8t\n"
119                     + "Call-ID: cdB34qLToC@terminal.vancouver.example.com\n"
120                     + "CSeq: 322723822 SUBSCRIBE\n"
121                     + "Contact: <sip:pres.vancouver.example.com>\n"
122                     + "Expires: 7200\n"
123                     + "Require: eventlist\n"
124                     + "Content-Length: 0",
125             new byte[0]);
126 
127     /**
128      * @return A new SIP request from the given parameters.
129      */
generateSipRequest(String requestMethod, String fromContact, String toContact, String toUri, String branchId, String callId, String fromTag, String toTag, Set<String> acceptContactTags)130     public static SipMessage generateSipRequest(String requestMethod, String fromContact,
131             String toContact, String toUri, String branchId, String callId, String fromTag,
132             String toTag, Set<String> acceptContactTags) {
133         String header = "Via: " + addParamToHeader(BASE_VIA_HEADER_VALUE, "branch", branchId);
134         header += "\n";
135         header += "From: " + addParamToHeader(fromContact, "tag", fromTag);
136         header += "\n";
137         // To tag is optional
138         header += "To: " + ((toTag != null)
139                 ? addParamToHeader(toContact, "tag", toTag) : toContact);
140         header += "\n";
141         header += "Call-ID: " + callId;
142         if (!acceptContactTags.isEmpty()) {
143             header += "\n";
144             header += "Accept-Contact: *";
145             for (String tag : acceptContactTags) {
146                 header += ";" + tag;
147             }
148         }
149         return new SipMessage(requestMethod + " " + toUri + " SIP/2.0", header, new byte[0]);
150     }
151 
152     /**
153      * @return Generates a SIP response.
154      */
generateSipResponse(String statusCode, String statusString, String fromContact, String toContact, String branchId, String callId, String fromTag, String toTag)155     public static SipMessage generateSipResponse(String statusCode, String statusString,
156             String fromContact, String toContact, String branchId, String callId, String fromTag,
157             String toTag) {
158         String header = "Via: " + addParamToHeader(BASE_VIA_HEADER_VALUE, "branch", branchId);
159         header += "\n";
160         header += "From: " + addParamToHeader(fromContact, "tag", fromTag);
161         header += "\n";
162         // To tag is optional
163         header += "To: " + ((toTag != null)
164                 ? addParamToHeader(toContact, "tag", toTag) : toContact);
165         header += "\n";
166         header += "Call-ID: " + callId;
167         return new SipMessage("SIP/2.0 " + statusCode + " " + statusString, header,
168                 new byte[0]);
169     }
170 
generateSipRequest(String requestMethod, SipDialogAttributes attr)171     public static SipMessage generateSipRequest(String requestMethod, SipDialogAttributes attr) {
172         return generateSipRequest(requestMethod, attr.fromHeader, attr.toHeader,
173                 attr.toUri, attr.branchId, attr.callId, attr.fromTag, attr.getToTag(),
174                 attr.getAcceptContactTags());
175     }
176 
generateSipResponse(String statusCode, String statusString, SipDialogAttributes attr)177     public static SipMessage generateSipResponse(String statusCode, String statusString,
178             SipDialogAttributes attr) {
179         return generateSipResponse(statusCode, statusString, attr.fromHeader,
180                 attr.toHeader, attr.branchId, attr.callId, attr.fromTag, attr.getToTag());
181     }
182 
addParamToHeader(String headerValue, String paramKey, String paramValue)183     private static String addParamToHeader(String headerValue, String paramKey, String paramValue) {
184         headerValue += PARAM_SEPARATOR + paramKey.trim() + PARAM_KEY_VALUE_SEPARATOR
185                 + paramValue.trim();
186         return headerValue;
187     }
188 }
189