Browse code

kazoo : timeout fixes & improvements

1) fixes names in parameters (timout corrected to timeout)

2) kazoo_query was always using the same timeout value which could be a problem, since there are different kinds of request and some may be given more time to process.
solved by adding amqp_query_timeout_avp parameter to allow usage of different timeouts.

(cherry picked from commit 0c3925e6f787c6e8d2e1bc7a45fec0c99ba203d8)

Luis Azedo authored on 05/02/2015 19:35:37
Showing 3 changed files
... ...
@@ -451,7 +451,7 @@ modparam("kazoo", "amqp_interprocess_timeout_micro", 200000)
451 451
     </section>    
452 452
 
453 453
     <section>
454
-        <title><varname>amqp_waitframe_timout</varname>(str)</title>
454
+        <title><varname>amqp_waitframe_tiemout</varname>(str)</title>
455 455
         <para>
456 456
         Timeout when checking for messages from rabbitmq.
457 457
         </para>
... ...
@@ -459,18 +459,18 @@ modparam("kazoo", "amqp_interprocess_timeout_micro", 200000)
459 459
         <emphasis>Default value is 100000 micro.</emphasis>
460 460
         </para>
461 461
         <example>
462
-        <title>Set <varname>amqp_waitframe_timout</varname> parameter</title>
462
+        <title>Set <varname>amqp_waitframe_timeout</varname> parameter</title>
463 463
         <programlisting format="linespecific">
464 464
 ...
465
-modparam("kazoo", "amqp_waitframe_timout_sec", 1)
466
-modparam("kazoo", "amqp_waitframe_timout_micro", 200000)
465
+modparam("kazoo", "amqp_waitframe_timeout_sec", 1)
466
+modparam("kazoo", "amqp_waitframe_timeout_micro", 200000)
467 467
 ...
468 468
 </programlisting>
469 469
         </example>
470 470
     </section>    
471 471
 
472 472
     <section>
473
-        <title><varname>amqp_query_timout</varname>(str)</title>
473
+        <title><varname>amqp_query_timeout</varname>(str)</title>
474 474
         <para>
475 475
         Timeout when checking for reply messages from rabbitmq for kazoo_query commands.
476 476
         </para>
... ...
@@ -478,16 +478,42 @@ modparam("kazoo", "amqp_waitframe_timout_micro", 200000)
478 478
         <emphasis>Default value is 2 sec.</emphasis>
479 479
         </para>
480 480
         <example>
481
-        <title>Set <varname>amqp_query_timout</varname> parameter</title>
481
+        <title>Set <varname>amqp_query_timeout</varname> parameter</title>
482 482
         <programlisting format="linespecific">
483 483
 ...
484
-modparam("kazoo", "amqp_query_timout_sec", 1)
485
-modparam("kazoo", "amqp_query_timout_micro", 200000)
484
+modparam("kazoo", "amqp_query_timeout_sec", 1)
485
+modparam("kazoo", "amqp_query_timeout_micro", 200000)
486 486
 ...
487 487
 </programlisting>
488 488
         </example>
489 489
     </section>    
490 490
  
491
+     <section>
492
+        <title><varname>amqp_query_timeout_avp</varname>(str)</title>
493
+        <para>
494
+        avp holding the value in seconds for Timeout when checking for reply messages from rabbitmq for kazoo_query commands.
495
+        </para>
496
+        <para>
497
+        <emphasis>Default value is NULL (no value).</emphasis>
498
+        </para>
499
+        <example>
500
+        <title>>Set <varname>amqp_query_timeout_avp</varname> parameter</title>
501
+        <programlisting format="linespecific">
502
+...
503
+modparam("kazoo", "amqp_query_timeout_avp", "$var(kz_timeout)")
504
+
505
+route[SOME_ROUTE]
506
+{
507
+    $var(kz_timeout) = 12;
508
+    kazoo_query(exchange, routingkey, payload);
509
+}    
510
+
511
+...
512
+</programlisting>
513
+        </example>
514
+    </section>    
515
+ 
516
+ 
491 517
     </section>
492 518
         
493 519
     <section>
... ...
@@ -96,6 +96,9 @@ db_func_t kz_pa_dbf;
96 96
 str kz_presentity_table = str_init("presentity");
97 97
 str kz_db_url = {0,0};
98 98
 
99
+str kz_query_timeout_avp = {0,0};
100
+pv_spec_t kz_query_timeout_spec;
101
+
99 102
 MODULE_VERSION
