Browse code

dispatcher(k): fixes to call load dispatching

- this alg implementation was not completed before
- exported some functions and parameters to cfg in order to cope with
stateless proxy mode

Daniel-Constantin Mierla authored on 08/09/2010 17:46:26
Showing 6 changed files
... ...
@@ -18,9 +18,9 @@ Carsten Bock
18 18
 
19 19
    Copyright © 2004 FhG FOKUS
20 20
 
21
-   Copyright © 2005 Voice-System.RO
22
-   Revision History
23
-   Revision $Revision$ $Date$
21
+   Copyright © 2005 Voice Sistem
22
+
23
+   Copyright © 2010 Daniel-Constantin Mierla (asipto.com)
24 24
      __________________________________________________________________
25 25
 
26 26
    Table of Contents
... ...
@@ -48,14 +48,20 @@ Carsten Bock
48 48
               3.11. dst_avp (str)
49 49
               3.12. grp_avp (str)
50 50
               3.13. cnt_avp (str)
51
-              3.14. hash_pvar (str)
52
-              3.15. setid_pvar (str)
53
-              3.16. ds_ping_method (string)
54
-              3.17. ds_ping_from (string)
55
-              3.18. ds_ping_interval (int)
56
-              3.19. ds_probing_threshhold (int)
57
-              3.20. ds_probing_mode (int)
58
-              3.21. ds_append_branch (int)
51
+              3.14. dstid_avp (str)
52
+              3.15. attrs_avp (str)
53
+              3.16. hash_pvar (str)
54
+              3.17. setid_pvar (str)
55
+              3.18. ds_ping_method (string)
56
+              3.19. ds_ping_from (string)
57
+              3.20. ds_ping_interval (int)
58
+              3.21. ds_probing_threshhold (int)
59
+              3.22. ds_probing_mode (int)
60
+              3.23. ds_append_branch (int)
61
+              3.24. ds_hash_size (int)
62
+              3.25. ds_hash_expire (int)
63
+              3.26. ds_hash_initexpire (int)
64
+              3.27. ds_hash_check_interval (int)
59 65
 
60 66
         4. Exported Functions
61 67
 
... ...
@@ -67,6 +73,8 @@ Carsten Bock
67 73
               4.6. ds_mark_dst("s")
68 74
               4.7. ds_is_from_list()
69 75
               4.8. ds_is_from_list("group")
76
+              4.9. ds_load_update()
77
+              4.10. ds_load_unset()
70 78
 
71 79
         5. Exported MI Functions
72 80
 
... ...
@@ -96,18 +104,25 @@ Carsten Bock
96 104
    1.11. Set the “dst_avp” parameter
97 105
    1.12. Set the “grp_avp” parameter
98 106
    1.13. Set the “cnt_avp” parameter
99
-   1.14. Use $avp(i:273) for hashing:
100
-   1.15. Use combination of PVs for hashing:
101
-   1.16. Set the “setid_pvar” parameter
102
-   1.17. Set the “ds_ping_method” parameter
103
-   1.18. Set the “ds_ping_from” parameter
104
-   1.19. Set the “ds_ping_interval” parameter
105
-   1.20. Set the “ds_probing_threshhold” parameter
106
-   1.21. Set the “ds_probing_mode” parameter
107
-   1.22. Set the “ds_append_branch” parameter
108
-   1.23. ds_select_dst usage
109
-   1.24. dispatcher list file
110
-   1.25. Kamailio config script - sample dispatcher usage
107
+   1.14. Set the “dstid_avp” parameter
108
+   1.15. Set the “attrs_avp” parameter
109
+   1.16. Use $avp(i:273) for hashing:
110
+   1.17. Use combination of PVs for hashing:
111
+   1.18. Set the “setid_pvar” parameter
112
+   1.19. Set the “ds_ping_method” parameter
113
+   1.20. Set the “ds_ping_from” parameter
114
+   1.21. Set the “ds_ping_interval” parameter
115
+   1.22. Set the “ds_probing_threshhold” parameter
116
+   1.23. Set the “ds_probing_mode” parameter
117
+   1.24. Set the “ds_append_branch” parameter
118
+   1.25. Set the “ds_hash_size” parameter
119
+   1.26. Set the “ds_hash_expire” parameter
120
+   1.27. Set the “ds_hash_initexpire” parameter
121
+   1.28. Set the “ds_hash_check_interval” parameter
122
+   1.29. ds_select_dst usage
123
+   1.30. ds_load_unset usage
124
+   1.31. dispatcher list file
125
+   1.32. Kamailio config script - sample dispatcher usage
111 126
 
112 127
 Chapter 1. Admin Guide
113 128
 
... ...
@@ -134,14 +149,20 @@ Chapter 1. Admin Guide
134 149
         3.11. dst_avp (str)
135 150
         3.12. grp_avp (str)
136 151
         3.13. cnt_avp (str)
137
-        3.14. hash_pvar (str)
138
-        3.15. setid_pvar (str)
139
-        3.16. ds_ping_method (string)
140
-        3.17. ds_ping_from (string)
141
-        3.18. ds_ping_interval (int)
142
-        3.19. ds_probing_threshhold (int)
143
-        3.20. ds_probing_mode (int)
144
-        3.21. ds_append_branch (int)
152
+        3.14. dstid_avp (str)
153
+        3.15. attrs_avp (str)
154
+        3.16. hash_pvar (str)
155
+        3.17. setid_pvar (str)
156
+        3.18. ds_ping_method (string)
157
+        3.19. ds_ping_from (string)
158
+        3.20. ds_ping_interval (int)
159
+        3.21. ds_probing_threshhold (int)
160
+        3.22. ds_probing_mode (int)
161
+        3.23. ds_append_branch (int)
162
+        3.24. ds_hash_size (int)
163
+        3.25. ds_hash_expire (int)
164
+        3.26. ds_hash_initexpire (int)
165
+        3.27. ds_hash_check_interval (int)
145 166
 
146 167
    4. Exported Functions
147 168
 
... ...
@@ -153,6 +174,8 @@ Chapter 1. Admin Guide
153 174
         4.6. ds_mark_dst("s")
154 175
         4.7. ds_is_from_list()
155 176
         4.8. ds_is_from_list("group")
177
+        4.9. ds_load_update()
178
+        4.10. ds_load_unset()
156 179
 
157 180
    5. Exported MI Functions
158 181
 
... ...
@@ -205,14 +228,20 @@ Chapter 1. Admin Guide
205 228
    3.11. dst_avp (str)
206 229
    3.12. grp_avp (str)
207 230
    3.13. cnt_avp (str)
208
-   3.14. hash_pvar (str)
209
-   3.15. setid_pvar (str)
210
-   3.16. ds_ping_method (string)
211
-   3.17. ds_ping_from (string)
212
-   3.18. ds_ping_interval (int)
213
-   3.19. ds_probing_threshhold (int)
214
-   3.20. ds_probing_mode (int)
215
-   3.21. ds_append_branch (int)
231
+   3.14. dstid_avp (str)
232
+   3.15. attrs_avp (str)
233
+   3.16. hash_pvar (str)
234
+   3.17. setid_pvar (str)
235
+   3.18. ds_ping_method (string)
236
+   3.19. ds_ping_from (string)
237
+   3.20. ds_ping_interval (int)
238
+   3.21. ds_probing_threshhold (int)
239
+   3.22. ds_probing_mode (int)
240
+   3.23. ds_append_branch (int)
241
+   3.24. ds_hash_size (int)
242
+   3.25. ds_hash_expire (int)
243
+   3.26. ds_hash_initexpire (int)
244
+   3.27. ds_hash_check_interval (int)
216 245
 
