Browse code

Merge remote branch 'origin/andrei/cancel_reason'

CANCEL Reason support, according to RFC 3326.
The Reason headers are added both for CANCELs generated due to a
received final reply and hop by hop CANCELs generated because of
a received CANCEL. Both cases can be turned on/off individually.

* origin/andrei/cancel_reason:
tm: no reason modparams if compiled with no cancelr. support
tm: option to compile without reason support
tm: docs: reason header modparams and script function
tm: improved Reason support for E2E CANCELs
tm: fix Reason generation for on-the-fly branch CANCELs
tm: CANCEL reason header on/off switches
tm: Reason header copy for received CANCELs
tm: Reason header generation for local CANCELs

Andrei Pelinescu-Onciul authored on 13/08/2010 19:44:36
Showing 19 changed files
... ...
@@ -109,6 +109,23 @@ modules:
109 109
             increase dramatically especially for large number of
110 110
             connections (>1000).
111 111
 tm:
112
+   - reason header support (RFC3326) both for CANCELs generated due to a
113
+      received final reply and for hop by hop CANCELs generated because of a
114
+      received CANCEL.
115
+      E.g.: reason header added for a CANCEL generated after a 200 reply was
116
+            received on one of the branches "Reason: SIP;cause=200".
117
+      The reason header support can be turned on/off using either tm
118
+      module parameters or in the end to end CANCEL case also on a per
119
+      transaction basis, using a script function:
120
+       local_cancel_reason = 0 | 1 (default 1/on) - turns on adding reason
121
+         headers for CANCELs generated due to a final reply. Can be changed
122
+         at runtime.
123
+       e2e_cancel_reason = 0 | 1 (default 1/on) - turns on copying reason
124
+         headers from a received end to end CANCEL (the generated hop by hop
125
+         CANCELs will have the same reason headers as the received CANCEL).
126
+         Can be changed at runtime.
127
+       t_set_no_e2e_cancel_reason(0|1) - enable/disable cancel reason 
128
+         header copying on a per transaction basis (0 - enable, 1 disable).
112 129
    - t_reply() can be used both from the main/core onreply_route{} and tm
113 130
      onreply_route[...]{}s.
114 131
 
... ...
@@ -8,9 +8,9 @@ Juha Heinanen
8 8
 
9 9
    <jh@tutpro.com>
10 10
 
11
-   Copyright © 2003 FhG FOKUS
11
+   Copyright � 2003 FhG FOKUS
12 12
 
13
-   Copyright © 2008 Juha Heinanen
13
+   Copyright � 2008 Juha Heinanen
14 14
    Revision History
15 15
    Revision $Revision$ $Date$
16 16
      __________________________________________________________________
... ...
@@ -57,6 +57,8 @@ Juha Heinanen
57 57
         1.4.35. disable_6xx_block (integer)
58 58
         1.4.36. local_ack_mode (integer)
59 59
         1.4.37. failure_reply_mode (integer)
60
+        1.4.38. local_cancel_reason (boolean)
61
+        1.4.39. e2e_cancel_reason (boolean)
60 62
 
61 63
    1.5. Functions
62 64
 
... ...
@@ -105,6 +107,7 @@ Juha Heinanen
105 107
         1.5.35. t_set_disable_failover(0|1)
106 108
         1.5.36. t_replicate(params)
107 109
         1.5.37. t_relay_to(proxy, flags)
110
+        1.5.38. t_set_no_e2e_cancel_reason(0|1)
108 111
 
109 112
    1.6. TM Module API
110 113
 
... ...
@@ -174,7 +177,7 @@ Juha Heinanen
174 177
 Note
175 178
 
176 179
    Several Kamailio (OpenSER) TM module functionalities are now
177
-   implemented in the TMX module: “modules_k/tmx”. Check it to see if what
180
+   implemented in the TMX module: "modules_k/tmx". Check it to see if what
178 181
    you are looking for is there.
179 182
 
180 183
 1.2. Serial Forking Based on Q Value
... ...
@@ -1131,6 +1134,42 @@ modparam("tm", "local_ack_mode", 1)
1131 1134
 modparam("tm", "failure_reply_mode", 3)
1132 1135
 ...
1133 1136
 
1137
+1.4.38. local_cancel_reason (boolean)
1138
+
1139
+   Enables/disables adding reason headers (RFC 3326) for CANCELs generated
1140
+   due to receiving a final reply. The reason header added will look like:
1141
+   "Reason: SIP;cause=<final_reply_code>".
1142
+
1143
+   Default value is 1 (enabled).
1144
+
1145
+   Can be set at runtime, e.g.:
1146
+        $ sercmd cfg.set_now_int tm local_cancel_reason 0
1147
+
1148
+   See also: e2e_cancel_reason.
1149
+
1150
+   Example 38. Set local_cancel_reason parameter
1151
+...
1152
+modparam("tm", "local_cancel_reason", "0")
1153
+...
1154
+
1155
+1.4.39. e2e_cancel_reason (boolean)
1156
+
1157
+   Enables/disables adding reason headers (RFC 3326) for CANCELs generated
1158
+   due to a received CANCEL. If enabled the reason headers from received
1159
+   CANCELs will be copied into the generated hop-by-hop CANCELs.
1160
+
1161
+   Default value is 1 (enabled).
1162
+
1163
+   Can be changed at runtime, e.g.:
1164
+        $ sercmd cfg.set_now_int tm e2e_cancel_reason 0
1165
+
1166
+   See also: t_set_no_e2e_cancel_reason() and local_cancel_reason.
1167
+
1168
+   Example 39. Set e2e_cancel_reason parameter
1169
+...
1170
+modparam("tm", "e2e_cancel_reason", "0")
1171
+...
1172
+
1134 1173
 1.5. Functions
1135 1174
 
1136 1175
    Revision History
... ...
@@ -1156,7 +1195,7 @@ t_relay_to_sctp(ip, port) t_relay_to_sctp()
1156 1195
    derived from the message uri (using sip sepcific DNS lookups), but with
1157 1196
    the protocol corresponding to the function name.
1158 1197
 
1159
-   Example 38. t_relay_to_udp usage
1198
+   Example 40. t_relay_to_udp usage
1160 1199
 ...
1161 1200
 if (src_ip==10.0.0.0/8)
1162 1201
         t_relay_to_udp("1.2.3.4", "5060"); # sent to 1.2.3.4:5060 over udp
... ...
@@ -1183,7 +1222,7 @@ else
1183 1222
    Returns a negative value on failure--you may still want to send a
1184 1223
    negative reply upstream statelessly not to leave upstream UAC in lurch.
1185 1224
 
1186
-   Example 39. t_relay usage
1225
+   Example 41. t_relay usage
1187 1226
 ...
1188 1227
 if (!t_relay())