100 103
 
101 104
 static tr_export_t mod_trans[] = {
... ...
@@ -149,13 +152,13 @@ static param_export_t params[] = {
149 152
     {"amqp_consumer_ack_timeout_sec", INT_PARAM, &kz_ack_tv.tv_sec},
150 153
     {"amqp_interprocess_timeout_micro", INT_PARAM, &kz_sock_tv.tv_usec},
151 154
     {"amqp_interprocess_timeout_sec", INT_PARAM, &kz_sock_tv.tv_sec},
152
-    {"amqp_waitframe_timout_micro", INT_PARAM, &kz_amqp_tv.tv_usec},
153
-    {"amqp_waitframe_timout_sec", INT_PARAM, &kz_amqp_tv.tv_sec},
155
+    {"amqp_waitframe_timeout_micro", INT_PARAM, &kz_amqp_tv.tv_usec},
156
+    {"amqp_waitframe_timeout_sec", INT_PARAM, &kz_amqp_tv.tv_sec},
154 157
     {"amqp_consumer_processes", INT_PARAM, &dbk_consumer_processes},
155 158
     {"amqp_consumer_event_key", STR_PARAM, &dbk_consumer_event_key.s},
156 159
     {"amqp_consumer_event_subkey", STR_PARAM, &dbk_consumer_event_subkey.s},
157
-    {"amqp_query_timout_micro", INT_PARAM, &kz_qtimeout_tv.tv_usec},
158
-    {"amqp_query_timout_sec", INT_PARAM, &kz_qtimeout_tv.tv_sec},
160
+    {"amqp_query_timeout_micro", INT_PARAM, &kz_qtimeout_tv.tv_usec},
161
+    {"amqp_query_timeout_sec", INT_PARAM, &kz_qtimeout_tv.tv_sec},
159 162
     {"amqp_internal_loop_count", INT_PARAM, &dbk_internal_loop_count},
160 163
     {"amqp_consumer_loop_count", INT_PARAM, &dbk_consumer_loop_count},
161 164
     {"amqp_consumer_ack_loop_count", INT_PARAM, &dbk_consumer_ack_loop_count},
... ...
@@ -165,6 +168,7 @@ static param_export_t params[] = {
165 168
     {"pua_mode", INT_PARAM, &dbk_pua_mode},
166 169
     {"single_consumer_on_reconnect", INT_PARAM, &dbk_single_consumer_on_reconnect},
167 170
     {"consume_messages_on_reconnect", INT_PARAM, &dbk_consume_messages_on_reconnect},
171
+    {"amqp_query_timeout_avp", STR_PARAM, &kz_query_timeout_avp.s},
168 172
     {0, 0, 0}
169 173
 };
170 174
 
... ...
@@ -184,6 +188,30 @@ struct module_exports exports = {
184 188
     mod_child_init				/* per-child init function */
185 189
 };
186 190
 
191
+inline static int kz_parse_avp( str *avp_spec, pv_spec_t *avp, char *txt)
192
+{
193
+	if (pv_parse_spec(avp_spec, avp)==NULL) {
194
+		LM_ERR("malformed or non AVP %s AVP definition\n",txt);
195
+		return -1;
196
+	}
197
+	return 0;
198
+}
199
+
200
+static int kz_init_avp(void) {
201
+	if(kz_query_timeout_avp.s)
202
+		kz_query_timeout_avp.len = strlen(kz_query_timeout_avp.s);
203
+
204
+	if ( kz_query_timeout_avp.s ) {
205
+		if ( kz_parse_avp(&kz_query_timeout_avp, &kz_query_timeout_spec, "amqp_query_timeout_avp") <0) {
206
+			return -1;
207
+		}
208
+	} else {
209
+		memset( &kz_query_timeout_spec, 0, sizeof(pv_spec_t));
210
+	}
211
+
212
+	return 0;
213
+}
214
+
187 215
 static int mod_init(void) {
188 216
 	int i;
189 217
     startup_time = (int) time(NULL);
... ...
@@ -198,13 +226,13 @@ static int mod_init(void) {
198 226
     dbk_consumer_event_key.len = strlen(dbk_consumer_event_key.s);
199 227
    	dbk_consumer_event_subkey.len = strlen(dbk_consumer_event_subkey.s);
200 228
 
201
-    kz_amqp_init();
202 229
 
203
-    if (kz_callid_init() < 0) {
204
-	LOG(L_CRIT, "Error while initializing Call-ID generator\n");
205
-	return -1;
206
-    }
230
+   	if(kz_init_avp()) {
231
+   		LM_ERR("Error in avp params\n");
232
+   		return -1;
233
+   	}
207 234
 
235
+    kz_amqp_init();
208 236
 
209 237
     if(dbk_pua_mode == 1) {
210 238
 		kz_db_url.len = kz_db_url.s ? strlen(kz_db_url.s) : 0;
... ...
@@ -277,15 +305,6 @@ static int mod_child_init(int rank)
277 305
 
278 306
 	fire_init_event(rank);
279 307
 
280
-	if (rank != PROC_INIT) {
281
-	   if (kz_callid_child_init(rank) < 0) { 
282
-		/* don't init callid for PROC_INIT*/
283
-		LOG(L_ERR, "ERROR: child_init: Error while initializing Call-ID"
284
-				" generator\n");
285
-		return -2;
286
-           }
287
-	}
288
-
289 308
 	if (rank==PROC_INIT || rank==PROC_TCP_MAIN)
290 309
 		return 0;
291 310
 
... ...
@@ -376,7 +395,6 @@ static int fire_init_event(int rank)
376 395
 static void mod_destroy(void) {
377 396
 	kz_amqp_destroy();
378 397
     shm_free(kz_pipe_fds);
379
-    kz_tr_clear_buffers();
380 398
 }
381 399
 
382 400
 
... ...
@@ -5,6 +5,7 @@
5 5
 #include <amqp_framing.h>
6 6
 #include <amqp_tcp_socket.h>
7 7
 #include <json.h>
8
+#include <uuid/uuid.h>
8 9
 #include "../../mem/mem.h"
9 10
 #include "../../timer_proc.h"
10 11
 #include "../../sr_module.h"
... ...
@@ -43,11 +44,11 @@ extern int dbk_consumer_ack_loop_count;
43 44
 extern int dbk_single_consumer_on_reconnect;
44 45
 extern int dbk_consume_messages_on_reconnect;
45 46
 
47
+extern pv_spec_t kz_query_timeout_spec;
48
+
46 49
 const amqp_bytes_t kz_amqp_empty_bytes = { 0, NULL };
47 50
 const amqp_table_t kz_amqp_empty_table = { 0, NULL };
48 51
 
49
-char* last_payload_result = NULL;
50
-
51 52
 
52 53
 static char *kz_amqp_str_dup(str *src)
53 54
 {
... ...
@@ -333,8 +334,6 @@ void kz_amqp_destroy() {
333 334
 		shm_free(kz_pool);
334 335
 	}
335 336
 
336
-	if(last_payload_result != NULL)
337
-		free(last_payload_result);
338 337
 
339 338
 }
340 339
 
... ...
@@ -621,7 +620,6 @@ int kz_amqp_pipe_send(str *str_exchange, str *str_routing_key, str *str_payload)
621 620
     str unique_string = { 0, 0 };
622 621
     char serverid[512];
623 622
 
624
-    /*
625 623
     uuid_t id;
626 624
     char uuid_buffer[40];
627 625
 
... ...
@@ -629,8 +627,6 @@ int kz_amqp_pipe_send(str *str_exchange, str *str_routing_key, str *str_payload)
629 627
     uuid_unparse_lower(id, uuid_buffer);
630 628
     unique_string.s = uuid_buffer;
631 629
     unique_string.len = strlen(unique_string.s);
632
-    */
633
-    kz_generate_callid(&unique_string);
634 630
 
635 631
     sprintf(serverid, "kamailio@%.*s-<%d>-script-%lu", dbk_node_hostname.len, dbk_node_hostname.s, my_pid(), rpl_query_routing_key_count++);
636 632
 
... ...
@@ -684,7 +680,7 @@ int kz_amqp_pipe_send(str *str_exchange, str *str_routing_key, str *str_payload)
684 680
 	return ret;
685 681
 }
686 682
 
687
-int kz_amqp_pipe_send_receive(str *str_exchange, str *str_routing_key, str *str_payload, json_obj_ptr* json_ret )
683
+int kz_amqp_pipe_send_receive(str *str_exchange, str *str_routing_key, str *str_payload, struct timeval* kz_timeout, json_obj_ptr* json_ret )
688 684
 {
689 685
 	int ret = 1;
690 686
     json_obj_ptr json_obj = NULL;
... ...
@@ -694,7 +690,6 @@ int kz_amqp_pipe_send_receive(str *str_exchange, str *str_routing_key, str *str_
694 690
     str unique_string = { 0, 0 };
695 691
     char serverid[512];
696 692
 
697
-    /*
698 693
     uuid_t id;
699 694
     char uuid_buffer[40];
700 695
 
... ...
@@ -702,9 +697,6 @@ int kz_amqp_pipe_send_receive(str *str_exchange, str *str_routing_key, str *str_
702 697
     uuid_unparse_lower(id, uuid_buffer);
703 698
     unique_string.s = uuid_buffer;
704 699
     unique_string.len = strlen(unique_string.s);
705
-    */
706
-    kz_generate_callid(&unique_string);
707
-
708 700
 
709 701
     sprintf(serverid, "kamailio@%.*s-<%d>-script-%lu", dbk_node_hostname.len, dbk_node_hostname.s, my_pid(), rpl_query_routing_key_count++);
710 702
 
... ...
@@ -728,7 +720,9 @@ int kz_amqp_pipe_send_receive(str *str_exchange, str *str_routing_key, str *str_
728 720
 	cmd->routing_key = kz_amqp_str_dup(str_routing_key);
729 721
 	cmd->reply_routing_key = kz_amqp_string_dup(serverid);
730 722
 	cmd->payload = kz_amqp_string_dup(payload);
731
-	cmd->timeout = kz_qtimeout_tv;
723
+
724
+	cmd->timeout = *kz_timeout;
725
+
732 726
 	if(cmd->payload == NULL || cmd->routing_key == NULL || cmd->exchange == NULL) {
733 727
 		LM_ERR("failed to allocate kz_amqp_cmd parameters in process %d\n", getpid());
734 728
 		goto error;
... ...
@@ -806,6 +800,9 @@ int kz_amqp_publish(struct sip_msg* msg, char* exchange, char* routing_key, char
806 800
 
807 801
 };
808 802
 
803
+
804
+char* last_payload_result = NULL;
805
+
809 806
 int kz_pv_get_last_query_result(struct sip_msg *msg, pv_param_t *param,	pv_value_t *res)
810 807
 {
811 808
 	return last_payload_result == NULL ? pv_get_null(msg, param, res) : pv_get_strzval(msg, param, res, last_payload_result);
... ...
@@ -817,9 +814,10 @@ int kz_amqp_query_ex(struct sip_msg* msg, char* exchange, char* routing_key, cha
817 814
 	  str json_s;
818 815
 	  str exchange_s;
819 816
 	  str routing_key_s;
817
+	  struct timeval kz_timeout = kz_qtimeout_tv;
820 818
 
821 819
 	  if(last_payload_result)
822
-		free(last_payload_result);
820
+		pkg_free(last_payload_result);
823 821
 
824 822
 	  last_payload_result = NULL;
825 823
 
... ...
@@ -847,8 +845,19 @@ int kz_amqp_query_ex(struct sip_msg* msg, char* exchange, char* routing_key, cha
847 845
 
848 846
 		json_object_put(j);
849 847
 
848
+		if(kz_query_timeout_spec.type != PVT_NONE) {
849
+			pv_value_t pv_val;
850
+			if(pv_get_spec_value( msg, &kz_query_timeout_spec, &pv_val) == 0) {
851
+				if((pv_val.flags & PV_VAL_INT) && pv_val.ri != 0 ) {
852
+					kz_timeout.tv_usec = 0;
853
+					kz_timeout.tv_sec = pv_val.ri;
854
+					LM_INFO("SET TIMEOUT TO %i\n", kz_timeout.tv_sec);
855
+				}
856
+			}
857
+		}
858
+
850 859
 		json_obj_ptr ret = NULL;
851
-		int res = kz_amqp_pipe_send_receive(&exchange_s, &routing_key_s, &json_s, &ret );
860
+		int res = kz_amqp_pipe_send_receive(&exchange_s, &routing_key_s, &json_s, &kz_timeout, &ret );
852 861
 
853 862
 		if(res != 0) {
854 863
 			return -1;
... ...
@@ -856,7 +865,7 @@ int kz_amqp_query_ex(struct sip_msg* msg, char* exchange, char* routing_key, cha
856 865
 
857 866
 		char* strjson = (char*)json_object_to_json_string(ret);
858 867
 		int len = strlen(strjson);
859
-		char* value = malloc(len+1);
868
+		char* value = pkg_malloc(len+1);
860 869
 		memcpy(value, strjson, len);
861 870
 		value[len] = '\0';
862 871
 		last_payload_result = value;
... ...
@@ -1161,7 +1170,7 @@ int get_channel_index() {
1161 1170
 int kz_amqp_bind_targeted_channel(kz_amqp_conn_ptr kz_conn, int loopcount, int idx )
1162 1171
 {
1163 1172
     kz_amqp_bind_ptr bind = NULL;
1164
-//    amqp_queue_declare_ok_t *r = NULL;
1173
+    amqp_queue_declare_ok_t *r = NULL;
1165 1174
     str rpl_exch = str_init("targeted");
1166 1175
     str rpl_exch_type = str_init("direct");
1167 1176
     int ret = -1;
... ...
@@ -1189,13 +1198,13 @@ int kz_amqp_bind_targeted_channel(kz_amqp_conn_ptr kz_conn, int loopcount, int i
1189 1198
 		goto error;
1190 1199
     }
1191 1200
 
1192
-    amqp_queue_declare(kz_conn->conn, channels[idx].channel, bind->queue, 0, 0, 1, 1, kz_amqp_empty_table);
1201
+    r = amqp_queue_declare(kz_conn->conn, channels[idx].channel, bind->queue, 0, 0, 1, 1, kz_amqp_empty_table);
1193 1202
     if (kz_amqp_error("Declaring queue", amqp_get_rpc_reply(kz_conn->conn)))
1194 1203
     {
1195 1204
 		goto error;
1196 1205
     }
1197 1206
 
1198
-    amqp_exchange_declare(kz_conn->conn, channels[idx].channel, bind->exchange, bind->exchange_type, 0, 0, kz_amqp_empty_table);
1207
+	amqp_exchange_declare(kz_conn->conn, channels[idx].channel, bind->exchange, bind->exchange_type, 0, 0, kz_amqp_empty_table);
1199 1208
     if (kz_amqp_error("Declaring exchange", amqp_get_rpc_reply(kz_conn->conn)))
1200 1209
     {
1201 1210
 		ret = -RET_AMQP_ERROR;
... ...
@@ -1554,7 +1563,7 @@ void kz_amqp_manager_loop(int child_no)
1554 1563
 	int INTERNAL_READ_COUNT , INTERNAL_READ_MAX_LOOP;
1555 1564
 	int CONSUMER_READ_COUNT , CONSUMER_READ_MAX_LOOP;
1556 1565
 	int ACK_READ_COUNT , ACK_READ_MAX_LOOP;
1557
-//	char* payload;
1566
+	char* payload;
1558 1567
 	int channel_res;
1559 1568
     kz_amqp_conn_ptr kzconn;
1560 1569
 	kz_amqp_cmd_ptr cmd;
... ...
@@ -1701,7 +1710,7 @@ void kz_amqp_manager_loop(int child_no)
1701 1710
 
1702 1711
     		CONSUMER_READ_COUNT = 0;
1703 1712
     	    while(CONSUME && (CONSUMER_READ_COUNT < CONSUMER_READ_MAX_LOOP || firstLoop)) {
1704
-//        		payload = NULL;
1713
+        		payload = NULL;
1705 1714
         		CONSUMER_READ_COUNT++;
1706 1715
 				amqp_envelope_t envelope;
1707 1716
 				amqp_maybe_release_buffers(kzconn->conn);
... ...
@@ -1795,135 +1804,3 @@ void kz_amqp_manager_loop(int child_no)
1795 1804
     	kz_amqp_fire_connection_event("closed", kzconn->info.host);
1796 1805
     }
1797 1806
 }
1798
-
1799
-
1800
-/**
1801
- * \brief Length of a Call-ID in TM
1802
- */
1803
-#define CALLID_NR_LEN 20
1804
-
1805
-/**
1806
- * \brief Length of the Call-ID suffix
1807
- */
1808
-#define CALLID_SUFFIX_LEN ( 1 /* - */                                            + \
1809
-			    5 /* pid */                                          + \
1810
-                           42 /* embedded v4inv6 address can be looong '128.' */ + \
1811
-	                    2 /* parenthesis [] */                               + \
1812
-                            1 /* ZT 0 */                                         + \
1813
-	                   16 /* one never knows ;-) */                            \
1814
-                          )
1815
-
1816
-
1817
-static unsigned long callid_nr;
1818
-static char callid_buf[CALLID_NR_LEN + CALLID_SUFFIX_LEN];
1819
-
1820
-static str callid_prefix;
1821
-static str callid_suffix;
1822
-
1823
-
1824
-/**
1825
- * \brief Initialize the Call-ID generator, generates random prefix
1826
- * \return 0 on success, -1 on error
1827
- */
1828
-int kz_callid_init(void)
1829
-{
1830
-	int rand_bits, i;
1831
-
1832
-	     /* calculate the initial call-id */
1833
-	     /* how many bits and chars do we need to display the 
1834
-	      * whole ULONG number */
1835
-	callid_prefix.len = sizeof(unsigned long) * 2;
1836
-	callid_prefix.s = callid_buf;
1837
-
1838
-	if (callid_prefix.len > CALLID_NR_LEN) {
1839
-		LOG(L_ERR, "ERROR: Too small callid buffer\n");
1840
-		return -1;
1841
-	}
1842
-	
1843
-	for(rand_bits = 1, i = RAND_MAX; i; i >>= 1, rand_bits++);  /* how long are the rand()s ? */
1844
-	i = callid_prefix.len * 4 / rand_bits; /* how many rands() fit in the ULONG ? */
1845
-
1846
-	     /* now fill in the callid with as many random
1847
-	      * numbers as you can + 1 */
1848
-       	callid_nr = rand(); /* this is the + 1 */
1849
-
1850
-	while(i--) {
1851
-		callid_nr <<= rand_bits;
1852
-		callid_nr |= rand();
1853
-	}
1854
-
1855
-	i = snprintf(callid_prefix.s, callid_prefix.len + 1, "%0*lx", callid_prefix.len, callid_nr);
1856
-	if ((i == -1) || (i > callid_prefix.len)) {
1857
-		LOG(L_CRIT, "BUG: SORRY, callid calculation failed\n");
1858
-		return -2;
1859
-	}
1860
-	
1861
-	DBG("Call-ID initialization: '%.*s'\n", callid_prefix.len, callid_prefix.s);
1862
-	return 0;
1863
-}
1864
-
1865
-
1866
-/**
1867
- * \brief Child initialization, generates suffix
1868
- * \param rank not used
1869
- * \return 0 on success, -1 on error
1870
- */
1871
-int kz_callid_child_init(int rank) 
1872
-{
1873
-	struct socket_info *si;
1874
-	
1875
-	/* on tcp/tls bind_address is 0 so try to get the first address we listen
1876
-	 * on no matter the protocol */
1877
-	si=bind_address?bind_address:get_first_socket();
1878
-	if (si==0){
1879
-		LOG(L_CRIT, "BUG: child_init_callid: null socket list\n");
1880
-		return -1;
1881
-	}
1882
-	callid_suffix.s = callid_buf + callid_prefix.len;
1883
-
1884
-	callid_suffix.len = snprintf(callid_suffix.s, CALLID_SUFFIX_LEN,
1885
-				     "%c%d@%.*s", '-', my_pid(), 
1886
-				     si->address_str.len,
1887
-				     si->address_str.s);
1888
-	if ((callid_suffix.len == -1) || (callid_suffix.len > CALLID_SUFFIX_LEN)) {
1889
-		LOG(L_ERR, "ERROR: child_init_callid: buffer too small\n");
1890
-		return -1;
1891
-	}
1892
-
1893
-	DBG("DEBUG: callid: '%.*s'\n", callid_prefix.len + callid_suffix.len, callid_prefix.s);
1894
-	return 0;
1895
-}
1896
-
1897
-
1898
-/**
1899
- * \brief Increment a character in hex, return the carry flag
1900
- * \param _c input character
1901
- * \return carry flag
1902
- */
1903
-static inline int inc_hexchar(char* _c)
1904
-{
1905
-	if (*_c == '9') {
1906
-		*_c = 'a';
1907
-		return 0;
1908
-	}
1909
-
1910
-	if (*_c == 'f') {
1911
-		*_c = '0';
1912
-		return 1;
1913
-	}
1914
-
1915
-	(*_c)++;
1916
-	return 0;
1917
-}
1918
-
1919
-
1920
-void kz_generate_callid(str* callid)
1921
-{
1922
-	int i;
1923
-
1924
-	for(i = callid_prefix.len; i; i--) {
1925
-		if (!inc_hexchar(callid_prefix.s + i - 1)) break;
1926
-	}
1927
-	callid->s = callid_prefix.s;
1928
-	callid->len = callid_prefix.len + callid_suffix.len;
1929
-}