217 246
 3.1. list_file (string)
218 247
 
... ...
@@ -354,13 +383,13 @@ modparam("dispatcher", "force_dst", 1)
354 383
 
355 384
 Note
356 385
 
357
-   You must set this parameter if you want do do load balancing fail over.
386
+   You must set this parameter if you want to do load balancing fail over.
358 387
 
359 388
    Default value is “null” - don't add AVPs.
360 389
 
361 390
    Example 1.11. Set the “dst_avp” parameter
362 391
  ...
363
- modparam("dispatcher", "dst_avp", "$avp(i:271)")
392
+ modparam("dispatcher", "dst_avp", "$avp(dsdst)")
364 393
  ...
365 394
 
366 395
 3.12. grp_avp (str)
... ...
@@ -370,13 +399,13 @@ Note
370 399
 
371 400
 Note
372 401
 
373
-   You must set this parameter if you want do do load balancing fail over.
402
+   You must set this parameter if you want to do load balancing fail over.
374 403
 
375 404
    Default value is “null” - don't add AVP.
376 405
 
377 406
    Example 1.12. Set the “grp_avp” parameter
378 407
  ...
379
- modparam("dispatcher", "grp_avp", "$avp(i:272)")
408
+ modparam("dispatcher", "grp_avp", "$avp(dsgrp)")
380 409
  ...
381 410
 
382 411
 3.13. cnt_avp (str)
... ...
@@ -386,16 +415,46 @@ Note
386 415
 
387 416
 Note
388 417
 
389
-   You must set this parameter if you want do do load balancing fail over.
418
+   You must set this parameter if you want to do load balancing fail over.
390 419
 
391 420
    Default value is “null” - don't add AVP.
392 421
 
393 422
    Example 1.13. Set the “cnt_avp” parameter
394 423
  ...
395
- modparam("dispatcher", "cnt_avp", "$avp(i:273)")
424
+ modparam("dispatcher", "cnt_avp", "$avp(dscnt)")
425
+ ...
426
+
427
+3.14. dstid_avp (str)
428
+
429
+   The name of the avp storing the destination unique ID used for call
430
+   load based dispatching.
431
+
432
+Note
433
+
434
+   You must set this parameter if you want to do load balancing on call
435
+   load (alg 10).
436
+
437
+   Default value is “null” - don't add AVP.
438
+
439
+   Example 1.14. Set the “dstid_avp” parameter
440
+ ...
441
+ modparam("dispatcher", "dstid_avp", "$avp(dsdstid)")
396 442
  ...
397 443
 
398
-3.14. hash_pvar (str)
444
+3.15. attrs_avp (str)
445
+
446
+   The name of the avp storing destination's attributes value.
447
+
448
+Note
449
+
450
+   Default value is “null” - don't add AVP.
451
+
452
+   Example 1.15. Set the “attrs_avp” parameter
453
+ ...
454
+ modparam("dispatcher", "attrs_avp", "$avp(dsattrs)")
455
+ ...
456
+
457
+3.16. hash_pvar (str)
399 458
 
400 459
    String with PVs used for the hashing algorithm 7.
401 460
 
... ...
@@ -406,29 +465,29 @@ Note
406 465
 
407 466
    Default value is “null” - disabled.
408 467
 
409
-   Example 1.14. Use $avp(i:273) for hashing:
468
+   Example 1.16. Use $avp(i:273) for hashing:
410 469
  ...
411 470
  modparam("dispatcher", "hash_pvar", "$avp(i:273)")
412 471
  ...
413 472
 
414
-   Example 1.15. Use combination of PVs for hashing:
473
+   Example 1.17. Use combination of PVs for hashing:
415 474
  ...
416 475
  modparam("dispatcher", "hash_pvar", "hash the $fU@$ci")
417 476
  ...
418 477
 
419
-3.15. setid_pvar (str)
478
+3.17. setid_pvar (str)
420 479
 
421 480
    The name of the PV where to store the set ID (group ID) when calling
422 481
    ds_is_from_list() with no parameter.
423 482
 
424 483
    Default value is “null” - don't set PV.
425 484
 
426
-   Example 1.16. Set the “setid_pvar” parameter
485
+   Example 1.18. Set the “setid_pvar” parameter
427 486
  ...
428 487
  modparam("dispatcher", "setid_pvar", "$var(setid)")
429 488
  ...
430 489
 
431
-3.16. ds_ping_method (string)
490
+3.18. ds_ping_method (string)
432 491
 
433 492
    With this Method you can define, with which method you want to probe
434 493
    the gateways. Pinging gateways feature depends on ds_ping_interval
... ...
@@ -436,12 +495,12 @@ Note
436 495
 
437 496
    Default value is “OPTIONS”.
438 497
 
439
-   Example 1.17. Set the “ds_ping_method” parameter
498
+   Example 1.19. Set the “ds_ping_method” parameter
440 499
  ...
441 500
  modparam("dispatcher", "ds_ping_method", "INFO")
442 501
  ...
443 502
 
444
-3.17. ds_ping_from (string)
503
+3.19. ds_ping_from (string)
445 504
 
446 505
    With this Method you can define the "From:"-Line for the request, sent
447 506
    to the failed gateways. This method is only available, if compiled with
... ...
@@ -449,12 +508,12 @@ Note
449 508
 
450 509
    Default value is “sip:dispatcher@localhost”.
451 510
 
452
-   Example 1.18. Set the “ds_ping_from” parameter
511
+   Example 1.20. Set the “ds_ping_from” parameter
453 512
  ...
454 513
  modparam("dispatcher", "ds_ping_from", "sip:proxy@sip.somehost.com")
455 514
  ...
456 515
 
457
-3.18. ds_ping_interval (int)
516
+3.20. ds_ping_interval (int)
458 517
 
459 518
    With this parameter you can define the interval for sending a request
460 519
    to a gateway marked as inactive upon a failed request routing to it.
... ...
@@ -463,12 +522,12 @@ Note
463 522
 
464 523
    Default value is “0”.
465 524
 
466
-   Example 1.19. Set the “ds_ping_interval” parameter
525
+   Example 1.21. Set the “ds_ping_interval” parameter
467 526
  ...
468 527
  modparam("dispatcher", "ds_ping_interval", 30)
469 528
  ...
470 529
 
471
-3.19. ds_probing_threshhold (int)
530
+3.21. ds_probing_threshhold (int)
472 531
 
473 532
    If you want to set a gateway into probing mode, you will need a
474 533
    specific number of requests until it will change from "active" to
... ...
@@ -476,12 +535,12 @@ Note
476 535
 
477 536
    Default value is “3”.
478 537
 
479
-   Example 1.20. Set the “ds_probing_threshhold” parameter
538
+   Example 1.22. Set the “ds_probing_threshhold” parameter
480 539
  ...
481 540
  modparam("dispatcher", "ds_probing_threshhold", 10)
482 541
  ...
483 542
 
484
-3.20. ds_probing_mode (int)
543
+3.22. ds_probing_mode (int)
485 544
 
486 545
    Controls what gateways are tested to see if they are reachable. If set
487 546
    to 0, only the gateways with state PROBING are tested, if set to 1, all
... ...
@@ -490,12 +549,12 @@ Note
490 549
 
491 550
    Default value is “0”.
492 551
 
493
-   Example 1.21. Set the “ds_probing_mode” parameter
552
+   Example 1.23. Set the “ds_probing_mode” parameter
494 553
  ...
495 554
  modparam("dispatcher", "ds_probing_mode", 1)
