00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include "../../usr_avp.h"
00031 #include "../../dset.h"
00032 #include "../../dprint.h"
00033 #include "../../qvalue.h"
00034 #include "../../parser/contact/parse_contact.h"
00035 #include "../../qvalue.h"
00036 #include "rd_filter.h"
00037 #include "rd_funcs.h"
00038
00039
00040 #define MAX_CONTACTS_PER_REPLY 16
00041 #define DEFAULT_Q_VALUE 10
00042
00043 static int shmcontact2dset(struct sip_msg *req, struct sip_msg *shrpl,
00044 long max, struct acc_param *reason, unsigned int bflags);
00045
00046
00047 int get_redirect( struct sip_msg *msg , int maxt, int maxb,
00048 struct acc_param *reason, unsigned int bflags)
00049 {
00050 struct cell *t;
00051 str backup_uri;
00052 int max;
00053 int cts_added;
00054 int n;
00055 int i;
00056
00057
00058 t = rd_tmb.t_gett();
00059 if (t==T_UNDEFINED || t==T_NULL_CELL)
00060 {
00061 LM_CRIT("no current transaction found\n");
00062 goto error;
00063 }
00064
00065 LM_DBG("resume branch=%d\n", t->first_branch);
00066
00067 cts_added = 0;
00068 backup_uri = msg->new_uri;
00069
00070
00071 for( i=t->first_branch ; i<t->nr_of_outgoings ; i++) {
00072 LM_DBG("checking branch=%d (added=%d)\n", i, cts_added);
00073
00074 if (t->uac[i].last_received<300 || t->uac[i].last_received>399)
00075 continue;
00076 LM_DBG("branch=%d is a redirect (added=%d)\n", i, cts_added);
00077
00078
00079 if (maxb==0) {
00080 max = maxt?(maxt-cts_added):(-1);
00081 } else {
00082 max = maxt?((maxt-cts_added>=maxb)?maxb:(maxt-cts_added)):maxb;
00083 }
00084 if (max==0)
00085 continue;
00086
00087 n = shmcontact2dset( msg, t->uac[i].reply, max, reason, bflags);
00088 if ( n<0 ) {
00089 LM_ERR("get contact from shm_reply branch %d failed\n",i);
00090
00091 } else {
00092
00093 cts_added += n;
00094 }
00095 }
00096
00097
00098 msg->new_uri = backup_uri;
00099
00100
00101 return (cts_added>0)?1:-1;
00102 error:
00103 return -1;
00104 }
00105
00106
00107
00108
00109 static int sort_contacts(contact_t *ct_list, contact_t **ct_array,
00110 qvalue_t *q_array)
00111 {
00112 param_t *q_para;
00113 qvalue_t q;
00114 int n;
00115 int i,j;
00116 char backup;
00117
00118 n = 0;
00119
00120 for( ; ct_list ; ct_list = ct_list->next ) {
00121
00122 backup = ct_list->uri.s[ct_list->uri.len];
00123 ct_list->uri.s[ct_list->uri.len] = 0;
00124 if ( run_filters( ct_list->uri.s )==-1 ){
00125 ct_list->uri.s[ct_list->uri.len] = backup;
00126 continue;
00127 }
00128 ct_list->uri.s[ct_list->uri.len] = backup;
00129
00130 q_para = ct_list->q;
00131 if (q_para==0 || q_para->body.len==0) {
00132 q = DEFAULT_Q_VALUE;
00133 } else {
00134 if (str2q( &q, q_para->body.s, q_para->body.len)!=0) {
00135 LM_ERR("invalid q param\n");
00136
00137 continue;
00138 }
00139 }
00140 LM_DBG("sort_contacts: <%.*s> q=%d\n",
00141 ct_list->uri.len,ct_list->uri.s,q);
00142
00143 for(i=0;i<n;i++) {
00144
00145 if (q_array[i]<=q)
00146 continue;
00147 break;
00148 }
00149 if (i!=MAX_CONTACTS_PER_REPLY) {
00150
00151 for( j=n-1-1*(n==MAX_CONTACTS_PER_REPLY) ; j>=i ; j-- ) {
00152 ct_array[j+1] = ct_array[j];
00153 q_array[j+1] = q_array[j];
00154 }
00155 ct_array[j+1] = ct_list;
00156 q_array[j+1] = q;
00157 if (n!=MAX_CONTACTS_PER_REPLY)
00158 n++;
00159 }
00160 }
00161 return n;
00162 }
00163
00164
00165
00166
00167
00168
00169
00170 static int shmcontact2dset(struct sip_msg *req, struct sip_msg *sh_rpl,
00171 long max, struct acc_param *reason, unsigned int bflags)
00172 {
00173 static struct sip_msg dup_rpl;
00174 static contact_t *scontacts[MAX_CONTACTS_PER_REPLY];
00175 static qvalue_t sqvalues[MAX_CONTACTS_PER_REPLY];
00176 struct hdr_field *hdr;
00177 struct hdr_field *contact_hdr;
00178 contact_t *contacts;
00179 int n,i;
00180 int added;
00181 int dup;
00182 int ret;
00183
00184
00185
00186
00187
00188
00189
00190 dup = 0;
00191 ret = 0;
00192 contact_hdr = 0;
00193
00194 if (sh_rpl==0 || sh_rpl==FAKED_REPLY)
00195 return 0;
00196
00197 if (sh_rpl->contact==0) {
00198
00199 if ( sh_rpl->msg_flags&FL_SHM_CLONE ) {
00200
00201
00202 memcpy( &dup_rpl, sh_rpl, sizeof(struct sip_msg) );
00203 dup = 2;
00204
00205 if ( parse_headers( &dup_rpl, HDR_CONTACT_T, 0)<0 ) {
00206 LM_ERR("dup_rpl parse failed\n");
00207 ret = -1;
00208 goto restore;
00209 }
00210 if (dup_rpl.contact==0) {
00211 LM_DBG("contact hdr not found in dup_rpl\n");
00212 goto restore;
00213 }
00214 contact_hdr = dup_rpl.contact;
00215 } else {
00216 dup = 3;
00217
00218 if ( parse_headers( sh_rpl, HDR_CONTACT_T, 0)<0 ) {
00219 LM_ERR("sh_rpl parse failed\n");
00220 ret = -1;
00221 goto restore;
00222 }
00223 if (sh_rpl->contact==0) {
00224 LM_DBG("contact hdr not found in sh_rpl\n");
00225 goto restore;
00226 }
00227 contact_hdr = sh_rpl->contact;
00228 }
00229 } else {
00230 contact_hdr = sh_rpl->contact;
00231 }
00232
00233
00234 if (contact_hdr->parsed==0) {
00235 if ( parse_contact(contact_hdr)<0 ) {
00236 LM_ERR("contact hdr parse failed\n");
00237 ret = -1;
00238 goto restore;
00239 }
00240 if (dup==0)
00241 dup = 1;
00242 }
00243
00244
00245
00246
00247 contacts = ((contact_body_t*)contact_hdr->parsed)->contacts;
00248 if (contacts==0) {
00249 LM_DBG("contact hdr has no contacts\n");
00250 goto restore;
00251 }
00252 n = sort_contacts( contacts, scontacts, sqvalues);
00253 if (n==0) {
00254 LM_DBG("no contacts left after filtering\n");
00255 goto restore;
00256 }
00257
00258
00259 if (max!=-1 && n>max)
00260 n = max;
00261
00262 added = 0;
00263
00264
00265 for ( i=0 ; i<n ; i++ ) {
00266 LM_DBG("adding contact <%.*s>\n", scontacts[i]->uri.len, scontacts[i]->uri.s);
00267 if (append_branch( 0, &scontacts[i]->uri, 0, 0, sqvalues[i], bflags, 0)<0) {
00268 LM_ERR("failed to add contact to dset\n");
00269 } else {
00270 added++;
00271 if (rd_acc_fct!=0 && reason) {
00272
00273 req->new_uri = scontacts[i]->uri;
00274
00275 rd_acc_fct( req, (char*)reason, acc_db_table, NULL, NULL, NULL, NULL);
00276 }
00277 }
00278 }
00279
00280 ret = (added==0)?-1:added;
00281 restore:
00282 if (dup==1) {
00283 free_contact( (contact_body_t**)(void*)(&contact_hdr->parsed) );
00284 } else if (dup==2) {
00285
00286 if (dup_rpl.last_header!=sh_rpl->last_header) {
00287
00288
00289 hdr = sh_rpl->last_header;
00290 free_hdr_field_lst(hdr->next);
00291 hdr->next=0;
00292 }
00293 }
00294 return ret;
00295
00296 }
00297