From 01b60a5f21381167b24400afea23a2126d3e01ef Mon Sep 17 00:00:00 2001 From: Benny Prijono Date: Fri, 9 Oct 2009 12:11:07 +0000 Subject: Fixed ticket #917, #936, and #967: - #917: CANCEL may be sent to different servers than the INVITE when DNS SRV is used (thanks Alexei Kuznetsov for the report) - #936: CANCEL must be sent with TCP if the INVITE was sent with TCP because of 1300 bytes message size/MTU limit (thanks Johan Lantz for the report) - #967: Wrong Route header generation in CANCEL request with strict route Save the server address(es) found by resolution process to tx_data, which is copied to CANCEL request. CANCEL request then uses this address rather than starting a fresh server resolution. git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@2932 74dad513-b988-da41-8d7b-12977e46ad98 --- pjsip/include/pjsip/sip_transport.h | 21 +++++++++ pjsip/include/pjsip/sip_util.h | 8 ---- pjsip/src/pjsip/sip_transaction.c | 5 ++- pjsip/src/pjsip/sip_util.c | 87 +++++++++++++++++++++++++------------ 4 files changed, 83 insertions(+), 38 deletions(-) (limited to 'pjsip') diff --git a/pjsip/include/pjsip/sip_transport.h b/pjsip/include/pjsip/sip_transport.h index 275196bf..0e461638 100644 --- a/pjsip/include/pjsip/sip_transport.h +++ b/pjsip/include/pjsip/sip_transport.h @@ -27,6 +27,7 @@ #include #include +#include #include #include #include @@ -522,6 +523,26 @@ struct pjsip_tx_data /** Callback to be called when this tx_data has been transmitted. */ void (*cb)(void*, pjsip_tx_data*, pj_ssize_t); + /** Destination information, to be used to determine the network address + * of the message. For a request, this information is initialized when + * the request is sent with #pjsip_endpt_send_request_stateless() and + * network address is resolved. For CANCEL request, this information + * will be copied from the original INVITE to make sure that the CANCEL + * request goes to the same physical network address as the INVITE + * request. + */ + struct + { + /** Server addresses resolved. + */ + pjsip_server_addresses addr; + + /** Current server address being tried. + */ + unsigned cur_addr; + + } dest_info; + /** Transport information, only valid during on_tx_request() and * on_tx_response() callback. */ diff --git a/pjsip/include/pjsip/sip_util.h b/pjsip/include/pjsip/sip_util.h index 57a4821c..02baf65f 100644 --- a/pjsip/include/pjsip/sip_util.h +++ b/pjsip/include/pjsip/sip_util.h @@ -451,14 +451,6 @@ typedef struct pjsip_send_state */ pjsip_tx_data *tdata; - /** Server addresses resolved. - */ - pjsip_server_addresses addr; - - /** Current server address being tried. - */ - unsigned cur_addr; - /** Current transport being used. */ pjsip_transport *cur_transport; diff --git a/pjsip/src/pjsip/sip_transaction.c b/pjsip/src/pjsip/sip_transaction.c index e7e2347b..455699bd 100644 --- a/pjsip/src/pjsip/sip_transaction.c +++ b/pjsip/src/pjsip/sip_transaction.c @@ -1626,6 +1626,7 @@ static void send_msg_callback( pjsip_send_state *send_state, pj_ssize_t sent, pj_bool_t *cont ) { pjsip_transaction *tsx = (pjsip_transaction*) send_state->token; + pjsip_tx_data *tdata = send_state->tdata; struct tsx_lock_data lck; lock_tsx(tsx, &lck); @@ -1644,9 +1645,9 @@ static void send_msg_callback( pjsip_send_state *send_state, pjsip_transport_add_ref(tsx->transport); /* Update remote address. */ - tsx->addr_len = send_state->addr.entry[send_state->cur_addr].addr_len; + tsx->addr_len = tdata->dest_info.addr.entry[tdata->dest_info.cur_addr].addr_len; pj_memcpy(&tsx->addr, - &send_state->addr.entry[send_state->cur_addr].addr, + &tdata->dest_info.addr.entry[tdata->dest_info.cur_addr].addr, tsx->addr_len); /* Update is_reliable flag. */ diff --git a/pjsip/src/pjsip/sip_util.c b/pjsip/src/pjsip/sip_util.c index cc5d71d0..cf3bc929 100644 --- a/pjsip/src/pjsip/sip_util.c +++ b/pjsip/src/pjsip/sip_util.c @@ -754,6 +754,18 @@ PJ_DEF(pj_status_t) pjsip_endpt_create_cancel( pjsip_endpoint *endpt, break; } + /* Must also copy the saved strict route header, otherwise CANCEL will be + * sent with swapped Route and request URI! + */ + if (req_tdata->saved_strict_route) { + cancel_tdata->saved_strict_route = (pjsip_route_hdr*) + pjsip_hdr_clone(cancel_tdata->pool, req_tdata->saved_strict_route); + } + + /* Finally copy the destination info from the original request */ + pj_memcpy(&cancel_tdata->dest_info, &req_tdata->dest_info, + sizeof(req_tdata->dest_info)); + /* Done. * Return the transmit buffer containing the CANCEL request. */ @@ -1057,7 +1069,7 @@ static void stateless_send_transport_cb( void *token, * (2) Failure (i.e. sent <= 0) */ cont = (sent > 0) ? PJ_FALSE : - (stateless_data->cur_addraddr.count-1); + (tdata->dest_info.cur_addrdest_info.addr.count-1); if (stateless_data->app_cb) { (*stateless_data->app_cb)(stateless_data, sent, &cont); } else { @@ -1084,11 +1096,11 @@ static void stateless_send_transport_cb( void *token, * first invocation. */ if (sent != -PJ_EPENDING) { - stateless_data->cur_addr++; + tdata->dest_info.cur_addr++; } /* Have next address? */ - if (stateless_data->cur_addr >= stateless_data->addr.count) { + if (tdata->dest_info.cur_addr >= tdata->dest_info.addr.count) { /* This only happens when a rather buggy application has * sent 'cont' to PJ_TRUE when the initial value was PJ_FALSE. * In this case just stop the processing; we don't need to @@ -1100,9 +1112,9 @@ static void stateless_send_transport_cb( void *token, } /* Keep current server address information handy. */ - cur_addr = &stateless_data->addr.entry[stateless_data->cur_addr].addr; - cur_addr_type = stateless_data->addr.entry[stateless_data->cur_addr].type; - cur_addr_len = stateless_data->addr.entry[stateless_data->cur_addr].addr_len; + cur_addr = &tdata->dest_info.addr.entry[tdata->dest_info.cur_addr].addr; + cur_addr_type = tdata->dest_info.addr.entry[tdata->dest_info.cur_addr].type; + cur_addr_len = tdata->dest_info.addr.entry[tdata->dest_info.cur_addr].addr_len; /* Acquire transport. */ status = pjsip_endpt_acquire_transport( stateless_data->endpt, @@ -1178,6 +1190,7 @@ stateless_send_resolver_callback( pj_status_t status, const struct pjsip_server_addresses *addr) { pjsip_send_state *stateless_data = (pjsip_send_state*) token; + pjsip_tx_data *tdata = stateless_data->tdata; /* Fail on server resolution. */ if (status != PJ_SUCCESS) { @@ -1185,12 +1198,16 @@ stateless_send_resolver_callback( pj_status_t status, pj_bool_t cont = PJ_FALSE; (*stateless_data->app_cb)(stateless_data, -status, &cont); } - pjsip_tx_data_dec_ref(stateless_data->tdata); + pjsip_tx_data_dec_ref(tdata); return; } /* Copy server addresses */ - pj_memcpy( &stateless_data->addr, addr, sizeof(pjsip_server_addresses)); + if (addr && addr != &tdata->dest_info.addr) { + pj_memcpy( &tdata->dest_info.addr, addr, + sizeof(pjsip_server_addresses)); + } + pj_assert(tdata->dest_info.addr.count != 0); #if !defined(PJSIP_DONT_SWITCH_TO_TCP) || PJSIP_DONT_SWITCH_TO_TCP==0 /* RFC 3261 section 18.1.1: @@ -1199,29 +1216,33 @@ stateless_send_resolver_callback( pj_status_t status, * using an RFC 2914 [43] congestion controlled transport protocol, such * as TCP. */ - if (stateless_data->tdata->msg->type == PJSIP_REQUEST_MSG && - addr->count > 0 && - addr->entry[0].type == PJSIP_TRANSPORT_UDP) + if (tdata->msg->type == PJSIP_REQUEST_MSG && + tdata->dest_info.addr.count > 0 && + tdata->dest_info.addr.entry[0].type == PJSIP_TRANSPORT_UDP) { int len; /* Encode the request */ - status = pjsip_tx_data_encode(stateless_data->tdata); + status = pjsip_tx_data_encode(tdata); if (status != PJ_SUCCESS) { if (stateless_data->app_cb) { pj_bool_t cont = PJ_FALSE; (*stateless_data->app_cb)(stateless_data, -status, &cont); } - pjsip_tx_data_dec_ref(stateless_data->tdata); + pjsip_tx_data_dec_ref(tdata); return; } /* Check if request message is larger than 1300 bytes. */ - len = stateless_data->tdata->buf.cur - - stateless_data->tdata->buf.start; + len = tdata->buf.cur - tdata->buf.start; if (len >= PJSIP_UDP_SIZE_THRESHOLD) { int i; - int count = stateless_data->addr.count; + int count = tdata->dest_info.addr.count; + + PJ_LOG(5,(THIS_FILE, "%s exceeds UDP size threshold (%u), " + "sending with TCP", + pjsip_tx_data_get_info(tdata), + PJSIP_UDP_SIZE_THRESHOLD)); /* Insert "TCP version" of resolved UDP addresses at the * beginning. @@ -1229,19 +1250,18 @@ stateless_send_resolver_callback( pj_status_t status, if (count * 2 > PJSIP_MAX_RESOLVED_ADDRESSES) count = PJSIP_MAX_RESOLVED_ADDRESSES / 2; for (i = 0; i < count; ++i) { - pj_memcpy(&stateless_data->addr.entry[i+count], - &stateless_data->addr.entry[i], - sizeof(stateless_data->addr.entry[0])); - stateless_data->addr.entry[i].type = PJSIP_TRANSPORT_TCP; + pj_memcpy(&tdata->dest_info.addr.entry[i+count], + &tdata->dest_info.addr.entry[i], + sizeof(tdata->dest_info.addr.entry[0])); + tdata->dest_info.addr.entry[i].type = PJSIP_TRANSPORT_TCP; } - stateless_data->addr.count = count * 2; + tdata->dest_info.addr.count = count * 2; } } #endif /* !PJSIP_DONT_SWITCH_TO_TCP */ /* Process the addresses. */ - stateless_send_transport_cb( stateless_data, stateless_data->tdata, - -PJ_EPENDING); + stateless_send_transport_cb( stateless_data, tdata, -PJ_EPENDING); } /* @@ -1275,11 +1295,22 @@ PJ_DEF(pj_status_t) pjsip_endpt_send_request_stateless(pjsip_endpoint *endpt, stateless_data->tdata = tdata; stateless_data->app_cb = cb; - /* Resolve destination host. - * The processing then resumed when the resolving callback is called. + /* If destination info has not been initialized (this applies for most + * all requests except CANCEL), resolve destination host. The processing + * then resumed when the resolving callback is called. For CANCEL, the + * destination info must have been copied from the original INVITE so + * proceed to sending the request directly. */ - pjsip_endpt_resolve( endpt, tdata->pool, &dest_info, stateless_data, - &stateless_send_resolver_callback); + if (tdata->dest_info.addr.count == 0) { + pjsip_endpt_resolve( endpt, tdata->pool, &dest_info, stateless_data, + &stateless_send_resolver_callback); + } else { + PJ_LOG(5,(THIS_FILE, "%s: skipping target resolution because " + "address is already set", + pjsip_tx_data_get_info(tdata))); + stateless_send_resolver_callback(PJ_SUCCESS, stateless_data, + &tdata->dest_info.addr); + } return PJ_SUCCESS; } @@ -1590,7 +1621,7 @@ static void send_response_resolver_cb( pj_status_t status, void *token, } /* Update address in send_state. */ - send_state->addr = *addr; + pj_memcpy(&send_state->tdata->dest_info.addr, addr, sizeof(*addr)); /* Send response using the transoprt. */ status = pjsip_transport_send( send_state->cur_transport, -- cgit v1.2.3