496 555
  ...
497 556
 
498
-3.21. ds_append_branch (int)
557
+3.23. ds_append_branch (int)
499 558
 
500 559
    If set to 1, functions will automaticall append a new branch if called
501 560
    in FAILURE_ROUTE. If set to 0, script writer has to call
... ...
@@ -503,11 +562,62 @@ Note
503 562
 
504 563
    Default value is “1”.
505 564
 
506
-   Example 1.22. Set the “ds_append_branch” parameter
565
+   Example 1.24. Set the “ds_append_branch” parameter
507 566
  ...
508 567
  modparam("dispatcher", "ds_append_branch", 0)
509 568
  ...
510 569
 
570
+3.24. ds_hash_size (int)
571
+
572
+   The value to be used as power of two to set the number of slots to hash
573
+   table storing data for call load dispatching (e.g., value 8 will create
574
+   a hash table with 256 slots). It must be greater than 0 to enable call
575
+   load dispatching feature (alg 10).
576
+
577
+   Default value is “0”.
578
+
579
+   Example 1.25. Set the “ds_hash_size” parameter
580
+ ...
581
+ modparam("dispatcher", "ds_hash_size", 9)
582
+ ...
583
+
584
+3.25. ds_hash_expire (int)
585
+
586
+   Expiration time in seconds to remove the load on a destination if no
587
+   BYE was received meanwhile.
588
+
589
+   Default value is “7200”.
590
+
591
+   Example 1.26. Set the “ds_hash_expire” parameter
592
+ ...
593
+ modparam("dispatcher", "ds_hash_expire", 3600)
594
+ ...
595
+
596
+3.26. ds_hash_initexpire (int)
597
+
598
+   Expiration time in seconds to remove the load on a destination if no
599
+   200 for INVITE was received meanwhile and state updated with
600
+   ds_load_update().
601
+
602
+   Default value is “7200”.
603
+
604
+   Example 1.27. Set the “ds_hash_initexpire” parameter
605
+ ...
606
+ modparam("dispatcher", "ds_hash_initexpire", 60)
607
+ ...
608
+
609
+3.27. ds_hash_check_interval (int)
610
+
611
+   Time interval in seconds to scan internal hash table with call load
612
+   dispatching data for expired items.
613
+
614
+   Default value is “30”.
615
+
616
+   Example 1.28. Set the “ds_hash_check_interval” parameter
617
+ ...
618
+ modparam("dispatcher", "ds_hash_check_interval", 60)
619
+ ...
620
+
511 621
 4. Exported Functions
512 622
 
513 623
    4.1. ds_select_dst(set, alg)
... ...
@@ -518,6 +628,8 @@ Note
518 628
    4.6. ds_mark_dst("s")
519 629
    4.7. ds_is_from_list()
520 630
    4.8. ds_is_from_list("group")
631
+   4.9. ds_load_update()
632
+   4.10. ds_load_unset()
521 633
 
522 634
 4.1.  ds_select_dst(set, alg)
523 635
 
... ...
@@ -541,6 +653,23 @@ Note
541 653
           + “7” - hash over the content of PVs string. Note: This works
542 654
             only when the parameter hash_pvar is set.
543 655
           + “8” - use first destination (good for failover).
656
+          + “9” - use weight based load distribution. You have to set the
657
+            attribute 'weight' per each address in destination set.
658
+          + “10” - use call load distribution. You have to set the
659
+            attribute 'duid' (as an unique string id) per each address in
660
+            destination set. Also, you must set parameters 'dstid_avp' and
661
+            'ds_hash_size'.
662
+            The algorithm can be used even with stateless proxy mode,
663
+            there is no SIP dialog tracking depending on other modules,
664
+            just an internal lightweight call tracking by Call-Id, thus is
665
+            fast and suitable even for embedded systems.
666
+            The first destination selected by this algorithm is the one
667
+            that has the least number of calls associated. The rest of the
668
+            destination list is taken in order of the entries in set -
669
+            anyhow, until a re-route to next destination happens, the load
670
+            on each address can change.
671
+            This algorithm can be used only for dispatching INVITE
672
+            requests as it is the only SIP method creating a SIP call.
544 673
           + “X” - if the algorithm is not implemented, the first entry in
545 674
             set is chosen.
546 675
 
... ...
@@ -551,7 +680,7 @@ Note
551 680
 
552 681
    This function can be used from REQUEST_ROUTE.
553 682
 
554
-   Example 1.23. ds_select_dst usage
683
+   Example 1.29. ds_select_dst usage
555 684
 ...
556 685
 ds_select_dst("1", "0");
557 686
 ...
... ...
@@ -629,6 +758,48 @@ ds_select_dst("1", "$var(a)");
629 758
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
630 759
    BRANCH_ROUTE and ONREPLY_ROUTE.
631 760
 
