diff --git a/Makefile b/Makefile index f09c54a74..7a582504f 100644 --- a/Makefile +++ b/Makefile @@ -56,3 +56,14 @@ xhdrid: cp /tmp/id $$f; \ done +prefix = /usr/local +install: + mkdir -p $(DESTDIR)$(prefix)/lib + cp -L $$(find . -name '*.a') $(DESTDIR)$(prefix)/lib + mkdir -p $(DESTDIR)$(prefix)/include + cp -RL $$(find . -name include) $(DESTDIR)$(prefix) + cd $(DESTDIR)$(prefix)/lib && for i in $$(find . -name 'libpj*a'); do\ + ln -s $$i $$(echo $$i | sed -e "s/-$(TARGET_NAME)//");\ + done + mkdir -p $(DESTDIR)$(prefix)/lib/pkgconfig + sed -e "s!@PREFIX@!$(DESTDIR)$(prefix)!" libpj.pc.in > $(DESTDIR)/$(prefix)/lib/pkgconfig/libpj.pc diff --git a/libpj.pc.in b/libpj.pc.in new file mode 100644 index 000000000..848e31f97 --- /dev/null +++ b/libpj.pc.in @@ -0,0 +1,12 @@ +# Package Information for pkg-config + +prefix=@PREFIX@ +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include + +Name: libpj +Description: Multimedia communication library +Version: 0.5.10.3 +Libs: -L${libdir} -lpjsua -lpjsip -lpjmedia -lpjsip-ua -lpjsip-simple -lpjsip-ua -lpjmedia-codec -lpjlib-util -lpj +Cflags: -I${includedir} diff --git a/pjlib-util/src/pjlib-util/scanner.c b/pjlib-util/src/pjlib-util/scanner.c index c7a9cf9b3..eeea13204 100644 --- a/pjlib-util/src/pjlib-util/scanner.c +++ b/pjlib-util/src/pjlib-util/scanner.c @@ -342,7 +342,9 @@ PJ_DEF(void) pj_scan_get_quote( pj_scanner *scanner, int begin_quote, int end_quote, pj_str_t *out) { - pj_scan_get_quotes(scanner, (char*)&begin_quote, (char*)&end_quote, 1, out); + char beg = (char)begin_quote; + char end = (char)end_quote; + pj_scan_get_quotes(scanner, &beg, &end, 1, out); } PJ_DEF(void) pj_scan_get_quotes(pj_scanner *scanner, diff --git a/pjlib/include/pj/string.h b/pjlib/include/pj/string.h index 1a75a402d..26e7fa6c5 100644 --- a/pjlib/include/pj/string.h +++ b/pjlib/include/pj/string.h @@ -517,6 +517,23 @@ PJ_DECL(char*) pj_create_random_string(char *str, pj_size_t length); */ PJ_DECL(unsigned long) pj_strtoul(const pj_str_t *str); +/** + * Convert strings to an unsigned long-integer value. + * This function stops reading the string input either when the number + * of characters has exceeded the length of the input or it has read + * the first character it cannot recognize as part of a number, that is + * a character greater than or equal to base. + * + * @param str The input string. + * @param endptr Optional pointer to receive the remainder/unparsed + * portion of the input. + * @param base Number base to use. + * + * @return the unsigned integer number. + */ +PJ_DECL(unsigned long) pj_strtoul2(const pj_str_t *str, pj_str_t *endptr, + unsigned base); + /** * Utility to convert unsigned integer to string. Note that the * string will be NULL terminated. diff --git a/pjlib/src/pj/hash.c b/pjlib/src/pj/hash.c index dc7da6734..5a97e5f18 100644 --- a/pjlib/src/pj/hash.c +++ b/pjlib/src/pj/hash.c @@ -133,6 +133,9 @@ static pj_hash_entry **find_entry( pj_pool_t *pool, pj_hash_table_t *ht, if (hval && *hval != 0) { hash = *hval; + if (keylen==PJ_HASH_KEY_STRING) { + keylen = pj_ansi_strlen((const char*)key); + } } else { /* This slightly differs with pj_hash_calc() because we need * to get the keylen when keylen is PJ_HASH_KEY_STRING. diff --git a/pjlib/src/pj/string.c b/pjlib/src/pj/string.c index 62da6a0fc..9a2ca0f2d 100644 --- a/pjlib/src/pj/string.c +++ b/pjlib/src/pj/string.c @@ -17,6 +17,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include +#include #include #include #include @@ -83,6 +84,42 @@ PJ_DEF(unsigned long) pj_strtoul(const pj_str_t *str) return value; } +PJ_DEF(unsigned long) pj_strtoul2(const pj_str_t *str, pj_str_t *endptr, + unsigned base) +{ + unsigned long value; + unsigned i; + + PJ_CHECK_STACK(); + + value = 0; + if (base <= 10) { + for (i=0; i<(unsigned)str->slen; ++i) { + unsigned c = (str->ptr[i] - '0'); + if (c >= base) + break; + value = value * base + c; + } + } else if (base == 16) { + for (i=0; i<(unsigned)str->slen; ++i) { + if (!pj_isxdigit(str->ptr[i])) + break; + value = value * 16 + pj_hex_digit_to_val(str->ptr[i]); + } + } else { + pj_assert(!"Unsupported base"); + i = 0; + value = 0xFFFFFFFFUL; + } + + if (endptr) { + endptr->ptr = str->ptr + i; + endptr->slen = str->slen - i; + } + + return value; +} + PJ_DEF(int) pj_utoa(unsigned long val, char *buf) { return pj_utoa_pad(val, buf, 0, 0); diff --git a/pjlib/src/pjlib-test/string.c b/pjlib/src/pjlib-test/string.c index c8bee0bc6..dd3649cc4 100644 --- a/pjlib/src/pjlib-test/string.c +++ b/pjlib/src/pjlib-test/string.c @@ -48,6 +48,7 @@ * - pj_strtrim() * - pj_utoa() * - pj_strtoul() + * - pj_strtoul2() * - pj_create_random_string() * - ... and mode.. * @@ -358,6 +359,32 @@ int string_test(void) if (pj_strtoul(&s5) != UL_VALUE) return -280; + /* + * pj_strtoul2() + */ + s5 = pj_str("123456"); + + pj_strtoul2(&s5, NULL, 10); /* Crash test */ + + if (pj_strtoul2(&s5, &s4, 10) != 123456UL) + return -290; + if (s4.slen != 0) + return -291; + if (pj_strtoul2(&s5, &s4, 16) != 0x123456UL) + return -292; + + s5 = pj_str("0123ABCD"); + if (pj_strtoul2(&s5, &s4, 10) != 123) + return -293; + if (s4.slen != 4) + return -294; + if (s4.ptr == NULL || *s4.ptr != 'A') + return -295; + if (pj_strtoul2(&s5, &s4, 16) != 0x123ABCDUL) + return -296; + if (s4.slen != 0) + return -297; + /* * pj_create_random_string() * Check that no duplicate strings are returned. diff --git a/pjmedia/include/pjmedia/alaw_ulaw.h b/pjmedia/include/pjmedia/alaw_ulaw.h index 5cafa8426..14f10495b 100644 --- a/pjmedia/include/pjmedia/alaw_ulaw.h +++ b/pjmedia/include/pjmedia/alaw_ulaw.h @@ -21,6 +21,8 @@ #include +PJ_BEGIN_DECL + #if defined(PJMEDIA_HAS_ALAW_ULAW_TABLE) && PJMEDIA_HAS_ALAW_ULAW_TABLE!=0 extern const pj_uint8_t pjmedia_linear2ulaw_tab[16384]; @@ -134,9 +136,9 @@ PJ_DECL(unsigned char) pjmedia_alaw2ulaw(unsigned char aval); */ PJ_DECL(unsigned char) pjmedia_ulaw2alaw(unsigned char uval); - #endif +PJ_END_DECL #endif /* __PJMEDIA_ALAW_ULAW_H__ */ diff --git a/pjmedia/src/pjmedia/alaw_ulaw.c b/pjmedia/src/pjmedia/alaw_ulaw.c index 1841192a2..5fd97479b 100644 --- a/pjmedia/src/pjmedia/alaw_ulaw.c +++ b/pjmedia/src/pjmedia/alaw_ulaw.c @@ -154,7 +154,7 @@ pjmedia_linear2alaw( */ PJ_DEF(int) pjmedia_alaw2linear( - unsigned char a_val) + unsigned a_val) { int t; int seg; diff --git a/pjmedia/src/pjmedia/sdp.c b/pjmedia/src/pjmedia/sdp.c index 0ef241b96..d9cc8289d 100644 --- a/pjmedia/src/pjmedia/sdp.c +++ b/pjmedia/src/pjmedia/sdp.c @@ -138,14 +138,17 @@ pjmedia_sdp_attr_find (unsigned count, const pj_str_t *c_fmt) { unsigned i; + unsigned c_pt = 0xFFFF; + + if (c_fmt) + c_pt = pj_strtoul(c_fmt); for (i=0; iname, name) == 0) { const pjmedia_sdp_attr *a = attr_array[i]; if (c_fmt) { - if (a->value.slen > c_fmt->slen && - pj_strncmp(&a->value, c_fmt, c_fmt->slen)==0) - { + unsigned pt = (unsigned) pj_strtoul2(&a->value, NULL, 10); + if (pt == c_pt) { return (pjmedia_sdp_attr*)a; } } else diff --git a/pjnath/build/Makefile b/pjnath/build/Makefile index 390bfd068..2f265f17d 100644 --- a/pjnath/build/Makefile +++ b/pjnath/build/Makefile @@ -10,7 +10,6 @@ RULES_MAK := $(PJDIR)/build/rules.mak PJLIB_LIB:=../../pjlib/lib/libpj-$(TARGET_NAME)$(LIBEXT) PJLIB_UTIL_LIB:=../../pjlib-util/lib/libpjlib-util-$(TARGET_NAME)$(LIBEXT) PJNATH_LIB:=../../pjnath/lib/libpjnath-$(TARGET_NAME)$(LIBEXT) -export PJNATH_LIB:=../lib/libpjnath-$(TARGET_NAME)$(LIBEXT) ############################################################################### # Gather all flags. @@ -27,7 +26,7 @@ export _LDFLAGS := $(subst /,$(HOST_PSEP),$(PJNATH_LIB)) \ $(LDFLAGS) ############################################################################### -# Defines for building PJLIB-UTIL library +# Defines for building PJNATH library # export PJNATH_SRCDIR = ../src/pjnath export PJNATH_OBJS += $(OS_OBJS) $(M_OBJS) $(CC_OBJS) $(HOST_OBJS) \ @@ -45,13 +44,34 @@ export PJNATH_TEST_LDFLAGS += $(_LDFLAGS) export PJNATH_TEST_EXE:=../bin/pjnath-test-$(TARGET_NAME)$(HOST_EXE) +############################################################################### +# Defines for building test client application +# +export PJSTUN_CLIENT_SRCDIR = ../src/pjstun-client +export PJSTUN_CLIENT_OBJS += client_main.o +export PJSTUN_CLIENT_CFLAGS += $(_CFLAGS) +export PJSTUN_CLIENT_LDFLAGS += $(_LDFLAGS) +export PJSTUN_CLIENT_EXE:=../bin/pjstun-client-$(TARGET_NAME)$(HOST_EXE) + +############################################################################### +# Defines for building test server application +# +export PJSTUN_SRV_TEST_SRCDIR = ../src/pjstun-srv-test +export PJSTUN_SRV_TEST_OBJS += bind_usage.o server.o turn_usage.o usage.o \ + main.o +export PJSTUN_SRV_TEST_CFLAGS += $(_CFLAGS) +export PJSTUN_SRV_TEST_LDFLAGS += $(_LDFLAGS) +export PJSTUN_SRV_TEST_EXE:=../bin/pjstun-srv-test-$(TARGET_NAME)$(HOST_EXE) + + + export CC_OUT CC AR RANLIB HOST_MV HOST_RM HOST_RMDIR HOST_MKDIR OBJEXT LD LDOUT ############################################################################### # Main entry # # $(TARGET) is defined in os-$(OS_NAME).mak file in current directory. # -TARGETS := pjnath pjnath-test +TARGETS := pjnath pjnath-test pjstun-client pjstun-srv-test all: $(TARGETS) @@ -69,6 +89,12 @@ pjnath: pjnath-test: $(PJLIB_LIB) $(PJLIB_UTIL_LIB) $(PJNATH_LIB) $(MAKE) -f $(RULES_MAK) APP=PJNATH_TEST app=pjnath-test $(PJNATH_TEST_EXE) +pjstun-client: $(PJLIB_LIB) $(PJLIB_UTIL_LIB) $(PJNATH_LIB) + $(MAKE) -f $(RULES_MAK) APP=PJSTUN_CLIENT app=pjstun-client $(PJSTUN_CLIENT_EXE) + +pjstun-srv-test: $(PJLIB_LIB) $(PJLIB_UTIL_LIB) $(PJNATH_LIB) + $(MAKE) -f $(RULES_MAK) APP=PJSTUN_SRV_TEST app=pjstun-srv-test $(PJSTUN_SRV_TEST_EXE) + .PHONY: ../lib/pjnath.ko ../lib/pjnath.ko: echo Making $@ diff --git a/pjnath/src/pjnath/ice_session.c b/pjnath/src/pjnath/ice_session.c index 6cdea360a..d68117689 100644 --- a/pjnath/src/pjnath/ice_session.c +++ b/pjnath/src/pjnath/ice_session.c @@ -549,7 +549,7 @@ PJ_DEF(pj_status_t) pj_ice_sess_add_cand(pj_ice_sess *ice, pj_status_t status = PJ_SUCCESS; char tmp[128]; - PJ_ASSERT_RETURN(ice && comp_id && local_pref && + PJ_ASSERT_RETURN(ice && comp_id && foundation && addr && base_addr && addr_len, PJ_EINVAL); PJ_ASSERT_RETURN(comp_id <= ice->comp_cnt, PJ_EINVAL); diff --git a/pjnath/src/pjnath/ice_strans.c b/pjnath/src/pjnath/ice_strans.c index d3ba78f48..a7e5f8f3d 100644 --- a/pjnath/src/pjnath/ice_strans.c +++ b/pjnath/src/pjnath/ice_strans.c @@ -212,10 +212,24 @@ static pj_status_t add_cand( pj_ice_strans *ice_st, pj_bool_t set_default) { pj_ice_strans_cand *cand; + unsigned i; PJ_ASSERT_RETURN(ice_st && comp && addr, PJ_EINVAL); PJ_ASSERT_RETURN(comp->cand_cnt < PJ_ICE_ST_MAX_CAND, PJ_ETOOMANY); + /* Check that we don't have candidate with the same + * address. + */ + for (i=0; icand_cnt; ++i) { + if (pj_memcmp(addr, &comp->cand_list[i].addr, + sizeof(pj_sockaddr_in))==0) + { + /* Duplicate */ + PJ_LOG(5,(ice_st->obj_name, "Duplicate candidate not added")); + return PJ_SUCCESS; + } + } + cand = &comp->cand_list[comp->cand_cnt]; pj_bzero(cand, sizeof(*cand)); @@ -225,7 +239,7 @@ static pj_status_t add_cand( pj_ice_strans *ice_st, cand->ice_cand_id = -1; cand->local_pref = local_pref; pj_ice_calc_foundation(ice_st->pool, &cand->foundation, type, - (const pj_sockaddr*)addr); + &comp->local_addr); if (set_default) comp->default_cand = comp->cand_cnt; diff --git a/pjnath/src/pjstun-client/client_main.c b/pjnath/src/pjstun-client/client_main.c index 11094e2b4..cb62788ef 100644 --- a/pjnath/src/pjstun-client/client_main.c +++ b/pjnath/src/pjstun-client/client_main.c @@ -66,7 +66,7 @@ static struct options static pj_status_t parse_addr(const char *input, pj_sockaddr_in *addr); -static my_perror(const char *title, pj_status_t status) +static void my_perror(const char *title, pj_status_t status) { char errmsg[PJ_ERR_MSG_SIZE]; pj_strerror(status, errmsg, sizeof(errmsg)); @@ -145,7 +145,7 @@ static int worker_thread(void *unused) n = pj_sock_select(g.sock+1, &readset, NULL, NULL, &timeout); if (n > 0) { if (PJ_FD_ISSET(g.sock, &readset)) { - char buffer[512]; + pj_uint8_t buffer[512]; pj_ssize_t len; pj_sockaddr_in addr; int addrlen; @@ -426,7 +426,7 @@ static void send_send_ind(void) PJ_STUN_ATTR_REMOTE_ADDR, PJ_FALSE, &g.peer_addr, sizeof(g.peer_addr)); pj_stun_msg_add_binary_attr(tdata->pool, tdata->msg, - PJ_STUN_ATTR_DATA, g.data, len); + PJ_STUN_ATTR_DATA, (pj_uint8_t*)g.data, len); rc = pj_stun_session_send_msg(g.sess, PJ_FALSE, &g.srv_addr, sizeof(g.srv_addr), @@ -520,7 +520,7 @@ static void set_peer_addr(void) printf("Input peer address in IP:PORT format: "); fflush(stdout); - gets(addr); + fgets(addr, sizeof(addr), stdin); if (parse_addr(addr, &g.peer_addr) != PJ_SUCCESS) { return; @@ -561,7 +561,7 @@ static void console_main(void) } else if (input[0]=='d' && input[1]=='t') { printf("Input data: "); - gets(g.data); + fgets(g.data, sizeof(g.data_buf), stdin); } else if (input[0]=='p' && input[1]=='r') { set_peer_addr(); diff --git a/pjsip-apps/src/pjsua/pjsua_app.c b/pjsip-apps/src/pjsua/pjsua_app.c index 5e56f6219..6d3739c21 100644 --- a/pjsip-apps/src/pjsua/pjsua_app.c +++ b/pjsip-apps/src/pjsua/pjsua_app.c @@ -320,7 +320,7 @@ static pj_status_t parse_args(int argc, char *argv[], { int c; int option_index; - enum { OPT_CONFIG_FILE, OPT_LOG_FILE, OPT_LOG_LEVEL, OPT_APP_LOG_LEVEL, + enum { OPT_CONFIG_FILE=127, OPT_LOG_FILE, OPT_LOG_LEVEL, OPT_APP_LOG_LEVEL, OPT_HELP, OPT_VERSION, OPT_NULL_AUDIO, OPT_LOCAL_PORT, OPT_IP_ADDR, OPT_PROXY, OPT_OUTBOUND_PROXY, OPT_REGISTRAR, OPT_REG_TIMEOUT, OPT_PUBLISH, OPT_ID, OPT_CONTACT, @@ -879,7 +879,7 @@ static pj_status_t parse_args(int argc, char *argv[], default: PJ_LOG(1,(THIS_FILE, "Argument \"%s\" is not valid. Use --help to see help", - argv[pj_optind])); + argv[pj_optind-1])); return -1; } } diff --git a/pjsip/include/pjsip/sip_transaction.h b/pjsip/include/pjsip/sip_transaction.h index d3a4c3e8d..1787f7870 100644 --- a/pjsip/include/pjsip/sip_transaction.h +++ b/pjsip/include/pjsip/sip_transaction.h @@ -73,21 +73,6 @@ typedef enum pjsip_tsx_state_e } pjsip_tsx_state_e; -/** - * Transaction timeout timer policy, to control the UAC transaction timeout - * scheduling (see #pjsip_tsx_set_uac_timeout()). - */ -typedef enum pjsip_tsx_timeout_policy -{ - PJSIP_TSX_IGNORE_100 = 1, /**< To make the UAC transaction NOT to cancel - the timeout timer when 100 response is - received.*/ - PJSIP_TSX_IGNORE_1xx = 3 /**< To make the UAC transaction NOT to cancel - the timeout timer when any 1xx responses - are received. */ -} pjsip_tsx_timeout_policy; - - /** * This structure describes SIP transaction object. The transaction object * is used to handle both UAS and UAC transaction. @@ -145,9 +130,6 @@ struct pjsip_transaction pj_timer_entry retransmit_timer;/**< Retransmit timer. */ pj_timer_entry timeout_timer; /**< Timeout timer. */ - unsigned msec_timeout; /**< User set timeout. */ - pjsip_tsx_timeout_policy timeout_policy; /**< Timeout policy. */ - /** Module specific data. */ void *mod_data[PJSIP_MAX_MODULE]; }; @@ -248,47 +230,6 @@ PJ_DECL(pj_status_t) pjsip_tsx_create_uas( pjsip_module *tsx_user, PJ_DECL(pj_status_t) pjsip_tsx_set_transport(pjsip_transaction *tsx, const pjsip_tpselector *sel); - -/** - * Set the UAC absolute transaction timeout. Normally UAC transaction will - * stop its timeout timer (timer B for INVITE and timer F for non-INVITE - * transactions) after a provisional response is received. - * - * When this timer is set, the transaction's timer B and F will use this - * value, and if the \a flag flag is set, the transaction will continue - * the scheduling of the timeout timer even when provisional response has - * been received. - * - * Note that this function MUST be called AFTER the transaction has been - * created AND BEFORE any request is transmitted. - * - * @param tsx The client/UAC transaction. - * @param msec_time The timeout value, in miliseconds. Currently this - * value must be non-zero (value zero is reserved for - * future use). - * @param flag Option flags to control whether the transaction should - * cancel the timeout timer on arrival of provisional - * responses (which is yes according to RFC 3261). - * The valid values are: - * - PJSIP_TSX_IGNORE_100, to make the UAC transaction - * NOT to cancel the timeout timer when 100 response - * is received. - * - PJSIP_TSX_IGNORE_1xx, to make the UAC transaction - * NOT to cancel the timeout timer when any 1xx - * responses are received. - * - * Note that regardless of the values in the \a flag - * argument, the provisional response would still be - * delivered to transaction user and it will still - * affect the transaction state. The \a flag flag only - * changes the behavior of the timeout timer of the - * transaction. - */ -PJ_DECL(pj_status_t) pjsip_tsx_set_uac_timeout(pjsip_transaction *tsx, - unsigned msec_time, - pjsip_tsx_timeout_policy flag); - - /** * Call this function to manually feed a message to the transaction. * For UAS transaction, application MUST call this function after diff --git a/pjsip/include/pjsua-lib/pjsua.h b/pjsip/include/pjsua-lib/pjsua.h index 10c192905..9f2450b0a 100644 --- a/pjsip/include/pjsua-lib/pjsua.h +++ b/pjsip/include/pjsua-lib/pjsua.h @@ -913,7 +913,8 @@ typedef struct pjsua_config pj_str_t stun_domain; /** - * Specify STUN server to be used. + * Specify STUN server to be used, in "HOST[:PORT]" format. If port is + * not specified, default port 3478 will be used. */ pj_str_t stun_host; diff --git a/pjsip/src/pjsip/sip_transaction.c b/pjsip/src/pjsip/sip_transaction.c index 911cd6c3f..9934e0ddc 100644 --- a/pjsip/src/pjsip/sip_transaction.c +++ b/pjsip/src/pjsip/sip_transaction.c @@ -132,6 +132,8 @@ typedef struct tsx_lock_data { /* Timer timeout value constants */ static const pj_time_val t1_timer_val = { PJSIP_T1_TIMEOUT/1000, PJSIP_T1_TIMEOUT%1000 }; +static const pj_time_val t2_timer_val = { PJSIP_T2_TIMEOUT/1000, + PJSIP_T2_TIMEOUT%1000 }; static const pj_time_val t4_timer_val = { PJSIP_T4_TIMEOUT/1000, PJSIP_T4_TIMEOUT%1000 }; static const pj_time_val td_timer_val = { PJSIP_TD_TIMEOUT/1000, @@ -1395,23 +1397,6 @@ PJ_DEF(pj_status_t) pjsip_tsx_set_transport(pjsip_transaction *tsx, } -/* - * Set the UAC absolute transaction timeout. - */ -PJ_DEF(pj_status_t) pjsip_tsx_set_uac_timeout(pjsip_transaction *tsx, - unsigned msec_time, - pjsip_tsx_timeout_policy policy) -{ - PJ_ASSERT_RETURN(tsx && tsx->role==PJSIP_ROLE_UAC && - tsx->state==PJSIP_TSX_STATE_NULL, PJ_EINVALIDOP); - - tsx->msec_timeout = msec_time; - tsx->timeout_policy = policy; - - return PJ_SUCCESS; -} - - /* * Set transaction status code and reason. */ @@ -1809,9 +1794,13 @@ static void tsx_resched_retransmission( pjsip_transaction *tsx ) pj_assert((tsx->transport_flag & TSX_HAS_PENDING_TRANSPORT) == 0); - msec_time = (1 << (tsx->retransmit_count)) * PJSIP_T1_TIMEOUT; + if (tsx->role==PJSIP_ROLE_UAC && tsx->status_code >= 100) + msec_time = PJSIP_T2_TIMEOUT; + else + msec_time = (1 << (tsx->retransmit_count)) * PJSIP_T1_TIMEOUT; if (tsx->role == PJSIP_ROLE_UAC) { + pj_assert(tsx->status_code < 200); /* Retransmission for non-INVITE transaction caps-off at T2 */ if (msec_time>PJSIP_T2_TIMEOUT && tsx->method.id!=PJSIP_INVITE_METHOD) msec_time = PJSIP_T2_TIMEOUT; @@ -1913,22 +1902,10 @@ static pj_status_t tsx_on_state_null( pjsip_transaction *tsx, } /* Start Timer B (or called timer F for non-INVITE) for transaction - * timeout. If user has configured the timeout value with - * pjsip_tsx_set_uac_timeout(), use the timeout value there. + * timeout. */ - if (tsx->msec_timeout > 0) { - pj_time_val timeout; - - timeout.sec = tsx->msec_timeout / 1000; - timeout.msec = tsx->msec_timeout % 1000; - - pjsip_endpt_schedule_timer( tsx->endpt, &tsx->timeout_timer, - &timeout); - - } else { - pjsip_endpt_schedule_timer( tsx->endpt, &tsx->timeout_timer, - &timeout_timer_val); - } + pjsip_endpt_schedule_timer( tsx->endpt, &tsx->timeout_timer, + &timeout_timer_val); /* Start Timer A (or timer E) for retransmission only if unreliable * transport is being used. @@ -2005,27 +1982,54 @@ static pj_status_t tsx_on_state_calling( pjsip_transaction *tsx, if (msg->type != PJSIP_RESPONSE_MSG) return PJSIP_ENOTRESPONSEMSG; - /* Cancel retransmission timer A. */ - if (tsx->retransmit_timer._timer_id != -1) { - pjsip_endpt_cancel_timer(tsx->endpt, &tsx->retransmit_timer); - tsx->retransmit_timer._timer_id = -1; + code = msg->line.status.code; + + /* If the response is final, cancel both retransmission and timeout + * timer. + */ + if (code >= 200) { + if (tsx->retransmit_timer._timer_id != -1) { + pjsip_endpt_cancel_timer(tsx->endpt, &tsx->retransmit_timer); + tsx->retransmit_timer._timer_id = -1; + } + + if (tsx->timeout_timer._timer_id != -1) { + pjsip_endpt_cancel_timer(tsx->endpt, &tsx->timeout_timer); + tsx->timeout_timer._timer_id = -1; + } + + } else { + /* Cancel retransmit timer (for non-INVITE transaction, the + * retransmit timer will be rescheduled at T2. + */ + if (tsx->retransmit_timer._timer_id != -1) { + pjsip_endpt_cancel_timer(tsx->endpt, &tsx->retransmit_timer); + tsx->retransmit_timer._timer_id = -1; + } + + /* For provisional response, only cancel retransmit when this + * is an INVITE transaction. For non-INVITE, section 17.1.2.1 + * of RFC 3261 says that: + * - retransmit timer is set to T2 + * - timeout timer F is not deleted. + */ + if (tsx->method.id == PJSIP_INVITE_METHOD) { + + /* Cancel timeout timer */ + pjsip_endpt_cancel_timer(tsx->endpt, &tsx->timeout_timer); + + } else { + if (!tsx->is_reliable) { + pjsip_endpt_schedule_timer(tsx->endpt, + &tsx->retransmit_timer, + &t2_timer_val); + } + } } + tsx->transport_flag &= ~(TSX_HAS_PENDING_RESCHED); - /* Cancel timer B (transaction timeout) but look at the timeout policy - * as set by pjsip_tsx_set_uac_timeout(). - */ - code = msg->line.status.code; - if ((code==100 && tsx->timeout_policy==PJSIP_TSX_IGNORE_100) || - (code<200 && tsx->timeout_policy==PJSIP_TSX_IGNORE_1xx)) - { - /* Don't cancel the timeout timer */ - } - else { - pjsip_endpt_cancel_timer(tsx->endpt, &tsx->timeout_timer); - } - /* Discard retransmission message if it is not INVITE. * The INVITE tdata is needed in case we have to generate ACK for * the final response. @@ -2367,7 +2371,17 @@ static pj_status_t tsx_on_state_proceeding_uac(pjsip_transaction *tsx, &msg->line.status.reason); } else { - tsx_set_status_code(tsx, PJSIP_SC_TSX_TIMEOUT, NULL); + if (event->body.timer.entry == &tsx->retransmit_timer) { + /* Retransmit message. */ + pj_status_t status; + + status = tsx_retransmit( tsx, 1 ); + + return status; + + } else { + tsx_set_status_code(tsx, PJSIP_SC_TSX_TIMEOUT, NULL); + } } if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code, 100)) { @@ -2406,6 +2420,12 @@ static pj_status_t tsx_on_state_proceeding_uac(pjsip_transaction *tsx, pjsip_endpt_schedule_timer( tsx->endpt, &tsx->timeout_timer, &timeout); + /* Cancel retransmission timer */ + if (tsx->retransmit_timer._timer_id != -1) { + pjsip_endpt_cancel_timer(tsx->endpt, &tsx->retransmit_timer); + tsx->retransmit_timer._timer_id = -1; + } + /* Move state to Completed, inform TU. */ tsx_set_state( tsx, PJSIP_TSX_STATE_COMPLETED, PJSIP_EVENT_RX_MSG, event->body.rx_msg.rdata ); diff --git a/pjsip/src/pjsip/sip_util_statefull.c b/pjsip/src/pjsip/sip_util_statefull.c index 8ea63fda3..27ce550ab 100644 --- a/pjsip/src/pjsip/sip_util_statefull.c +++ b/pjsip/src/pjsip/sip_util_statefull.c @@ -94,6 +94,7 @@ PJ_DEF(pj_status_t) pjsip_endpt_send_request( pjsip_endpoint *endpt, /* Check that transaction layer module is registered to endpoint */ PJ_ASSERT_RETURN(mod_stateful_util.id != -1, PJ_EINVALIDOP); + PJ_UNUSED_ARG(timeout); status = pjsip_tsx_create_uac(&mod_stateful_util, tdata, &tsx); if (status != PJ_SUCCESS) { @@ -105,11 +106,6 @@ PJ_DEF(pj_status_t) pjsip_endpt_send_request( pjsip_endpoint *endpt, tsx_data->token = token; tsx_data->cb = cb; - if (timeout >= 0) { - status = pjsip_tsx_set_uac_timeout(tsx, timeout, PJSIP_TSX_IGNORE_1xx); - pj_assert(status == PJ_SUCCESS); - } - tsx->mod_data[mod_stateful_util.id] = tsx_data; status = pjsip_tsx_send_msg(tsx, NULL); diff --git a/pjsip/src/pjsua-lib/pjsua_core.c b/pjsip/src/pjsua-lib/pjsua_core.c index dd0b26227..96ca174a4 100644 --- a/pjsip/src/pjsua-lib/pjsua_core.c +++ b/pjsip/src/pjsua-lib/pjsua_core.c @@ -678,14 +678,34 @@ static void stun_dns_srv_resolver_cb(void *user_data, * it with gethostbyname() */ if (pjsua_var.ua_cfg.stun_host.slen) { + pj_str_t str_host, str_port; + int port; pj_hostent he; - pjsua_var.stun_status = pj_gethostbyname(&pjsua_var.ua_cfg.stun_host, &he); + str_port.ptr = pj_strchr(&pjsua_var.ua_cfg.stun_host, ':'); + if (str_port.ptr != NULL) { + str_host.ptr = pjsua_var.ua_cfg.stun_host.ptr; + str_host.slen = (str_port.ptr - str_host.ptr); + str_port.ptr++; + str_port.slen = pjsua_var.ua_cfg.stun_host.slen - + str_host.slen - 1; + port = (int)pj_strtoul(&str_port); + if (port < 1 || port > 65535) { + pjsua_perror(THIS_FILE, "Invalid STUN server", PJ_EINVAL); + pjsua_var.stun_status = PJ_EINVAL; + return; + } + } else { + str_host = pjsua_var.ua_cfg.stun_host; + port = 3478; + } + + pjsua_var.stun_status = pj_gethostbyname(&str_host, &he); if (pjsua_var.stun_status == PJ_SUCCESS) { pj_sockaddr_in_init(&pjsua_var.stun_srv.ipv4, NULL, 0); pjsua_var.stun_srv.ipv4.sin_addr = *(pj_in_addr*)he.h_addr; - pjsua_var.stun_srv.ipv4.sin_port = pj_htons((pj_uint16_t)3478); + pjsua_var.stun_srv.ipv4.sin_port = pj_htons((pj_uint16_t)port); PJ_LOG(3,(THIS_FILE, "STUN server %.*s resolved, address is %s:%d", @@ -772,14 +792,35 @@ pj_status_t pjsua_resolve_stun_server(pj_bool_t wait) * gethostbyname(). */ else if (pjsua_var.ua_cfg.stun_host.slen) { + pj_str_t str_host, str_port; + int port; pj_hostent he; - pjsua_var.stun_status = pj_gethostbyname(&pjsua_var.ua_cfg.stun_host, &he); + str_port.ptr = pj_strchr(&pjsua_var.ua_cfg.stun_host, ':'); + if (str_port.ptr != NULL) { + str_host.ptr = pjsua_var.ua_cfg.stun_host.ptr; + str_host.slen = (str_port.ptr - str_host.ptr); + str_port.ptr++; + str_port.slen = pjsua_var.ua_cfg.stun_host.slen - + str_host.slen - 1; + port = (int)pj_strtoul(&str_port); + if (port < 1 || port > 65535) { + pjsua_perror(THIS_FILE, "Invalid STUN server", PJ_EINVAL); + pjsua_var.stun_status = PJ_EINVAL; + return pjsua_var.stun_status; + } + } else { + str_host = pjsua_var.ua_cfg.stun_host; + port = 3478; + } + + + pjsua_var.stun_status = pj_gethostbyname(&str_host, &he); if (pjsua_var.stun_status == PJ_SUCCESS) { pj_sockaddr_in_init(&pjsua_var.stun_srv.ipv4, NULL, 0); pjsua_var.stun_srv.ipv4.sin_addr = *(pj_in_addr*)he.h_addr; - pjsua_var.stun_srv.ipv4.sin_port = pj_htons((pj_uint16_t)3478); + pjsua_var.stun_srv.ipv4.sin_port = pj_htons((pj_uint16_t)port); PJ_LOG(3,(THIS_FILE, "STUN server %.*s resolved, address is %s:%d", @@ -1055,8 +1096,8 @@ static pj_status_t create_sip_udp_sock(pj_in_addr bound_addr, * STUN is specified, resolve the address with STUN. */ status = pjstun_get_mapped_addr(&pjsua_var.cp.factory, 1, &sock, - &stun_srv, 3478, - &stun_srv, 3478, + &stun_srv, pj_ntohs(pjsua_var.stun_srv.ipv4.sin_port), + &stun_srv, pj_ntohs(pjsua_var.stun_srv.ipv4.sin_port), p_pub_addr); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "Error contacting STUN server", status); diff --git a/pjsip/src/pjsua-lib/pjsua_media.c b/pjsip/src/pjsua-lib/pjsua_media.c index 66efe68c1..09c65cbf6 100644 --- a/pjsip/src/pjsua-lib/pjsua_media.c +++ b/pjsip/src/pjsua-lib/pjsua_media.c @@ -289,8 +289,8 @@ static pj_status_t create_rtp_rtcp_sock(const pjsua_transport_config *cfg, stun_srv = pj_str(ip_addr); status=pjstun_get_mapped_addr(&pjsua_var.cp.factory, 2, sock, - &stun_srv, 3478, - &stun_srv, 3478, + &stun_srv, pj_ntohs(pjsua_var.stun_srv.ipv4.sin_port), + &stun_srv, pj_ntohs(pjsua_var.stun_srv.ipv4.sin_port), mapped_addr); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "STUN resolve error", status);