From 2068f13bc42cf3a47374aa2765f82724a5782028 Mon Sep 17 00:00:00 2001 From: Liong Sauw Ming Date: Mon, 24 Oct 2011 09:28:13 +0000 Subject: Re #1395: Backport of PJSIP 1.x branch into PJSIP 2.0 trunk * Backport of r3557:r3832 TODO: ticket #1268 (Option for automatic/manual sending of RTCP SDES/BYE for the stream) for video stream. git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@3841 74dad513-b988-da41-8d7b-12977e46ad98 --- pjlib-util/include/pjlib-util/http_client.h | 30 ++++++++++++++ pjlib-util/src/pjlib-util/http_client.c | 61 ++++++++++++++++++++++++----- pjlib-util/src/pjlib-util/pcap.c | 14 ++++++- 3 files changed, 95 insertions(+), 10 deletions(-) (limited to 'pjlib-util') diff --git a/pjlib-util/include/pjlib-util/http_client.h b/pjlib-util/include/pjlib-util/http_client.h index e2490e4c..b75c7ea8 100644 --- a/pjlib-util/include/pjlib-util/http_client.h +++ b/pjlib-util/include/pjlib-util/http_client.h @@ -188,6 +188,36 @@ typedef struct pj_http_req_param */ pj_http_auth_cred auth_cred; + /** + * Optional source port range to use when binding the socket. + * This can be used if the source port needs to be within a certain range + * for instance due to strict firewall settings. The port used will be + * randomized within the range. + * + * Note that if authentication is configured, the authentication response + * will be a new transaction + * + * Default is 0 (The OS will select the source port automatically) + */ + pj_uint16_t source_port_range_start; + + /** + * Optional source port range to use when binding. + * The size of the port restriction range + * + * Default is 0 (The OS will select the source port automatically)) + */ + pj_uint16_t source_port_range_size; + + /** + * Max number of retries if binding to a port fails. + * Note that this does not adress the scenario where a request times out + * or errors. This needs to be taken care of by the on_complete callback. + * + * Default is 3 + */ + pj_uint16_t max_retries; + } pj_http_req_param; /** diff --git a/pjlib-util/src/pjlib-util/http_client.c b/pjlib-util/src/pjlib-util/http_client.c index d455cc20..cf96a2df 100644 --- a/pjlib-util/src/pjlib-util/http_client.c +++ b/pjlib-util/src/pjlib-util/http_client.c @@ -26,15 +26,17 @@ #include #include #include +#include #include #include #include #include #include +#define THIS_FILE "http_client.c" + #if 0 /* Enable some tracing */ - #define THIS_FILE "http_client.c" #define TRACE_(arg) PJ_LOG(3,arg) #else #define TRACE_(arg) @@ -764,6 +766,7 @@ PJ_DEF(void) pj_http_req_param_default(pj_http_req_param *param) pj_strset2(¶m->version, (char*)HTTP_1_0); param->timeout.msec = PJ_HTTP_DEFAULT_TIMEOUT; pj_time_val_normalize(¶m->timeout); + param->max_retries = 3; } /* Get the location of '@' character to indicate the end of @@ -1004,11 +1007,13 @@ PJ_DEF(void*) pj_http_req_get_user_data(pj_http_req *http_req) return http_req->param.user_data; } -PJ_DEF(pj_status_t) pj_http_req_start(pj_http_req *http_req) +static pj_status_t start_http_req(pj_http_req *http_req, + pj_bool_t notify_on_fail) { pj_sock_t sock = PJ_INVALID_SOCKET; pj_status_t status; pj_activesock_cb asock_cb; + int retry = 0; PJ_ASSERT_RETURN(http_req, PJ_EINVAL); /* Http request is not idle, a request was initiated before and @@ -1031,7 +1036,7 @@ PJ_DEF(pj_status_t) pj_http_req_start(pj_http_req *http_req) (http_req->param.addr_family==pj_AF_INET() && http_req->addr.ipv4.sin_addr.s_addr==PJ_INADDR_NONE)) { - return status; // cannot resolve host name + goto on_return; } http_req->resolved = PJ_TRUE; } @@ -1045,6 +1050,32 @@ PJ_DEF(pj_status_t) pj_http_req_start(pj_http_req *http_req) asock_cb.on_data_read = &http_on_data_read; asock_cb.on_data_sent = &http_on_data_sent; asock_cb.on_connect_complete = &http_on_connect; + + do + { + pj_sockaddr_in bound_addr; + pj_uint16_t port = 0; + + /* If we are using port restriction. + * Get a random port within the range + */ + if (http_req->param.source_port_range_start != 0) { + port = (pj_uint16_t) + (http_req->param.source_port_range_start + + (pj_rand() % http_req->param.source_port_range_size)); + } + + pj_sockaddr_in_init(&bound_addr, NULL, port); + status = pj_sock_bind(sock, &bound_addr, sizeof(bound_addr)); + + } while (status != PJ_SUCCESS && (retry++ < http_req->param.max_retries)); + + if (status != PJ_SUCCESS) { + PJ_PERROR(1,(THIS_FILE, status, + "Unable to bind to the requested port")); + pj_sock_close(sock); + goto on_return; + } // TODO: should we set whole data to 0 by default? // or add it in the param? @@ -1052,8 +1083,7 @@ PJ_DEF(pj_status_t) pj_http_req_start(pj_http_req *http_req) NULL, http_req->ioqueue, &asock_cb, http_req, &http_req->asock); if (status != PJ_SUCCESS) { - if (sock != PJ_INVALID_SOCKET) - pj_sock_close(sock); + pj_sock_close(sock); goto on_return; // error creating activesock } @@ -1074,7 +1104,9 @@ PJ_DEF(pj_status_t) pj_http_req_start(pj_http_req *http_req) pj_sockaddr_get_len(&http_req->addr)); if (status == PJ_SUCCESS) { http_req->state = SENDING_REQUEST; - return http_req_start_sending(http_req); + status = http_req_start_sending(http_req); + if (status != PJ_SUCCESS) + goto on_return; } else if (status != PJ_EPENDING) { goto on_return; // error connecting } @@ -1082,10 +1114,21 @@ PJ_DEF(pj_status_t) pj_http_req_start(pj_http_req *http_req) return PJ_SUCCESS; on_return: - http_req_end_request(http_req); + http_req->error = status; + if (notify_on_fail) + pj_http_req_cancel(http_req, PJ_TRUE); + else + http_req_end_request(http_req); + return status; } +/* Starts an asynchronous HTTP request to the URL specified. */ +PJ_DEF(pj_status_t) pj_http_req_start(pj_http_req *http_req) +{ + return start_http_req(http_req, PJ_FALSE); +} + /* Respond to basic authentication challenge */ static pj_status_t auth_respond_basic(pj_http_req *hreq) { @@ -1345,7 +1388,7 @@ static pj_status_t auth_respond_digest(pj_http_req *hreq) */ const pj_str_t STR_MD5 = { "MD5", 3 }; const pj_str_t qop = pj_str("auth"); - const pj_str_t nc = pj_str("1"); + const pj_str_t nc = pj_str("00000001"); const pj_str_t cnonce = pj_str("b39971"); auth_create_digest_response(&digest_response, cred, @@ -1433,7 +1476,7 @@ static void restart_req_with_auth(pj_http_req *hreq) http_req_end_request(hreq); - status = pj_http_req_start(hreq); + status = start_http_req(hreq, PJ_TRUE); if (status != PJ_SUCCESS) goto on_error; diff --git a/pjlib-util/src/pjlib-util/pcap.c b/pjlib-util/src/pjlib-util/pcap.c index e0a86fa8..bf45b714 100644 --- a/pjlib-util/src/pjlib-util/pcap.c +++ b/pjlib-util/src/pjlib-util/pcap.c @@ -368,8 +368,20 @@ PJ_DEF(pj_status_t) pj_pcap_read_udp(pj_pcap_file *file, *udp_payload_size = sz; + // Some layers may have trailer, e.g: link eth2. /* Check that we've read all the packets */ - PJ_ASSERT_RETURN(sz_read == rec_incl, PJ_EBUG); + //PJ_ASSERT_RETURN(sz_read == rec_incl, PJ_EBUG); + + /* Skip trailer */ + while (sz_read < rec_incl) { + sz = rec_incl - sz_read; + status = read_file(file, &tmp.eth, &sz); + if (status != PJ_SUCCESS) { + TRACE_((file->obj_name, "Error reading trailer: %d", status)); + return status; + } + sz_read += sz; + } return PJ_SUCCESS; } -- cgit v1.2.3