761
+4.9.  ds_load_update()
762
+
763
+   Updates the load state:
764
+     * if it is a BYE or CANCEL - remove the load from destination address
765
+       used to forward the INVITE
766
+     * if it is a reply to INVITE - set internal state to confirmed for
767
+       call load structure when reply code is 2xx.
768
+
769
+   This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
770
+   BRANCH_ROUTE and ONREPLY_ROUTE.
771
+
772
+4.10.  ds_load_unset()
773
+
774
+   Remove the call load for the destination that routed the call.
775
+
776
+   This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
777
+   BRANCH_ROUTE and ONREPLY_ROUTE.
778
+
779
+   Example 1.30. ds_load_unset usage
780
+...
781
+route {
782
+    ...
783
+        if(is_method("BYE|CANCEL"))
784
+        ds_load_update();
785
+    ...
786
+        ds_select_dst("1", "10");
787
+    ...
788
+}
789
+
790
+onreply_route {
791
+    ...
792
+    if(is_method("INVITE")
793
+        {
794
+        if(status=~"2[0-9][0-9]")
795
+            ds_load_update();
796
+        else if(status=~"[3-7][0-9][0-9]")
797
+            ds_load_unset();
798
+    }
799
+    ...
800
+}
801
+...
802
+
632 803
 5. Exported MI Functions
633 804
 
634 805
    5.1. ds_set_state
... ...
@@ -687,14 +858,33 @@ ds_select_dst("1", "$var(a)");
687 858
 
688 859
 6.1. Destination List File
689 860
 
690
-   Each destination point must be on one line. First token is the set id,
691
-   followed by destination address. Optionally, the third field can be
692
-   flags value (1 - destination inactive, 2 - destination in probing mod
693
-   -- you can do bitwise OR to set both flags). The set id must be an
694
-   integer value. Destination address must be a valid SIP URI. Empty lines
695
-   or lines starting with “#” are ignored.
861
+   Each destination point must be on one line. First token is the set id
862
+   (an integer value), followed by destination address (s string value in
863
+   SIP URI format).
864
+
865
+   Optionally, these fields can be followed by:
866
+     * flags: 1 - destination inactive, 2 - destination in probing mode --
867
+       you can do bitwise OR to set both flags
868
+     * priority: sets the priority in destination list (based on it is
869
+       done the initial ordering inside the set)
870
+     * attributes: extra filed in form of name1=value1;...;nameN=valueN.
871
+       There are some predefined names that are used of weight and call
872
+       load dispatching.
873
+
874
+   Line format is:
875
+...
876
+setid(int) destination(sip uri) flags(int,opt) priority(int,opt) attrs(str,opt)
877
+...
878
+
879
+   Full line example:
880
+...
881
+1 sip:127.0.0.1:5080 0 0 duid=abc;my=xyz
882
+...
883
+
884
+   For database, each element of a line resides in a different column.
885
+   Next is a dispatcher.list file example:
696 886
 
697
-   Example 1.24. dispatcher list file
887
+   Example 1.31. dispatcher list file
698 888
 ...
699 889
 # $Id$
700 890
 # dispatcher destination sets
... ...
@@ -718,7 +908,7 @@ ds_select_dst("1", "$var(a)");
718 908
 
719 909
    Next picture displays a sample usage of dispatcher.
720 910
 
721
-   Example 1.25. Kamailio config script - sample dispatcher usage
911
+   Example 1.32. Kamailio config script - sample dispatcher usage
722 912
 ...
723 913
 # $Id$
724 914
 # sample config file for dispatcher module
... ...
@@ -18,8 +18,8 @@
18 18
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 19
  * GNU General Public License for more details.
20 20
  *
21
- * You should have received a copy of the GNU General Public License 
22
- * along with this program; if not, write to the Free Software 
21
+ * You should have received a copy of the GNU General Public License
22
+ * along with this program; if not, write to the Free Software
23 23
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24 24
  *
25 25
  * History
... ...
@@ -35,7 +35,7 @@
35 35
  * re-enabling of destinations (carsten)
36 36
  * 2007-05-08  Ported the changes to SVN-Trunk, renamed ds_is_domain to
37 37
  * ds_is_from_list and modified the function to work with IPv6 adresses.
38
- * 2007-07-18  removed index stuff 
38
+ * 2007-07-18  removed index stuff
39 39
  * 			   added DB support to load/reload data(ancuta)
40 40
  * 2007-09-17  added list-file support for reload data (carstenbock)
41 41
  */
... ...
@@ -78,13 +78,17 @@
78 78
 #define DS_TABLE_VERSION3	3
79 79
 #define DS_TABLE_VERSION4	4
80 80
 
81
+#define DS_ALG_RROBIN	4
82
+#define DS_ALG_LOAD		10
83
+
81 84
 static int _ds_table_version = DS_TABLE_VERSION;
82 85
 
83 86
 static ds_ht_t *_dsht_load = NULL;
84 87
 
85 88
 typedef struct _ds_attrs
86 89
 {
87
-	char duid[DS_DUID_SIZE];
90
+	str body;
91
+	str duid;
88 92
 	int maxload;
89 93
 	int weight;
90 94
 } ds_attrs_t;
... ...
@@ -129,6 +133,34 @@ int *next_idx   = NULL;
129 133
 
130 134
 void destroy_list(int);
131 135
 
136
+/**
137
+ *
138
+ */
139
+int ds_hash_load_init(unsigned int htsize, int expire, int initexpire)
140
+{
141
+	if(_dsht_load != NULL)
142
+		return 0;
143
+	_dsht_load = ds_ht_init(htsize, expire, initexpire);
144
+	if(_dsht_load == NULL)
145
+		return -1;
146
+	return 0;
147
+}
148
+
149
+/**
150
+ *
151
+ */
152
+int ds_hash_load_destroy(void)
153
+{
154
+	if(_dsht_load == NULL)
155
+		return -1;
156
+	ds_ht_destroy(_dsht_load);
157
+	_dsht_load = NULL;
158
+	return 0;
159
+}
160
+
161
+/**
162
+ *
163
+ */
132 164
 int ds_print_sets(void)
133 165
 {
134 166
 	ds_set_t *si = NULL;
... ...
@@ -143,10 +175,11 @@ int ds_print_sets(void)
143 175
 	{
144 176
 		for(i=0; i<si->nr; i++)
145 177
 		{
146
-			LM_DBG("dst>> %d %.*s %d %d (%s,%d,%d)\n", si->id,
178
+			LM_DBG("dst>> %d %.*s %d %d (%.*s,%d,%d)\n", si->id,
147 179
 					si->dlist[i].uri.len, si->dlist[i].uri.s,
148 180
 					si->dlist[i].flags, si->dlist[i].priority,
149
-					si->dlist[i].attrs.duid, si->dlist[i].attrs.maxload,
181
+					si->dlist[i].attrs.duid.len, si->dlist[i].attrs.duid.s,
182
+					si->dlist[i].attrs.maxload,
150 183
 					si->dlist[i].attrs.weight);
151 184
 		}
152 185
 		si = si->next;
... ...
@@ -155,6 +188,9 @@ int ds_print_sets(void)
155 188
 	return 0;
156 189
 }
157 190
 
191
+/**
192
+ *
193
+ */
158 194
 int init_data(void)
159 195
 {
160 196
 	int * p;
... ...
@@ -183,45 +219,53 @@ int init_data(void)
183 219
 	return 0;
184 220
 }
185 221
 
222
+/**
223
+ *
224
+ */
186 225
 int ds_set_attrs(ds_dest_t *dest, str *attrs)
187 226
 {
188 227
 	param_t* params_list = NULL;
189 228
 	param_hooks_t phooks;
190 229
 	param_t *pit=NULL;
230
+	str param;
191 231
 
192 232
 	if(attrs==NULL || attrs->len<=0)
193 233
 		return 0;
194 234
 	if(attrs->s[attrs->len-1]==';')
195 235
 		attrs->len--;
196
-	if (parse_params(attrs, CLASS_ANY, &phooks, &params_list)<0)
236
+	/* clone in shm */
237
+	dest->attrs.body.s = (char*)shm_malloc(attrs->len+1);
238
+	if(dest->attrs.body.s==NULL)
239
+	{
240
+		LM_ERR("no more shm\n");
241
+		return -1;
242
+	}
243
+	memcpy(dest->attrs.body.s, attrs->s, attrs->len);
244
+	dest->attrs.body.s[attrs->len] = '\0';
245
+	dest->attrs.body.len = attrs->len;
246
+
247
+	param = dest->attrs.body;
248
+	if (parse_params(&param, CLASS_ANY, &phooks, &params_list)<0)
197 249
 		return -1;
198 250
 	for (pit = params_list; pit; pit=pit->next)
199 251
 	{
200 252
 		if (pit->name.len==4
201 253
 				&& strncasecmp(pit->name.s, "duid", 4)==0) {
202
-			if(pit->body.len>=DS_DUID_SIZE)
203
-			{
204
-				LM_ERR("dest unique id too long: %.*s\n",
205
-						pit->body.len, pit->body.s);
206
-				return -1;
207
-			}
208
-			memcpy(dest->attrs.duid, pit->body.s, pit->body.len);
209
-			dest->attrs.duid[pit->body.len] = '\0';
254
+			dest->attrs.duid = pit->body;
210 255
 		} else if(pit->name.len==6
211 256
 				&& strncasecmp(pit->name.s, "weight", 4)==0) {
212 257
 			str2sint(&pit->body, &dest->attrs.weight);
213 258
 		} else if(pit->name.len==7
214 259
 				&& strncasecmp(pit->name.s, "maxload", 7)==0) {
215 260
 			str2sint(&pit->body, &dest->attrs.maxload);
216
-		} else {
217
-			LM_ERR("unknown dest attribute: %.*s\n",
218
-						pit->name.len, pit->name.s);
219
-			return -1;
220 261
 		}
221 262
 	}
222 263
 	return 0;
223 264
 }
224 265
 
266
+/**
267
+ *
268
+ */
225 269
 int add_dest2list(int id, str uri, int flags, int priority, str *attrs,
226 270
 		int list_idx, int * setn)
227 271
 {
... ...
@@ -351,6 +395,9 @@ err:
351 395
 	return -1;
352 396
 }
353 397
 
398
+/**
399
+ *
400
+ */
354 401
 int dp_init_weights(ds_set_t *dset)
355 402
 {
356 403
 	int j;
... ...
@@ -571,10 +618,13 @@ error:
571 618
 	if(f!=NULL)
572 619
 		fclose(f);
573 620
 	destroy_list(*next_idx);
574
-	*next_idx = *crt_idx; 
621
+	*next_idx = *crt_idx;
575 622
 	return -1;
576 623
 }
577 624
 
625
+/**
626
+ *
627
+ */
578 628
 int ds_connect_db(void)
579 629
 {
580 630
 	if(!ds_db_url.s)
... ...
@@ -593,6 +643,9 @@ int ds_connect_db(void)
593 643
 	return 0;
594 644
 }
595 645
 
646
+/**
647
+ *
648
+ */
596 649
 void ds_disconnect_db(void)
597 650
 {
598 651
 	if(ds_db_handle)
... ...
@@ -627,17 +680,18 @@ int init_ds_db(void)
627 680
 	}
628 681
 	
629 682
 	_ds_table_version = db_table_version(&ds_dbf, ds_db_handle, &ds_table_name);
630
-	if (_ds_table_version < 0) 
683
+	if (_ds_table_version < 0)
631 684
 	{
632 685
 		LM_ERR("failed to query table version\n");
633 686
 		return -1;
634 687
 	} else if (_ds_table_version != DS_TABLE_VERSION
635 688
 			&& _ds_table_version != DS_TABLE_VERSION2
636
-			&& _ds_table_version != DS_TABLE_VERSION3) {
637
-		LM_ERR("invalid table version (found %d , required %d, %d or %d)\n"
689
+			&& _ds_table_version != DS_TABLE_VERSION3
690
+			&& _ds_table_version != DS_TABLE_VERSION4) {
691
+		LM_ERR("invalid table version (found %d , required %d, %d, %d or %d)\n"
638 692
 			"(use kamdbctl reinit)\n",
639 693
 			_ds_table_version, DS_TABLE_VERSION, DS_TABLE_VERSION2,
640
-			DS_TABLE_VERSION3);
694
+			DS_TABLE_VERSION3, DS_TABLE_VERSION4);
641 695
 		return -1;
642 696
 	}
643 697
 
... ...
@@ -754,7 +808,7 @@ int ds_load_db(void)
754 808
 err2:
755 809
 	destroy_list(*next_idx);
756 810
 	ds_dbf.free_result(ds_db_handle, res);
757
-	*next_idx = *crt_idx; 
811
+	*next_idx = *crt_idx;
758 812
 
759 813
 	return -1;
760 814
 }
... ...
@@ -774,6 +828,9 @@ int ds_destroy_list(void)
774 828
 	return 0;
775 829
 }
776 830
 
831
+/**
832
+ *
833
+ */
777 834
 void destroy_list(int list_id)
778 835
 {
779 836
 	ds_set_t  *sp = NULL;
... ...
@@ -823,8 +880,8 @@ unsigned int ds_get_hash(str *x, str *y)
823 880
 		}
824 881
 		v=0;
825 882
 		for (;p<(x->s+x->len); p++)
826
-		{ 
827
-			v<<=8; 
883
+		{
884
+			v<<=8;
828 885
 			v+=*p;
829 886
 		}
830 887
 		h+=v^(v>>3);
... ...
@@ -832,7 +889,7 @@ unsigned int ds_get_hash(str *x, str *y)
832 889
 	if(y)
833 890
 	{
834 891
 		p=y->s;
835
-		if (y->len>=4) 
892
+		if (y->len>=4)
836 893
 		{
837 894
 			for (; p<=(y->s+y->len-4); p+=4)
838 895
 			{
... ...
@@ -843,8 +900,8 @@ unsigned int ds_get_hash(str *x, str *y)
843 900
 	
844 901
 		v=0;
845 902
 		for (;p<(y->s+y->len); p++)
846
-		{ 
847
-			v<<=8; 
903
+		{
904
+			v<<=8;
848 905
 			v+=*p;
849 906
 		}
850 907
 		h+=v^(v>>3);
... ...
@@ -919,7 +976,6 @@ error:
919 976
 }
920 977
 
921 978
 
922
-
923 979
 /**
924 980
  *
925 981
  */
... ...
@@ -957,7 +1013,6 @@ int ds_hash_fromuri(struct sip_msg *msg, unsigned int *hash)
957 1013
 }
958 1014
 
959 1015
 
960
-
961 1016
 /**
962 1017
  *
963 1018
  */
... ...
@@ -991,7 +1046,6 @@ int ds_hash_touri(struct sip_msg *msg, unsigned int *hash)
991 1046
 }
992 1047
 
993 1048
 
994
-
995 1049
 /**
996 1050
  *
997 1051
  */
... ...
@@ -1021,7 +1075,9 @@ int ds_hash_callid(struct sip_msg *msg, unsigned int *hash)
1021 1075
 }
1022 1076
 
1023 1077
 
1024
-
1078
+/**
1079
+ *
1080
+ */
1025 1081
 int ds_hash_ruri(struct sip_msg *msg, unsigned int *hash)
1026 1082
 {
1027 1083
 	str* uri;
... ...
@@ -1047,6 +1103,9 @@ int ds_hash_ruri(struct sip_msg *msg, unsigned int *hash)
1047 1103
 	return 0;
1048 1104
 }
1049 1105
 
1106
+/**
1107
+ *
1108
+ */
1050 1109
 int ds_hash_authusername(struct sip_msg *msg, unsigned int *hash)
1051 1110
 {
1052 1111
 	/* Header, which contains the authorization */
... ...
@@ -1108,6 +1167,9 @@ int ds_hash_authusername(struct sip_msg *msg, unsigned int *hash)
1108 1167
 }
1109 1168
 
1110 1169
 
1170
+/**
1171
+ *
1172
+ */
1111 1173
 int ds_hash_pvar(struct sip_msg *msg, unsigned int *hash)
1112 1174
 {
1113 1175
 	/* The String to create the hash */
... ...
@@ -1136,6 +1198,41 @@ int ds_hash_pvar(struct sip_msg *msg, unsigned int *hash)
1136 1198
 	return 0;
1137 1199
 }
1138 1200
 
1201
+/**
1202
+ *
1203
+ */
1204
+static inline int ds_get_index(int group, ds_set_t **index)
1205
+{
1206
+	ds_set_t *si = NULL;
1207
+	
1208
+	if(index==NULL || group<0 || _ds_list==NULL)
1209
+		return -1;
1210
+	
1211
+	/* get the index of the set */
1212
+	si = _ds_list;
1213
+	while(si)
1214
+	{
1215
+		if(si->id == group)
1216
+		{
1217
+			*index = si;
1218
+			break;
1219
+		}
1220
+		si = si->next;
1221
+	}
1222
+
1223
+	if(si==NULL)
1224
+	{
1225
+		LM_ERR("destination set [%d] not found\n", group);
1226
+		return -1;
1227
+	}
1228
+
1229
+	return 0;
1230
+}
1231
+
1232
+
1233
+/**
1234
+ *
1235
+ */
1139 1236
 int ds_get_leastloaded(ds_set_t *dset)
1140 1237
 {
1141 1238
 	int j;
... ...
@@ -1159,9 +1256,12 @@ int ds_get_leastloaded(ds_set_t *dset)
1159 1256
 	return k;
1160 1257
 }
1161 1258
 
1162
-int ds_update_load(struct sip_msg *msg, ds_set_t *dset, int setid, int dst)
1259
+/**
1260
+ *
1261
+ */
1262
+int ds_load_add(struct sip_msg *msg, ds_set_t *dset, int setid, int dst)
1163 1263
 {
1164
-	if(dset->dlist[dst].attrs.duid[0]=='\0')
1264
+	if(dset->dlist[dst].attrs.duid.len==0)
1165 1265
 	{
1166 1266
 		LM_ERR("dst unique id not set for %d (%.*s)\n", setid,
1167 1267
 				msg->callid->body.len, msg->callid->body.s);
... ...
@@ -1169,7 +1269,7 @@ int ds_update_load(struct sip_msg *msg, ds_set_t *dset, int setid, int dst)
1169 1269
 	}
1170 1270
 
1171 1271
 	if(ds_add_cell(_dsht_load, &msg->callid->body,
1172
-			dset->dlist[dst].attrs.duid, setid)<0)
1272
+			&dset->dlist[dst].attrs.duid, setid)<0)
1173 1273
 	{
1174 1274
 		LM_ERR("cannot add load to %d (%.*s)\n", setid,
1175 1275
 				msg->callid->body.len, msg->callid->body.s);
... ...
@@ -1179,34 +1279,257 @@ int ds_update_load(struct sip_msg *msg, ds_set_t *dset, int setid, int dst)
1179 1279
 	return 0;
1180 1280
 }
1181 1281
 
1182
-static inline int ds_get_index(int group, ds_set_t **index)
1282
+/**
1283
+ *
1284
+ */
1285
+int ds_load_replace(struct sip_msg *msg, str *duid)
1183 1286
 {
1184
-	ds_set_t *si = NULL;
1185
-	
1186
-	if(index==NULL || group<0 || _ds_list==NULL)
1287
+	ds_cell_t *it;
1288
+	int set;
1289
+	int olddst;
1290
+	int newdst;
1291
+	ds_set_t *idx = NULL;
1292
+	int i;
1293
+
1294
+	if(duid->len<=0)
1295
+	{
1296
+		LM_ERR("invalid dst unique id not set for (%.*s)\n",
1297
+				msg->callid->body.len, msg->callid->body.s);
1187 1298
 		return -1;
1188
-	
1299
+	}
1300
+
1301
+	if((it=ds_get_cell(_dsht_load, &msg->callid->body))==NULL)
1302
+	{
1303
+		LM_ERR("cannot find load for (%.*s)\n",
1304
+				msg->callid->body.len, msg->callid->body.s);
1305
+		return -1;
1306
+	}
1307
+	set = it->dset;
1189 1308
 	/* get the index of the set */
1190
-	si = _ds_list;
1191
-	while(si)
1309
+	if(ds_get_index(set, &idx)!=0)
1192 1310
 	{
1193
-		if(si->id == group)
1311
+		ds_unlock_cell(_dsht_load, &msg->callid->body);
1312
+		LM_ERR("destination set [%d] not found\n", set);
1313
+		return -1;
1314
+	}
1315
+	olddst = -1;
1316
+	newdst = -1;
1317
+	for(i=0; i<idx->nr; i++)
1318
+	{
1319
+		if(idx->dlist[i].attrs.duid.len==it->duid.len
1320
+				&& strncasecmp(idx->dlist[i].attrs.duid.s, it->duid.s,
1321
+					it->duid.len)==0)
1194 1322
 		{
1195
-			*index = si;
1323
+			olddst = i;
1324
+			if(newdst!=-1)
1325
+				break;
1326
+		}
1327
+		if(idx->dlist[i].attrs.duid.len==duid->len
1328
+				&& strncasecmp(idx->dlist[i].attrs.duid.s, duid->s,
1329
+					duid->len)==0)
1330
+		{
1331
+			newdst = i;
1332
+			if(olddst!=-1)
1333
+				break;
1334
+		}
1335
+	}
1336
+	if(olddst==-1)
1337
+	{
1338
+		ds_unlock_cell(_dsht_load, &msg->callid->body);
1339
+		LM_ERR("old destination address not found for [%d, %.*s]\n", set,
1340
+				it->duid.len, it->duid.s);
1341
+		return -1;
1342
+	}
1343
+	if(newdst==-1)
1344
+	{
1345
+		ds_unlock_cell(_dsht_load, &msg->callid->body);
1346
+		LM_ERR("new destination address not found for [%d, %.*s]\n", set,
1347
+				duid->len, duid->s);
1348
+		return -1;
1349
+	}
1350
+
1351
+	ds_unlock_cell(_dsht_load, &msg->callid->body);
1352
+	ds_del_cell(_dsht_load, &msg->callid->body);
1353
+	idx->dlist[olddst].dload--;
1354
+
1355
+	if(ds_load_add(msg, idx, set, newdst)<0)
1356
+	{
1357
+		LM_ERR("unable to replace destination load [%.*s / %.*s]\n",
1358
+			duid->len, duid->s, msg->callid->body.len, msg->callid->body.s);
1359
+		return -1;
1360
+	}
1361
+	return 0;
1362
+}
1363
+
1364
+/**
1365
+ *
1366
+ */
1367
+int ds_load_remove(struct sip_msg *msg)
1368
+{
1369
+	ds_cell_t *it;
1370
+	int set;
1371
+	int olddst;
1372
+	ds_set_t *idx = NULL;
1373
+	int i;
1374
+
1375
+	if((it=ds_get_cell(_dsht_load, &msg->callid->body))==NULL)
1376
+	{
1377
+		LM_ERR("cannot find load for (%.*s)\n",
1378
+				msg->callid->body.len, msg->callid->body.s);
1379
+		return -1;
1380
+	}
1381
+	set = it->dset;
1382
+	/* get the index of the set */
1383
+	if(ds_get_index(set, &idx)!=0)
1384
+	{
1385
+		ds_unlock_cell(_dsht_load, &msg->callid->body);
1386
+		LM_ERR("destination set [%d] not found\n", set);
1387
+		return -1;
1388
+	}
1389
+	olddst = -1;
1390
+	for(i=0; i<idx->nr; i++)
1391
+	{
1392
+		if(idx->dlist[i].attrs.duid.len==it->duid.len
1393
+				&& strncasecmp(idx->dlist[i].attrs.duid.s, it->duid.s,
1394
+					it->duid.len)==0)
1395
+		{
1396
+			olddst = i;
1196 1397
 			break;
1197 1398
 		}
1198
-		si = si->next;
1399
+	}
1400
+	if(olddst==-1)
1401
+	{
1402
+		ds_unlock_cell(_dsht_load, &msg->callid->body);
1403
+		LM_ERR("old destination address not found for [%d, %.*s]\n", set,
1404
+				it->duid.len, it->duid.s);
1405
+		return -1;
1199 1406
 	}
1200 1407
 
1201
-	if(si==NULL)
1408
+	ds_unlock_cell(_dsht_load, &msg->callid->body);
1409
+	ds_del_cell(_dsht_load, &msg->callid->body);
1410
+	idx->dlist[olddst].dload--;
1411
+
1412
+	return 0;
1413
+}
1414
+
1415
+
1416
+/**
1417
+ *
1418
+ */
1419
+int ds_load_remove_byid(int set, str *duid)
1420
+{
1421
+	int olddst;
1422
+	ds_set_t *idx = NULL;
1423
+	int i;
1424
+
1425
+	/* get the index of the set */
1426
+	if(ds_get_index(set, &idx)!=0)
1202 1427
 	{
1203
-		LM_ERR("destination set [%d] not found\n", group);
1428
+		LM_ERR("destination set [%d] not found\n", set);
1429
+		return -1;
1430
+	}
1431
+	olddst = -1;
1432
+	for(i=0; i<idx->nr; i++)
1433
+	{
1434
+		if(idx->dlist[i].attrs.duid.len==duid->len
1435
+				&& strncasecmp(idx->dlist[i].attrs.duid.s, duid->s,
1436
+					duid->len)==0)
1437
+		{
1438
+			olddst = i;
1439
+			break;
1440
+		}
1441
+	}
1442
+	if(olddst==-1)
1443
+	{
1444
+		LM_ERR("old destination address not found for [%d, %.*s]\n", set,
1445
+				duid->len, duid->s);
1446
+		return -1;
1447
+	}
1448
+
1449
+	idx->dlist[olddst].dload--;
1450
+
1451
+	return 0;
1452
+}
1453
+
1454
+/**
1455
+ *
1456
+ */
1457
+int ds_load_state(struct sip_msg *msg, int state)
1458
+{
1459
+	ds_cell_t *it;
1460
+
1461
+	if((it=ds_get_cell(_dsht_load, &msg->callid->body))==NULL)
1462
+	{
1463
+		LM_DBG("cannot find load for (%.*s)\n",
1464
+				msg->callid->body.len, msg->callid->body.s);
1204 1465
 		return -1;
1205 1466
 	}
1206 1467
 
1468
+	it->state = state;
1469
+	ds_unlock_cell(_dsht_load, &msg->callid->body);
1470
+
1471
+	return 0;
1472
+}
1473
+
1474
+
1475
+/**
1476
+ *
1477
+ */
1478
+int ds_load_update(struct sip_msg *msg)
1479
+{
1480
+    if(parse_headers(msg, HDR_CSEQ_F|HDR_CALLID_F, 0)!=0
1481
+			|| msg->cseq==NULL || msg->callid==NULL)
1482
+    {
1483
+        LM_ERR("cannot parse cseq and callid headers\n");
1484
+        return -1;
1485
+    }
1486
+	if(msg->first_line.type==SIP_REQUEST)
1487
+    {
1488
+		if(msg->first_line.u.request.method_value==METHOD_BYE
1489
+				|| msg->first_line.u.request.method_value==METHOD_CANCEL)
1490
+		{
1491
+			/* off-load call */
1492
+			ds_load_remove(msg);
1493
+		}
1494
+		return 0;
1495
+	}
1496
+
1497
+	if(get_cseq(msg)->method_id==METHOD_INVITE)
1498
+	{
1499
+		/* if status is 2xx then set state to confirmed */
1500
+		if(REPLY_CLASS(msg)==2)
1501
+			ds_load_state(msg, DS_LOAD_CONFIRMED);
1502
+	}
1207 1503
 	return 0;
1208 1504
 }
1209 1505
 
1506
+/**
1507
+ *
1508
+ */
1509
+int ds_load_unset(struct sip_msg *msg)
1510
+{
1511
+	struct search_state st;
1512
+	struct usr_avp *prev_avp;
1513
+	int_str avp_value;
1514
+	
1515
+	if(dstid_avp_name.n==0)
1516
+		return 0;
1517
+
1518
+	/* for INVITE requests should be called after dst list is built */
1519
+	if(msg->first_line.type==SIP_REQUEST
1520
+			&&  msg->first_line.u.request.method_value==METHOD_INVITE)
1521
+    {
1522
+		prev_avp = search_first_avp(dstid_avp_type, dstid_avp_name,
1523
+				&avp_value, &st);
1524
+		if(prev_avp==NULL)
1525
+			return 0;
1526
+	}
1527
+	return ds_load_remove(msg);
1528
+}
1529
+
1530
+/**
1531
+ *
1532
+ */
1210 1533
 static inline int ds_update_dst(struct sip_msg *msg, str *uri, int mode)
1211 1534
 {
1212 1535
 	struct action act;
... ...
@@ -1218,7 +1541,7 @@ static inline int ds_update_dst(struct sip_msg *msg, str *uri, int mode)
1218 1541
 			memset(&act, '\0', sizeof(act));
1219 1542
 			act.type = SET_HOSTALL_T;
1220 1543
 			act.val[0].type = STRING_ST;
1221
-			if(uri->len>4 
1544
+			if(uri->len>4
1222 1545
 					&& strncasecmp(uri->s,"sip:",4)==0)
1223 1546
 				act.val[0].u.string = uri->s+4;
1224 1547
 			else
... ...
@@ -1322,7 +1645,7 @@ int ds_select_dst(struct sip_msg *msg, int set, int alg, int mode)
1322 1645
 				return -1;
1323 1646
 			}
1324 1647
 		break;
1325
-		case 4: /* round robin */
1648
+		case DS_ALG_RROBIN: /* round robin */
1326 1649
 			hash = idx->last;
1327 1650
 			idx->last = (idx->last+1) % idx->nr;
1328 1651
 		break;
... ...
@@ -1361,9 +1684,30 @@ int ds_select_dst(struct sip_msg *msg, int set, int alg, int mode)
1361 1684
 			hash = idx->wlist[idx->wlast];
1362 1685
 			idx->wlast = (idx->wlast+1) % 100;
1363 1686
 		break;
1364
-		case 10: /* load based distribution */
1365
-			hash = ds_get_leastloaded(idx);
1366
-			ds_update_load(msg, idx, set, hash);
1687
+		case DS_ALG_LOAD: /* call load based distribution */
1688
+			/* only INVITE can start a call */
1689
+			if(msg->first_line.u.request.method_value!=METHOD_INVITE)
1690
+			{
1691
+				/* use first entry */
1692
+				hash = 0;
1693
+				alg = 0;
1694
+				break;
1695
+			}
1696
+			if(dstid_avp_name.n==0)
1697
+			{
1698
+				LM_ERR("no dst ID avp for load distribution"
1699
+						" - using first entry...\n");
1700
+				hash = 0;
1701
+				alg = 0;
1702
+			} else {
1703
+				hash = ds_get_leastloaded(idx);
1704
+				if(ds_load_add(msg, idx, set, hash)<0)
1705
+				{
1706
+					LM_ERR("unable to update destination load"
1707
+							" - classic dispatching\n");
1708
+					alg = 0;
1709
+				}
1710
+			}
1367 1711
 		break;
1368 1712
 		default:
1369 1713
 			LM_WARN("algo %d not implemented - using first entry...\n", alg);
... ...
@@ -1404,7 +1748,7 @@ int ds_select_dst(struct sip_msg *msg, int set, int alg, int mode)
1404 1748
 		return -1;
1405 1749
 	}
1406 1750
 	/* if alg is round-robin then update the shortcut to next to be used */
1407
-	if(alg==4)
1751
+	if(alg==DS_ALG_RROBIN)
1408 1752
 		idx->last = (hash+1) % idx->nr;
1409 1753
 	
1410 1754
 	LM_DBG("selected [%d-%d/%d] <%.*s>\n", alg, set, hash,
... ...
@@ -1420,6 +1764,28 @@ int ds_select_dst(struct sip_msg *msg, int set, int alg, int mode)
1420 1764
 			avp_val.s = idx->dlist[idx->nr-1].uri;
1421 1765
 			if(add_avp(AVP_VAL_STR|dst_avp_type, dst_avp_name, avp_val)!=0)
1422 1766
 				return -1;
1767
+
1768
+			if(attrs_avp_name.n!=0 && idx->dlist[idx->nr-1].attrs.body.len>0)
1769
+			{
1770
+				avp_val.s = idx->dlist[idx->nr-1].attrs.body;
1771
+				if(add_avp(AVP_VAL_STR|attrs_avp_type, attrs_avp_name,
1772
+							avp_val)!=0)
1773
+					return -1;
1774
+			}
1775
+			if(alg==DS_ALG_LOAD)
1776
+			{
1777
+				if(idx->dlist[idx->nr-1].attrs.duid.len<=0)
1778
+				{
1779
+					LM_ERR("no uid for destination: %d %.*s\n", set,
1780
+							idx->dlist[idx->nr-1].uri.len,
1781
+							idx->dlist[idx->nr-1].uri.s);
1782
+					return -1;
1783
+				}
1784
+				avp_val.s = idx->dlist[idx->nr-1].attrs.duid;
1785
+				if(add_avp(AVP_VAL_STR|dstid_avp_type, dstid_avp_name,
1786
+							avp_val)!=0)
1787
+					return -1;
1788
+			}
1423 1789
 			cnt++;
1424 1790
 		}
1425 1791
 	
... ...
@@ -1434,6 +1800,28 @@ int ds_select_dst(struct sip_msg *msg, int set, int alg, int mode)
1434 1800
 			avp_val.s = idx->dlist[i].uri;
1435 1801
 			if(add_avp(AVP_VAL_STR|dst_avp_type, dst_avp_name, avp_val)!=0)
1436 1802
 				return -1;
1803
+
1804
+			if(attrs_avp_name.n!=0 && idx->dlist[i].attrs.body.len>0)
1805
+			{
1806
+				avp_val.s = idx->dlist[i].attrs.body;
1807
+				if(add_avp(AVP_VAL_STR|attrs_avp_type, attrs_avp_name,
1808
+							avp_val)!=0)
1809
+					return -1;
1810
+			}
1811
+			if(alg==DS_ALG_LOAD)
1812
+			{
1813
+				if(idx->dlist[i].attrs.duid.len<=0)
1814
+				{
1815
+					LM_ERR("no uid for destination: %d %.*s\n", set,
1816
+							idx->dlist[i].uri.len,
1817
+							idx->dlist[i].uri.s);
1818
+					return -1;
1819
+				}
1820
+				avp_val.s = idx->dlist[i].attrs.duid;
1821
+				if(add_avp(AVP_VAL_STR|dstid_avp_type, dstid_avp_name,
1822
+							avp_val)!=0)
1823
+					return -1;
1824
+			}
1437 1825
 			cnt++;
1438 1826
 		}
