Hello,
I'm attempting to load test a simple dispatcher script in OpenSER 1.3.x using SIPp (built-in UAC and UAS scenarios). My dispatcher.list only has one address 8.XX.XX.12 (a SIPp instance, UAS). SIPp on 8.XX.XX.10 sends the INVITE messages to 63.XXX.XXX.110. Everything goes well until the UAC sends ACK and BYE in quick sequence. OpenSER tries to t_relay() it to itself, which results in a "too many hops" error:
2008-08-18 11:16:56:708 1219072616.708649: Aborting call on unexpected message for Call-Id '1-3548@8.XX.XX.10': while expecting '200' (index 8), received 'SIP/2.0 483 To Many Hops Via: SIP/2.0/UDP 8.XX.XX.10:5061;branch=z9hG4bK-3548-1-7 From: sipp sip:sipp@8.XX.XX.10:5061;tag=3548SIPpTag001 To: sut sip:service@63.XXX.XXX.110:5060;tag=2148SIPpTag011 Call-ID: 1-3548@8.XX.XX.10 CSeq: 2 BYE Server: OpenSER (1.3.2-notls (x86_64/linux)) Content-Length: 0
I have tried modifying the SIPp UAC script to re-use the Contact: header from the SIP 200 OK message in the R-URI of the SIP ACK and SIP BYE, to no avail. I have loaded the TM module but I suppose that since the SIP 200 OK is the final message of the transaction, SIP ACK and SIP BYE won't automatically be relayed to 8.XX.XX.12.
Is this an OpenSER issue or a SIPp scripting issue? Any advice would be appreciated. Please find below some relevant lines from my openser.cfg:
route{ xlog("TRACE:ROUTE: src($si:$sp) dst($Ri:$Rp) msg($mb)\n");
# initial checkings if ( !mf_process_maxfwd_header("10") ) { xlog("SCRIPT:ERROR: $rm (from $si:$sp) too many hops\n"); sl_send_reply("483","To Many Hops"); exit; };
if (method==CANCEL) { if (t_check_trans()) t_relay(); exit; }
# routing if (has_totag()) { xlog("SCRIPT0:INFO: $rm RURI=[$ru] - routing to dst-uri [$du] cnt [$avp(i:273)] dst set [$avp(i:271)]\n"); loose_route(); if (method=="INVITE") record_route(); route(1); exit; }
The SIP ACK and SIP BYE follow the route defined in the above if {} statement. The SIP INVITE follows the dispatcher route shown below:
record_route();
# perform load balancing
# set algorithm (4 = round robin) $avp(alg) = 4; # set the group $avp(grp) = 2;
if (method=="INVITE") xlog("CALL_START: RURI=[$ru] group=[$avp(grp)] callid=$ci\n");
# do balancing if(!ds_select_dst("$avp(grp)", "$avp(alg)")) { xlog("CALL_DROP:INTERNAL: no destinations for [$ru] group=[$avp(grp)], callid=$ci\n"); sl_send_reply("404", "no dst"); exit; }
if(avp_check("$avp(i:273)", "eq/i:1")) { if(!avp_pushto("$ruri","$avp(i:271)")) { xlog("CALL_DROP:INTERNAL: cannot push to ruri [$avp(i:271)], group=[$avp(grp)], callid=$ci\n"); sl_send_reply("500", "cannot get dst"); exit; } } else { # redundancy t_on_failure("1"); }
xlog("SCRIPT:INFO: $rm RURI=[$ru] - routing to dst-uri [$du] cnt [$avp(i:273)] dst set [$avp(i:271)]\n");
# do forward route(1); exit;
Hello,
is your sipp script dealing with record routing properly? Can you post a sample sip call from invite to bye (e.g., ngrep trace)? Will show better whose fault is. I doubt it has something to do with openser.
Cheers, Daniel
On 08/18/08 18:48, sergejf wrote:
Hello,
I'm attempting to load test a simple dispatcher script in OpenSER 1.3.x using SIPp (built-in UAC and UAS scenarios). My dispatcher.list only has one address 8.XX.XX.12 (a SIPp instance, UAS). SIPp on 8.XX.XX.10 sends the INVITE messages to 63.XXX.XXX.110. Everything goes well until the UAC sends ACK and BYE in quick sequence. OpenSER tries to t_relay() it to itself, which results in a "too many hops" error:
2008-08-18 11:16:56:708 1219072616.708649: Aborting call on unexpected message for Call-Id '1-3548@8.XX.XX.10': while expecting '200' (index 8), received 'SIP/2.0 483 To Many Hops Via: SIP/2.0/UDP 8.XX.XX.10:5061;branch=z9hG4bK-3548-1-7 From: sipp sip:sipp@8.XX.XX.10:5061;tag=3548SIPpTag001 To: sut sip:service@63.XXX.XXX.110:5060;tag=2148SIPpTag011 Call-ID: 1-3548@8.XX.XX.10 CSeq: 2 BYE Server: OpenSER (1.3.2-notls (x86_64/linux)) Content-Length: 0
I have tried modifying the SIPp UAC script to re-use the Contact: header from the SIP 200 OK message in the R-URI of the SIP ACK and SIP BYE, to no avail. I have loaded the TM module but I suppose that since the SIP 200 OK is the final message of the transaction, SIP ACK and SIP BYE won't automatically be relayed to 8.XX.XX.12.
Is this an OpenSER issue or a SIPp scripting issue? Any advice would be appreciated. Please find below some relevant lines from my openser.cfg:
route{ xlog("TRACE:ROUTE: src($si:$sp) dst($Ri:$Rp) msg($mb)\n");
# initial checkings if ( !mf_process_maxfwd_header("10") ) { xlog("SCRIPT:ERROR: $rm (from $si:$sp) too many hops\n"); sl_send_reply("483","To Many Hops"); exit; }; if (method==CANCEL) { if (t_check_trans()) t_relay(); exit; } # routing if (has_totag()) { xlog("SCRIPT0:INFO: $rm RURI=[$ru] - routing to dst-uri
[$du] cnt [$avp(i:273)] dst set [$avp(i:271)]\n"); loose_route(); if (method=="INVITE") record_route(); route(1); exit; }
The SIP ACK and SIP BYE follow the route defined in the above if {} statement. The SIP INVITE follows the dispatcher route shown below:
record_route(); # perform load balancing # set algorithm (4 = round robin) $avp(alg) = 4; # set the group $avp(grp) = 2; if (method=="INVITE") xlog("CALL_START: RURI=[$ru] group=[$avp(grp)]
callid=$ci\n");
# do balancing if(!ds_select_dst("$avp(grp)", "$avp(alg)")) { xlog("CALL_DROP:INTERNAL: no destinations for [$ru]
group=[$avp(grp)], callid=$ci\n"); sl_send_reply("404", "no dst"); exit; }
if(avp_check("$avp(i:273)", "eq/i:1")) { if(!avp_pushto("$ruri","$avp(i:271)")) { xlog("CALL_DROP:INTERNAL: cannot push to ruri
[$avp(i:271)], group=[$avp(grp)], callid=$ci\n"); sl_send_reply("500", "cannot get dst"); exit; } } else { # redundancy t_on_failure("1"); }
xlog("SCRIPT:INFO: $rm RURI=[$ru] - routing to dst-uri [$du] cnt
[$avp(i:273)] dst set [$avp(i:271)]\n");
# do forward route(1); exit;
Hi Daniel,
Please find below the capture of a call from INVITE to BYE using the default SIPp UAC and UAS scenarios that I modified to copy the Contact: header content to the R-URI of ACK and BYE and the Record-Route: header content to Route: (though I'm not sure whether it is the desired behaviour; I just based it on traces I saw from successful calls to a VoIP carrier going through the same OpenSER configuration). The call fails with a SIP 503 at the very end.
There is also a SIP INVITE retransmit from OpenSER that I do not understand - why does the OpenSER do this? Since the UAS scenario of SIPp doesn't expect that SIP INVITE it aborts with an "unexpected message" condition. Further BYE messages are not answered by SIPp UAS.
The scenario actually works for the first few calls. I had up to 10 calls processed successfully like that. It starts failing when more calls are made (e.g. 50) and unexpected SIP messages start to occur.
I hope the trace below helps in figuring out whether Record Routing handling in SIPp is the culprit here.
Thanks a lot for your help.
Serge
14:28:33.902070 IP (tos 0x0, ttl 124, id 14924, offset 0, flags [none], proto: UDP (17), length: 542) tmo120.sip-tls > sip100.sip: [udp sum ok] SIP, length: 514 INVITE sip:service@63.XXX.XX.110:5060 SIP/2.0 Via: SIP/2.0/UDP 8.XX.XX.10:5061;branch=z9hG4bK-4068-8-0 From: sipp sip:sipp@8.XX.XX.10:5061;tag=4068SIPpTag008 To: sut sip:service@63.XXX.XX.110:5060 Call-ID: 8-4068@8.XX.XX.10 CSeq: 1 INVITE Contact: sip:sipp@8.XX.XX.10:5061 Max-Forwards: 70 Subject: Performance Test Content-Type: application/sdp Content-Length: 129
v=0 o=user1 53655765 2353687637 IN IP4 8.XX.XX.10 s=- c=IN IP4 8.XX.XX.10 t=0 0 m=audio 6000 RTP/AVP 0 a=rtpmap:0 PCMU/8000
14:28:34.459706 IP (tos 0x10, ttl 64, id 0, offset 0, flags [DF], proto: UDP (17), length: 323) sip100.sip > tmo120.sip-tls: [bad udp cksum 3cbc!] SIP, length: 295 SIP/2.0 100 Giving a try Via: SIP/2.0/UDP 8.XX.XX.10:5061;branch=z9hG4bK-4068-8-0 From: sipp sip:sipp@8.XX.XX.10:5061;tag=4068SIPpTag008 To: sut sip:service@63.XXX.XX.110:5060 Call-ID: 8-4068@8.XX.XX.10 CSeq: 1 INVITE Server: OpenSER (1.3.2-notls (x86_64/linux)) Content-Length: 0
14:28:34.603824 IP (tos 0x10, ttl 64, id 0, offset 0, flags [DF], proto: UDP (17), length: 651) sip100.sip > tmo122.sip: [bad udp cksum 1e2f!] SIP, length: 623 INVITE sip:8.XX.XX.12:5060 SIP/2.0 Record-Route: sip:63.XXX.XX.110;lr;ftag=4068SIPpTag008 Via: SIP/2.0/UDP 63.XXX.XX.110;branch=z9hG4bK5016.872b3ad4.0 Via: SIP/2.0/UDP 8.XX.XX.10:5061;branch=z9hG4bK-4068-8-0 From: sipp sip:sipp@8.XX.XX.10:5061;tag=4068SIPpTag008 To: sut sip:service@63.XXX.XX.110:5060 Call-ID: 8-4068@8.XX.XX.10 CSeq: 1 INVITE Contact: sip:sipp@8.XX.XX.10:5061 Max-Forwards: 12 Subject: Performance Test Content-Type: application/sdp Content-Length: 129
v=0 o=user1 53655765 2353687637 IN IP4 8.XX.XX.10 s=- c=IN IP4 8.XX.XX.10 t=0 0 m=audio 6000 RTP/AVP 0 a=rtpmap:0 PCMU/8000
14:28:34.604602 IP (tos 0x0, ttl 124, id 20573, offset 0, flags [none], proto: UDP (17), length: 446) tmo122.sip > sip100.sip: [udp sum ok] SIP, length: 418 SIP/2.0 180 Ringing Via: SIP/2.0/UDP 63.XXX.XX.110;branch=z9hG4bK5016.872b3ad4.0, SIP/2.0/UDP 8.XX.XX.10:5061;branch=z9hG4bK-4068-8-0 From: sipp sip:sipp@8.XX.XX.10:5061;tag=4068SIPpTag008 To: sut sip:service@63.XXX.XX.110:5060;tag=2964SIPpTag018 Call-ID: 8-4068@8.XX.XX.10 CSeq: 1 INVITE Contact: sip:8.XX.XX.12:5060;transport=UDP Route: sip:63.XXX.XX.110;lr;ftag=4068SIPpTag008 Content-Length: 0
14:28:34.604936 IP (tos 0x0, ttl 124, id 20574, offset 0, flags [none], proto: UDP (17), length: 605) tmo122.sip > sip100.sip: [udp sum ok] SIP, length: 577 SIP/2.0 200 OK Via: SIP/2.0/UDP 63.XXX.XX.110;branch=z9hG4bK5016.872b3ad4.0, SIP/2.0/UDP 8.XX.XX.10:5061;branch=z9hG4bK-4068-8-0 From: sipp sip:sipp@8.XX.XX.10:5061;tag=4068SIPpTag008 To: sut sip:service@63.XXX.XX.110:5060;tag=2964SIPpTag018 Call-ID: 8-4068@8.XX.XX.10 CSeq: 1 INVITE Contact: sip:8.XX.XX.12:5060;transport=UDP Route: sip:63.XXX.XX.110;lr;ftag=4068SIPpTag008 Content-Type: application/sdp Content-Length: 129
v=0 o=user1 53655765 2353687637 IN IP4 8.XX.XX.12 s=- c=IN IP4 8.XX.XX.12 t=0 0 m=audio 6000 RTP/AVP 0 a=rtpmap:0 PCMU/8000
14:28:35.083466 IP (tos 0x10, ttl 64, id 0, offset 0, flags [DF], proto: UDP (17), length: 651) sip100.sip > tmo122.sip: [bad udp cksum 1e2f!] SIP, length: 623 INVITE sip:8.XX.XX.12:5060 SIP/2.0 Record-Route: sip:63.XXX.XX.110;lr;ftag=4068SIPpTag008 Via: SIP/2.0/UDP 63.XXX.XX.110;branch=z9hG4bK5016.872b3ad4.0 Via: SIP/2.0/UDP 8.XX.XX.10:5061;branch=z9hG4bK-4068-8-0 From: sipp sip:sipp@8.XX.XX.10:5061;tag=4068SIPpTag008 To: sut sip:service@63.XXX.XX.110:5060 Call-ID: 8-4068@8.XX.XX.10 CSeq: 1 INVITE Contact: sip:sipp@8.XX.XX.10:5061 Max-Forwards: 12 Subject: Performance Test Content-Type: application/sdp Content-Length: 129
v=0 o=user1 53655765 2353687637 IN IP4 8.XX.XX.10 s=- c=IN IP4 8.XX.XX.10 t=0 0 m=audio 6000 RTP/AVP 0 a=rtpmap:0 PCMU/8000
14:28:35.272943 IP (tos 0x10, ttl 64, id 0, offset 0, flags [DF], proto: UDP (17), length: 389) sip100.sip > tmo120.sip-tls: [bad udp cksum cf26!] SIP, length: 361 SIP/2.0 180 Ringing Via: SIP/2.0/UDP 8.XX.XX.10:5061;branch=z9hG4bK-4068-8-0 From: sipp sip:sipp@8.XX.XX.10:5061;tag=4068SIPpTag008 To: sut sip:service@63.XXX.XX.110:5060;tag=2964SIPpTag018 Call-ID: 8-4068@8.XX.XX.10 CSeq: 1 INVITE Contact: sip:8.XX.XX.12:5060;transport=UDP Route: sip:63.XXX.XX.110;lr;ftag=4068SIPpTag008 Content-Length: 0
14:28:35.346657 IP (tos 0x10, ttl 64, id 0, offset 0, flags [DF], proto: UDP (17), length: 548) sip100.sip > tmo120.sip-tls: [bad udp cksum b2a1!] SIP, length: 520 SIP/2.0 200 OK Via: SIP/2.0/UDP 8.XX.XX.10:5061;branch=z9hG4bK-4068-8-0 From: sipp sip:sipp@8.XX.XX.10:5061;tag=4068SIPpTag008 To: sut sip:service@63.XXX.XX.110:5060;tag=2964SIPpTag018 Call-ID: 8-4068@8.XX.XX.10 CSeq: 1 INVITE Contact: sip:8.XX.XX.12:5060;transport=UDP Route: sip:63.XXX.XX.110;lr;ftag=4068SIPpTag008 Content-Type: application/sdp Content-Length: 129
v=0 o=user1 53655765 2353687637 IN IP4 8.XX.XX.12 s=- c=IN IP4 8.XX.XX.12 t=0 0 m=audio 6000 RTP/AVP 0 a=rtpmap:0 PCMU/8000
14:28:35.347459 IP (tos 0x0, ttl 124, id 15702, offset 0, flags [none], proto: UDP (17), length: 403) tmo120.sip-tls > sip100.sip: [udp sum ok] SIP, length: 375 ACK sip:service@8.XX.XX.12:5060 SIP/2.0 Via: SIP/2.0/UDP 8.XX.XX.10:5061;branch=z9hG4bK-4068-8-5 From: sipp sip:sipp@8.XX.XX.10:5061;tag=4068SIPpTag008 To: sut sip:service@63.XXX.XX.110:5060;tag=2964SIPpTag018 Call-ID: 8-4068@8.XX.XX.10 CSeq: 1 ACK Contact: sip:sipp@8.XX.XX.10:5061 Max-Forwards: 70 Route: (null) Subject: Performance Test Content-Length: 0
14:28:35.347721 IP (tos 0x0, ttl 124, id 15703, offset 0, flags [none], proto: UDP (17), length: 403) tmo120.sip-tls > sip100.sip: [udp sum ok] SIP, length: 375 BYE sip:service@8.XX.XX.12:5060 SIP/2.0 Via: SIP/2.0/UDP 8.XX.XX.10:5061;branch=z9hG4bK-4068-8-7 From: sipp sip:sipp@8.XX.XX.10:5061;tag=4068SIPpTag008 To: sut sip:service@63.XXX.XX.110:5060;tag=2964SIPpTag018 Call-ID: 8-4068@8.XX.XX.10 CSeq: 2 BYE Contact: sip:sipp@8.XX.XX.10:5061 Max-Forwards: 70 Route: (null) Subject: Performance Test Content-Length: 0
14:28:37.238897 IP (tos 0x10, ttl 64, id 0, offset 0, flags [DF], proto: UDP (17), length: 465) sip100.sip > tmo122.sip: [bad udp cksum ccfe!] SIP, length: 437 ACK sip:service@8.XX.XX.12:5060 SIP/2.0 Via: SIP/2.0/UDP 63.XXX.XX.110;branch=z9hG4bK5016.872b3ad4.2 Via: SIP/2.0/UDP 8.XX.XX.10:5061;branch=z9hG4bK-4068-8-5 From: sipp sip:sipp@8.XX.XX.10:5061;tag=4068SIPpTag008 To: sut sip:service@63.XXX.XX.110:5060;tag=2964SIPpTag018 Call-ID: 8-4068@8.XX.XX.10 CSeq: 1 ACK Contact: sip:sipp@8.XX.XX.10:5061 Max-Forwards: 12 Route: (null) Subject: Performance Test Content-Length: 0
14:28:37.401885 IP (tos 0x10, ttl 64, id 0, offset 0, flags [DF], proto: UDP (17), length: 465) sip100.sip > tmo122.sip: [bad udp cksum a539!] SIP, length: 437 BYE sip:service@8.XX.XX.12:5060 SIP/2.0 Via: SIP/2.0/UDP 63.XXX.XX.110;branch=z9hG4bK2016.2ea42581.0 Via: SIP/2.0/UDP 8.XX.XX.10:5061;branch=z9hG4bK-4068-8-7 From: sipp sip:sipp@8.XX.XX.10:5061;tag=4068SIPpTag008 To: sut sip:service@63.XXX.XX.110:5060;tag=2964SIPpTag018 Call-ID: 8-4068@8.XX.XX.10 CSeq: 2 BYE Contact: sip:sipp@8.XX.XX.10:5061 Max-Forwards: 12 Route: (null) Subject: Performance Test Content-Length: 0
14:28:37.883523 IP (tos 0x10, ttl 64, id 0, offset 0, flags [DF], proto: UDP (17), length: 465) sip100.sip > tmo122.sip: [bad udp cksum a539!] SIP, length: 437 BYE sip:service@8.XX.XX.12:5060 SIP/2.0 Via: SIP/2.0/UDP 63.XXX.XX.110;branch=z9hG4bK2016.2ea42581.0 Via: SIP/2.0/UDP 8.XX.XX.10:5061;branch=z9hG4bK-4068-8-7 From: sipp sip:sipp@8.XX.XX.10:5061;tag=4068SIPpTag008 To: sut sip:service@63.XXX.XX.110:5060;tag=2964SIPpTag018 Call-ID: 8-4068@8.XX.XX.10 CSeq: 2 BYE Contact: sip:sipp@8.XX.XX.10:5061 Max-Forwards: 12 Route: (null) Subject: Performance Test Content-Length: 0
14:28:38.883574 IP (tos 0x10, ttl 64, id 0, offset 0, flags [DF], proto: UDP (17), length: 465) sip100.sip > tmo122.sip: [bad udp cksum a539!] SIP, length: 437 BYE sip:service@8.XX.XX.12:5060 SIP/2.0 Via: SIP/2.0/UDP 63.XXX.XX.110;branch=z9hG4bK2016.2ea42581.0 Via: SIP/2.0/UDP 8.XX.XX.10:5061;branch=z9hG4bK-4068-8-7 From: sipp sip:sipp@8.XX.XX.10:5061;tag=4068SIPpTag008 To: sut sip:service@63.XXX.XX.110:5060;tag=2964SIPpTag018 Call-ID: 8-4068@8.XX.XX.10 CSeq: 2 BYE Contact: sip:sipp@8.XX.XX.10:5061 Max-Forwards: 12 Route: (null) Subject: Performance Test Content-Length: 0
14:28:40.883600 IP (tos 0x10, ttl 64, id 0, offset 0, flags [DF], proto: UDP (17), length: 465) sip100.sip > tmo122.sip: [bad udp cksum a539!] SIP, length: 437 BYE sip:service@8.XX.XX.12:5060 SIP/2.0 Via: SIP/2.0/UDP 63.XXX.XX.110;branch=z9hG4bK2016.2ea42581.0 Via: SIP/2.0/UDP 8.XX.XX.10:5061;branch=z9hG4bK-4068-8-7 From: sipp sip:sipp@8.XX.XX.10:5061;tag=4068SIPpTag008 To: sut sip:service@63.XXX.XX.110:5060;tag=2964SIPpTag018 Call-ID: 8-4068@8.XX.XX.10 CSeq: 2 BYE Contact: sip:sipp@8.XX.XX.10:5061 Max-Forwards: 12 Route: (null) Subject: Performance Test Content-Length: 0
14:28:44.883740 IP (tos 0x10, ttl 64, id 0, offset 0, flags [DF], proto: UDP (17), length: 465) sip100.sip > tmo122.sip: [bad udp cksum a539!] SIP, length: 437 BYE sip:service@8.XX.XX.12:5060 SIP/2.0 Via: SIP/2.0/UDP 63.XXX.XX.110;branch=z9hG4bK2016.2ea42581.0 Via: SIP/2.0/UDP 8.XX.XX.10:5061;branch=z9hG4bK-4068-8-7 From: sipp sip:sipp@8.XX.XX.10:5061;tag=4068SIPpTag008 To: sut sip:service@63.XXX.XX.110:5060;tag=2964SIPpTag018 Call-ID: 8-4068@8.XX.XX.10 CSeq: 2 BYE Contact: sip:sipp@8.XX.XX.10:5061 Max-Forwards: 12 Route: (null) Subject: Performance Test Content-Length: 0
14:28:46.483874 IP (tos 0x10, ttl 64, id 0, offset 0, flags [DF], proto: UDP (17), length: 346) sip100.sip > tmo120.sip-tls: [bad udp cksum 926e!] SIP, length: 318 SIP/2.0 503 Service Unavailable Via: SIP/2.0/UDP 8.XX.XX.10:5061;branch=z9hG4bK-4068-8-7 From: sipp sip:sipp@8.XX.XX.10:5061;tag=4068SIPpTag008 To: sut sip:service@63.XXX.XX.110:5060;tag=2964SIPpTag018 Call-ID: 8-4068@8.XX.XX.10 CSeq: 2 BYE Server: OpenSER (1.3.2-notls (x86_64/linux)) Content-Length: 0
14:28:46.485241 IP (tos 0x0, ttl 124, id 21542, offset 0, flags [none], proto: UDP (17), length: 381) tmo120.sip-tls > sip100.sip: [udp sum ok] SIP, length: 353 BYE sip:service@63.XXX.XX.110:5060 SIP/2.0 Via: SIP/2.0/UDP 8.XX.XX.10:5061;branch=z9hG4bK-4068-8--1 From: sipp sip:sipp@8.XX.XX.10:5061;tag=4068SIPpTag008 To: sut sip:service@63.XXX.XX.110:5060;tag=2964SIPpTag018 Call-ID: 8-4068@8.XX.XX.10 CSeq: 3 BYE Max-Forwards: 70 Contact: sip:sipp@8.XX.XX.10:5061;transport=UDP Content-Length: 0