private static String _InternalSerialize(TSIP_Uri uri, Boolean with_params) { /* sip:alice:[email protected]:65535 */ String uriString = String.Format("{0}:{1}{2}{3}{4}{5}{6}{7}{8}{9}", uri.Scheme != null ? uri.Scheme : "sip", /* default scheme is sip: */ uri.UserName != null ? uri.UserName : "", uri.Password != null ? ":" : "", uri.Password != null ? uri.Password : "", uri.Host != null ? (uri.UserName != null ? "@" : "") : "", uri.HostType == tsip_host_type_t.IPv6 ? "[" : "", uri.Host != null ? uri.Host : "", uri.HostType == tsip_host_type_t.IPv6 ? "]" : "", uri.Port != 0 ? ":" : "", uri.Port != 0 ? uri.Port.ToString() : "" ); /* Params */ if (with_params && uri.Params.Count > 0) { uriString += ";"; uriString += TSK_Param.ToString(uri.Params, ';'); } return(uriString); }
/* #line 124 "./ragel/tsip_parser_uri.rl" */ public static TSIP_Uri Parse(String data) { if (String.IsNullOrEmpty(data)) { return(null); } int cs = 0; int p = 0; int pe = data.Length; int eof = pe; int ts = 0, te = 0; int act = 0; TSIP_Uri uri = TSIP_Uri.Create(tsip_uri_type_t.Unknown); int tag_start = 0; /* #line 395 "../Parsers/TSIP_ParserUri.cs" */ { cs = tsip_machine_parser_uri_start; ts = -1; te = -1; act = 0; } /* #line 145 "./ragel/tsip_parser_uri.rl" */ /* #line 405 "../Parsers/TSIP_ParserUri.cs" */ { sbyte _klen; short _trans; sbyte _acts; sbyte _nacts; short _keys; if (p == pe) { goto _test_eof; } if (cs == 0) { goto _out; } _resume: _acts = _tsip_machine_parser_uri_from_state_actions[cs]; _nacts = _tsip_machine_parser_uri_actions[_acts++]; while (_nacts-- > 0) { switch (_tsip_machine_parser_uri_actions[_acts++]) { case 12: /* #line 1 "./ragel/tsip_parser_uri.rl" */ { ts = p; } break; /* #line 426 "../Parsers/TSIP_ParserUri.cs" */ default: break; } } _keys = _tsip_machine_parser_uri_key_offsets[cs]; _trans = (short)_tsip_machine_parser_uri_index_offsets[cs]; _klen = _tsip_machine_parser_uri_single_lengths[cs]; if (_klen > 0) { short _lower = _keys; short _mid; short _upper = (short)(_keys + _klen - 1); while (true) { if (_upper < _lower) { break; } _mid = (short)(_lower + ((_upper - _lower) >> 1)); if (data[p] < _tsip_machine_parser_uri_trans_keys[_mid]) { _upper = (short)(_mid - 1); } else if (data[p] > _tsip_machine_parser_uri_trans_keys[_mid]) { _lower = (short)(_mid + 1); } else { _trans += (short)(_mid - _keys); goto _match; } } _keys += (short)_klen; _trans += (short)_klen; } _klen = _tsip_machine_parser_uri_range_lengths[cs]; if (_klen > 0) { short _lower = _keys; short _mid; short _upper = (short)(_keys + (_klen << 1) - 2); while (true) { if (_upper < _lower) { break; } _mid = (short)(_lower + (((_upper - _lower) >> 1) & ~1)); if (data[p] < _tsip_machine_parser_uri_trans_keys[_mid]) { _upper = (short)(_mid - 2); } else if (data[p] > _tsip_machine_parser_uri_trans_keys[_mid + 1]) { _lower = (short)(_mid + 2); } else { _trans += (short)((_mid - _keys) >> 1); goto _match; } } _trans += (short)_klen; } _match: _trans = (short)_tsip_machine_parser_uri_indicies[_trans]; _eof_trans: cs = _tsip_machine_parser_uri_trans_targs[_trans]; if (_tsip_machine_parser_uri_trans_actions[_trans] == 0) { goto _again; } _acts = _tsip_machine_parser_uri_trans_actions[_trans]; _nacts = _tsip_machine_parser_uri_actions[_acts++]; while (_nacts-- > 0) { switch (_tsip_machine_parser_uri_actions[_acts++]) { case 0: /* #line 36 "./ragel/tsip_parser_uri.rl" */ { tag_start = p; } break; case 1: /* #line 41 "./ragel/tsip_parser_uri.rl" */ { uri.Scheme = "sip"; uri.Type = tsip_uri_type_t.Sip; } break; case 2: /* #line 42 "./ragel/tsip_parser_uri.rl" */ { uri.Scheme = "sips"; uri.Type = tsip_uri_type_t.Sips; } break; case 3: /* #line 43 "./ragel/tsip_parser_uri.rl" */ { uri.Scheme = "tel"; uri.Type = tsip_uri_type_t.Tel; } break; case 4: /* #line 46 "./ragel/tsip_parser_uri.rl" */ { uri.HostType = tsip_host_type_t.IPv4; } break; case 5: /* #line 47 "./ragel/tsip_parser_uri.rl" */ { uri.HostType = tsip_host_type_t.IPv6; } break; case 6: /* #line 48 "./ragel/tsip_parser_uri.rl" */ { uri.HostType = tsip_host_type_t.Hostname; } break; case 7: /* #line 54 "./ragel/tsip_parser_uri.rl" */ { uri.UserName = TSK_RagelState.Parser.GetString(data, p, tag_start); } break; case 8: /* #line 58 "./ragel/tsip_parser_uri.rl" */ { uri.Password = TSK_RagelState.Parser.GetString(data, p, tag_start); } break; case 9: /* #line 70 "./ragel/tsip_parser_uri.rl" */ { TSK_Param param = TSK_RagelState.Parser.GetParam(data, p, tag_start); if (param != null) { uri.Params.Add(param); } } break; case 10: /* #line 84 "./ragel/tsip_parser_uri.rl" */ { { cs = 26; if (true) { goto _again; } } } break; case 13: /* #line 1 "./ragel/tsip_parser_uri.rl" */ { te = p + 1; } break; case 14: /* #line 97 "./ragel/tsip_parser_uri.rl" */ { te = p + 1; { uri.Host = TSK_RagelState.Scanner.GetString(data, ts, te); if (uri.HostType == tsip_host_type_t.IPv6) { uri.Host = TSK_String.UnQuote(uri.Host, '[', ']'); } } } break; case 15: /* #line 88 "./ragel/tsip_parser_uri.rl" */ { te = p; p--; { if (TSK_String.Contains(data.Substring(te), (pe - te), "@")) { { cs = 18; if (true) { goto _again; } } } } } break; case 16: /* #line 94 "./ragel/tsip_parser_uri.rl" */ { te = p; p--; { } } break; case 17: /* #line 97 "./ragel/tsip_parser_uri.rl" */ { te = p; p--; { uri.Host = TSK_RagelState.Scanner.GetString(data, ts, te); if (uri.HostType == tsip_host_type_t.IPv6) { uri.Host = TSK_String.UnQuote(uri.Host, '[', ']'); } } } break; case 18: /* #line 105 "./ragel/tsip_parser_uri.rl" */ { te = p; p--; { ts++; uri.Port = (ushort)TSK_RagelState.Scanner.GetInt32(data, ts, te); } } break; case 19: /* #line 110 "./ragel/tsip_parser_uri.rl" */ { te = p; p--; { } } break; case 20: /* #line 111 "./ragel/tsip_parser_uri.rl" */ { te = p; p--; { } } break; case 21: /* #line 94 "./ragel/tsip_parser_uri.rl" */ { { p = ((te)) - 1; } { } } break; case 22: /* #line 97 "./ragel/tsip_parser_uri.rl" */ { { p = ((te)) - 1; } { uri.Host = TSK_RagelState.Scanner.GetString(data, ts, te); if (uri.HostType == tsip_host_type_t.IPv6) { uri.Host = TSK_String.UnQuote(uri.Host, '[', ']'); } } } break; case 23: /* #line 110 "./ragel/tsip_parser_uri.rl" */ { { p = ((te)) - 1; } { } } break; /* #line 615 "../Parsers/TSIP_ParserUri.cs" */ default: break; } } _again: _acts = _tsip_machine_parser_uri_to_state_actions[cs]; _nacts = _tsip_machine_parser_uri_actions[_acts++]; while (_nacts-- > 0) { switch (_tsip_machine_parser_uri_actions[_acts++]) { case 11: /* #line 1 "./ragel/tsip_parser_uri.rl" */ { ts = -1; } break; /* #line 629 "../Parsers/TSIP_ParserUri.cs" */ default: break; } } if (cs == 0) { goto _out; } if (++p != pe) { goto _resume; } _test_eof : {} if (p == eof) { if (_tsip_machine_parser_uri_eof_trans[cs] > 0) { _trans = (short)(_tsip_machine_parser_uri_eof_trans[cs] - 1); goto _eof_trans; } } _out : {} } /* #line 146 "./ragel/tsip_parser_uri.rl" */ if (cs < /* #line 653 "../Parsers/TSIP_ParserUri.cs" */ 26 /* #line 147 "./ragel/tsip_parser_uri.rl" */ ) { TSK_Debug.Error("Failed to parse SIP/SIPS/TEL URI"); uri.Dispose(); return(null); } return(uri); }
protected Int64 GetNewDelay(TSIP_Response response) { Int64 expires = mExpires; Int64 newdelay = expires; /* default value */ TSIP_Header hdr; int i; /*== NOTIFY with subscription-state header with expires parameter */ if (response.CSeq.RequestType == TSIP_Message.tsip_request_type_t.NOTIFY) { TSIP_HeaderSubscriptionState hdr_state = response.GetHeader(TSIP_Header.tsip_header_type_t.Subscription_State) as TSIP_HeaderSubscriptionState; if (hdr_state != null && hdr_state.Expires > 0) { expires = TSK_Time.Seconds2Milliseconds(hdr_state.Expires); goto compute; } } /*== Expires header */ if ((hdr = response.GetHeader(TSIP_Header.tsip_header_type_t.Expires)) != null) { expires = TSK_Time.Seconds2Milliseconds((hdr as TSIP_HeaderExpires).DeltaSeconds); goto compute; } /*== Contact header */ for (i = 0; (hdr = response.GetHeaderAtIndex(TSIP_Header.tsip_header_type_t.Contact, i)) != null; i++) { TSIP_HeaderContact contact = hdr as TSIP_HeaderContact; if (contact != null && contact.Uri != null) { String transport = TSK_Param.GetValueByName(contact.Uri.Params, "transport"); TSIP_Uri contactUri = this.Stack.GetContactUri(String.IsNullOrEmpty(transport) ? "udp" : transport); if (contactUri != null) { if (String.Equals(contact.Uri.UserName, contactUri.UserName) && String.Equals(contact.Uri.Host, contactUri.Host) && contact.Uri.Port == contactUri.Port) { if (contact.Expires >= 0) /* No expires parameter ==> -1*/ { expires = TSK_Time.Seconds2Milliseconds(contact.Expires); goto compute; } } } } } /* * 3GPP TS 24.229 - * * The UE shall reregister the public user identity either 600 seconds before the expiration time if the initial * registration was for greater than 1200 seconds, or when half of the time has expired if the initial registration * was for 1200 seconds or less. */ compute: expires = TSK_Time.Milliseconds2Seconds(expires); newdelay = (expires > 1200) ? (expires - 600) : (expires / 2); return(TSK_Time.Seconds2Milliseconds(newdelay)); }
protected TSIP_Request CreateRequest(String method) { TSIP_Request request = null; TSIP_Uri to_uri, from_uri, request_uri; String call_id; int copy_routes_start = -1; /* NONE */ /* * RFC 3261 - 12.2.1.1 Generating the Request * * The Call-ID of the request MUST be set to the Call-ID of the dialog. */ call_id = mCallId; /* * RFC 3261 - 12.2.1.1 Generating the Request * * Requests within a dialog MUST contain strictly monotonically * increasing and contiguous CSeq sequence numbers (increasing-by-one) * in each direction (excepting ACK and CANCEL of course, whose numbers * equal the requests being acknowledged or cancelled). Therefore, if * the local sequence number is not empty, the value of the local * sequence number MUST be incremented by one, and this value MUST be * placed into the CSeq header field. */ /*if(!tsk_striequals(method, "ACK") && !tsk_striequals(method, "CANCEL")) * { * TSIP_DIALOG(self)->cseq_value +=1; * } * ===> See send method (cseq will be incremented before sending the request) */ /* * RFC 3261 - 12.2.1.1 Generating the Request * * The URI in the To field of the request MUST be set to the remote URI * from the dialog state. The tag in the To header field of the request * MUST be set to the remote tag of the dialog ID. The From URI of the * request MUST be set to the local URI from the dialog state. The tag * in the From header field of the request MUST be set to the local tag * of the dialog ID. If the value of the remote or local tags is null, * the tag parameter MUST be omitted from the To or From header fields, * respectively. */ to_uri = mUriRemote; from_uri = mUriLocal; /* * RFC 3261 - 12.2.1.1 Generating the Request * * If the route set is empty, the UAC MUST place the remote target URI * into the Request-URI. The UAC MUST NOT add a Route header field to * the request. */ if (mRecordRoutes == null || mRecordRoutes.Count == 0) { request_uri = mUriRemoteTarget; } /* * RFC 3261 - 12.2.1.1 Generating the Request * * If the route set is not empty, and the first URI in the route set * contains the lr parameter (see Section 19.1.1), the UAC MUST place * the remote target URI into the Request-URI and MUST include a Route * header field containing the route set values in order, including all * parameters. * * If the route set is not empty, and its first URI does not contain the * lr parameter, the UAC MUST place the first URI from the route set * into the Request-URI, stripping any parameters that are not allowed * in a Request-URI. The UAC MUST add a Route header field containing * the remainder of the route set values in order, including all * parameters. The UAC MUST then place the remote target URI into the * Route header field as the last value. * * For example, if the remote target is sip:user@remoteua and the route * set contains: * * <sip:proxy1>,<sip:proxy2>,<sip:proxy3;lr>,<sip:proxy4> */ else { TSIP_Uri first_route = mRecordRoutes[0].Uri; if (TSK_Param.HasParam(first_route.Params, "lr")) { request_uri = mUriRemoteTarget; copy_routes_start = 0; /* Copy all */ } else { request_uri = first_route; copy_routes_start = 1; /* Copy starting at index 1. */ } } /*===================================================================== */ request = new TSIP_Request(method, request_uri, from_uri, to_uri, call_id, (Int32)mCSeqValue); request.To.Tag = mTagRemote; request.From.Tag = mTagLocal; request.ShouldUpdate = true; /* Now signal that the message should be updated by the transport layer (Contact, SigComp, IPSec, ...) */ /* * RFC 3261 - 12.2.1.1 Generating the Request * * A UAC SHOULD include a Contact header field in any target refresh * requests within a dialog, and unless there is a need to change it, * the URI SHOULD be the same as used in previous requests within the * dialog. If the "secure" flag is true, that URI MUST be a SIPS URI. * As discussed in Section 12.2.2, a Contact header field in a target * refresh request updates the remote target URI. This allows a UA to * provide a new contact address, should its address change during the * duration of the dialog. */ switch (request.RequestType) { case TSIP_Message.tsip_request_type_t.MESSAGE: case TSIP_Message.tsip_request_type_t.PUBLISH: case TSIP_Message.tsip_request_type_t.BYE: { if (request.RequestType == TSIP_Message.tsip_request_type_t.PUBLISH) { request.AddHeader(new TSIP_HeaderExpires(mExpires)); } /* add caps in Accept-Contact headers */ foreach (TSK_Param param in mSipSession.Caps) { request.AddHeader(new TSIP_HeaderDummy("Accept-Contact", String.Format("*;{0}{1}{2}", param.Name, !String.IsNullOrEmpty(param.Value) ? "=" : String.Empty, !String.IsNullOrEmpty(param.Value) ? param.Value : String.Empty) )); } break; } default: { String contact = null; List <TSIP_HeaderContact> hdr_contacts = null; if (request.RequestType == TSIP_Message.tsip_request_type_t.OPTIONS || request.RequestType == TSIP_Message.tsip_request_type_t.PUBLISH || request.RequestType == TSIP_Message.tsip_request_type_t.REGISTER) { /**** with expires */ contact = String.Format("m: <{0}:{1}@{2}:{3}>;expires={4}\r\n", "sip", from_uri.UserName, "127.0.0.1", 5060, TSK_Time.Milliseconds2Seconds(mExpires)); } else { /**** without expires */ if (request.RequestType == TSIP_Message.tsip_request_type_t.SUBSCRIBE) { /* RFC 3265 - 3.1.1. Subscription Duration * An "expires" parameter on the "Contact" header has no semantics for SUBSCRIBE and is explicitly * not equivalent to an "Expires" header in a SUBSCRIBE request or response. */ request.AddHeader(new TSIP_HeaderExpires(TSK_Time.Milliseconds2Seconds(mExpires))); } contact = String.Format("m: <{0}:{1}@{2}:{3}>\r\n", "sip", from_uri.UserName, "127.0.0.1", 5060); } hdr_contacts = TSIP_HeaderContact.Parse(contact); if (hdr_contacts != null && hdr_contacts.Count > 0) { request.Contact = hdr_contacts[0]; } /* Add capabilities as per RFC 3840 */ if (request.Contact != null) { foreach (TSK_Param param in mSipSession.Caps) { request.Contact.Params = TSK_Param.AddParam(request.Contact.Params, param.Name, param.Value); } } break; } } /* Update authorizations */ if (mState == tsip_dialog_state_t.Initial && mChallenges == null || mChallenges.Count == 0) { /* 3GPP TS 33.978 6.2.3.1 Procedures at the UE * On sending a REGISTER request in order to indicate support for early IMS security procedures, the UE shall not * include an Authorization header field and not include header fields or header field values as required by RFC3329. */ if (request.IsREGISTER && !this.Stack.EarlyIMS) { /* 3GPP TS 24.229 - 5.1.1.2.2 Initial registration using IMS AKA * On sending a REGISTER request, the UE shall populate the header fields as follows: * a) an Authorization header field, with: * - the "username" header field parameter, set to the value of the private user identity; * - the "realm" header field parameter, set to the domain name of the home network; * - the "uri" header field parameter, set to the SIP URI of the domain name of the home network; * - the "nonce" header field parameter, set to an empty value; and * - the "response" header field parameter, set to an empty value; */ String realm = this.Stack.Realm != null ? this.Stack.Realm.Host : "(null)"; String request_uri_ = TSIP_Uri.ToString(request.Uri, false, false); TSIP_Header auth_hdr = TSIP_Challenge.CreateEmptyAuthorization(this.Stack.PrivateIdentity, realm, request_uri_); if (auth_hdr != null) { request.AddHeader(auth_hdr); } } } else if (mChallenges != null && mChallenges.Count > 0) { TSIP_Header auth_hdr; foreach (TSIP_Challenge challenge in mChallenges) { auth_hdr = challenge.CreateHeaderAuthorization(request); if (auth_hdr != null) { request.AddHeader(auth_hdr); } } } /* Update CSeq */ /* RFC 3261 - 13.2.2.4 2xx Responses * Generating ACK: The sequence number of the CSeq header field MUST be * the same as the INVITE being acknowledged, but the CSeq method MUST * be ACK. The ACK MUST contain the same credentials as the INVITE. If * the 2xx contains an offer (based on the rules above), the ACK MUST * carry an answer in its body. * ==> CSeq number will be added/updated by the caller of this function, * credentials were added above. */ if (!request.IsACK && !request.IsCANCEL) { request.CSeq.CSeq = ++mCSeqValue; } /* Route generation * ==> http://betelco.blogspot.com/2008/11/proxy-and-service-route-discovery-in.html * The dialog Routes have been copied above. * * 3GPP TS 24.229 - 5.1.2A.1 UE-originating case * * The UE shall build a proper preloaded Route header field value for all new dialogs and standalone transactions. The UE * shall build a list of Route header field values made out of the following, in this order: * a) the P-CSCF URI containing the IP address or the FQDN learnt through the P-CSCF discovery procedures; and * b) the P-CSCF port based on the security mechanism in use: * * - if IMS AKA or SIP digest with TLS is in use as a security mechanism, the protected server port learnt during * the registration procedure; * - if SIP digest without TLS, NASS-IMS bundled authentciation or GPRS-IMS-Bundled authentication is in * use as a security mechanism, the unprotected server port used during the registration procedure; * c) and the values received in the Service-Route header field saved from the 200 (OK) response to the last * registration or re-registration of the public user identity with associated contact address. */ if (!request.IsREGISTER) { // According to the above link ==> Initial/Re/De registration do not have routes. if (copy_routes_start != -1) { /* The dialog already have routes ==> copy them. */ if (mState == tsip_dialog_state_t.Early || mState == tsip_dialog_state_t.Established) { Int32 index = -1; foreach (TSIP_HeaderRecordRoute record_route in mRecordRoutes) { TSIP_Uri uri = record_route.Uri; if (++index < copy_routes_start || uri == null) { continue; } TSIP_HeaderRoute route = new TSIP_HeaderRoute(uri); // copy parameters: see http://code.google.com/p/imsdroid/issues/detail?id=52 route.Params.AddRange(record_route.Params); request.AddHeader(route); } } } } else {/* No routes associated to this dialog. */ if (mState == tsip_dialog_state_t.Initial || mState == tsip_dialog_state_t.Early) { /* GPP TS 24.229 section 5.1.2A [Generic procedures applicable to all methods excluding the REGISTER method]: * The UE shall build a proper preloaded Route header field value for all new dialogs and standalone transactions. The UE * shall build a list of Route header field values made out of the following, in this order: * a) the P-CSCF URI containing the IP address or the FQDN learnt through the P-CSCF discovery procedures; and * b) the P-CSCF port based on the security mechanism in use: * - if IMS AKA or SIP digest with TLS is in use as a security mechanism, the protected server port learnt during * the registration procedure; * - if SIP digest without TLS, NASS-IMS bundled authentciation or GPRS-IMS-Bundled authentication is in * use as a security mechanism, the unprotected server port used during the registration procedure; * c) and the values received in the Service-Route header field saved from the 200 (OK) response to the last * registration or re-registration of the public user identity with associated contact address. */ #if _DEBUG && SDS_HACK /* Ericsson SDS hack (INVITE with Proxy-CSCF as First route fail) */ #else TSIP_Uri uri = this.Stack.GetProxyCSCFUri(true); // Proxy-CSCF as first route if (uri != null) { request.AddHeader(new TSIP_HeaderRoute(uri)); } #endif // Service routes foreach (TSIP_Uri uriServiceRoute in mServiceRoutes) { request.AddHeader(new TSIP_HeaderRoute(uriServiceRoute)); } } } /* Add headers associated to the dialog's session */ foreach (TSK_Param param in mSipSession.Headers) { request.AddHeader(new TSIP_HeaderDummy(param.Name, param.Value)); } /* Add headers associated to the dialog's stack */ foreach (TSK_Param param in this.Stack.Headers) { request.AddHeader(new TSIP_HeaderDummy(param.Name, param.Value)); } /* Add common headers */ this.AddCommonHeaders(request); /* SigComp */ return(request); }