1439 1827
 
... ...
@@ -1446,6 +1834,28 @@ int ds_select_dst(struct sip_msg *msg, int set, int alg, int mode)
1446 1834
 			avp_val.s = idx->dlist[i].uri;
1447 1835
 			if(add_avp(AVP_VAL_STR|dst_avp_type, dst_avp_name, avp_val)!=0)
1448 1836
 				return -1;
1837
+
1838
+			if(attrs_avp_name.n!=0 && idx->dlist[i].attrs.body.len>0)
1839
+			{
1840
+				avp_val.s = idx->dlist[i].attrs.body;
1841
+				if(add_avp(AVP_VAL_STR|attrs_avp_type, attrs_avp_name,
1842
+							avp_val)!=0)
1843
+					return -1;
1844
+			}
1845
+			if(alg==DS_ALG_LOAD)
1846
+			{
1847
+				if(idx->dlist[i].attrs.duid.len<=0)
1848
+				{
1849
+					LM_ERR("no uid for destination: %d %.*s\n", set,
1850
+							idx->dlist[i].uri.len,
1851
+							idx->dlist[i].uri.s);
1852
+					return -1;
1853
+				}
1854
+				avp_val.s = idx->dlist[i].attrs.duid;
1855
+				if(add_avp(AVP_VAL_STR|dstid_avp_type, dstid_avp_name,
1856
+							avp_val)!=0)
1857
+					return -1;
1858
+			}
1449 1859
 			cnt++;