1189 1228
 {
... ...
@@ -1212,7 +1251,7 @@ if (!t_relay())
1212 1251
    Meaning of the parameters is as follows:
1213 1252
      * failure_route - Failure route block to be called.
1214 1253
 
1215
-   Example 40. t_on_failure usage
1254
+   Example 42. t_on_failure usage
1216 1255
 ...
1217 1256
 route {
1218 1257
     t_on_failure("1");
... ...
@@ -1238,7 +1277,7 @@ failure_route[1] {
1238 1277
    Meaning of the parameters is as follows:
1239 1278
      * onreply_route - Onreply route block to be called.
1240 1279
 
1241
-   Example 41. t_on_reply usage
1280
+   Example 43. t_on_reply usage
1242 1281
 ...
1243 1282
 loadmodule "/usr/local/lib/ser/modules/nathelper.so"
1244 1283
 ...
... ...
@@ -1270,7 +1309,7 @@ es');
1270 1309
    Meaning of the parameters is as follows:
1271 1310
      * branch_route - branch route block to be called.
1272 1311
 
1273
-   Example 42. t_on_branch usage
1312
+   Example 44. t_on_branch usage
1274 1313
 ...
1275 1314
 route {
1276 1315
         t_on_branch("1");
... ...
@@ -1288,7 +1327,7 @@ branch_route[1] {
1288 1327
    Similarly to t_fork_to, it extends destination set by a new entry. The
1289 1328
    difference is that current URI is taken as new entry.
1290 1329
 
1291
-   Example 43. append_branch usage
1330
+   Example 45. append_branch usage
1292 1331
 ...
1293 1332
 set_user("john");
1294 1333
 t_fork();
... ...
@@ -1303,7 +1342,7 @@ t_relay();
1303 1342
    the only way a script can add a new transaction in an atomic way.
1304 1343
    Typically, it is used to deploy a UAS.
1305 1344
 
1306
-   Example 44. t_newtran usage
1345
+   Example 46. t_newtran usage
1307 1346
 ...
1308 1347
 if (t_newtran()) {
1309 1348
     log("UAS logic");
... ...
@@ -1322,7 +1361,7 @@ if (t_newtran()) {
1322 1361
      * code - Reply code number.
1323 1362
      * reason_phrase - Reason string.
1324 1363
 
1325
-   Example 45. t_reply usage
1364
+   Example 47. t_reply usage
1326 1365
 ...
1327 1366
 t_reply("404", "Not found");
1328 1367
 ...
... ...
@@ -1335,7 +1374,7 @@ t_reply("404", "Not found");
1335 1374
    none was found. However this is safely (atomically) done using
1336 1375
    t_newtran.
1337 1376
 
1338
-   Example 46. t_lookup_request usage
1377
+   Example 48. t_lookup_request usage
1339 1378
 ...
1340 1379
 if (t_lookup_request()) {
1341 1380
     ...
... ...
@@ -1346,7 +1385,7 @@ if (t_lookup_request()) {
1346 1385
 
1347 1386
    Retransmits a reply sent previously by UAS transaction.
1348 1387
 
1349
-   Example 47. t_retransmit_reply usage
1388
+   Example 49. t_retransmit_reply usage
1350 1389
 ...
1351 1390
 t_retransmit_reply();
1352 1391
 ...
... ...
@@ -1356,7 +1395,7 @@ t_retransmit_reply();
1356 1395
    Remove transaction from memory (it will be first put on a wait timer to
1357 1396
    absorb delayed messages).
1358 1397
 
1359
-   Example 48. t_release usage
1398
+   Example 50. t_release usage
1360 1399
 ...
1361 1400
 t_release();
1362 1401
 ...
... ...
@@ -1371,7 +1410,7 @@ t_forward_nonack_tls(ip, port) t_forward_nonack_sctp(ip, port)
1371 1410
      * ip - IP address where the message should be sent.
1372 1411
      * port - Port number.
1373 1412
 
1374
-   Example 49. t_forward_nonack usage
1413
+   Example 51. t_forward_nonack usage
1375 1414
 ...
1376 1415
 t_forward_nonack("1.2.3.4", "5060");
1377 1416
 ...
... ...
@@ -1394,7 +1433,7 @@ t_forward_nonack("1.2.3.4", "5060");
1394 1433
 
1395 1434
    See also: fr_timer, fr_inv_timer, t_reset_fr().
1396 1435
 
1397
-   Example 50. t_set_fr usage
1436
+   Example 52. t_set_fr usage
1398 1437
 ...
1399 1438
 route {
1400 1439
         t_set_fr(10000); # set only fr invite timeout to 10s
... ...
@@ -1421,7 +1460,7 @@ branch_route[1] {
1421 1460
 
1422 1461
    See also: fr_timer, fr_inv_timer, t_set_fr.
1423 1462
 
1424
-   Example 51. t_reset_fr usage
1463
+   Example 53. t_reset_fr usage
1425 1464
 ...
1426 1465
 route {
1427 1466
 ...
... ...
@@ -1447,7 +1486,7 @@ route {
1447 1486
 
1448 1487
    See also: max_inv_lifetime, max_noninv_lifetime, t_reset_max_lifetime.
1449 1488
 
1450
-   Example 52. t_set_max_lifetime usage
1489
+   Example 54. t_set_max_lifetime usage
1451 1490
 ...
1452 1491
 route {
1453 1492
     if (src_ip=1.2.3.4)
... ...
@@ -1469,7 +1508,7 @@ route {
1469 1508
 
1470 1509
    See also: max_inv_lifetime, max_noninv_lifetime, t_set_max_lifetime.
1471 1510
 
1472
-   Example 53. t_reset_max_lifetime usage
1511
+   Example 55. t_reset_max_lifetime usage
1473 1512
 ...
1474 1513
 route {
1475 1514
 ...
... ...
@@ -1507,7 +1546,7 @@ route {
1507 1546
 
1508 1547
    See also: retr_timer1, retr_timer2, t_reset_retr().
1509 1548
 
1510
-   Example 54. t_set_retr usage
1549
+   Example 56. t_set_retr usage
1511 1550
 ...
1512 1551
 route {
1513 1552
         t_set_retr(250, 0); # set only T1 to 250 ms
... ...
@@ -1534,7 +1573,7 @@ branch_route[1] {
1534 1573
 
1535 1574
    See also: retr_timer1, retr_timer2, t_set_retr.
1536 1575
 
1537
-   Example 55. t_reset_retr usage
1576
+   Example 57. t_reset_retr usage
1538 1577
 ...
1539 1578
 route {
1540 1579
 ...
... ...
@@ -1550,7 +1589,7 @@ route {
1550 1589
 
1551 1590
    See also: auto_inv_100.
1552 1591
 
1553
-   Example 56. t_set_auto_inv_100 usage
1592
+   Example 58. t_set_auto_inv_100 usage
1554 1593
 ...
1555 1594
 route {
1556 1595
 ...
... ...
@@ -1564,7 +1603,7 @@ route {
1564 1603
    Returns true if the failure route is executed for a branch that did
1565 1604
    timeout. It can be used only from the failure_route.
1566 1605
 
1567
-   Example 57. t_branch_timeout usage
1606
+   Example 59. t_branch_timeout usage
1568 1607
 ...
1569 1608
 failure_route[0]{
1570 1609
         if (t_branch_timeout()){
... ...
@@ -1579,7 +1618,7 @@ failure_route[0]{
1579 1618
    receive at least one reply in the past (the "current" reply is not
1580 1619
    taken into account). It can be used only from the failure_route.
1581 1620
 
1582
-   Example 58. t_branch_replied usage
1621
+   Example 60. t_branch_replied usage
1583 1622
 ...
1584 1623
 failure_route[0]{
1585 1624
         if (t_branch_timeout()){
... ...
@@ -1596,7 +1635,7 @@ failure_route[0]{
1596 1635
    Returns true if at least one of the current transactions branches did
1597 1636
    timeout.
1598 1637
 
1599
-   Example 59. t_any_timeout usage
1638
+   Example 61. t_any_timeout usage
1600 1639
 ...
1601 1640
 failure_route[0]{
1602 1641
         if (!t_branch_timeout()){
... ...
@@ -1613,7 +1652,7 @@ failure_route[0]{
1613 1652
    receive some reply in the past. If called from a failure or onreply
1614 1653
    route, the "current" reply is not taken into account.
1615 1654
 
1616
-   Example 60. t_any_replied usage
1655
+   Example 62. t_any_replied usage
1617 1656
 ...
1618 1657
 onreply_route[0]{
1619 1658
         if (!t_any_replied()){
... ...
@@ -1627,7 +1666,7 @@ onreply_route[0]{
1627 1666
    Returns true if "code" is the final reply received (or locally
1628 1667
    generated) in at least one of the current transactions branches.
1629 1668
 
1630
-   Example 61. t_grep_status usage
1669
+   Example 63. t_grep_status usage
1631 1670
 ...
1632 1671
 onreply_route[0]{
1633 1672
         if (t_grep_status("486")){
... ...
@@ -1640,7 +1679,7 @@ onreply_route[0]{
1640 1679
 
1641 1680
    Returns true if the current transaction was canceled.
1642 1681
 
1643
-   Example 62. t_is_canceled usage
1682
+   Example 64. t_is_canceled usage
1644 1683
 ...
1645 1684
 failure_route[0]{
1646 1685
         if (t_is_canceled()){
... ...
@@ -1654,7 +1693,7 @@ failure_route[0]{
1654 1693
    Returns true if the current transaction has already been expired, i.e.
1655 1694
    the max_inv_lifetime/max_noninv_lifetime interval has already elapsed.
1656 1695
 
1657
-   Example 63. t_is_expired usage
1696
+   Example 65. t_is_expired usage
1658 1697
 ...
1659 1698
 failure_route[0]{
1660 1699
         if (t_is_expired()){
... ...
@@ -1675,7 +1714,7 @@ failure_route[0]{
1675 1714
    CANCELs were successfully sent to the pending branches, true if the
1676 1715
    INVITE was not found, and false in case of any error.
1677 1716
 
1678
-   Example 64. t_relay_cancel usage
1717
+   Example 66. t_relay_cancel usage
1679 1718
 if (method == CANCEL) {
1680 1719
         if (!t_relay_cancel()) {  # implicit drop if relaying was successful,
1681 1720
                                   # nothing to do
... ...
@@ -1702,7 +1741,7 @@ if (method == CANCEL) {
1702 1741
    overwritten with the flags of the INVITE. isflagset() can be used to
1703 1742
    check the flags of the previously forwarded INVITE in this case.
1704 1743
 
1705
-   Example 65. t_lookup_cancel usage
1744
+   Example 67. t_lookup_cancel usage
1706 1745
 if (method == CANCEL) {
1707 1746
         if (t_lookup_cancel()) {
1708 1747
                 log("INVITE transaction exists");
... ...
@@ -1732,7 +1771,7 @@ if (method == CANCEL) {
1732 1771
    Dropping replies works only if a new branch is added to the
1733 1772
    transaction, or it is explicitly replied in the script!
1734 1773
 
1735
-   Example 66. t_drop_replies() usage
1774
+   Example 68. t_drop_replies() usage
1736 1775
 ...
1737 1776
 failure_route[0]{
1738 1777
         if (t_check_status("5[0-9][0-9]")){
... ...
@@ -1763,7 +1802,7 @@ failure_route[0]{
1763 1802
    The transaction must be created by t_newtran() before calling
1764 1803
    t_save_lumps().
1765 1804
 
1766
-   Example 67. t_save_lumps() usage
1805
+   Example 69. t_save_lumps() usage
1767 1806
 route {
1768 1807
         ...
1769 1808
         t_newtran();
... ...
@@ -1833,7 +1872,7 @@ failure_route[1] {
1833 1872
 
1834 1873
    This function can be used from REQUEST_ROUTE.
1835 1874
 
1836
-   Example 68. t_load_contacts usage
1875
+   Example 70. t_load_contacts usage
1837 1876
 ...
1838 1877
 if (!t_load_contacts()) {
1839 1878
         sl_send_reply("500", "Server Internal Error - Cannot load contacts");
... ...
@@ -1874,7 +1913,7 @@ if (!t_load_contacts()) {
1874 1913
    anymore set. Based on that test, you can then use t_set_fr() function
1875 1914
    to set timers according to your needs.
1876 1915
 
1877
-   Example 69. t_next_contacts usage
1916
+   Example 71. t_next_contacts usage
1878 1917
 ...
1879 1918
 # First call after t_load_contacts() when transaction does not exist yet
1880 1919
 # and contacts should be available
... ...
@@ -1938,7 +1977,7 @@ Note
1938 1977
 
1939 1978
    See also: t_lookup_request(), t_lookup_cancel().
1940 1979
 
1941
-   Example 70. t_check_trans usage
1980
+   Example 72. t_check_trans usage
1942 1981
 if ( method == "CANCEL" && !t_check_trans())
1943 1982
         sl_reply("403", "cancel out of the blue forbidden");
1944 1983
 # note: in this example t_check_trans() can be replaced by t_lookup_cancel()
... ...
@@ -1953,7 +1992,7 @@ if ( method == "CANCEL" && !t_check_trans())
1953 1992
 
1954 1993
    See also: disable_6xx_block.
1955 1994
 
1956
-   Example 71. t_set_disable_6xx usage
1995
+   Example 73. t_set_disable_6xx usage
1957 1996
 ...
1958 1997
 route {
1959 1998
 ...
... ...
@@ -1968,7 +2007,7 @@ route {
1968 2007
 
1969 2008
    See also: use_dns_failover.
1970 2009
 
1971
-   Example 72. t_set_disable_failover usage
2010
+   Example 74. t_set_disable_failover usage
1972 2011
 ...
1973 2012
 route {
1974 2013
 ...
... ...
@@ -1999,7 +2038,7 @@ route {
1999 2038
      * hostport - address in "host:port" format. It can be given via an
2000 2039
        AVP.
2001 2040
 
2002
-   Example 73. t_replicate usage
2041
+   Example 75. t_replicate usage
2003 2042
 ...
2004 2043
 # sent to 1.2.3.4:5060 over tcp
2005 2044
 t_replicate("sip:1.2.3.4:5060;transport=tcp");
... ...
@@ -2034,7 +2073,7 @@ t_replicate_to_udp("1.2.3.4", "5060");
2034 2073
             effect anymore).
2035 2074
           + 0x04 - disable dns failover.
2036 2075
 
2037
-   Example 74. t_replicate usage
2076
+   Example 76. t_replicate usage
2038 2077
 ...
2039 2078
 # sent to 1.2.3.4:5060 over tcp
2040 2079
 t_relay_to("tcp:1.2.3.4:5060");
... ...
@@ -2046,6 +2085,27 @@ t_relay_to("tls:1.2.3.4");
2046 2085
 t_relay_to("0x01");
2047 2086
 ...
2048 2087
 
2088
+1.5.38.  t_set_no_e2e_cancel_reason(0|1)
2089
+
2090
+   Enables/disables reason header (RFC 3326) copying from the triggering
2091
+   received CANCEL to the generated hop-by-hop CANCEL. 0 enables and 1
2092
+   disables.
2093
+
2094
+   It overrides the e2e_cancel_reason setting (module parameter) for the
2095
+   current transaction.
2096
+
2097
+   See also: e2e_cancel_reason.
2098
+
2099
+   Example 77. t_set_no_e2e_cancel_reason usage
2100
+...
2101
+route {
2102
+...
2103
+        if (src_ip!=10.0.0.0/8) #  don't trust CANCELs from the outside
2104
+                t_set_no_e2e_cancel_reason(1); # turn off CANCEL reason header c
2105
+opying
2106
+...
2107
+}
2108
+
2049 2109
 1.6. TM Module API
2050 2110
 
2051 2111
    Revision History
... ...
@@ -24,10 +24,9 @@
24 24
  *  2008-02-05	adapting tm module for the configuration framework (Miklos)
25 25
  */
26 26
 
27
-/*!
28
- * \file 
29
- * \brief TM :: Configuration
30
- * \ingroup tm
27
+/** TM :: Runtime configuration variables.
28
+ * @file
29
+ * @ingroup tm
31 30
  */
32 31
 
33 32
 
... ...
@@ -94,7 +93,11 @@ struct cfg_group_tm	default_tm_cfg = {
94 93
 	1,	/* cancel_b_method used for e2e and 6xx cancels*/
95 94
 	1,	/* reparse_on_dns_failover */
96 95
 	0, /* disable_6xx, by default off */
97
-	0  /* local_ack_mode, default 0 (rfc3261 conformant) */
96
+	0,  /* local_ack_mode, default 0 (rfc3261 conformant) */
97
+	1, /* local_cancel_reason -- add Reason header to locally generated
98
+		  CANCELs; on by default */
99
+	1  /* e2e_cancel_reason -- copy the Reason headers from incoming CANCELs
100
+		  into the corresp. hop-by-hop CANCELs, on by default */
98 101
 };
99 102
 
100 103
 void	*tm_cfg = &default_tm_cfg;
... ...
@@ -196,5 +199,11 @@ cfg_def_t	tm_cfg_def[] = {
196 199
 		" it is not set to 0 but allows dealing with NATed contacts in some "
197 200
 		"simple cases)"
198 201
 		},
202
+	{"local_cancel_reason",	CFG_VAR_INT | CFG_ATOMIC,	0, 1, 0, 0,
203
+		"if set to 1, a Reason header is added to locally generated CANCELs"
204
+		" (see RFC3326)" },
205
+	{"e2e_cancel_reason",	CFG_VAR_INT | CFG_ATOMIC,	0, 1, 0, 0,
206
+		"if set to 1, Reason headers from received CANCELs are copied into"
207
+		" the corresponding generated hop-by-hop CANCELs"},
199 208
 	{0, 0, 0, 0, 0, 0}
200 209
 };
... ...
@@ -21,10 +21,9 @@
21 21
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22 22
  */
23 23
 
24
-/*!
25
- * \file 
26
- * \brief TM :: Configuration
27
- * \ingroup tm
24
+/** TM :: Runtime configuration variables.
25
+ * @file
26
+ * @ingroup tm
28 27
  */
29 28
 
30 29
 
... ...
@@ -136,6 +135,8 @@ struct cfg_group_tm {
136 135
 	int	reparse_on_dns_failover;
137 136
 	int disable_6xx;
138 137
 	int local_ack_mode;
138
+	int local_cancel_reason;
139
+	int e2e_cancel_reason;
139 140
 };
140 141
 
141 142
 extern struct cfg_group_tm	default_tm_cfg;
... ...
@@ -1213,7 +1213,9 @@ if (!t_next_contacts()) {
1213 1213
 				INVITE transactions) it will return true if the corresponding
1214 1214
 				INVITE transaction is found and still active and false if not.
1215 1215
 				</para>
1216
-				<note>Note that the e2e ACK matching is more of a hint
1216
+				<note>
1217
+				<para>
1218
+				Note that the e2e ACK matching is more of a hint
1217 1219
 				then a certainty. A delayed e2e ACK might arrive after the
1218 1220
 				transaction wait time elapses, when the INVITE transaction no
1219 1221
 				longer exists and thus would not match anything. There are
... ...
@@ -1221,6 +1223,7 @@ if (!t_next_contacts()) {
1221 1223
 				for e2e ACK matching (since this is not needed for a statefull
1222 1224
 				proxy and it requires additional memory, tm will not keep this
1223 1225
 				information unless needed by some other module or callbacks).
1226
+				</para>
1224 1227
 				</note>
1225 1228
 			</listitem>
1226 1229
 			<listitem>
... ...
@@ -1321,27 +1324,27 @@ route {
1321 1324
 	<para>
1322 1325
 		There are several function prototypes:
1323 1326
 		<itemizedlist>
1324
-		<listitem>
1327
+		<listitem><para>
1325 1328
 	    <function>t_replicate(uri)</function>,
1326
-		</listitem>
1327
-		<listitem>
1329
+		</para></listitem>
1330
+		<listitem><para>
1328 1331
 	    <function>t_replicate(host, port)</function>,
1329
-		</listitem>
1330
-		<listitem>
1332
+		</para></listitem>
1333
+		<listitem><para>
1331 1334
 	    <function>t_replicat_udp(host, port)</function>
1332
-		</listitem>
1333
-		<listitem>
1335
+		</para></listitem>
1336
+		<listitem><para>
1334 1337
 	    <function>t_replicate_tcp(host, port)</function>
1335
-		</listitem>
1336
-		<listitem>
1338
+		</para></listitem>
1339
+		<listitem><para>
1337 1340
 	    <function>t_replicate_tls(host, port)</function>
1338
-		</listitem>
1339
-		<listitem>
1341
+		</para></listitem>
1342
+		<listitem><para>
1340 1343
 	    <function>t_replicate_sctp(host, port)</function>
1341
-		</listitem>
1342
-		<listitem>
1344
+		</para></listitem>
1345
+		<listitem><para>
1343 1346
 	    <function>t_replicate_to(proto, hostport)</function>
1344
-		</listitem>
1347
+		</para></listitem>
1345 1348
 		</itemizedlist>
1346 1349
 	</para>
1347 1350
 	<para>Meaning of the parameters is as follows:</para>
... ...
@@ -1397,18 +1400,18 @@ t_replicate_to_udp("1.2.3.4", "5060");
1397 1400
 	<para>
1398 1401
 		There are several function prototypes:
1399 1402
 		<itemizedlist>
1400
-		<listitem>
1403
+		<listitem><para>
1401 1404
 	    <function>t_relay_to()</function>,
1402
-		</listitem>
1403
-		<listitem>
1405
+		</para></listitem>
1406
+		<listitem><para>
1404 1407
 	    <function>t_relay_to(proxy)</function>,
1405
-		</listitem>
1406
-		<listitem>
1408
+		</para></listitem>
1409
+		<listitem><para>
1407 1410
 	    <function>t_relay_to(flags)</function>
1408
-		</listitem>
1409
-		<listitem>
1411
+		</para></listitem>
1412
+		<listitem><para>
1410 1413
 	    <function>t_relay_to(proxy, flags)</function>
1411
-		</listitem>
1414
+		</para></listitem>
1412 1415
 		</itemizedlist>
1413 1416
 	</para>
1414 1417
 	<para>Meaning of the parameters is as follows:</para>
... ...
@@ -1457,4 +1460,36 @@ t_relay_to("0x01");
1457 1460
 	</example>
1458 1461
     </section>
1459 1462
 
1463
+
1464
+	<section id="t_set_no_e2e_cancel_reason">
1465
+	<title>
1466
+		<function>t_set_no_e2e_cancel_reason(0|1)</function>
1467
+	</title>
1468
+	<para>
1469
+		Enables/disables reason header (RFC 3326) copying from the triggering
1470
+		received CANCEL to the generated hop-by-hop CANCEL. 0 enables and
1471
+		1 disables.
1472
+	</para>
1473
+	<para>
1474
+		It overrides the <varname>e2e_cancel_reason</varname> setting (module
1475
+		 parameter) for the current transaction.
1476
+	</para>
1477
+	<para>
1478
+		See also: <varname>e2e_cancel_reason</varname>.
1479
+	</para>
1480
+	<example>
1481
+		<title><function>t_set_no_e2e_cancel_reason</function> usage</title>
1482
+		<programlisting>
1483
+...
1484
+route {
1485
+...
1486
+	if (src_ip!=10.0.0.0/8) #  don't trust CANCELs from the outside
1487
+		t_set_no_e2e_cancel_reason(1); # turn off CANCEL reason header copying
1488
+...
1489
+}
1490
+		</programlisting>
1491
+	</example>
1492
+	</section>
1493
+
1494
+
1460 1495
 </section>
... ...
@@ -45,9 +45,11 @@ modparam("tm", "fr_timer", 10000)
45 45
 	</para>
46 46
 	<para>
47 47
 	</para>
48
+	<para>
48 49
 		Note: this timer can be restarted when a provisional response is
49 50
 		received. For more details see
50 51
 		<varname>restart_fr_on_each_reply</varname>.
52
+	</para>
51 53
 	<para>
52 54
 	    Default value is 120000 ms (120 seconds).
53 55
 	</para>
... ...
@@ -1094,11 +1096,11 @@ modparam("tm", "disable_6xx_block", 1)
1094 1096
 		reply.
1095 1097
 		</para></listitem>
1096 1098
 	</itemizedlist>
1097
-	<note>
1099
+	<note><para>
1098 1100
 	Mode 1 and 2 break the rfc, but are useful to deal with some simple UAs
1099 1101
 	behind the NAT cases (no different routing for the ACK and the contact 
1100 1102
 	contains an address behind the NAT).
1101
-	</note>
1103
+	</para></note>
1102 1104
 	<para>
1103 1105
 		The default value is 0 (rfc conformant behaviour).
1104 1106
 	</para>
... ...
@@ -1172,4 +1174,66 @@ modparam("tm", "failure_reply_mode", 3)
1172 1174
 	</example>
1173 1175
 	</section>
1174 1176
 
1177
+
1178
+	<section id="local_cancel_reason">
1179
+		<title><varname>local_cancel_reason</varname> (boolean)</title>
1180
+		<para>
1181
+			Enables/disables adding reason headers (RFC 3326) for CANCELs
1182
+			generated due to receiving a final reply. The reason header added
1183
+			will look like: "Reason: SIP;cause=&lt;final_reply_code&gt;".
1184
+		</para>
1185
+		<para>
1186
+			Default value is 1 (enabled).
1187
+		</para>
1188
+		<para>
1189
+			Can be set at runtime, e.g.:
1190
+			<programlisting>
1191
+	$ sercmd cfg.set_now_int tm local_cancel_reason 0
1192
+			</programlisting>
1193
+		</para>
1194
+		<para>
1195
+			See also: <varname>e2e_cancel_reason</varname>.
1196
+		</para>
1197
+		<example>
1198
+			<title>Set <varname>local_cancel_reason</varname> parameter</title>
1199
+			<programlisting>
1200
+...
1201
+modparam("tm", "local_cancel_reason", "0")
1202
+...
1203
+			</programlisting>
1204
+		</example>
1205
+	</section>
1206
+
1207
+
1208
+	<section id="e2e_cancel_reason">
1209
+		<title><varname>e2e_cancel_reason</varname> (boolean)</title>
1210
+		<para>
1211
+			Enables/disables adding reason headers (RFC 3326) for CANCELs
1212
+			generated due to a received CANCEL.  If enabled the reason headers
1213
+			from received CANCELs will be copied into the generated hop-by-hop
1214
+			CANCELs.
1215
+		</para>
1216
+		<para>
1217
+			Default value is 1 (enabled).
1218
+		</para>
1219
+		<para>
1220
+			Can be changed at runtime, e.g.:
1221
+			<programlisting>
1222
+	$ sercmd cfg.set_now_int tm e2e_cancel_reason 0
1223
+			</programlisting>
1224
+		</para>
1225
+		<para>
1226
+			See also: <function>t_set_no_e2e_cancel_reason()</function> and
1227
+						<varname>local_cancel_reason</varname>.
1228
+		</para>
1229
+		<example>
1230
+			<title>Set <varname>e2e_cancel_reason</varname> parameter</title>
1231
+			<programlisting>
1232
+...
1233
+modparam("tm", "e2e_cancel_reason", "0")
1234
+...
1235
+			</programlisting>
1236
+		</example>
1237
+	</section>
1238
+
1175 1239
 </section>
... ...
@@ -1,6 +1,13 @@
1 1
 <?xml version="1.0" encoding="UTF-8"?>
2 2
 <!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" 
3
-   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
3
+	"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
4
+	[ <!ENTITY % local.common.attrib
5
+	 "xmlns:xi CDATA #FIXED 'http://www.w3.org/2001/XInclude'">
6
+	 <!-- Include general documentation entities -->
7
+	 <!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
8
+	 %docentities;
9
+	]
10
+>
4 11
 
5 12
 <section id="tm" xmlns:xi="http://www.w3.org/2001/XInclude">
6 13
     <sectioninfo>
... ...
@@ -141,6 +141,10 @@ void free_cell( struct cell* dead_cell )
141 141
 		sip_msg_free_unsafe( dead_cell->uas.request );
142 142
 	if ( dead_cell->uas.response.buffer )
143 143
 		shm_free_unsafe( dead_cell->uas.response.buffer );
144
+#ifdef CANCEL_REASON_SUPPORT
145
+	if (unlikely(dead_cell->uas.cancel_reas))
146
+		shm_free_unsafe(dead_cell->uas.cancel_reas);
147
+#endif /* CANCEL_REASON_SUPPORT */
144 148
 
145 149
 	/* callbacks */
146 150
 	for( cbs=(struct tm_callback*)dead_cell->tmcb_hl.first ; cbs ; ) {
... ...
@@ -40,10 +40,9 @@
40 40
  *              inlined often used functions (andrei)
41 41
  */
42 42
 
43
-/*!
44
- * \file 
45
- * \brief TM :: 
46
- * \ingroup tm
43
+/**  TM :: hash table, flags and other general defines.
44
+ * @file 
45
+ * @ingroup tm
47 46
  */
48 47
 
49 48
 
... ...
@@ -192,6 +191,10 @@ typedef struct ua_server
192 191
 	 * we need them for dialog-wise matching of ACKs;
193 192
 	 * the pointer shows to shmem-ed reply */
194 193
 	str				 local_totag;
194
+#ifdef CANCEL_REASON_SUPPORT
195
+	struct cancel_reason* cancel_reas; /* pointer to cancel reason, used
196
+										  for e2e cancels */
197
+#endif /* CANCEL_REASON_SUPPORT */
195 198
 	unsigned int     status;
196 199
 }ua_server_type;
197 200
 
... ...
@@ -281,6 +284,9 @@ struct totag_elem {
281 284
 
282 285
 #define T_DISABLE_6xx (1<<8) /* treat 6xx as a normal reply */
283 286
 #define T_DISABLE_FAILOVER (1<<9) /* don't perform dns failover */
287
+#ifdef CANCEL_REASON_SUPPORT
288
+#define T_NO_E2E_CANCEL_REASON (1<<10) /* don't propagate CANCEL Reason */
289
+#endif /* CANCEL_REASON_SUPPORT */
284 290
 #define T_DONT_FORK   (T_CANCELED|T_6xx)
285 291
 
286 292
 /* unsigned short should be enough for a retr. timer: max. 65535 ticks =>
... ...
@@ -46,6 +46,7 @@
46 46
  *              reflecting its purpose
47 47
  *             prepare_to_cancel() takes now an additional skip_branches
48 48
  *              bitmap parameter (andrei)
49
+ * 2010-02-26  cancel reason (rfc3326) basic support (andrei)
49 50
  */
50 51
 
51 52
 #include <stdio.h> /* for FILE* in fifo_uac_cancel */
... ...
@@ -102,13 +103,14 @@ void prepare_to_cancel(struct cell *t, branch_bm_t *cancel_bm,
102 103
 
103 104
 /* cancel branches scheduled for deletion
104 105
  * params: t          - transaction
105
- *          cancel_bm - bitmap with the branches that are supposed to be 
106
- *                       canceled 
106
+ *          cancel_data - structure filled with the cancel bitmap (bitmap with
107
+ *                       the branches that are supposed to be canceled) and
108
+ *                       the cancel reason.
107 109
  *          flags     - how_to_cancel flags, see cancel_branch()
108 110
  * returns: bitmap with the still active branches (on fr timer)
109
- * WARNING: always fill cancel_bm using prepare_to_cancel(), supplying values
110
- *          in any other way is a bug*/
111
-int cancel_uacs( struct cell *t, branch_bm_t cancel_bm, int flags)
111
+ * WARNING: always fill cancel_data->cancel_bitmap using prepare_to_cancel(),
112
+ *          supplying values in any other way is a bug*/
113
+int cancel_uacs( struct cell *t, struct cancel_info* cancel_data, int flags)
112 114
 {
113 115
 	int i;
114 116
 	int ret;
... ...
@@ -117,10 +119,13 @@ int cancel_uacs( struct cell *t, branch_bm_t cancel_bm, int flags)
117 119
 	ret=0;
118 120
 	/* cancel pending client transactions, if any */
119 121
 	for( i=0 ; i<t->nr_of_outgoings ; i++ ) 
120
-		if (cancel_bm & (1<<i)){
122
+		if (cancel_data->cancel_bitmap & (1<<i)){
121 123
 			r=cancel_branch(
122 124
 				t,
123 125
 				i,
126
+#ifdef CANCEL_REASON_SUPPORT
127
+				&cancel_data->reason,
128
+#endif /* CANCEL_REASON_SUPPORT */
124 129
 				flags | ((t->uac[i].request.buffer==NULL)?
125 130
 					F_CANCEL_B_FAKE_REPLY:0) /* blind UAC? */
126 131
 			);
... ...
@@ -131,7 +136,7 @@ int cancel_uacs( struct cell *t, branch_bm_t cancel_bm, int flags)
131 136
 
132 137
 int cancel_all_uacs(struct cell *trans, int how)
133 138
 {
134
-	branch_bm_t cancel_bm;
139
+	struct cancel_info cancel_data;
135 140
 	int i,j;
136 141
 
137 142
 #ifdef EXTRA_DEBUG
... ...
@@ -139,10 +144,10 @@ int cancel_all_uacs(struct cell *trans, int how)
139 144
 #endif
140 145
 	DBG("Canceling T@%p [%u:%u]\n", trans, trans->hash_index, trans->label);
141 146
 	
142
-	cancel_bm=0;
143
-	prepare_to_cancel(trans, &cancel_bm, 0);
147
+	init_cancel_info(&cancel_data);
148
+	prepare_to_cancel(trans, &cancel_data.cancel_bitmap, 0);
144 149
 	 /* tell tm to cancel the call */
145
-	i=cancel_uacs(trans, cancel_bm, how);
150
+	i=cancel_uacs(trans, &cancel_data, how);
146 151
 	
147 152
 	if (how & F_CANCEL_UNREF)
148 153
 #ifndef TM_DEL_UNREF
... ...
@@ -172,6 +177,7 @@ int cancel_all_uacs(struct cell *trans, int how)
172 177
  *
173 178
  * params:  t - transaction
174 179
  *          branch - branch number to be canceled
180
+ *          reason - cancel reason structure
175 181
  *          flags - howto cancel: 
176 182
  *                   F_CANCEL_B_KILL - will completely stop the 
177 183
  *                     branch (stops the timers), use with care
... ...
@@ -202,13 +208,17 @@ int cancel_all_uacs(struct cell *trans, int how)
202 208
  *          - checking for buffer==0 under REPLY_LOCK is no enough, an 
203 209
  *           atomic_cmpxhcg or atomic_get_and_set _must_ be used.
204 210
  */
205
-int cancel_branch( struct cell *t, int branch, int flags )
211
+int cancel_branch( struct cell *t, int branch,
212
+	#ifdef CANCEL_REASON_SUPPORT
213
+					struct cancel_reason* reason,
214
+	#endif /* CANCEL_REASON_SUPPORT */
215
+					int flags )
206 216
 {
207 217
 	char *cancel;
208 218
 	unsigned int len;
209 219
 	struct retr_buf *crb, *irb;
210 220
 	int ret;
211
-	branch_bm_t tmp_bm;
221
+	struct cancel_info tmp_cd;
212 222
 	void* pcbuf;
213 223
 
214 224
 	crb=&t->uac[branch].local_cancel;
... ...
@@ -236,7 +246,7 @@ int cancel_branch( struct cell *t, int branch, int flags )
236 246
 			atomic_set_long(pcbuf, 0);
237 247
 			if (flags & F_CANCEL_B_FAKE_REPLY){
238 248
 				LOCK_REPLIES(t);
239
-				if (relay_reply(t, FAKED_REPLY, branch, 487, &tmp_bm, 1) == 
249
+				if (relay_reply(t, FAKED_REPLY, branch, 487, &tmp_cd, 1) == 
240 250
 										RPS_ERROR){
241 251
 					return -1;
242 252
 				}
... ...
@@ -257,7 +267,7 @@ int cancel_branch( struct cell *t, int branch, int flags )
257 267
 				if (flags & F_CANCEL_B_FAKE_REPLY){
258 268
 					stop_rb_timers( irb ); /* stop even the fr timer */
259 269
 					LOCK_REPLIES(t);
260
-					if (relay_reply(t, FAKED_REPLY, branch, 487, &tmp_bm, 1)== 
270
+					if (relay_reply(t, FAKED_REPLY, branch, 487, &tmp_cd, 1)== 
261 271
 											RPS_ERROR){
262 272
 						return -1;
263 273
 					}
... ...
@@ -272,10 +282,19 @@ int cancel_branch( struct cell *t, int branch, int flags )
272 282
 
273 283
 	if (cfg_get(tm, tm_cfg, reparse_invite)) {
274 284
 		/* build the CANCEL from the INVITE which was sent out */
275
-		cancel = build_local_reparse(t, branch, &len, CANCEL, CANCEL_LEN, &t->to);
285
+		cancel = build_local_reparse(t, branch, &len, CANCEL, CANCEL_LEN,
286
+									 &t->to
287
+	#ifdef CANCEL_REASON_SUPPORT
288
+									 , reason
289
+	#endif /* CANCEL_REASON_SUPPORT */
290
+									 );
276 291
 	} else {
277
-		/* build the CANCEL from the reveived INVITE */
278
-		cancel = build_local(t, branch, &len, CANCEL, CANCEL_LEN, &t->to);
292
+		/* build the CANCEL from the received INVITE */
293
+		cancel = build_local(t, branch, &len, CANCEL, CANCEL_LEN, &t->to
294
+	#ifdef CANCEL_REASON_SUPPORT
295
+								, reason
296
+	#endif /* CANCEL_REASON_SUPPORT */
297
+								);
279 298
 	}
280 299
 	if (!cancel) {
281 300
 		LOG(L_ERR, "ERROR: attempt to build a CANCEL failed\n");
... ...
@@ -333,7 +352,7 @@ void rpc_cancel(rpc_t* rpc, void* c)
333 352
 {
334 353
 	struct cell *trans;
335 354
 	static char cseq[128], callid[128];
336
-	branch_bm_t cancel_bm;
355
+	struct cancel_info cancel_data;
337 356
 	int i,j;
338 357
 
339 358
 	str cseq_s;   /* cseq */
... ...
@@ -341,7 +360,7 @@ void rpc_cancel(rpc_t* rpc, void* c)
341 360
 
342 361
 	cseq_s.s=cseq;
343 362
 	callid_s.s=callid;
344
-	cancel_bm=0;
363
+	init_cancel_info(&cancel_data);
345 364
 
346 365
 	if (rpc->scan(c, "SS", &callid_s, &cseq_s) < 2) {
347 366
 		rpc->fault(c, 400, "Callid and CSeq expected as parameters");
... ...
@@ -354,10 +373,10 @@ void rpc_cancel(rpc_t* rpc, void* c)
354 373
 		return;
355 374
 	}
356 375
 	/*  find the branches that need cancel-ing */
357
-	prepare_to_cancel(trans, &cancel_bm, 0);
376
+	prepare_to_cancel(trans, &cancel_data.cancel_bitmap, 0);
358 377
 	 /* tell tm to cancel the call */
359 378
 	DBG("Now calling cancel_uacs\n");
360
-	i=cancel_uacs(trans, cancel_bm, 0); /* don't fake 487s, 
379
+	i=cancel_uacs(trans, &cancel_data, 0); /* don't fake 487s, 
361 380
 										 just wait for timeout */
362 381
 	
363 382
 	/* t_lookup_callid REF`d the transaction for us, we must UNREF here! */
... ...
@@ -35,6 +35,7 @@
35 35
  *  2009-07-14  should_cancel_branch() renamed to prepare_cancel_branch() to
36 36
  *               better reflect its purpose
37 37
  *              which_cancel() renamed to prepare_to_cancel() (andrei)
38
+ * 2010-02-26  cancel reason (rfc3326) basic support (andrei)
38 39
  */
39 40
 
40 41
 
... ...
@@ -46,6 +47,7 @@
46 47
 #include "../../atomic_ops.h"
47 48
 #include "defs.h"
48 49
 #include "h_table.h"
50
+#include "t_reply.h"
49 51
 
50 52
 
51 53
 /* a buffer is empty but cannot be used by anyone else;
... ...
@@ -79,9 +81,13 @@
79 81
 
80 82
 
81 83
 void prepare_to_cancel(struct cell *t, branch_bm_t *cancel_bm, branch_bm_t s);
82
-int cancel_uacs( struct cell *t, branch_bm_t cancel_bm, int flags );
84
+int cancel_uacs( struct cell *t, struct cancel_info* cancel_data, int flags );
83 85
 int cancel_all_uacs(struct cell *trans, int how);
84
-int cancel_branch( struct cell *t, int branch, int flags );
86
+int cancel_branch( struct cell *t, int branch,
87
+#ifdef CANCEL_REASON_SUPPORT
88
+					struct cancel_reason* reason,
89
+#endif /* CANCEL_REASON_SUPPORT */
90
+					int flags );
85 91
 
86 92
 typedef int(*cancel_uacs_f)( struct cell *t, branch_bm_t cancel_bm,
87 93
 								int flags );
... ...
@@ -929,7 +929,11 @@ int e2e_cancel_branch( struct sip_msg *cancel_msg, struct cell *t_cancel,
929 929
 			"thus lumps are not applied to the message!\n");
930 930
 		}
931 931
 		shbuf=build_local_reparse( t_invite, branch, &len, CANCEL,
932
-									CANCEL_LEN, &t_invite->to);
932
+									CANCEL_LEN, &t_invite->to
933
+#ifdef CANCEL_REASON_SUPPORT
934
+									, 0
935
+#endif /* CANCEL_REASON_SUPPORT */
936
+									);
933 937
 		if (unlikely(!shbuf)) {
934 938
 			LOG(L_ERR, "e2e_cancel_branch: printing e2e cancel failed\n");
935 939
 			ret=ser_error=E_OUT_OF_MEM;
... ...
@@ -962,13 +966,118 @@ error:
962 966
 
963 967
 
964 968
 
965
-void e2e_cancel( struct sip_msg *cancel_msg, 
969
+#ifdef CANCEL_REASON_SUPPORT
970
+/** create a cancel reason structure packed into a single shm. block.
971
+  * From a cause and a pointer to a str or cancel_msg, build a
972
+  * packed cancel reason structure (CANCEL_REAS_PACKED_HDRS), using a
973
+  * single memory allocation (so that it can be freed by a simple shm_free().
974
+  * @param cause - cancel cause, @see cancel_reason for more details.
975
+  * @param data - depends on the cancel cause.
976
+  * @return pointer to shm. packed cancel reason struct. on success,
977
+  *        0 on error
978
+  */
979
+static struct cancel_reason* cancel_reason_pack(short cause, void* data,
980
+													struct cell* t)
981
+{
982
+	char* d;
983
+	struct cancel_reason* cr;
984
+	int reason_len;
985
+	int code_len;
986
+	struct hdr_field *reas1, *reas_last, *hdr;
987
+	str* txt;
988
+	struct sip_msg* e2e_cancel;
989
+	
990
+	if (likely(cause != CANCEL_REAS_UNKNOWN)){
991
+		reason_len = 0;
992
+		txt = 0;
993
+		e2e_cancel = 0;
994
+		reas1 = 0;
995
+		reas_last = 0;
996
+		if (likely(cause == CANCEL_REAS_RCVD_CANCEL &&
997
+					data && !(t->flags & T_NO_E2E_CANCEL_REASON))) {
998
+			/* parse the entire cancel, to get all the Reason headers */
999
+			e2e_cancel = data;
1000
+			parse_headers(e2e_cancel, HDR_EOH_F, 0);
1001
+			for(hdr=get_hdr(e2e_cancel, HDR_REASON_T), reas1=hdr;
1002
+					hdr; hdr=next_sibling_hdr(hdr)) {
1003
+				/* hdr->len includes CRLF */
1004
+				reason_len += hdr->len;
1005
+				reas_last=hdr;
1006
+			}
1007
+		} else if (likely(cause > 0 &&
1008
+					cfg_get(tm, tm_cfg, local_cancel_reason))){
1009
+			txt = (str*) data;
1010
+			/* Reason: SIP;cause=<reason->cause>[;text=<reason->u.text.s>] */
1011
+			reason_len = REASON_PREFIX_LEN + USHORT2SBUF_MAX_LEN +
1012
+				((txt && txt->s)?
1013
+					REASON_TEXT_LEN + 1 + txt->len + 1 : 0) +
1014
+				CRLF_LEN;
1015
+		} else if (cause == CANCEL_REAS_PACKED_HDRS &&
1016
+					!(t->flags & T_NO_E2E_CANCEL_REASON) && data) {
1017
+			txt = (str*) data;
1018
+			reason_len = txt?txt->len:0;
1019
+		} else if (unlikely(cause < CANCEL_REAS_MIN)) {
1020
+			BUG("unhandled reason cause %d\n", cause);
1021
+			goto error;
1022
+		}
1023
+		
1024
+		if (unlikely(reason_len == 0))
1025
+			return 0; /* nothing to do, no reason */
1026
+		cr = shm_malloc(sizeof(struct cancel_reason) + reason_len);
1027
+		if (unlikely(cr == 0))
1028
+				goto error;
1029
+		d = (char*)cr +sizeof(*cr);
1030
+		cr->cause = CANCEL_REAS_PACKED_HDRS;
1031
+		cr->u.packed_hdrs.s = d;
1032
+		cr->u.packed_hdrs.len = reason_len;
1033
+		
1034
+		if (cause == CANCEL_REAS_RCVD_CANCEL) {
1035
+			for(hdr=reas1; hdr; hdr=next_sibling_hdr(hdr)) {
1036
+				/* hdr->len includes CRLF */
1037
+				append_str(d, hdr->name.s, hdr->len);
1038
+				if (likely(hdr==reas_last))
1039
+					break;
1040
+			}
1041
+		} else if (likely(cause > 0)) {
1042
+			append_str(d, REASON_PREFIX, REASON_PREFIX_LEN);
1043
+			code_len=ushort2sbuf(cause, d, reason_len - 
1044
+									(int)(d - (char*)cr - sizeof(*cr)));
1045
+			if (unlikely(code_len==0)) {
1046
+				shm_free(cr);
1047
+				cr = 0;
1048
+				BUG("not enough space to write reason code");
1049
+				goto error;
1050
+			}
1051
+			d+=code_len;
1052
+			if (txt && txt->s){
1053
+				append_str(d, REASON_TEXT, REASON_TEXT_LEN);
1054
+				*d='"'; d++;
1055
+				append_str(d, txt->s, txt->len);
1056
+				*d='"'; d++;
1057
+			}
1058
+			append_str(d, CRLF, CRLF_LEN);
1059
+		} else if (cause == CANCEL_REAS_PACKED_HDRS) {
1060
+			append_str(d, txt->s, txt->len);
1061
+		}
1062
+		return cr;
1063
+	}
1064
+error:
1065
+	return 0;
1066
+}
1067
+#endif /* CANCEL_REASON_SUPPORT */
1068
+
1069
+
1070
+
1071
+void e2e_cancel( struct sip_msg *cancel_msg,
966 1072
 	struct cell *t_cancel, struct cell *t_invite )
967 1073
 {
968 1074
 	branch_bm_t cancel_bm;
969 1075
 #ifndef E2E_CANCEL_HOP_BY_HOP
970 1076
 	branch_bm_t tmp_bm;
971
-#endif
1077
+#elif defined (CANCEL_REASON_SUPPORT)
1078
+	struct cancel_reason* reason;
1079
+	int free_reason;
1080
+#endif /* E2E_CANCEL_HOP_BY_HOP */
972 1081
 	int i;
973 1082
 	int lowest_error;
974 1083
 	int ret;
... ...
@@ -1013,6 +1122,21 @@ void e2e_cancel( struct sip_msg *cancel_msg,
1013 1122
 	 * have 0 branches and we check for the branch number in 
1014 1123
 	 * t_reply_matching() ).
1015 1124
 	 */
1125
+#ifdef CANCEL_REASON_SUPPORT
1126
+	free_reason = 0;
1127
+	reason = 0;
1128
+	if (likely(t_invite->uas.cancel_reas == 0)){
1129
+		reason = cancel_reason_pack(CANCEL_REAS_RCVD_CANCEL, cancel_msg,
1130
+									t_invite);
1131
+		/* set if not already set */
1132
+		if (unlikely(reason &&
1133
+					atomic_cmpxchg_long((void*)&t_invite->uas.cancel_reas,
1134
+										0, (long)reason) != 0)) {
1135
+			/* already set, failed to re-set it */
1136
+			free_reason = 1;
1137
+		}
1138
+	}
1139
+#endif /* CANCEL_REASON_SUPPORT */
1016 1140
 	for (i=0; i<t_invite->nr_of_outgoings; i++)
1017 1141
 		if (cancel_bm & (1<<i)) {
1018 1142
 			/* it's safe to get the reply lock since e2e_cancel is
... ...
@@ -1022,6 +1146,9 @@ void e2e_cancel( struct sip_msg *cancel_msg,
1022 1146
 			ret=cancel_branch(
1023 1147
 				t_invite,
1024 1148
 				i,
1149
+#ifdef CANCEL_REASON_SUPPORT
1150
+				reason,
1151
+#endif /* CANCEL_REASON_SUPPORT */
1025 1152
 				cfg_get(tm,tm_cfg, cancel_b_flags)
1026 1153
 					| ((t_invite->uac[i].request.buffer==NULL)?
1027 1154
 						F_CANCEL_B_FAKE_REPLY:0) /* blind UAC? */
... ...
@@ -1029,6 +1156,12 @@ void e2e_cancel( struct sip_msg *cancel_msg,
1029 1156
 			if (ret<0) cancel_bm &= ~(1<<i);
1030 1157
 			if (ret<lowest_error) lowest_error=ret;
1031 1158
 		}
1159
+#ifdef CANCEL_REASON_SUPPORT
1160
+	if (unlikely(free_reason)) {
1161
+		/* reason was not set as the global reason => free it */
1162
+		shm_free(reason);
1163
+	}
1164
+#endif /* CANCEL_REASON_SUPPORT */
1032 1165
 #else /* ! E2E_CANCEL_HOP_BY_HOP */
1033 1166
 	/* fix label -- it must be same for reply matching (the label is part of
1034 1167
 	 * the generated via branch for the cancels sent upstream and if it
... ...
@@ -1266,6 +1266,10 @@ static inline void init_new_t(struct cell *new_cell, struct sip_msg *p_msg)
1266 1266
 					(!cfg_get(tm, tm_cfg, tm_auto_inv_100) -1);
1267 1267
 		new_cell->flags|=T_DISABLE_6xx &
1268 1268
 					(!cfg_get(tm, tm_cfg, disable_6xx) -1);
1269
+#ifdef CANCEL_REASON_SUPPORT
1270
+		new_cell->flags|=T_NO_E2E_CANCEL_REASON &
1271
+					(!!cfg_get(tm, tm_cfg, e2e_cancel_reason) -1);
1272
+#endif /* CANCEL_REASON_SUPPORT */
1269 1273
 		/* reset flags */
1270 1274
 		new_cell->flags &=
1271 1275
 			(~ get_msgid_val(user_cell_reset_flags, p_msg->id, int));
... ...
@@ -46,6 +46,7 @@
46 46
  *               resolving nexthop twice (andrei)
47 47
  * 2007-05-28: build_local_reparse() is introdued: it uses the outgoing
48 48
  *             INVITE as a source to construct a CANCEL or ACK (Miklos)
49
+ * 2010-02-26  cancel reason (rfc3326) basic support (andrei)
49 50
  */
50 51
 
51 52
 #include "defs.h"
... ...
@@ -72,6 +73,7 @@
72 73
 #include "../../cfg_core.h" /* cfg_get(core, core_cfg, use_dns_failover) */
73 74
 #endif
74 75
 
76
+
75 77
 /* convenience macros */
76 78
 #define memapp(_d,_s,_len) \
77 79
 	do{\
... ...
@@ -84,7 +86,11 @@
84 86
    customers of this function are local ACK and local CANCEL
85 87
  */
86 88
 char *build_local(struct cell *Trans,unsigned int branch,
87
-	unsigned int *len, char *method, int method_len, str *to)
89
+	unsigned int *len, char *method, int method_len, str *to
90
+#ifdef CANCEL_REASON_SUPPORT
91
+	, struct cancel_reason* reason
92
+#endif /* CANCEL_REASON_SUPPORT */
93
+	)
88 94
 {
89 95
 	char                *cancel_buf, *p, *via;
90 96
 	unsigned int         via_len;
... ...
@@ -94,6 +100,10 @@ char *build_local(struct cell *Trans,unsigned int branch,
94 100
 	str branch_str;
95 101
 	str via_id;
96 102
 	struct hostport hp;
103
+#ifdef CANCEL_REASON_SUPPORT
104
+	int reason_len, code_len;
105
+	struct hdr_field *reas1, *reas_last;
106
+#endif /* CANCEL_REASON_SUPPORT */
97 107
 
98 108
 	/* init */
99 109
 	via_id.s=0;
... ...
@@ -157,7 +167,40 @@ char *build_local(struct cell *Trans,unsigned int branch,
157 167
 		*len += user_agent_hdr.len + CRLF_LEN;
158 168
 	}
159 169
 	/* Content Length, EoM */
160
-	*len+=CONTENT_LENGTH_LEN+1 + CRLF_LEN + CRLF_LEN;
170
+	*len+=CONTENT_LENGTH_LEN+1 + CRLF_LEN;
171
+#ifdef CANCEL_REASON_SUPPORT
172
+	reason_len = 0;
173
+	reas1 = 0;
174
+	reas_last = 0;
175
+	/* compute reason size (if no reason or disabled => reason_len == 0)*/
176
+	if (reason && reason->cause != CANCEL_REAS_UNKNOWN){
177
+		if (likely(reason->cause > 0 &&
178
+					cfg_get(tm, tm_cfg, local_cancel_reason))){
179
+			/* Reason: SIP;cause=<reason->cause>[;text=<reason->u.text.s>] */
180
+			reason_len = REASON_PREFIX_LEN + USHORT2SBUF_MAX_LEN +
181
+				(reason->u.text.s?
182
+					REASON_TEXT_LEN + 1 + reason->u.text.len + 1 : 0) +
183
+				CRLF_LEN;
184
+		} else if (likely(reason->cause == CANCEL_REAS_PACKED_HDRS &&
185
+					!(Trans->flags & T_NO_E2E_CANCEL_REASON))) {
186
+			reason_len = reason->u.packed_hdrs.len;
187
+		} else if (reason->cause == CANCEL_REAS_RCVD_CANCEL &&
188
+					reason->u.e2e_cancel &&
189
+					!(Trans->flags & T_NO_E2E_CANCEL_REASON)) {
190
+			/* parse the entire cancel, to get all the Reason headers */
191
+			parse_headers(reason->u.e2e_cancel, HDR_EOH_F, 0);
192
+			for(hdr=get_hdr(reason->u.e2e_cancel, HDR_REASON_T), reas1=hdr;
193
+					hdr; hdr=next_sibling_hdr(hdr)) {
194
+				/* hdr->len includes CRLF */
195
+				reason_len += hdr->len;
196
+				reas_last=hdr;
197
+			}
198
+		} else if (unlikely(reason->cause < CANCEL_REAS_MIN))
199
+			BUG("unhandled reason cause %d\n", reason->cause);
200
+	}
201
+	*len+= reason_len;
202
+#endif /* CANCEL_REASON_SUPPORT */
203
+	*len+= CRLF_LEN; /* end of msg. */
161 204
 
162 205
 	cancel_buf=shm_malloc( *len+1 );
163 206
 	if (!cancel_buf)
... ...
@@ -197,9 +240,38 @@ char *build_local(struct cell *Trans,unsigned int branch,
197 240
 		append_str(p, user_agent_hdr.s, user_agent_hdr.len );
198 241
 		append_str(p, CRLF, CRLF_LEN );
199 242
 	}
200
-	/* Content Length, EoM */
201
-	append_str(p, CONTENT_LENGTH "0" CRLF CRLF ,
202
-		CONTENT_LENGTH_LEN+1 + CRLF_LEN + CRLF_LEN);
243
+	/* Content Length */
244
+	append_str(p, CONTENT_LENGTH "0" CRLF, CONTENT_LENGTH_LEN + 1 + CRLF_LEN);
245
+#ifdef CANCEL_REASON_SUPPORT
246
+	/* add reason if needed */
247
+	if (reason_len) {
248
+		if (likely(reason->cause > 0)) {
249
+			append_str(p, REASON_PREFIX, REASON_PREFIX_LEN);
250
+			code_len=ushort2sbuf(reason->cause, p,
251
+									*len-(int)(p-cancel_buf));
252
+			if (unlikely(code_len==0))
253
+				BUG("not enough space to write reason code");
254
+			p+=code_len;
255
+			if (reason->u.text.s){
256
+				append_str(p, REASON_TEXT, REASON_TEXT_LEN);
257
+				*p='"'; p++;
258
+				append_str(p, reason->u.text.s, reason->u.text.len);
259
+				*p='"'; p++;
260
+			}
261
+			append_str(p, CRLF, CRLF_LEN);
262
+		} else if (likely(reason->cause == CANCEL_REAS_PACKED_HDRS)) {
263
+			append_str(p, reason->u.packed_hdrs.s, reason->u.packed_hdrs.len);
264
+		} else if (reason->cause == CANCEL_REAS_RCVD_CANCEL) {
265
+			for(hdr=reas1; hdr; hdr=next_sibling_hdr(hdr)) {
266
+				/* hdr->len includes CRLF */
267
+				append_str(p, hdr->name.s, hdr->len);
268
+				if (likely(hdr==reas_last))
269
+					break;
270
+			}
271
+		}
272
+	}
273
+#endif /* CANCEL_REASON_SUPPORT */
274
+	append_str(p, CRLF, CRLF_LEN); /* msg. end */
203 275
 	*p=0;
204 276
 
205 277
 	pkg_free(via);
... ...
@@ -217,7 +289,11 @@ error:
217 289
  * Can not be used to build other type of requests!
218 290
  */
219 291
 char *build_local_reparse(struct cell *Trans,unsigned int branch,
220
-	unsigned int *len, char *method, int method_len, str *to)
292
+	unsigned int *len, char *method, int method_len, str *to
293
+#ifdef CANCEL_REASON_SUPPORT
294
+	, struct cancel_reason *reason
295
+#endif /* CANCEL_REASON_SUPPORT */
296
+	)
221 297
 {
222 298
 	char	*invite_buf, *invite_buf_end;
223 299
 	char	*cancel_buf;
... ...
@@ -225,6 +301,11 @@ char *build_local_reparse(struct cell *Trans,unsigned int branch,
225 301
 	short	invite_len;
226 302
 	enum _hdr_types_t	hf_type;
227 303
 	int	first_via, to_len;
304
+	int cancel_buf_len;
305
+#ifdef CANCEL_REASON_SUPPORT
306
+	int reason_len, code_len;
307
+	struct hdr_field *reas1, *reas_last, *hdr;
308
+#endif /* CANCEL_REASON_SUPPORT */
228 309
 
229 310
 	invite_buf = Trans->uac[branch].request.buffer;
230 311
 	invite_len = Trans->uac[branch].request.buffer_len;
... ...
@@ -234,9 +315,43 @@ char *build_local_reparse(struct cell *Trans,unsigned int branch,
234 315
 		goto error;
235 316
 	}
236 317
 	if ((*invite_buf != 'I') && (*invite_buf != 'i')) {
237
-		LOG(L_ERR, "ERROR: build_local_reparse: trying to call build_local_reparse() for a non-INVITE request?\n");
318
+		LOG(L_ERR, "ERROR: trying to call build_local_reparse()"
319
+					" for a non-INVITE request?\n");
238 320
 		goto error;
239 321
 	}
322
+	
323
+#ifdef CANCEL_REASON_SUPPORT
324
+	reason_len = 0;
325
+	reas1 = 0;
326
+	reas_last = 0;
327
+	/* compute reason size (if no reason or disabled => reason_len == 0)*/
328
+	if (reason && reason->cause != CANCEL_REAS_UNKNOWN){
329
+		if (likely(reason->cause > 0 &&
330
+					cfg_get(tm, tm_cfg, local_cancel_reason))){
331
+			/* Reason: SIP;cause=<reason->cause>[;text=<reason->u.text.s>] */
332
+			reason_len = REASON_PREFIX_LEN + USHORT2SBUF_MAX_LEN +
333
+				(reason->u.text.s?
334
+					REASON_TEXT_LEN + 1 + reason->u.text.len + 1 : 0) +
335
+				CRLF_LEN;
336
+		} else if (likely(reason->cause == CANCEL_REAS_PACKED_HDRS &&
337
+					!(Trans->flags & T_NO_E2E_CANCEL_REASON))) {
338
+			reason_len = reason->u.packed_hdrs.len;
339
+		} else if (reason->cause == CANCEL_REAS_RCVD_CANCEL &&
340
+					reason->u.e2e_cancel &&
341
+					!(Trans->flags & T_NO_E2E_CANCEL_REASON)) {
342
+			/* parse the entire cancel, to get all the Reason headers */
343
+			parse_headers(reason->u.e2e_cancel, HDR_EOH_F, 0);
344
+			for(hdr=get_hdr(reason->u.e2e_cancel, HDR_REASON_T), reas1=hdr;
345
+					hdr; hdr=next_sibling_hdr(hdr)) {
346
+				/* hdr->len includes CRLF */
347
+				reason_len += hdr->len;
348
+				reas_last=hdr;
349
+			}
350
+		} else if (unlikely(reason->cause < CANCEL_REAS_MIN))
351
+			BUG("unhandled reason cause %d\n", reason->cause);
352
+	}
353
+#endif /* CANCEL_REASON_SUPPORT */
354
+
240 355
 	invite_buf_end = invite_buf + invite_len;
241 356
 	s = invite_buf;
242 357
 
... ...
@@ -245,10 +360,15 @@ char *build_local_reparse(struct cell *Trans,unsigned int branch,
245 360
 	I just extend it with the length of new To HF to be sure.
246 361
 	Ugly, but we avoid lots of checks and memory allocations this way */
247 362
 	to_len = to ? to->len : 0;
248
-	cancel_buf = shm_malloc(sizeof(char)*(invite_len + to_len));
363
+#ifdef CANCEL_REASON_SUPPORT
364
+	cancel_buf_len = invite_len + to_len + reason_len;
365
+#else
366
+	cancel_buf_len = invite_len + to_len;
367
+#endif /* CANCEL_REASON_SUPPORT */
368
+	cancel_buf = shm_malloc(sizeof(char)*cancel_buf_len);
249 369
 	if (!cancel_buf)
250 370
 	{
251
-		LOG(L_ERR, "ERROR: build_local_reparse: cannot allocate shared memory\n");
371
+		LOG(L_ERR, "ERROR: cannot allocate shared memory\n");
252 372
 		goto error;
253 373
 	}
254 374
 	d = cancel_buf;
... ...
@@ -281,7 +401,8 @@ char *build_local_reparse(struct cell *Trans,unsigned int branch,
281 401
 			case HDR_CSEQ_T:
282 402
 				/* find the method name and replace it */
283 403
 				while ((s < invite_buf_end)
284
-					&& ((*s == ':') || (*s == ' ') || (*s == '\t') || ((*s >= '0') && (*s <= '9')))
404
+					&& ((*s == ':') || (*s == ' ') || (*s == '\t') ||
405
+						((*s >= '0') && (*s <= '9')))
285 406
 					) s++;
286 407
 				append_str(d, s1, s - s1);
287 408
 				append_str(d, method, method_len);
... ...
@@ -300,7 +421,8 @@ char *build_local_reparse(struct cell *Trans,unsigned int branch,
300 421
 
301 422
 			case HDR_TO_T:
302 423
 				if (to_len == 0) {
303
-					/* there is no To tag required, just copy paste the header */
424
+					/* there is no To tag required, just copy paste
425
+					   the header */
304 426
 					s = lw_next_line(s, invite_buf_end);
305 427
 					append_str(d, s1, s - s1);
306 428
 				} else {
... ...
@@ -336,6 +458,41 @@ char *build_local_reparse(struct cell *Trans,unsigned int branch,
336 458
 
337 459
 			case HDR_EOH_T:
338 460
 				/* end of SIP message found */
461
+#ifdef CANCEL_REASON_SUPPORT
462