Browse code

modules/tm: added outbound support to t_load_contact()/t_next_contacts()

- added new function t_next_contact_flows()
- readme not updated yet

Juha Heinanen authored on 12/12/2012 14:11:50
Showing 3 changed files
... ...
@@ -48,12 +48,18 @@ struct contact {
48 48
     qvalue_t q;
49 49
     str dst_uri;
50 50
     str path;
51
-    unsigned int flags;
52 51
     struct socket_info* sock;
52
+    str instance;
53
+    unsigned int flags;
53 54
     unsigned short q_flag;
54 55
     struct contact *next;
55 56
 };
56 57
 
58
+struct instance_list {
59
+    str instance;
60
+    struct instance_list *next;
61
+};
62
+
57 63
 /* 
58 64
  * Frees contact list used by load_contacts function
59 65
  */
... ...
@@ -66,151 +72,74 @@ static inline void free_contact_list(struct contact *curr) {
66 66
     }
67 67
 }
68 68
 
69
-/* Encode branch info from contact struct to str */
70
-static inline int encode_branch_info(str *info, struct contact *con)
71
-{
72
-    char *at, *s;
73
-    int len;
74
-
75
-    info->len = con->uri.len + con->dst_uri.len +
76
-		con->path.len + MAX_SOCKET_STR + INT2STR_MAX_LEN + 5;
77
-    info->s = pkg_malloc(info->len);
78
-    if (!info->s) {
79
-		LM_ERR("no memory left for branch info\n");
80
-		return 0;
81
-    }
82
-    at = info->s;
83
-    append_str(at, con->uri.s, con->uri.len);
84
-    append_chr(at, '\n');
85
-    append_str(at, con->dst_uri.s, con->dst_uri.len);
86
-    append_chr(at, '\n');
87
-    append_str(at, con->path.s, con->path.len);
88
-    append_chr(at, '\n');
89
-    if (con->sock) {
90
-		len = MAX_SOCKET_STR;
91
-		if (socket2str(at, &len, con->sock) < 0) {
92
-			LM_ERR("failed to convert socket to str\n");
93
-			return 0;
94
-		}
95
-    } else {
96
-		len = 0;
69
+/* 
70
+ * Frees instance list used by next_contacts function
71
+ */
72
+static inline void free_instance_list(struct instance_list *curr) {
73
+    struct instance_list *prev;
74
+    while (curr) {
75
+	pkg_free(curr->instance.s);
76
+	prev = curr;
77
+	curr = curr->next;
78
+	pkg_free(prev);
97 79
     }
98
-    at = at + len;
99
-    append_chr(at, '\n');
100
-    s = int2str(con->flags, &len);
101
-    append_str(at, s, len);
102
-    append_chr(at, '\n');
103
-    info->len = at - info->s + 1;
104
-
105
-    return 1;
106 80
 }
107 81
 
82
+static str uri_name = {"uri", 3};
83
+static str dst_uri_name = {"dst_uri", 7};
84
+static str path_name = {"path", 4};
85
+static str sock_name = {"sock", 4};
86
+static str instance_name = {"instance", 8};
87
+static str flags_name = {"flags", 5};
88
+static str q_flag_name = {"q_flag", 6};
108 89
 
109
-/* Encode branch info from str */
110
-static inline int decode_branch_info(char *info, str *uri, str *dst, str *path,
111
-									 struct socket_info **sock,
112
-									 unsigned int *flags)
90
+void add_contacts_avp(str *uri, str *dst_uri, str *path, str *sock_str,
91
+		      unsigned int flags, unsigned int q_flag, str *instance)
113 92
 {
114
-    str s, host;
115
-    int port, proto;
116
-    char *pos, *at, *tmp;
93
+    sr_xavp_t *record;
94
+    sr_xval_t val;
117 95
 
118
-	if (info == NULL) {
119
-		ERR("decode_branch_info: Invalid input string.\n");
120
-		return 0;
121
-	}
122
-	
123
-	/* Reset or return arguments to sane defaults */
124
-	uri->s = 0; uri->len = 0;
125
-	dst->s = 0; dst->len = 0;
126
-	path->s = 0; path->len = 0;
127
-	*sock = NULL;
128
-	*flags = 0;
129
-	
130
-	/* Make sure that we have at least a non-empty URI string, it is fine if
131
-	 * everything else is missing, but we need at least the URI. */
132
-	uri->s = info; 
133
-	if ((pos = strchr(info, '\n')) == NULL) { 
134
-		uri->len = strlen(info); 
135
-			/* We don't even have the URI string, this is bad, report an
136
-			 * error. */
137
-		if (uri->len == 0) goto uri_missing;
138
-		return 1;
139
-    }
140
-	uri->len = pos - info;
141
-	if (uri->len == 0) goto uri_missing;
142
-
143
-	/* If we get here we have at least the branch URI, now try to parse as
144
-	 * much as you can. All output variable have been initialized above, so it
145
-	 * is OK if any of the fields are missing from now on. */
146
-    dst->s = at = pos + 1;
147
-    if ((pos = strchr(at, '\n')) == NULL) {
148
-		dst->len = strlen(dst->s);
149
-		return 1;
150
-    }
151
-	dst->len = pos - at;
152
-
153
-    path->s = at = pos + 1;
154
-    if ((pos = strchr(at, '\n')) == NULL) {
155
-		path->len = strlen(path->s);
156
-		return 1;
157
-    }
158
-    path->len = pos - at;
159
-
160
-    s.s = at = pos + 1;
161
-    if ((pos = strchr(at, '\n')) == NULL) {
162
-		/* No LF found, that means we take the string till the final zero
163
-		 * termination character and pass it directly to parse_phostport
164
-		 * without making a zero-terminated copy. */
165
-		tmp = s.s;
166
-		s.len = strlen(s.s);
167
-	} else {
168
-		/* Our string is terminated by LF, so we need to make a
169
-		 * zero-terminated copy of the string before we pass it to
170
-		 * parse_phostport. */
171
-		s.len = pos - at;
172
-		if ((tmp = as_asciiz(&s)) == NULL) {
173
-			ERR("No memory left\n");
174
-			return 0;
175
-		}
176
-	}	
177
-	if (s.len) {
178
-		if (parse_phostport(tmp, &host.s, &host.len,
179
-							&port, &proto) != 0) {
180
-			LM_ERR("parsing of socket info <%s> failed\n", tmp);
181
-			if (pos) pkg_free(tmp);
182
-			return 0;
183
-		}
96
+    record = NULL;
184 97
 
185
-		*sock = grep_sock_info(&host, (unsigned short)port,
186
-							   (unsigned short)proto);
187
-		if (*sock == 0) {
188
-			LM_ERR("invalid socket <%s>\n", tmp);
189
-			if (pos) pkg_free(tmp);
190
-			return 0;
191
-		}
192
-	}
193
-	
194
-	if (pos) pkg_free(tmp);
195
-	else return 1;
196
-	
197
-    s.s = at = pos + 1;
198
-    if ((pos = strchr(at, '\n')) == NULL) s.len = strlen(s.s);
199
-    else s.len = pos - s.s;
200
-
201
-    if (s.len) {
202
-		if (str2int(&s, flags) != 0) {
203
-			LM_ERR("failed to decode flags <%.*s>\n", STR_FMT(&s));
204
-			return 0;
205
-		}
98
+    val.type = SR_XTYPE_STR;
99
+    val.v.s = *uri;
100
+    xavp_add_value(&uri_name, &val, &record);
101
+
102
+    if (dst_uri->len > 0) {
103
+	val.type = SR_XTYPE_STR;
104
+	val.v.s = *dst_uri;
105
+	xavp_add_value(&dst_uri_name, &val, &record);
206 106
     }
207
-    return 1;
208 107
 
209
-uri_missing:
210
-	ERR("decode_branch_info: Cannot decode branch URI.\n");
211
-	return 0;
212
-}
108
+    if (path->len > 0) {
109
+	val.type = SR_XTYPE_STR;
110
+	val.v.s = *path;
111
+	xavp_add_value(&path_name, &val, &record);
112
+    }
113
+
114
+    if (sock_str->len > 0) {
115
+	val.v.s = *sock_str;
116
+	xavp_add_value(&sock_name, &val, &record);
117
+    }
118
+
119
+    val.type = SR_XTYPE_INT;
120
+    val.v.i = flags;
121
+    xavp_add_value(&flags_name, &val, &record);
122
+
123
+    val.type = SR_XTYPE_INT;
124
+    val.v.i = q_flag;
125
+    xavp_add_value(&q_flag_name, &val, &record);
126
+
127
+    if (instance->len > 0) {
128
+	val.type = SR_XTYPE_STR;
129
+	val.v.s = *instance;
130
+	xavp_add_value(&instance_name, &val, &record);
131
+    }
213 132
 
133
+    val.type = SR_XTYPE_XAVP;
134
+    val.v.xavp = record;
135
+    xavp_add_value(&contacts_avp, &val, NULL);
136
+}
214 137
 
215 138
 /* 
216 139
  * Loads contacts in destination set into contacts_avp in reverse
... ...
@@ -220,149 +149,143 @@ uri_missing:
220 220
  */
221 221
 int t_load_contacts(struct sip_msg* msg, char* key, char* value)
222 222
 {
223
-    str uri, tmp, dst_uri, path, branch_info, *ruri;
224
-    qvalue_t first_q, q;
223
+    branch_t *branch;
224
+    str *ruri, sock_str;
225 225
     struct contact *contacts, *next, *prev, *curr;
226
-    int_str val;
227
-    int first_idx, idx;
228
-    struct socket_info* sock;
229
-    unsigned int flags;
226
+    int first_idx, idx, len;
227
+    char sock_buf[MAX_SOCKET_STR];
230 228
 
231 229
     /* Check if contacts_avp has been defined */
232
-    if (contacts_avp.n == 0) {
233
-		LM_ERR("feature has been disabled - "
234
-		       "to enable define contacts_avp module parameter");
235
-		return -1;
230
+    if (contacts_avp.len == 0) {
231
+	LM_ERR("feature has been disabled - "
232
+	       "to enable define contacts_avp module parameter");
233
+	return -1;
236 234
     }
237 235
 
238 236
     /* Check if anything needs to be done */
239
-    if (nr_branches == 0) {
240
-		LM_DBG("t_load_contacts(): nothing to do - no branches!\n");
241
-		return 1;
242
-    }
243
-
244
-    ruri = (str *)0;
245
-	if (ruri_is_new) {
246
-		/* Take first q from Request-URI */
247
-		ruri = GET_RURI(msg);
248
-		if (!ruri) {
249
-			LM_ERR("no Request-URI found\n");
250
-			return -1;
251
-		}
252
-		first_q = get_ruri_q();
253
-		first_idx = 0;
254
-	} else {
255
-		/* Take first q from first branch */
256
-		uri.s = get_branch(0, &uri.len, &first_q, &dst_uri, &path, &flags,
257
-			               &sock);
258
-		first_idx = 1;
259
-    }
237
+    LM_DBG("nr_branches is %d\n", nr_branches);
260 238
 
261
-    /* Check if all q values are equal */
262
-    for(idx = first_idx; (tmp.s = get_branch(idx, &tmp.len, &q, 0, 0, 0, 0))
263
-			!= 0; idx++) {
264
-		if (q != first_q) {
265
-			goto rest;
266
-		}
239
+    if ((nr_branches == 0) || ((nr_branches == 1) && !ruri_is_new)) {
240
+	LM_DBG("nothing to do - only one contact!\n");
241
+	return 1;
267 242
     }
268 243
 
269
-    LM_DBG("t_load_contacts(): nothing to do - all contacts have same q!\n");
270
-    return 1;
271
-
272
-rest:
273
-
274 244
     /* Allocate memory for first contact */
275 245
     contacts = (struct contact *)pkg_malloc(sizeof(struct contact));
276 246
     if (!contacts) {
277
-		LM_ERR("no memory for contact info\n");
278
-		return -1;
247
+	LM_ERR("no memory for contact info\n");
248
+	return -1;
279 249
     }
280 250
 
281
-	if (ruri_is_new) {
282
-		/* Insert Request-URI branch to first contact */
283
-		contacts->uri.s = ruri->s;
284
-		contacts->uri.len = ruri->len;
285
-		contacts->dst_uri = msg->dst_uri;
286
-		contacts->sock = msg->force_send_socket;
287
-		getbflagsval(0, &contacts->flags);
288
-		contacts->path = msg->path_vec;
289
-	} else {
290
-		/* Insert first branch to first contact */
291
-		contacts->uri = uri;
292
-		contacts->dst_uri = dst_uri;
293
-		contacts->sock = sock;
294
-		contacts->flags = flags;
295
-		contacts->path = path;
251
+    if (ruri_is_new) {
252
+	ruri = GET_RURI(msg);
253
+	if (!ruri) {
254
+	    LM_ERR("no Request-URI found\n");
255
+	    return -1;
256
+	}	
257
+	/* Insert Request-URI branch to first contact */
258
+	contacts->uri.s = ruri->s;
259
+	contacts->uri.len = ruri->len;
260
+	contacts->dst_uri = msg->dst_uri;
261
+	contacts->sock = msg->force_send_socket;
262
+	getbflagsval(0, &contacts->flags);
263
+	contacts->path = msg->path_vec;
264
+	contacts->q = get_ruri_q();
265
+	contacts->instance = msg->instance;
266
+	first_idx = 0;
267
+    } else {
268
+	/* Insert first branch to first contact */
269
+	branch = get_sip_branch(0);
270
+	contacts->uri.s = branch->uri;
271
+	contacts->uri.len = branch->len;
272
+	contacts->dst_uri.s = branch->dst_uri;
273
+	contacts->dst_uri.len = branch->dst_uri_len;
274
+	contacts->sock = branch->force_send_socket;
275
+	contacts->flags = branch->flags;
276
+	contacts->path.s = branch->path;
277
+	contacts->path.len = branch->path_len;
278
+	contacts->q = branch->q;
279
+	contacts->instance.s = branch->instance;
280
+	contacts->instance.len = branch->instance_len;
281
+	first_idx = 1;
296 282
     }
297
-	contacts->q = first_q;
298
-	contacts->next = (struct contact *)0;
283
+
284
+    contacts->next = (struct contact *)0;
299 285
 
300 286
     /* Insert (remaining) branches to contact list in increasing q order */
287
+    for (idx = first_idx; (branch = get_sip_branch(idx)) != 0; idx++) {
301 288
 
302
-    for(idx = first_idx;
303
-		(uri.s = get_branch(idx,&uri.len,&q,&dst_uri,&path,&flags,&sock))
304
-			!= 0;
305
-		idx++ ) {
306
-		next = (struct contact *)pkg_malloc(sizeof(struct contact));
307
-		if (!next) {
308
-			LM_ERR("no memory for contact info\n");
309
-			free_contact_list(contacts);
310
-			return -1;
311
-		}
312
-		next->uri = uri;
313
-		next->q = q;
314
-		next->dst_uri = dst_uri;
315
-		next->path = path;
316
-		next->flags = flags;
317
-		next->sock = sock;
318
-		next->next = (struct contact *)0;
319
-		prev = (struct contact *)0;
320
-		curr = contacts;
321
-		while (curr && (curr->q < q)) {
322
-			prev = curr;
323
-			curr = curr->next;
324
-		}
325
-		if (!curr) {
326
-			next->next = (struct contact *)0;
327
-			prev->next = next;
328
-		} else {
329
-			next->next = curr;
330
-			if (prev) {
331
-				prev->next = next;
332
-			} else {
333
-				contacts = next;
334
-			}
335
-		}    
289
+	next = (struct contact *)pkg_malloc(sizeof(struct contact));
290
+	if (!next) {
291
+	    LM_ERR("no memory for contact info\n");
292
+	    free_contact_list(contacts);
293
+	    return -1;
294
+	}
295
+
296
+	next->uri.s = branch->uri;
297
+	next->uri.len = branch->len;
298
+	next->dst_uri.s = branch->dst_uri;
299
+	next->dst_uri.len = branch->dst_uri_len;
300
+	next->sock = branch->force_send_socket;
301
+	next->flags = branch->flags;
302
+	next->path.s = branch->path;
303
+	next->path.len = branch->path_len;
304
+	next->q = branch->q;
305
+	next->instance.s = branch->instance;
306
+	next->instance.len = branch->instance_len;
307
+	next->next = (struct contact *)0;
308
+
309
+	prev = (struct contact *)0;
310
+	curr = contacts;
311
+	while (curr && (curr->q < branch->q)) {
312
+	    prev = curr;
313
+	    curr = curr->next;
314
+	}
315
+	if (!curr) {
316
+	    next->next = (struct contact *)0;
317
+	    prev->next = next;
318
+	} else {
319
+	    next->next = curr;
320
+	    if (prev) {
321
+		prev->next = next;
322
+	    } else {
323
+		contacts = next;
324
+	    }
325
+	}    
336 326
     }
337 327
 
338 328
     /* Assign values for q_flags */
339 329
     curr = contacts;
340 330
     curr->q_flag = 0;
341 331
     while (curr->next) {
342
-		if (curr->q < curr->next->q) {
343
-			curr->next->q_flag = Q_FLAG;
344
-		} else {
345
-			curr->next->q_flag = 0;
346
-		}
347
-		curr = curr->next;
332
+	if (curr->q < curr->next->q) {
333
+	    curr->next->q_flag = Q_FLAG;
334
+	} else {
335
+	    curr->next->q_flag = 0;
336
+	}
337
+	curr = curr->next;
348 338
     }
349 339
 
350 340
     /* Add contacts to contacts_avp */
351 341
     curr = contacts;
352 342
     while (curr) {
353
-		if (encode_branch_info(&branch_info, curr) == 0) {
354
-			LM_ERR("encoding of branch info failed\n");
355
-			free_contact_list(contacts);
356
-			if (branch_info.s) pkg_free(branch_info.s);
357
-			return -1;
358
-		}
359
-		val.s = branch_info;
360
-		add_avp(contacts_avp_type|AVP_VAL_STR|(curr->q_flag),
361
-				contacts_avp, val);
362
-		pkg_free(branch_info.s);
363
-		LM_DBG("loaded contact <%.*s> with q_flag <%d>\n",
364
-		       STR_FMT(&val.s), curr->q_flag);
365
-		curr = curr->next;
343
+
344
+	if (curr->sock) {
345
+	    len = MAX_SOCKET_STR - 1;
346
+	    if (socket2str(sock_buf, &len, curr->sock) < 0) {
347
+		LM_ERR("failed to convert socket to str\n");
348
+		return -1;
349
+	    }
350
+	    sock_buf[len] = 0;
351
+	    sock_str.s = sock_buf;
352
+	    sock_str.len = len + 1;
353
+	}
354
+
355
+	add_contacts_avp(&(curr->uri), &(curr->dst_uri), &(curr->path),
356
+			 &sock_str, curr->flags, curr->q_flag,
357
+			 &(curr->instance));
358
+
359
+	curr = curr->next;
366 360
     }
367 361
 
368 362
     /* Clear all branches */
... ...
@@ -374,90 +297,515 @@ rest:
374 374
     return 1;
375 375
 }
376 376
 
377
+void add_contact_flows_avp(str *uri, str *dst_uri, str *path, str *sock_str,
378
+			   unsigned int flags, str *instance)
379
+{
380
+    sr_xavp_t *record;
381
+    sr_xval_t val;
382
+
383
+    record = NULL;
384
+
385
+    val.type = SR_XTYPE_STR;
386
+    val.v.s = *uri;
387
+    xavp_add_value(&uri_name, &val, &record);
388
+
389
+    if (dst_uri->len > 0) {
390
+	val.type = SR_XTYPE_STR;
391
+	val.v.s = *dst_uri;
392
+	xavp_add_value(&dst_uri_name, &val, &record);
393
+    }
394
+
395
+    if (path->len > 0) {
396
+	val.type = SR_XTYPE_STR;
397
+	val.v.s = *path;
398
+	xavp_add_value(&path_name, &val, &record);
399
+    }
400
+
401
+    if (sock_str->len > 0) {
402
+	val.v.s = *sock_str;
403
+	xavp_add_value(&sock_name, &val, &record);
404
+    }
405
+
406
+    if (instance->len > 0) {
407
+	val.type = SR_XTYPE_STR;
408
+	val.v.s = *instance;
409
+	xavp_add_value(&instance_name, &val, &record);
410
+    }
411
+
412
+    val.type = SR_XTYPE_INT;
413
+    val.v.i = flags;
414
+    xavp_add_value(&flags_name, &val, &record);
415
+
416
+    val.type = SR_XTYPE_XAVP;
417
+    val.v.xavp = record;
418
+    xavp_add_value(&contact_flows_avp, &val, NULL);
419
+}
377 420
 
378 421
 /*
379
- * Adds to request a new destination set that includes all highest
380
- * priority class contacts in contacts_avp.   Request URI is rewritten with
381
- * first contact and the remaining contacts (if any) are added as branches.
382
- * Removes used contacts from contacts_avp.  Returns 1, if contacts_avp
383
- * was not empty and a destination set was successfully added.  Returns -2,
384
- * if contacts_avp was empty and thus there was nothing to do.
385
- * Returns -1 in case of an error. */
422
+ * Adds to request a new destination set that includes highest
423
+ * priority class contacts in contacts_avp, but only one contact with same
424
+ * +sip.instance value is included.  Others are added to contact_flows_avp
425
+ * for later consumption by next_contact_flows().
426
+ * Request URI is rewritten with first contact and the remaining contacts
427
+ * (if any) are added as branches. Removes all highest priority contacts
428
+ * from contacts_avp.
429
+ * Returns 1, if contacts_avp was not empty and a destination set was
430
+ * successfully added.  Returns -2, if contacts_avp was empty and thus
431
+ * there was nothing to do. Returns -1 in case of an error. */
386 432
 int t_next_contacts(struct sip_msg* msg, char* key, char* value)
387 433
 {
388
-    struct usr_avp *avp, *prev;
389
-    int_str val;
390
-    str uri, dst, path;
434
+    str uri, dst_uri, path, instance, host, sock_str;
391 435
     struct socket_info *sock;
392
-    unsigned int flags;
393
-    struct search_state st;
436
+    unsigned int flags, q_flag;
437
+    sr_xavp_t *xavp_list, *xavp, *prev_xavp, *vavp;
438
+    int port, proto;
439
+    struct instance_list *il, *ilp;
394 440
 
395 441
     /* Check if contacts_avp has been defined */
396
-    if (contacts_avp.n == 0) {
397
-		LM_ERR("feature has been disabled - "
398
-			   "to enable define contacts_avp module parameter");
399
-		return -1;
442
+    if (contacts_avp.len == 0) {
443
+	LM_ERR("feature has been disabled - "
444
+	       "to enable define contacts_avp module parameter");
445
+	return -1;
400 446
     }
401 447
 
402 448
     /* Load Request-URI and branches */
403 449
 
404 450
     /* Find first contacts_avp value */
405
-    avp = search_first_avp(contacts_avp_type, contacts_avp, &val, &st);
406
-    if (!avp) {
407
-	LM_DBG("no AVPs - we are done!\n");
451
+    xavp_list = xavp_get(&contacts_avp, NULL);
452
+    if (!xavp_list) {
453
+	LM_DBG("no contacts in contacts_avp - we are done!\n");
408 454
 	return -2;
409 455
     }
410 456
 
411
-    LM_DBG("next contact is <%.*s>\n", STR_FMT(&val.s));
457
+    xavp = xavp_list;
412 458
 
413
-    if (decode_branch_info(val.s.s, &uri, &dst, &path, &sock, &flags)
414
-	== 0) {
415
-	LM_ERR("decoding of branch info <%.*s> failed\n", STR_FMT(&val.s));
416
-	destroy_avp(avp);
417
-	return -1;
459
+    vavp = xavp_get(&uri_name, xavp->val.v.xavp);
460
+    uri = vavp->val.v.s;
461
+
462
+    vavp = xavp_get(&dst_uri_name, xavp->val.v.xavp);
463
+    if (vavp != NULL) {
464
+	dst_uri = vavp->val.v.s;
465
+    } else {
466
+	dst_uri.s = 0;
467
+	dst_uri.len = 0;
468
+    }
469
+
470
+    vavp = xavp_get(&path_name, xavp->val.v.xavp);
471
+    if (vavp != NULL) {
472
+	path = vavp->val.v.s;
473
+    } else {
474
+	path.s = 0;
475
+	path.len = 0;
476
+    }
477
+
478
+    vavp = xavp_get(&sock_name, xavp->val.v.xavp);
479
+    if (vavp != NULL) {
480
+	sock_str.s = vavp->val.v.s.s;
481
+	if (parse_phostport(sock_str.s, &host.s, &host.len, &port, &proto)
482
+	    != 0) {
483
+	    LM_ERR("parsing of socket info <%s> failed\n", sock_str.s);
484
+	    xavp_destroy_list(&xavp_list);
485
+	    return -1;
486
+	}
487
+	sock = grep_sock_info(&host, (unsigned short)port,
488
+			      (unsigned short)proto);
489
+	if (sock == 0) {
490
+	    xavp_destroy_list(&xavp_list);
491
+	    return -1;
492
+	}
493
+    } else {
494
+	sock = NULL;
495
+    }
496
+
497
+    vavp = xavp_get(&flags_name, xavp->val.v.xavp);
498
+    flags = vavp->val.v.i;
499
+
500
+    vavp = xavp_get(&q_flag_name, xavp->val.v.xavp);
501
+    q_flag = vavp->val.v.i;
502
+
503
+    vavp = xavp_get(&instance_name, xavp->val.v.xavp);
504
+    il = (struct instance_list *)0;
505
+    if ((vavp != NULL) && !q_flag) {
506
+	instance = vavp->val.v.s;
507
+	il = (struct instance_list *)pkg_malloc(sizeof(struct instance_list));
508
+	if (!il) {
509
+	    LM_ERR("no memory for instance list entry\n");
510
+	    return -1;
511
+	}
512
+	il->instance.s = pkg_malloc(instance.len);
513
+	if (!il->instance.s) {
514
+	    pkg_free(il);
515
+	    LM_ERR("no memory for instance list instance\n");
516
+	    return -1;
517
+	}
518
+	il->instance.len = instance.len;
519
+	memcpy(il->instance.s, instance.s, instance.len);
520
+	il->next = (struct instance_list *)0;
418 521
     }
419
-    
522
+
420 523
     /* Rewrite Request-URI */
421 524
     rewrite_uri(msg, &uri);
422
-    if (dst.s && dst.len) set_dst_uri(msg, &dst);
423
-    else reset_dst_uri(msg);
424
-    if (path.s && path.len) set_path_vector(msg, &path);
425
-    else reset_path_vector(msg);
525
+
526
+    if (dst_uri.len) {
527
+	set_dst_uri(msg, &dst_uri);
528
+    } else {
529
+	reset_dst_uri(msg);
530
+    }
531
+
532
+    if (path.len) {
533
+	set_path_vector(msg, &path);
534
+    } else {
535
+	reset_path_vector(msg);
536
+    }
537
+
426 538
     set_force_socket(msg, sock);
539
+
427 540
     setbflagsval(0, flags);
428 541
 
429
-    if (avp->flags & Q_FLAG) {
430
-	destroy_avp(avp);
542
+    /* Check if there was only one contact at this priority */
543
+    if (q_flag) {
544
+	xavp_rm(xavp, NULL);
431 545
 	return 1;
432 546
     }
433 547
 		
434 548
     /* Append branches until out of branches or Q_FLAG is set */
435
-    prev = avp;
436
-    while ((avp = search_next_avp(&st, &val))) {
437
-	destroy_avp(prev);
438
-	LM_DBG("next contact is <%.*s>\n", STR_FMT(&val.s));
439
-	
440
-	if (decode_branch_info(val.s.s, &uri, &dst, &path, &sock, &flags)
441
-	    == 0) {
442
-	    LM_ERR("decoding of branch info <%.*s> failed\n", STR_FMT(&val.s));
443
-	    destroy_avp(avp);
444
-	    return -1;
549
+    /* If a branch has same instance value as some previous branch, */
550
+    /* instead of appending it, add it to contact_flows_avp */
551
+
552
+    xavp_rm_by_name(&contact_flows_avp, 1, NULL);
553
+    prev_xavp = xavp;
554
+
555
+    while ((xavp = xavp_get_next(prev_xavp)) != NULL) {
556
+
557
+	xavp_rm(prev_xavp, NULL);
558
+
559
+	vavp = xavp_get(&q_flag_name, xavp->val.v.xavp);
560
+	q_flag = vavp->val.v.i;
561
+
562
+	vavp = xavp_get(&uri_name, xavp->val.v.xavp);
563
+	uri = vavp->val.v.s;
564
+
565
+	vavp = xavp_get(&dst_uri_name, xavp->val.v.xavp);
566
+	if (vavp != NULL) {
567
+	    dst_uri = vavp->val.v.s;
568
+	} else {
569
+	    dst_uri.len = 0;
570
+	}
571
+
572
+	vavp = xavp_get(&path_name, xavp->val.v.xavp);
573
+	if (vavp != NULL) {
574
+	    path = vavp->val.v.s;
575
+	} else {
576
+	    path.len = 0;
577
+	}
578
+
579
+	vavp = xavp_get(&sock_name, xavp->val.v.xavp);
580
+	if (vavp != NULL) {
581
+	    sock_str = vavp->val.v.s;
582
+	    if (parse_phostport(sock_str.s, &host.s, &host.len, &port, &proto)
583
+		!= 0) {
584
+		LM_ERR("parsing of socket info <%s> failed\n", sock_str.s);
585
+		free_instance_list(il);
586
+		xavp_destroy_list(&xavp_list);
587
+		return -1;
588
+	    }
589
+	    sock = grep_sock_info(&host, (unsigned short)port,
590
+				  (unsigned short)proto);
591
+	    if (sock == 0) {
592
+		free_instance_list(il);
593
+		xavp_destroy_list(&xavp_list);
594
+		return -1;
595
+	    }
596
+	} else {
597
+	    sock = NULL;
598
+	}
599
+
600
+	vavp = xavp_get(&flags_name, xavp->val.v.xavp);
601
+	flags = vavp->val.v.i;
602
+
603
+	vavp = xavp_get(&instance_name, xavp->val.v.xavp);
604
+	if (vavp != NULL) {
605
+	    instance = vavp->val.v.s;
606
+	    ilp = il;
607
+	    while (ilp) {
608
+		if ((instance.len == ilp->instance.len) &&
609
+		    (strncmp(instance.s, ilp->instance.s, instance.len) == 0))
610
+		    break;
611
+		ilp = ilp->next;
612
+	    }
613
+	    if (ilp) {
614
+		add_contact_flows_avp(&uri, &dst_uri, &path, &sock_str,
615
+				      flags, &instance);
616
+		goto check_q_flag;
617
+	    }
618
+	    if (!q_flag) {
619
+		ilp = (struct instance_list *)
620
+		    pkg_malloc(sizeof(struct instance_list));
621
+		if (!ilp) {
622
+		    LM_ERR("no memory for instance list element\n");
623
+		    free_instance_list(il);
624
+		    return -1;
625
+		}
626
+		ilp->instance.s = pkg_malloc(instance.len);
627
+		if (!ilp->instance.s) {
628
+		    LM_ERR("no memory for instance list instance\n");
629
+		    pkg_free(ilp);
630
+		    free_instance_list(il);
631
+		    return -1;
632
+		}
633
+		ilp->instance.len = instance.len;
634
+		memcpy(ilp->instance.s, instance.s, instance.len);
635
+		ilp->next = il;
636
+		il = ilp;
637
+	    }
445 638
 	}
446 639
 
447
-	if (append_branch(msg, &uri, &dst, &path, 0, flags, sock, 0, 0) != 1) {
640
+	if (append_branch(msg, &uri, &dst_uri, &path, 0, flags, sock, 0, 0)
641
+	    != 1) {
448 642
 	    LM_ERR("appending branch failed\n");
449
-	    destroy_avp(avp);
643
+	    free_instance_list(il);
644
+	    xavp_destroy_list(&xavp_list);
450 645
 	    return -1;
451 646
 	}
452 647
 
453
-	if (avp->flags & Q_FLAG) {
454
-	    destroy_avp(avp);
648
+    check_q_flag:
649
+	if (q_flag) {
650
+	    free_instance_list(il);
651
+	    xavp_rm(xavp, NULL);
455 652
 	    return 1;
456 653
 	}
457
-	prev = avp;
654
+
655
+	prev_xavp = xavp;
656
+    }
657
+
658
+    free_instance_list(il);
659
+    xavp_rm(prev_xavp, NULL);
660
+
661
+    return 1;
662
+}
663
+
664
+/*
665
+ * Adds to request a new destination set that includes contacts
666
+ * from contact_flows_avp.  Only one contact with same +sip.instance
667
+ * value is included.
668
+ * Request URI is rewritten with first contact and the remaining contacts
669
+ * (if any) are added as branches. Removes all used contacts
670
+ * from contacts_avp.
671
+ * Returns 1, if contact_flows_avp was not empty and a destination set was
672
+ * successfully added.  Returns -2, if contact_flows_avp was empty and thus
673
+ * there was nothing to do. Returns -1 in case of an error. */
674
+int t_next_contact_flows(struct sip_msg* msg, char* key, char* value)
675
+{
676
+    str uri, dst_uri, path, instance, host;
677
+    struct socket_info *sock;
678
+    unsigned int flags;
679
+    sr_xavp_t *xavp_list, *xavp, *next_xavp, *vavp;
680
+    char *tmp;
681
+    int port, proto;
682
+    struct instance_list *il, *ilp;
683
+
684
+    /* Check if contact_flows_avp has been defined */
685
+    if (contact_flows_avp.len == 0) {
686
+	LM_ERR("feature has been disabled - "
687
+	       "to enable define contact_flows_avp module parameter");
688
+	return -1;
689
+    }
690
+
691
+    /* Load Request-URI and branches */
692
+
693
+    /* Find first contact_flows_avp value */
694
+    xavp_list = xavp_get(&contact_flows_avp, NULL);
695
+    if (!xavp_list) {
696
+	LM_DBG("no contacts in contact_flows_avp - we are done!\n");
697
+	return -2;
698
+    }
699
+
700
+    xavp = xavp_list;
701
+    next_xavp = xavp_get_next(xavp);
702
+
703
+    vavp = xavp_get(&uri_name, xavp->val.v.xavp);
704
+    uri = vavp->val.v.s;
705
+
706
+    vavp = xavp_get(&dst_uri_name, xavp->val.v.xavp);
707
+    if (vavp != NULL) {
708
+	dst_uri = vavp->val.v.s;
709
+    } else {
710
+	dst_uri.s = 0;
711
+	dst_uri.len = 0;
712
+    }
713
+
714
+    vavp = xavp_get(&path_name, xavp->val.v.xavp);
715
+    if (vavp != NULL) {
716
+	path = vavp->val.v.s;
717
+    } else {
718
+	path.s = 0;
719
+	path.len = 0;
720
+    }
721
+
722
+    vavp = xavp_get(&sock_name, xavp->val.v.xavp);
723
+    if (vavp != NULL) {
724
+	tmp = vavp->val.v.s.s;
725
+	if (parse_phostport(tmp, &host.s, &host.len, &port, &proto) != 0) {
726
+	    LM_ERR("parsing of socket info <%s> failed\n", tmp);
727
+	    xavp_destroy_list(&xavp_list);
728
+	    return -1;
729
+	}
730
+	sock = grep_sock_info(&host, (unsigned short)port,
731
+			      (unsigned short)proto);
732
+	if (sock == 0) {
733
+	    xavp_destroy_list(&xavp_list);
734
+	    return -1;
735
+	}
736
+    } else {
737
+	sock = NULL;
738
+    }
739
+
740
+    vavp = xavp_get(&flags_name, xavp->val.v.xavp);
741
+    flags = vavp->val.v.i;
742
+
743
+    vavp = xavp_get(&instance_name, xavp->val.v.xavp);
744
+    il = (struct instance_list *)0;
745
+    if ((vavp != NULL) && next_xavp) {
746
+	instance = vavp->val.v.s;
747
+	il = (struct instance_list *)pkg_malloc(sizeof(struct instance_list));
748
+	if (!il) {
749
+	    LM_ERR("no memory for instance list entry\n");
750
+	    return -1;
751
+	}
752
+	il->instance.s = pkg_malloc(instance.len);
753
+	if (!il->instance.s) {
754
+	    pkg_free(il);
755
+	    LM_ERR("no memory for instance list instance\n");
756
+	    return -1;
757
+	}
758
+	il->instance.len = instance.len;
759
+	memcpy(il->instance.s, instance.s, instance.len);
760
+	il->next = (struct instance_list *)0;
761
+    }
762
+
763
+    /* Rewrite Request-URI */
764
+    rewrite_uri(msg, &uri);
765
+
766
+    if (dst_uri.len) {
767
+	set_dst_uri(msg, &dst_uri);
768
+    } else {
769
+	reset_dst_uri(msg);
770
+    }
771
+
772
+    if (path.len) {
773
+	set_path_vector(msg, &path);
774
+    } else {
775
+	reset_path_vector(msg);
776
+    }
777
+
778
+    set_force_socket(msg, sock);
779
+
780
+    setbflagsval(0, flags);
781
+
782
+    /* Append branches until out of branches. */
783
+    /* Do not include a branch that has same instance value as some */
784
+    /* previous branch. */
785
+
786
+    xavp_rm(xavp, NULL);
787
+    xavp = next_xavp;
788
+
789
+    while (xavp) {
790
+	
791
+	next_xavp = xavp_get_next(xavp);
792
+
793
+	vavp = xavp_get(&instance_name, xavp->val.v.xavp);
794
+	if (vavp != NULL) {
795
+	    instance = vavp->val.v.s;
796
+	    ilp = il;
797
+	    while (ilp) {
798
+		if ((instance.len == ilp->instance.len) &&
799
+		    (strncmp(instance.s, ilp->instance.s, instance.len) == 0))
800
+		    break;
801
+		ilp = ilp->next;
802
+	    }
803
+	    if (ilp) {
804
+		/* skip already appended instance */
805
+		xavp = next_xavp;
806
+		continue;
807
+	    }
808
+	    if (next_xavp) {
809
+		ilp = (struct instance_list *)
810
+		pkg_malloc(sizeof(struct instance_list));
811
+		if (!ilp) {
812
+		    LM_ERR("no memory for new instance list entry\n");
813
+		    free_instance_list(il);
814
+		    return -1;
815
+		}
816
+		ilp->instance.s = pkg_malloc(instance.len);
817
+		if (!ilp->instance.s) {
818
+		    pkg_free(il);
819
+		    LM_ERR("no memory for instance list instance\n");
820
+		    return -1;
821
+		}
822
+		ilp->instance.len = instance.len;
823
+		memcpy(ilp->instance.s, instance.s, instance.len);
824
+		ilp->next = il;
825
+		il = ilp;
826
+	    } else {
827
+		LM_ERR("instance missing from contact_flow_avp contact\n");
828
+		free_instance_list(il);
829
+		return -1;
830
+	    }
831
+	}
832
+
833
+	vavp = xavp_get(&uri_name, xavp->val.v.xavp);
834
+	uri = vavp->val.v.s;
835
+
836
+	vavp = xavp_get(&dst_uri_name, xavp->val.v.xavp);
837
+	if (vavp != NULL) {
838
+	    dst_uri = vavp->val.v.s;
839
+	} else {
840
+	    dst_uri.len = 0;
841
+	}
842
+
843
+	vavp = xavp_get(&path_name, xavp->val.v.xavp);
844
+	if (vavp != NULL) {
845
+	    path = vavp->val.v.s;
846
+	} else {
847
+	    path.len = 0;
848
+	}
849
+
850
+	vavp = xavp_get(&sock_name, xavp->val.v.xavp);
851
+	if (vavp != NULL) {
852
+	    tmp = vavp->val.v.s.s;
853
+	    if (parse_phostport(tmp, &host.s, &host.len, &port, &proto) != 0) {
854
+		LM_ERR("parsing of socket info <%s> failed\n", tmp);
855
+		free_instance_list(il);
856
+		xavp_destroy_list(&xavp_list);
857
+		return -1;
858
+	    }
859
+	    sock = grep_sock_info(&host, (unsigned short)port,
860
+				  (unsigned short)proto);
861
+	    if (sock == 0) {
862
+		free_instance_list(il);
863
+		xavp_destroy_list(&xavp_list);
864
+		return -1;
865
+	    }
866
+	} else {
867
+	    sock = NULL;
868
+	}
869
+
870
+	vavp = xavp_get(&flags_name, xavp->val.v.xavp);
871
+	flags = vavp->val.v.i;
872
+
873
+	if (append_branch(msg, &uri, &dst_uri, &path, 0, flags, sock, 0, 0)
874
+	    != 1) {
875
+	    LM_ERR("appending branch failed\n");
876
+	    free_instance_list(il);
877
+	    xavp_destroy_list(&xavp_list);
878
+	    return -1;
879
+	}
880
+
881
+	xavp_rm(xavp, NULL);
882
+	xavp = next_xavp;
458 883
     }
459 884
 
460
-    destroy_avp(prev);
885
+    free_instance_list(il);
461 886
 
462 887
     return 1;
463 888
 }
... ...
@@ -33,3 +33,5 @@ extern int fr_inv_timer_next;
33 33
 int t_load_contacts(struct sip_msg* msg, char* key, char* value);
34 34
 
35 35
 int t_next_contacts(struct sip_msg* msg, char* key, char* value);
36
+
37
+int t_next_contact_flows(struct sip_msg* msg, char* key, char* value);
... ...
@@ -306,7 +306,9 @@ static int w_t_is_set(struct sip_msg* msg, char* target, char* bar);
306 306
  * searched for nothing each time a new transaction is created */
307 307
 static char *fr_timer_param = 0 /*FR_TIMER_AVP*/;
308 308
 static char *fr_inv_timer_param = 0 /*FR_INV_TIMER_AVP*/;
309
-static char *contacts_avp_param = 0;
309
+
310
+str contacts_avp = {0, 0};
311
+str contact_flows_avp = {0, 0};
310 312
 
311 313
 int tm_remap_503_500 = 1;
312 314
 
... ...
@@ -473,6 +475,8 @@ static cmd_export_t cmds[]={
473 473
 			REQUEST_ROUTE | FAILURE_ROUTE},
474 474
 	{"t_next_contacts", t_next_contacts,            0, 0,
475 475
 			REQUEST_ROUTE | FAILURE_ROUTE},
476
+	{"t_next_contact_flows", t_next_contact_flows,            0, 0,
477
+			REQUEST_ROUTE | FAILURE_ROUTE},
476 478
 
477 479
 	/* not applicable from the script */
478 480
 	{"load_tm",            (cmd_function)load_tm,           NO_SCRIPT,   0, 0},
... ...
@@ -519,7 +523,8 @@ static param_export_t params[]={
519 519
 	{"cancel_b_method",     PARAM_INT, &default_tm_cfg.cancel_b_flags},
520 520
 	{"reparse_on_dns_failover", PARAM_INT, &default_tm_cfg.reparse_on_dns_failover},
521 521
 	{"on_sl_reply",         PARAM_STRING|PARAM_USE_FUNC, fixup_on_sl_reply   },
522
-	{"contacts_avp",        PARAM_STRING, &contacts_avp_param                },
522
+	{"contacts_avp",        PARAM_STR, &contacts_avp                },
523
+	{"contact_flows_avp",   PARAM_STR, &contact_flows_avp           },
523 524
 	{"disable_6xx_block",   PARAM_INT, &default_tm_cfg.disable_6xx           },
524 525
 	{"local_ack_mode",      PARAM_INT, &default_tm_cfg.local_ack_mode        },
525 526
 	{"failure_reply_mode",  PARAM_INT, &failure_reply_mode                   },
... ...
@@ -840,11 +845,15 @@ static int mod_init(void)
840 840
 		return -1;
841 841
 	}
842 842
 
843
-	if (init_avp_params( fr_timer_param, fr_inv_timer_param,
844
-						 contacts_avp_param)<0 ){
843
+	if (init_avp_params(fr_timer_param, fr_inv_timer_param) < 0) {
845 844
 		LOG(L_ERR,"ERROR:tm:mod_init: failed to process AVP params\n");
846 845
 		return -1;
847 846
 	}
847
+	if ((contacts_avp.len > 0) && (contact_flows_avp.len == 0)) {
848
+	    LOG(L_ERR,"ERROR:tm:mod_init: contact_flows_avp param has not been defined\n");
849
+	    return -1;
850
+	}
851
+
848 852
 #ifdef WITH_EVENT_LOCAL_REQUEST
849 853
 	goto_on_local_req=route_lookup(&event_rt, "tm:local-request");
850 854
 	if (goto_on_local_req>=0 && event_rt.rlist[goto_on_local_req]==0)