1450 1860
 		}
1451 1861
 	
... ...
@@ -1453,6 +1863,28 @@ int ds_select_dst(struct sip_msg *msg, int set, int alg, int mode)
1453 1863
 		avp_val.s = idx->dlist[hash].uri;
1454 1864
 		if(add_avp(AVP_VAL_STR|dst_avp_type, dst_avp_name, avp_val)!=0)
1455 1865
 			return -1;
1866
+
1867
+		if(attrs_avp_name.n!=0 && idx->dlist[hash].attrs.body.len>0)
1868
+		{
1869
+			avp_val.s = idx->dlist[hash].attrs.body;
1870
+			if(add_avp(AVP_VAL_STR|attrs_avp_type, attrs_avp_name,
1871
+						avp_val)!=0)
1872
+				return -1;
1873
+		}
1874
+		if(alg==DS_ALG_LOAD)
1875
+		{
1876
+			if(idx->dlist[hash].attrs.duid.len<=0)
1877
+			{
1878
+				LM_ERR("no uid for destination: %d %.*s\n", set,
1879
+							idx->dlist[hash].uri.len,
1880
+							idx->dlist[hash].uri.s);
1881
+				return -1;
1882
+			}
1883
+			avp_val.s = idx->dlist[hash].attrs.duid;
1884
+			if(add_avp(AVP_VAL_STR|dstid_avp_type, dstid_avp_name,
1885
+						avp_val)!=0)
1886
+				return -1;
1887
+		}
1456 1888
 		cnt++;
