| module SIP_Templates { |
| |
| import from SIPmsg_Types all; |
| import from Osmocom_Types all; |
| |
| /* wrapper type to encapsulate the Addr_Union + parameter list used in From, To. ... */ |
| type record SipAddr { |
| Addr_Union addr, |
| SemicolonParam_List params optional |
| } |
| |
| const charstring c_SIP_VERSION := "SIP/2.0"; |
| |
| template (value) SipUrl ts_SipUrl(template (value) HostPort host_port, |
| template (omit) UserInfo user_info := omit) := { |
| scheme := "sip", |
| userInfo := user_info, |
| hostPort := host_port, |
| urlParameters := omit, |
| headers := omit |
| } |
| template (present) SipUrl tr_SipUrl(template (present) HostPort host_port := ?, |
| template UserInfo user_info := *) := { |
| scheme := "sip", |
| userInfo := user_info, |
| hostPort := host_port, |
| urlParameters := *, |
| headers := * |
| } |
| |
| template (value) SipUrl ts_SipUrlHost(template (value) charstring host) |
| := ts_SipUrl(ts_HostPort(host)); |
| |
| // [20.10] |
| template (present) NameAddr tr_NameAddr(template (present) SipUrl addrSpec := ?, |
| template charstring displayName := *) := { |
| displayName := displayName, |
| addrSpec := addrSpec |
| } |
| template (value) NameAddr ts_NameAddr(template (value) SipUrl addrSpec, |
| template (omit) charstring displayName := omit) := { |
| displayName := displayName, |
| addrSpec := addrSpec |
| } |
| |
| template (present) Addr_Union tr_Addr_Union_NameAddr(template (present) NameAddr nameAddr := ?) := { |
| nameAddr := nameAddr |
| } |
| template (value) Addr_Union ts_Addr_Union_NameAddr(template (value) NameAddr nameAddr) := { |
| nameAddr := nameAddr |
| } |
| |
| template (present) Addr_Union tr_Addr_Union_SipUrl(template (present) SipUrl sipUrl := ?) := { |
| addrSpecUnion := sipUrl |
| } |
| template (value) Addr_Union ts_Addr_Union_SipUrl(template (value) SipUrl sipUrl) := { |
| addrSpecUnion := sipUrl |
| } |
| |
| |
| template (present) ContactAddress tr_ContactAddress(template (present) Addr_Union addressField := ?, |
| template SemicolonParam_List contactParams := *) := { |
| addressField := addressField, |
| contactParams := contactParams |
| } |
| template (value) ContactAddress ts_ContactAddress(template (value) Addr_Union addressField, |
| template (omit) SemicolonParam_List contactParams := omit) := { |
| addressField := addressField, |
| contactParams := contactParams |
| } |
| |
| template (present) Contact tr_Contact(template (present) ContactAddress_List contactAddresses := ?) := { |
| fieldName := CONTACT_E, |
| contactBody := { |
| contactAddresses := contactAddresses |
| } |
| } |
| template (value) Contact ts_Contact(template (value) ContactAddress_List contactAddresses) := { |
| fieldName := CONTACT_E, |
| contactBody := { |
| contactAddresses := contactAddresses |
| } |
| } |
| |
| template (value) Contact ts_ContactWildcard := { |
| fieldName := CONTACT_E, |
| contactBody := { |
| wildcard := "*" |
| } |
| } |
| |
| template (present) Contact tr_Contact_SipAddr(template (present) SipAddr contact_addr := ?) |
| := tr_Contact({ tr_ContactAddress(contact_addr.addr, contact_addr.params) }); |
| |
| private function f_tr_Contact_SipAddr(template SipAddr contact_addr) return template Contact |
| { |
| if (istemplatekind(contact_addr, "omit")) { |
| return omit; |
| } else if (istemplatekind(contact_addr, "*")) { |
| return *; |
| } |
| return tr_Contact_SipAddr(contact_addr); |
| } |
| |
| template (value) Contact ts_Contact_SipAddr(template (value) SipAddr contact_addr) |
| := ts_Contact({ ts_ContactAddress(contact_addr.addr, contact_addr.params) }); |
| private function ts_Contact_SipAddr_omit(template (omit) SipAddr contact_addr := omit) return template (omit) Contact |
| { |
| if (istemplatekind(contact_addr, "omit")) { |
| return omit; |
| } |
| return ts_Contact_SipAddr(contact_addr); |
| } |
| |
| |
| // [20.19] |
| template (value) Expires ts_Expires(template (value) DeltaSec deltaSec := "7200") := { |
| fieldName := EXPIRES_E, |
| deltaSec := deltaSec |
| } |
| |
| template (value) SipAddr ts_SipAddr(template (value) HostPort host_port, |
| template (omit) UserInfo user_info := omit, |
| template (omit) charstring displayName := omit, |
| template (omit) SemicolonParam_List params := omit) := { |
| addr := { |
| nameAddr := { |
| displayName := displayName, |
| addrSpec := ts_SipUrl(host_port, user_info) |
| } |
| }, |
| params := params |
| } |
| template (present) SipAddr tr_SipAddr(template (present) HostPort host_port := ?, |
| template UserInfo user_info := *, |
| template charstring displayName := *, |
| template SemicolonParam_List params := *) := { |
| addr := { |
| nameAddr := { |
| displayName := displayName, |
| addrSpec := tr_SipUrl(host_port, user_info) |
| } |
| }, |
| params := params |
| } |
| |
| /* build a receive template from a value: substitute '*' for omit */ |
| function tr_SipAddr_from_val(SipAddr tin) return template (present) SipAddr { |
| var template (present) SipAddr ret := tin; |
| if (tin.addr.nameAddr.displayName == omit) { |
| ret.addr.nameAddr.displayName := *; |
| } |
| if (tin.addr.nameAddr.addrSpec.userInfo.password == omit) { |
| ret.addr.nameAddr.addrSpec.userInfo.password := *; |
| } |
| if (tin.params == omit) { |
| ret.params := *; |
| } |
| return ret; |
| } |
| |
| template (value) HostPort ts_HostPort(template (omit) charstring host := omit, |
| template (omit) integer portField := omit) := { |
| host := host, |
| portField := portField |
| } |
| function tr_HostPort(template HostPort hp) return template HostPort { |
| var template HostPort hpout := hp; |
| /* if the port number is 5060, it may be omitted */ |
| if (isvalue(hp.portField) and valueof(hp.portField) == 5060) { |
| hpout.portField := 5060 ifpresent; |
| } |
| return hpout; |
| } |
| |
| |
| template (value) UserInfo ts_UserInfo(template (value) charstring userOrTelephoneSubscriber, |
| template (omit) charstring password := omit) := { |
| userOrTelephoneSubscriber := userOrTelephoneSubscriber, |
| password := password |
| } |
| template (present) UserInfo tr_UserInfo(template (present) charstring userOrTelephoneSubscriber := ?, |
| template charstring password := *) := { |
| userOrTelephoneSubscriber := userOrTelephoneSubscriber, |
| password := password |
| } |
| |
| template (value) RequestLine ts_SIP_ReqLine(Method method, |
| template (value) SipUrl uri, |
| charstring ver := c_SIP_VERSION) := { |
| method := method, |
| requestUri := uri, |
| sipVersion := ver |
| } |
| template (present) RequestLine tr_SIP_ReqLine(template (present) Method method := ?, |
| template (present) SipUrl uri := ?, |
| template (present) charstring ver := c_SIP_VERSION) := { |
| method := method, |
| requestUri := uri, |
| sipVersion := ver |
| } |
| |
| template (value) StatusLine ts_SIP_StatusLine(integer status_code, charstring reason) := { |
| sipVersion := "SIP/2.0", |
| statusCode := status_code, |
| reasonPhrase := reason |
| } |
| template (present) StatusLine tr_SIP_StatusLine(template integer status_code, |
| template charstring reason) := { |
| sipVersion := "SIP/2.0", |
| statusCode := status_code, |
| reasonPhrase := reason |
| } |
| |
| |
| template (value) PDU_SIP_Request ts_SIP_req(template (value) RequestLine rl) := { |
| requestLine := rl, |
| msgHeader := c_SIP_msgHeader_empty, |
| messageBody := omit, |
| payload := omit |
| } |
| |
| const Method_List c_SIP_defaultMethods := { |
| "INVITE", "ACK", "BYE", "CANCEL", "OPTIONS", "PRACK", "MESSAGE", "SUBSCRIBE", |
| "NOTIFY", "REFER", "UPDATE" }; |
| |
| private function f_ContentTypeOrOmit(template (omit) ContentType ct, template (omit) charstring body) |
| return template (omit) ContentType { |
| /* if user explicitly stated no content type */ |
| if (istemplatekind(ct, "omit")) { |
| return omit; |
| } |
| /* if there's no body, then there's no content-type either */ |
| if (istemplatekind(body, "omit")) { |
| return omit; |
| } |
| return ct; |
| } |
| |
| template (value) ContentType ts_CT_SDP := { |
| fieldName := CONTENT_TYPE_E, |
| mediaType := "application/sdp" |
| }; |
| |
| template (value) Via ts_Via_from(template (value) HostPort addr) := { |
| fieldName := VIA_E, |
| viaBody := { |
| { |
| sentProtocol := { "SIP", "2.0", "UDP" }, |
| sentBy := addr, |
| viaParams := omit |
| } |
| } |
| } |
| template (present) Via tr_Via_from(template (present) HostPort host_port := ?, |
| template SemicolonParam_List viaParams := *) := { |
| fieldName := VIA_E, |
| viaBody := { |
| { |
| sentProtocol := { "SIP", "2.0", "UDP" }, |
| sentBy := host_port, |
| viaParams := viaParams |
| } |
| } |
| } |
| |
| template (value) MessageHeader ts_SIP_msgHeader_empty := c_SIP_msgHeader_empty; |
| template (value) MessageHeader |
| ts_SIP_msgh_std(template (value) CallidString call_id, |
| template (value) SipAddr from_addr, |
| template (value) SipAddr to_addr, |
| template (omit) Contact contact, |
| template (value) charstring method, |
| template (value) integer seq_nr, |
| template (value) Via via, |
| template (omit) ContentType content_type := omit, |
| template (value) Method_List allow_methods := c_SIP_defaultMethods, |
| template (omit) Expires expires := omit |
| ) modifies ts_SIP_msgHeader_empty := { |
| allow := { |
| fieldName := ALLOW_E, |
| methods := allow_methods |
| }, |
| callId := { |
| fieldName := CALL_ID_E, |
| callid := call_id |
| }, |
| contact := contact, |
| contentType := content_type, |
| cSeq := { |
| fieldName := CSEQ_E, |
| seqNumber := seq_nr, |
| method := method |
| }, |
| expires := expires, |
| fromField := { |
| fieldName := FROM_E, |
| addressField := from_addr.addr, |
| fromParams := from_addr.params |
| }, |
| toField := { |
| fieldName := TO_E, |
| addressField := to_addr.addr, |
| toParams := to_addr.params |
| }, |
| userAgent := { |
| fieldName := USER_AGENT_E, |
| userAgentBody := { |
| "osmo-ttcn3-hacks/0.23" |
| } |
| }, |
| via := via |
| } |
| |
| function tr_AllowMethods(template Method_List allow_methods) return template Allow { |
| if (istemplatekind(allow_methods, "omit")) { |
| return omit; |
| } else if (istemplatekind(allow_methods, "*")) { |
| return *; |
| } else if (istemplatekind(allow_methods, "?")) { |
| return ?; |
| } |
| var template (present) Allow ret := { |
| fieldName := ALLOW_E, |
| methods := allow_methods |
| } |
| return ret |
| } |
| |
| template (present) MessageHeader |
| tr_SIP_msgh_std(template CallidString call_id, |
| template SipAddr from_addr, |
| template SipAddr to_addr, |
| template Contact contact, |
| template (present) Via via := tr_Via_from(?), |
| template charstring method, |
| template ContentType content_type := *, |
| template integer seq_nr := ?, |
| template Method_List allow_methods := *, |
| template Expires expires := * |
| ) modifies t_SIP_msgHeader_any := { |
| allow := tr_AllowMethods(allow_methods), |
| callId := { |
| fieldName := CALL_ID_E, |
| callid := call_id |
| }, |
| contact := contact, |
| contentType := content_type, |
| cSeq := { |
| fieldName := CSEQ_E, |
| seqNumber := seq_nr, |
| method := method |
| }, |
| expires := expires, |
| fromField := { |
| fieldName := FROM_E, |
| addressField := from_addr.addr, |
| fromParams := from_addr.params |
| }, |
| toField := { |
| fieldName := TO_E, |
| addressField := to_addr.addr, |
| toParams := to_addr.params |
| }, |
| userAgent := *, |
| via := via |
| } |
| |
| |
| template (value) PDU_SIP_Request |
| ts_SIP_REGISTER(template (value) SipUrl sip_url_host_port, |
| template (value) CallidString call_id, |
| template (value) SipAddr from_addr, |
| template (value) SipAddr to_addr, |
| template (value) Via via, |
| integer seq_nr, |
| template (omit) Contact contact, |
| template (omit) Expires expires, |
| template (omit) charstring body := omit) := { |
| requestLine := ts_SIP_ReqLine(REGISTER_E, sip_url_host_port), |
| msgHeader := ts_SIP_msgh_std(call_id, from_addr, to_addr, contact, |
| "REGISTER", seq_nr, via, |
| f_ContentTypeOrOmit(ts_CT_SDP, body), |
| expires := expires), |
| messageBody := body, |
| payload := omit |
| } |
| template (present) PDU_SIP_Request |
| tr_SIP_REGISTER(template (present) SipUrl sip_url_host_port := ?, |
| template (present) CallidString call_id := ?, |
| template (present) SipAddr from_addr := ?, |
| template (present) SipAddr to_addr := ?, |
| template integer seq_nr := *, |
| template Contact contact := *, |
| template Expires expires := *, |
| template charstring body := *) := { |
| requestLine := tr_SIP_ReqLine(REGISTER_E, sip_url_host_port), |
| msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, contact, |
| tr_Via_from(tr_HostPort(from_addr.addr.nameAddr.addrSpec.hostPort)), |
| "INVITE", *, seq_nr, |
| expires := expires), |
| messageBody := body, |
| payload := omit |
| } |
| |
| template (value) PDU_SIP_Request |
| ts_SIP_INVITE(CallidString call_id, |
| SipAddr from_addr, |
| SipAddr to_addr, |
| integer seq_nr, |
| template (omit) charstring body := omit) := { |
| requestLine := ts_SIP_ReqLine(INVITE_E, to_addr.addr.nameAddr.addrSpec), |
| msgHeader := ts_SIP_msgh_std(call_id, from_addr, to_addr, |
| ts_Contact_SipAddr(from_addr), |
| "INVITE", seq_nr, |
| ts_Via_from(from_addr.addr.nameAddr.addrSpec.hostPort), |
| f_ContentTypeOrOmit(ts_CT_SDP, body)), |
| messageBody := body, |
| payload := omit |
| } |
| template (present) PDU_SIP_Request |
| tr_SIP_INVITE(template CallidString call_id, |
| template SipAddr from_addr, |
| template SipAddr to_addr, |
| template integer seq_nr, |
| template charstring body) := { |
| requestLine := tr_SIP_ReqLine(INVITE_E, to_addr.addr.nameAddr.addrSpec), |
| msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, ?, |
| tr_Via_from(tr_HostPort(from_addr.addr.nameAddr.addrSpec.hostPort)), |
| "INVITE", *, seq_nr), |
| messageBody := body, |
| payload := omit |
| } |
| |
| template (value) PDU_SIP_Request |
| ts_SIP_BYE(CallidString call_id, |
| SipAddr from_addr, |
| SipAddr to_addr, |
| integer seq_nr, |
| template (omit) charstring body) := { |
| requestLine := ts_SIP_ReqLine(BYE_E, to_addr.addr.nameAddr.addrSpec), |
| msgHeader := ts_SIP_msgh_std(call_id, from_addr, to_addr, omit, "BYE", seq_nr, |
| ts_Via_from(from_addr.addr.nameAddr.addrSpec.hostPort), |
| f_ContentTypeOrOmit(ts_CT_SDP, body)), |
| messageBody := body, |
| payload := omit |
| } |
| |
| template (present) PDU_SIP_Request |
| tr_SIP_BYE(template CallidString call_id, |
| template SipAddr from_addr, |
| template SipAddr to_addr, |
| template integer seq_nr, |
| template charstring body) := { |
| requestLine := tr_SIP_ReqLine(BYE_E, to_addr.addr.nameAddr.addrSpec), |
| msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, omit, |
| tr_Via_from(tr_HostPort(from_addr.addr.nameAddr.addrSpec.hostPort)), |
| "BYE", *, seq_nr), |
| messageBody := body, |
| payload := omit |
| } |
| |
| |
| template (value) PDU_SIP_Request |
| ts_SIP_ACK(CallidString call_id, |
| SipAddr from_addr, |
| SipAddr to_addr, |
| integer seq_nr, |
| template (omit) charstring body) := { |
| requestLine := ts_SIP_ReqLine(ACK_E, to_addr.addr.nameAddr.addrSpec), |
| msgHeader := ts_SIP_msgh_std(call_id, from_addr, to_addr, |
| ts_Contact_SipAddr(from_addr), |
| "ACK", seq_nr, |
| ts_Via_from(from_addr.addr.nameAddr.addrSpec.hostPort), |
| f_ContentTypeOrOmit(ts_CT_SDP, body)), |
| messageBody := body, |
| payload := omit |
| } |
| template (present) PDU_SIP_Request |
| tr_SIP_ACK(template CallidString call_id, |
| template SipAddr from_addr, |
| template SipAddr to_addr, |
| template integer seq_nr, |
| template charstring body) := { |
| requestLine := tr_SIP_ReqLine(ACK_E, to_addr.addr.nameAddr.addrSpec), |
| msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, *, |
| tr_Via_from(tr_HostPort(from_addr.addr.nameAddr.addrSpec.hostPort)), |
| "ACK", *, seq_nr), |
| messageBody := body, |
| payload := omit |
| } |
| |
| template (value) PDU_SIP_Response |
| ts_SIP_Response(CallidString call_id, |
| SipAddr from_addr, |
| SipAddr to_addr, |
| charstring method, |
| integer status_code, |
| integer seq_nr, |
| charstring reason, |
| Via via, |
| template (omit) charstring body := omit) := { |
| statusLine := ts_SIP_StatusLine(status_code, reason), |
| msgHeader := ts_SIP_msgh_std(call_id, from_addr, to_addr, omit, method, seq_nr, |
| via, f_ContentTypeOrOmit(ts_CT_SDP, body)), |
| messageBody := body, |
| payload := omit |
| } |
| |
| template (present) PDU_SIP_Response |
| tr_SIP_Response(template CallidString call_id, |
| template SipAddr from_addr, |
| template SipAddr to_addr, |
| template Contact contact, |
| template charstring method, |
| template integer status_code, |
| template integer seq_nr := ?, |
| template charstring reason := ?, |
| template charstring body := ?) := { |
| statusLine := tr_SIP_StatusLine(status_code, reason), |
| msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, contact, |
| tr_Via_from(tr_HostPort(from_addr.addr.nameAddr.addrSpec.hostPort)), |
| method, *, seq_nr), |
| messageBody := body, |
| payload := omit |
| } |
| |
| |
| /* RFC 3261 8.1.1.5: |
| * "The sequence number value MUST be expressible as a 32-bit unsigned integer |
| * and MUST be less than 2**31." |
| */ |
| function f_sip_rand_seq_nr() return integer { |
| /* 2**31 = 2147483648 */ |
| return f_rnd_int(2147483648) |
| } |
| |
| } |