### Description
I want convert INVITE message with SDP body to multypart body. To do this is used patch for reference kamailio.cfg ``` [root@safarov-dell kamailio]# diff -u kamailio.cfg kamailio2.cfg --- kamailio.cfg 2018-11-09 18:28:36.000000000 +0300 +++ kamailio2.cfg 2018-11-10 22:49:43.604132033 +0300 @@ -1,5 +1,10 @@ #!KAMAILIO # +#!define WITH_DEBUG +#!define WITH_MYSQL +#!define WITH_AUTH +#!define WITH_USRLOCDB +# # Kamailio (OpenSER) SIP Server v5.2 - default configuration script # - web: https://www.kamailio.org # - git: https://github.com/kamailio/kamailio @@ -286,6 +291,8 @@ loadmodule "debugger.so" #!endif
+loadmodule "textopsx.so" + # ----------------- setting module-specific parameters ---------------
@@ -495,6 +502,10 @@ # account only INVITEs if (is_method("INVITE")) { setflag(FLT_ACC); # do accounting + set_body_multipart("test", "text/plain", "delimiter"); + msg_apply_changes(); + # # $var(b) = "7e Od 04 55 75 69 20 4d 61 6b 65 43 61 6c 6c"; + # # append_body_part("$var(b)", "application/vnd.cirpack.isdn-ext", "signal;handling=required"); }
# dispatch requests to foreign domains ``` After `msg_apply_changes` kamailio send INVITE without original SDP and without trailing delimiter. ``` INVITE sip:safarov@192.168.100.28:43749;transport=tcp SIP/2.0 Record-Route: sip:192.168.100.31;transport=tcp;r2=on;lr Record-Route: sip:192.168.100.31;r2=on;lr Via: SIP/2.0/TCP 192.168.100.31;branch=z9hG4bK9a1.9a042f2f4fe26e1e0fa9b65185f3a733.0 Via: SIP/2.0/UDP 192.168.100.31:35060;received=192.168.100.31;rport=35060;branch=z9hG4bK1985869670 From: sip:safarov@aio.kazoo;tag=988293340 To: sip:safarov@aio.kazoo Call-ID: 1851253425 CSeq: 21 INVITE Contact: sip:safarov@192.168.100.31:35060 Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO Max-Forwards: 69 User-Agent: Linphone/3.6.1 (eXosip2/3.6.0) Subject: Phone call Content-Length: 60 Content-Type: multipart/mixed;boundary="delimiter" Mime-Version: 1.0
--delimiter Content-Type: text/plain
test --delimiter
``` ### Troubleshooting NA
#### Reproduction
1) Need to apply patch provided above; 2) create any sip account; 3) register SIP client using auth data for created sip account; 4) place call for created account.
#### Debugging Data
NA
#### Log Messages
[kamailio.log](https://github.com/kamailio/kamailio/files/2568706/kamailio.log)
#### SIP Traffic
[kamailio.pcapng.gz](https://github.com/kamailio/kamailio/files/2568707/kamailio.pcapng.gz)
### Possible Solutions
Not known
### Additional Information
* **Kamailio Version** - output of `kamailio -v` Tested current master ``` version: kamailio 5.3.0-dev0 (x86_64/linux) flags: STATS: Off, USE_TCP, USE_TLS, USE_SCTP, TLS_HOOKS, USE_RAW_SOCKS, DISABLE_NAGLE, USE_MCAST, DNS_IP_HACK, SHM_MEM, SHM_MMAP, PKG_MALLOC, Q_MALLOC, F_MALLOC, TLSF_MALLOC, DBG_SR_MEMORY, USE_FUTEX, FAST_LOCK-ADAPTIVE_WAIT, USE_DNS_CACHE, USE_DNS_FAILOVER, USE_NAPTR, USE_DST_BLACKLIST, HAVE_RESOLV_RES ADAPTIVE_WAIT_LOOPS=1024, MAX_RECV_BUFFER_SIZE 262144 MAX_URI_SIZE 1024, BUF_SIZE 65535, DEFAULT PKG_SIZE 8MB poll method support: poll, epoll_lt, epoll_et, sigio_rt, select. id: unknown compiled on 14:49:40 Nov 9 2018 with gcc 8.2.0 ```
* **Operating System**:
``` /etc/kamailio # cat /etc/os-release NAME="Alpine Linux" ID=alpine VERSION_ID=3.8.0 PRETTY_NAME="Alpine Linux v3.8" HOME_URL="http://alpinelinux.org" BUG_REPORT_URL="http://bugs.alpinelinux.org" /etc/kamailio # ```
INVITE after modification is present in packet 16 of pcap file
This may be related to log ``` 16(27) ERROR: {1 21 INVITE 1851253425} <core> [core/msg_translator.c:3290]: sip_msg_apply_changes(): cannot apply msg changes after adding record-route header - it breaks conditional 2nd header ``` Think in this case must be send original INVITE.
Same results when used UDP transport on caller and callee legs. And when `set_body_multipart` is applied at start of `request_route` block ``` /* Main SIP request routing logic * - processing of any incoming SIP request starts with this route * - note: this is the same as route { ... } */ request_route { if (is_method("INVITE")) { set_body_multipart("test", "text/plain", "delimiter"); msg_apply_changes(); # # $var(b) = "7e Od 04 55 75 69 20 4d 61 6b 65 43 61 6c 6c"; # # append_body_part("$var(b)", "application/vnd.cirpack.isdn-ext", "signal;handling=required"); }
# per request initial checks route(REQINIT); ```
``` 26(174) DEBUG: tm [h_table.c:133]: free_cell_helper(): freeing transaction 0x7f289269dd08 from timer.c:654 16(164) DEBUG: <core> [core/udp_server.c:514]: udp_rcv_loop(): probing packet received from 192.168.100.28 50195 13(161) DEBUG: <core> [core/udp_server.c:491]: udp_rcv_loop(): received on udp socket: (106/100/820) [[INVITE sip:safarov@aio.kazoo SIP/2.0 0D 0A Via: SIP/2.0/UDP 192.168.100.31:35060;rport;branch=z9hG4bK1459]] 13(161) DEBUG: <core> [core/parser/msg_parser.c:610]: parse_msg(): SIP Request: 13(161) DEBUG: <core> [core/parser/msg_parser.c:612]: parse_msg(): method: <INVITE> 13(161) DEBUG: <core> [core/parser/msg_parser.c:614]: parse_msg(): uri: sip:safarov@aio.kazoo 13(161) DEBUG: <core> [core/parser/msg_parser.c:616]: parse_msg(): version: <SIP/2.0> 13(161) DEBUG: <core> [core/parser/parse_via.c:1303]: parse_via_param(): Found param type 235, <rport> = <n/a>; state=6 13(161) DEBUG: <core> [core/parser/parse_via.c:1303]: parse_via_param(): Found param type 232, <branch> = <z9hG4bK1459394859>; state=16 13(161) DEBUG: <core> [core/parser/parse_via.c:2639]: parse_via(): end of header reached, state=5 13(161) DEBUG: <core> [core/parser/msg_parser.c:498]: parse_headers(): Via found, flags=2 13(161) DEBUG: <core> [core/parser/msg_parser.c:500]: parse_headers(): this is the first via 13(161) DEBUG: <core> [core/parser/parse_addr_spec.c:864]: parse_addr_spec(): end of header reached, state=10 13(161) DEBUG: <core> [core/parser/msg_parser.c:171]: get_hdr_field(): <To> [25]; uri=[sip:safarov@aio.kazoo] 13(161) DEBUG: <core> [core/parser/msg_parser.c:174]: get_hdr_field(): to body [sip:safarov@aio.kazoo ], to tag [] 13(161) DEBUG: <core> [core/parser/msg_parser.c:152]: get_hdr_field(): cseq <CSeq>: <20> <INVITE> 13(161) DEBUG: <core> [core/receive.c:240]: receive_msg(): --- received sip message - request - call-id: [392320003] - cseq: [20 INVITE] 13(161) DEBUG: <core> [core/parser/msg_parser.c:185]: get_hdr_field(): content_length=333 13(161) DEBUG: <core> [core/parser/msg_parser.c:89]: get_hdr_field(): found end of header 13(161) DEBUG: {1 20 INVITE 392320003} <core> [core/receive.c:295]: receive_msg(): preparing to run routing scripts... 13(161) exec: {1 20 INVITE 392320003} *** cfgtrace:request_route=[DEFAULT_ROUTE] c=[/etc/kamailio/kamailio.cfg] l=471 a=16 n=if 13(161) exec: {1 20 INVITE 392320003} *** cfgtrace:request_route=[DEFAULT_ROUTE] c=[/etc/kamailio/kamailio.cfg] l=463 a=25 n=is_method 13(161) exec: {1 20 INVITE 392320003} *** cfgtrace:request_route=[DEFAULT_ROUTE] c=[/etc/kamailio/kamailio.cfg] l=464 a=27 n=set_body_multipart 13(161) DEBUG: {1 20 INVITE 392320003} textops [textops.c:2248]: ki_set_multibody(): delimiter<9>:[delimiter] 13(161) DEBUG: {1 20 INVITE 392320003} textops [textops.c:2139]: generate_boundary(): adding final CRLF+CRLF 13(161) DEBUG: {1 20 INVITE 392320003} textops [textops.c:2367]: ki_set_multibody(): content-type<52>:[Content-Type: multipart/mixed;boundary="delimiter" ] 13(161) DEBUG: {1 20 INVITE 392320003} textops [textops.c:2404]: ki_set_multibody(): set flag FL_BODY_MULTIPART 13(161) exec: {1 20 INVITE 392320003} *** cfgtrace:request_route=[DEFAULT_ROUTE] c=[/etc/kamailio/kamailio.cfg] l=465 a=24 n=msg_apply_changes 13(161) INFO: {1 20 INVITE 392320003} <core> [core/msg_translator.c:1716]: get_boundary(): Content-Type hdr has no params <application/sdp> 13(161) WARNING: {1 20 INVITE 392320003} <core> [core/msg_translator.c:1983]: build_req_buf_from_sip_req(): check_boundaries error 13(161) DEBUG: {1 20 INVITE 392320003} <core> [core/msg_translator.c:432]: clen_builder(): content-length: 60 (60) 13(161) DEBUG: {1 20 INVITE 392320003} <core> [core/msg_translator.c:3258]: sip_msg_update_buffer(): SIP message content updated - reparsing 13(161) DEBUG: {1 20 INVITE 392320003} <core> [core/parser/msg_parser.c:610]: parse_msg(): SIP Request: 13(161) DEBUG: {1 20 INVITE 392320003} <core> [core/parser/msg_parser.c:612]: parse_msg(): method: <INVITE> 13(161) DEBUG: {1 20 INVITE 392320003} <core> [core/parser/msg_parser.c:614]: parse_msg(): uri: sip:safarov@aio.kazoo 13(161) DEBUG: {1 20 INVITE 392320003} <core> [core/parser/msg_parser.c:616]: parse_msg(): version: <SIP/2.0> 13(161) DEBUG: {1 20 INVITE 392320003} <core> [core/parser/parse_via.c:1303]: parse_via_param(): Found param type 235, <rport> = <n/a>; state=6 13(161) DEBUG: {1 20 INVITE 392320003} <core> [core/parser/parse_via.c:1303]: parse_via_param(): Found param type 232, <branch> = <z9hG4bK1459394859>; state=16 13(161) DEBUG: {1 20 INVITE 392320003} <core> [core/parser/parse_via.c:2639]: parse_via(): end of header reached, state=5 13(161) DEBUG: {1 20 INVITE 392320003} <core> [core/parser/msg_parser.c:498]: parse_headers(): Via found, flags=2 13(161) DEBUG: {1 20 INVITE 392320003} <core> [core/parser/msg_parser.c:500]: parse_headers(): this is the first via 13(161) exec: {1 20 INVITE 392320003} *** cfgtrace:request_route=[DEFAULT_ROUTE] c=[/etc/kamailio/kamailio.cfg] l=471 a=5 n=route 13(161) exec: {1 20 INVITE 392320003} *** cfgtrace:request_route=[REQINIT] c=[/etc/kamailio/kamailio.cfg] l=583 a=16 n=if 13(161) DEBUG: {1 20 INVITE 392320003} <core> [core/parser/parse_addr_spec.c:864]: parse_addr_spec(): end of header reached, state=10 13(161) DEBUG: {1 20 INVITE 392320003} <core> [core/parser/msg_parser.c:171]: get_hdr_field(): <To> [25]; uri=[sip:safarov@aio.kazoo] 13(161) DEBUG: {1 20 INVITE 392320003} <core> [core/parser/msg_parser.c:174]: get_hdr_field(): to body [sip:safarov@aio.kazoo ], to tag [] 13(161) DEBUG: {1 20 INVITE 392320003} <core> [core/parser/msg_parser.c:152]: get_hdr_field(): cseq <CSeq>: <20> <INVITE> 13(161) exec: {1 20 INVITE 392320003} *** cfgtrace:request_route=[REQINIT] c=[/etc/kamailio/kamailio.cfg] l=588 a=16 n=if 13(161) exec: {1 20 INVITE 392320003} *** cfgtrace:request_route=[REQINIT] c=[/etc/kamailio/kamailio.cfg] l=583 a=25 n=mf_process_maxfwd_header 13(161) DEBUG: {1 20 INVITE 392320003} maxfwd [mf_funcs.c:74]: is_maxfwd_present(): value = 70 13(161) exec: {1 20 INVITE 392320003} *** cfgtrace:request_route=[REQINIT] c=[/etc/kamailio/kamailio.cfg] l=593 a=16 n=if 13(161) exec: {1 20 INVITE 392320003} *** cfgtrace:request_route=[REQINIT] c=[/etc/kamailio/kamailio.cfg] l=588 a=25 n=is_method 13(161) exec: {1 20 INVITE 392320003} *** cfgtrace:request_route=[REQINIT] c=[/etc/kamailio/kamailio.cfg] l=597 a=16 n=if 13(161) exec: {1 20 INVITE 392320003} *** cfgtrace:request_route=[REQINIT] c=[/etc/kamailio/kamailio.cfg] l=593 a=26 n=sanity_check 13(161) DEBUG: {1 20 INVITE 392320003} sanity [sanity.c:247]: check_ruri_sip_version(): check_ruri_sip_version entered 13(161) DEBUG: {1 20 INVITE 392320003} sanity [sanity.c:270]: check_ruri_sip_version(): check_ruri_sip_version passed 13(161) DEBUG: {1 20 INVITE 392320003} sanity [sanity.c:277]: check_ruri_scheme(): check_ruri_scheme entered 13(161) DEBUG: {1 20 INVITE 392320003} sanity [sanity.c:297]: check_ruri_scheme(): check_ruri_scheme passed 13(161) DEBUG: {1 20 INVITE 392320003} sanity [sanity.c:305]: check_required_headers(): check_required_headers entered 13(161) DEBUG: {1 20 INVITE 392320003} sanity [sanity.c:313]: check_required_headers(): check_required_headers passed 13(161) DEBUG: {1 20 INVITE 392320003} sanity [sanity.c:321]: check_via1_header(): check via1 header 13(161) DEBUG: {1 20 INVITE 392320003} sanity [sanity.c:479]: check_cseq_method(): check_cseq_method entered 13(161) DEBUG: {1 20 INVITE 392320003} sanity [sanity.c:512]: check_cseq_method(): check_cseq_method passed 13(161) DEBUG: {1 20 INVITE 392320003} sanity [sanity.c:521]: check_cseq_value(): check_cseq_value entered 13(161) DEBUG: {1 20 INVITE 392320003} sanity [sanity.c:549]: check_cseq_value(): check_cseq_value passed ```
This may be related to log
16(27) ERROR: {1 21 INVITE 1851253425} <core> [core/msg_translator.c:3290]: sip_msg_apply_changes(): cannot apply msg changes after adding record-route header - it breaks conditional 2nd header
Think in this case must be send original INVITE.
Hi. You need to do record_route() after convert body to multipart. I have this case in production. ``` if( is_method("INVITE") && has_body("application/sdp")) { if (msg_apply_changes()) { xlog("L_INFO", "ISUP 0 Changes Applied Succesfully"); } set_body_multipart(,"2123894789_1257887457"); if (msg_apply_changes()) { xlog("L_INFO", "ISUP 1 Changes Applied Succesfully"); } append_body_part_hex("01 10 48 00 0a 00 02 09 07 03 90 90 13 71 32 20 0a 04 02 13 73 12 00","application/isup;version=itu-t92+","signal;handling=optional"); if(msg_apply_changes()) { xlog("L_INFO", "ISUP 2 Changes Applied Succesfully $rU \n"); } record_route(); } ```
Thanks @sergey-vb I have done this and tested. Please looks messages 1) [config change](https://github.com/kamailio/kamailio/issues/1719#issuecomment-437619001); 2) [logs](https://github.com/kamailio/kamailio/issues/1719#issuecomment-437619183).
Sorry for delay. But according to doc for textops module: Set multipart body to a SIP message. If called with **no parameters, will convert present body** to multipart.
So if you have look at my part of CFG: 1. I use **set_body_multipart(,"2123894789_1257887457");** to convert Corrent current body with SDP to multipart. 2. then do **msg_apply_changes()** 3. next do **append_body_part_hex("01");** to append new part to current multipart body 4. do **msg_apply_changes()** to save changes into current message structure
It works normally in this way.
Thanks @sergey-vb I have tested your suggestions. In this case message is converted to multipart properly. Looks as issue when added new body part. Related to https://github.com/kamailio/kamailio/issues/1631
Is this a lack of mention in the docs that msg_apply_changes() has to be used?
Think requirement of use msg_apply_changes after `msg_apply_changes` is need to add. Is required add protections to prevent crash when admin not applied changes?
May be set flag that need to call `msg_apply_changes` and when call processing is finished check flag. If flag is set, then log error message or force apply `msg_apply_changes`.
Also questions Is need fix packet modifications when called "set_body_multipart" with 3 arguments? Please look original description.
In your 2nd comment above, I think you wrote same function name:
``` ... use msg_apply_changes after msg_apply_changes ... ```
probably you wanted to say a different function name there, right?
Daniel @miconda please look this [textops](https://www.kamailio.org/docs/modules/5.2.x/modules/textops.html#textops.f.s...) doc page Here is present usage example: ``` set_body_multipart("test", "text/plain", "delimiter"); msg_apply_changes(); append_body_part(...); ``` first two comands 1) convert body to multipart; 2) add payload with content type text/plain.
I have [tested this two commands](https://github.com/kamailio/kamailio/issues/1719#issuecomment-437619001). And this not produce valid body.
Trying to figure out what solution worked and has to be given in the docs -- is it the next one?
``` set_body_multipart("test", "text/plain", "delimiter"); msg_apply_changes(); append_body_part(...); msg_apply_changes(); ```
Is "append_body_part" usage mandatory here? Can we use next example if required "SDP + one additional content" ``` set_body_multipart("test", "text/plain", "delimiter"); msg_apply_changes(); ```
I added notes in docs that msg_apply_changes() may be required for each of multi-part manipulation functions. You can make pull requests if you want to add more there or other content.
Closed #1719.