1457 1889
 	}
1458 1890
 
... ...
@@ -1481,6 +1913,7 @@ int ds_next_dst(struct sip_msg *msg, int mode)
1481 1913
 	struct usr_avp *avp;
1482 1914
 	struct usr_avp *prev_avp;
1483 1915
 	int_str avp_value;
1916
+	int alg = 0;
1484 1917
 	
1485 1918
 	if(!(ds_flags&DS_FAILOVER_ON) || dst_avp_name.n==0)
1486 1919
 	{
... ...
@@ -1488,6 +1921,28 @@ int ds_next_dst(struct sip_msg *msg, int mode)
1488 1921
 		return -1;
1489 1922
 	}
1490 1923
 
1924
+	if(dstid_avp_name.n!=0)
1925
+	{
1926
+		prev_avp = search_first_avp(dstid_avp_type, dstid_avp_name,
1927
+				&avp_value, &st);
1928
+		if(prev_avp!=NULL)
1929
+		{
1930
+			/* load based dispatching */
1931
+			alg = DS_ALG_LOAD;
1932
+			/* off-load destination id */
1933
+			destroy_avp(prev_avp);
1934
+		}
1935
+	}
1936
+
1937
+	if(attrs_avp_name.n!=0)
1938
+	{
1939
+		prev_avp = search_first_avp(attrs_avp_type,
1940
+					attrs_avp_name, &avp_value, &st);
1941
+		if(prev_avp!=NULL)
1942
+		{
1943
+			destroy_avp(prev_avp);
1944
+		}
1945
+	}
1491 1946
 
1492 1947
 	prev_avp = search_first_avp(dst_avp_type, dst_avp_name, &avp_value, &st);
1493 1948
 	if(prev_avp==NULL)
... ...
@@ -1504,6 +1959,21 @@ int ds_next_dst(struct sip_msg *msg, int mode)
1504 1959
 		return -1;
1505 1960
 	}
1506 1961
 	LM_DBG("using [%.*s]\n", avp_value.s.len, avp_value.s.s);
1962
+	if(alg==DS_ALG_LOAD)
1963
+	{
1964
+		prev_avp = search_first_avp(dstid_avp_type, dstid_avp_name,
1965
+				&avp_value, &st);
1966
+		if(prev_avp!=NULL)
1967
+		{
1968
+			LM_ERR("cannot uid for dst addr\n");