From 727da5e28aa110f7931b696f1b1ba74e805bb9b4 Mon Sep 17 00:00:00 2001 From: Riza Sulistyo Date: Thu, 19 Jun 2014 05:07:12 +0000 Subject: Re #1771: Implement run-time configuration to set specific socket option. git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@4860 74dad513-b988-da41-8d7b-12977e46ad98 --- pjlib/include/pj/sock.h | 37 +++++++++++++++++++++++++++ pjlib/include/pj/ssl_sock.h | 16 ++++++++++++ pjlib/src/pj/sock_bsd.c | 44 ++++++++++++++++++++++++++++++++- pjlib/src/pj/sock_linux_kernel.c | 30 ++++++++++++++++++++++ pjlib/src/pj/ssl_sock_common.c | 2 ++ pjlib/src/pj/ssl_sock_ossl.c | 27 ++++++++++++++++++++ pjsip/include/pjsip/sip_transport_tcp.h | 8 ++++++ pjsip/include/pjsip/sip_transport_tls.h | 18 ++++++++++++++ pjsip/include/pjsua-lib/pjsua.h | 8 ++++++ pjsip/src/pjsip/sip_transport_tcp.c | 16 ++++++++++++ pjsip/src/pjsip/sip_transport_tls.c | 14 +++++++++++ pjsip/src/pjsua-lib/pjsua_core.c | 8 ++++++ pjsip/src/pjsua-lib/pjsua_media.c | 8 ++++++ 13 files changed, 235 insertions(+), 1 deletion(-) diff --git a/pjlib/include/pj/sock.h b/pjlib/include/pj/sock.h index b7d1cb05..44d0fecd 100644 --- a/pjlib/include/pj/sock.h +++ b/pjlib/include/pj/sock.h @@ -616,6 +616,32 @@ typedef struct pj_ip_mreq { pj_in_addr imr_interface; /**< local IP address of interface. */ } pj_ip_mreq; +/* Maximum number of socket options. */ +#define PJ_MAX_SOCKOPT_PARAMS 4 + +/** + * Options to be set for the socket. + */ +typedef struct pj_sockopt_params +{ + /* The number of options to be applied. */ + unsigned cnt; + + /* Array of options to be applied. */ + struct { + /* The level at which the option is defined. */ + int level; + + /* Option name. */ + int optname; + + /* Pointer to the buffer in which the option is specified. */ + void *optval; + + /* Buffer size of the buffer pointed by optval. */ + int optlen; + } options[PJ_MAX_SOCKOPT_PARAMS]; +} pj_sockopt_params; /***************************************************************************** * @@ -1305,6 +1331,17 @@ PJ_DECL(pj_status_t) pj_sock_setsockopt( pj_sock_t sockfd, const void *optval, int optlen); +/** + * Set socket options associated with a socket. This method will apply all the + * options specified, and ignore any errors that might be raised. + * + * @param sockfd The socket descriptor. + * @param params The socket options. + * + * @return PJ_SUCCESS or the last error code. + */ +PJ_DECL(pj_status_t) pj_sock_setsockopt_params( pj_sock_t sockfd, + const pj_sockopt_params *params); /** * Helper function to set socket buffer size using #pj_sock_setsockopt() diff --git a/pjlib/include/pj/ssl_sock.h b/pjlib/include/pj/ssl_sock.h index 0d24a494..23843717 100644 --- a/pjlib/include/pj/ssl_sock.h +++ b/pjlib/include/pj/ssl_sock.h @@ -749,6 +749,22 @@ typedef struct pj_ssl_sock_param */ pj_bool_t qos_ignore_error; + /** + * Specify options to be set on the transport. + * + * By default there is no options. + * + */ + pj_sockopt_params sockopt_params; + + /** + * Specify if the transport should ignore any errors when setting the + * sockopt parameters. + * + * Default: PJ_TRUE + * + */ + pj_bool_t sockopt_ignore_error; } pj_ssl_sock_param; diff --git a/pjlib/src/pj/sock_bsd.c b/pjlib/src/pj/sock_bsd.c index 107f5247..1688668b 100644 --- a/pjlib/src/pj/sock_bsd.c +++ b/pjlib/src/pj/sock_bsd.c @@ -26,6 +26,8 @@ #include #include +#define THIS_FILE "sock_bsd.c" + /* * Address families conversion. * The values here are indexed based on pj_addr_family. @@ -765,13 +767,53 @@ PJ_DEF(pj_status_t) pj_sock_setsockopt( pj_sock_t sock, const void *optval, int optlen) { + int status; PJ_CHECK_STACK(); - if (setsockopt(sock, level, optname, (const char*)optval, optlen) != 0) + +#if (defined(PJ_WIN32) && PJ_WIN32) || (defined(PJ_SUNOS) && PJ_SUNOS) + /* Some opt may still need int value (e.g:SO_EXCLUSIVEADDRUSE in win32). */ + status = setsockopt(sock, + level, + ((optname&0xff00)==0xff00)?(int)optname|0xffff0000:optname, + (const char*)optval, optlen); +#else + status = setsockopt(sock, level, optname, (const char*)optval, optlen); +#endif + + if (status != 0) return PJ_RETURN_OS_ERROR(pj_get_native_netos_error()); else return PJ_SUCCESS; } +/* + * Set socket option. + */ +PJ_DEF(pj_status_t) pj_sock_setsockopt_params( pj_sock_t sockfd, + const pj_sockopt_params *params) +{ + unsigned int i = 0; + pj_status_t retval = PJ_SUCCESS; + PJ_CHECK_STACK(); + PJ_ASSERT_RETURN(params, PJ_EINVAL); + + for (;icnt && ioptions[i].level, + (pj_uint16_t)params->options[i].optname, + params->options[i].optval, + params->options[i].optlen); + if (status != PJ_SUCCESS) { + retval = status; + PJ_PERROR(4,(THIS_FILE, status, + "Warning: error applying sock opt %d", + params->options[i].optname)); + } + } + + return retval; +} + /* * Connect socket. */ diff --git a/pjlib/src/pj/sock_linux_kernel.c b/pjlib/src/pj/sock_linux_kernel.c index 89c2f0e0..899b486e 100644 --- a/pjlib/src/pj/sock_linux_kernel.c +++ b/pjlib/src/pj/sock_linux_kernel.c @@ -36,6 +36,8 @@ #include /* FIONBIO */ #include /* for pj_gethostname() */ +#define THIS_FILE "sock_linux_kernel.c" + /* * Address families conversion. * The values here are indexed based on pj_addr_family-0xFF00. @@ -625,6 +627,34 @@ PJ_DEF(pj_status_t) pj_sock_setsockopt( pj_sock_t sockfd, return PJ_SUCCESS; } +/* + * Set socket option. + */ +PJ_DEF(pj_status_t) pj_sock_setsockopt_params( pj_sock_t sockfd, + const pj_sockopt_params *params) +{ + unsigned int i = 0; + pj_status_t retval = PJ_SUCCESS; + PJ_CHECK_STACK(); + PJ_ASSERT_RETURN(params, PJ_EINVAL); + + for (;icnt && ioptions[i].level, + params->options[i].optname, + params->options[i].optval, + params->options[i].optlen); + if (status != PJ_SUCCESS) { + retval = status; + PJ_PERROR(4,(THIS_FILE, status, + "Warning: error applying sock opt %d", + params->options[i].optname)); + } + } + + return retval; +} + /* * Shutdown socket. */ diff --git a/pjlib/src/pj/ssl_sock_common.c b/pjlib/src/pj/ssl_sock_common.c index 67a8d63c..60248372 100644 --- a/pjlib/src/pj/ssl_sock_common.c +++ b/pjlib/src/pj/ssl_sock_common.c @@ -41,6 +41,8 @@ PJ_DEF(void) pj_ssl_sock_param_default(pj_ssl_sock_param *param) param->qos_type = PJ_QOS_TYPE_BEST_EFFORT; param->qos_ignore_error = PJ_TRUE; + param->sockopt_ignore_error = PJ_TRUE; + /* Security config */ param->proto = PJ_SSL_SOCK_PROTO_DEFAULT; } diff --git a/pjlib/src/pj/ssl_sock_ossl.c b/pjlib/src/pj/ssl_sock_ossl.c index 7c7b6d00..3aa85b0d 100644 --- a/pjlib/src/pj/ssl_sock_ossl.c +++ b/pjlib/src/pj/ssl_sock_ossl.c @@ -1650,6 +1650,14 @@ static pj_bool_t asock_on_accept_complete (pj_activesock_t *asock, if (status != PJ_SUCCESS && !ssock->param.qos_ignore_error) goto on_return; + /* Apply socket options, if specified */ + if (ssock->param.sockopt_params.cnt) { + status = pj_sock_setsockopt_params(ssock->sock, + &ssock->param.sockopt_params); + if (status != PJ_SUCCESS && !ssock->param.sockopt_ignore_error) + goto on_return; + } + /* Update local address */ ssock->addr_len = src_addr_len; status = pj_sock_getsockname(ssock->sock, &ssock->local_addr, @@ -2452,9 +2460,19 @@ PJ_DEF(pj_status_t) pj_ssl_sock_start_accept (pj_ssl_sock_t *ssock, status = pj_sock_apply_qos2(ssock->sock, ssock->param.qos_type, &ssock->param.qos_params, 2, ssock->pool->obj_name, NULL); + if (status != PJ_SUCCESS && !ssock->param.qos_ignore_error) goto on_error; + /* Apply socket options, if specified */ + if (ssock->param.sockopt_params.cnt) { + status = pj_sock_setsockopt_params(ssock->sock, + &ssock->param.sockopt_params); + + if (status != PJ_SUCCESS && !ssock->param.sockopt_ignore_error) + goto on_error; + } + /* Bind socket */ status = pj_sock_bind(ssock->sock, localaddr, addr_len); if (status != PJ_SUCCESS) @@ -2537,6 +2555,15 @@ PJ_DECL(pj_status_t) pj_ssl_sock_start_connect(pj_ssl_sock_t *ssock, if (status != PJ_SUCCESS && !ssock->param.qos_ignore_error) goto on_error; + /* Apply socket options, if specified */ + if (ssock->param.sockopt_params.cnt) { + status = pj_sock_setsockopt_params(ssock->sock, + &ssock->param.sockopt_params); + + if (status != PJ_SUCCESS && !ssock->param.sockopt_ignore_error) + goto on_error; + } + /* Bind socket */ status = pj_sock_bind(ssock->sock, localaddr, addr_len); if (status != PJ_SUCCESS) diff --git a/pjsip/include/pjsip/sip_transport_tcp.h b/pjsip/include/pjsip/sip_transport_tcp.h index 28169fcc..a97f845f 100644 --- a/pjsip/include/pjsip/sip_transport_tcp.h +++ b/pjsip/include/pjsip/sip_transport_tcp.h @@ -104,6 +104,14 @@ typedef struct pjsip_tcp_transport_cfg */ pj_qos_params qos_params; + /** + * Specify options to be set on the transport. + * + * By default there is no options. + * + */ + pj_sockopt_params sockopt_params; + } pjsip_tcp_transport_cfg; diff --git a/pjsip/include/pjsip/sip_transport_tls.h b/pjsip/include/pjsip/sip_transport_tls.h index 00d8fe76..b6deafc7 100644 --- a/pjsip/include/pjsip/sip_transport_tls.h +++ b/pjsip/include/pjsip/sip_transport_tls.h @@ -205,6 +205,23 @@ typedef struct pjsip_tls_setting */ pj_bool_t qos_ignore_error; + /** + * Specify options to be set on the transport. + * + * By default there is no options. + * + */ + pj_sockopt_params sockopt_params; + + /** + * Specify if the transport should ignore any errors when setting the + * sockopt parameters. + * + * Default: PJ_TRUE + * + */ + pj_bool_t sockopt_ignore_error; + } pjsip_tls_setting; @@ -234,6 +251,7 @@ PJ_INLINE(void) pjsip_tls_setting_default(pjsip_tls_setting *tls_opt) tls_opt->reuse_addr = PJSIP_TLS_TRANSPORT_REUSEADDR; tls_opt->qos_type = PJ_QOS_TYPE_BEST_EFFORT; tls_opt->qos_ignore_error = PJ_TRUE; + tls_opt->sockopt_ignore_error = PJ_TRUE; } diff --git a/pjsip/include/pjsua-lib/pjsua.h b/pjsip/include/pjsua-lib/pjsua.h index 895d9bd8..8e0e3156 100644 --- a/pjsip/include/pjsua-lib/pjsua.h +++ b/pjsip/include/pjsua-lib/pjsua.h @@ -2296,6 +2296,14 @@ typedef struct pjsua_transport_config */ pj_qos_params qos_params; + /** + * Specify options to be set on the transport. + * + * By default there is no options. + * + */ + pj_sockopt_params sockopt_params; + } pjsua_transport_config; diff --git a/pjsip/src/pjsip/sip_transport_tcp.c b/pjsip/src/pjsip/sip_transport_tcp.c index 6a0eaffb..70ae300e 100644 --- a/pjsip/src/pjsip/sip_transport_tcp.c +++ b/pjsip/src/pjsip/sip_transport_tcp.c @@ -60,6 +60,7 @@ struct tcp_listener pj_sockaddr bound_addr; pj_qos_type qos_type; pj_qos_params qos_params; + pj_sockopt_params sockopt_params; }; @@ -284,6 +285,8 @@ PJ_DEF(pj_status_t) pjsip_tcp_transport_start3( listener->qos_type = cfg->qos_type; pj_memcpy(&listener->qos_params, &cfg->qos_params, sizeof(cfg->qos_params)); + pj_memcpy(&listener->sockopt_params, &cfg->sockopt_params, + sizeof(cfg->sockopt_params)); pj_ansi_strcpy(listener->factory.obj_name, "tcplis"); if (listener->factory.type==PJSIP_TRANSPORT_TCP6) @@ -316,6 +319,10 @@ PJ_DEF(pj_status_t) pjsip_tcp_transport_start3( } } + /* Apply socket options, if specified */ + if (cfg->sockopt_params.cnt) + status = pj_sock_setsockopt_params(sock, &cfg->sockopt_params); + /* Bind address may be different than factory.local_addr because * factory.local_addr will be resolved below. */ @@ -918,6 +925,11 @@ static pj_status_t lis_create_transport(pjsip_tpfactory *factory, 2, listener->factory.obj_name, "outgoing SIP TCP socket"); + /* Apply socket options, if specified */ + if (listener->sockopt_params.cnt) + status = pj_sock_setsockopt_params(sock, &listener->sockopt_params); + + /* Bind to listener's address and any port */ pj_bzero(&local_addr, sizeof(local_addr)); pj_sockaddr_cp(&local_addr, &listener->bound_addr); @@ -1036,6 +1048,10 @@ static pj_bool_t on_accept_complete(pj_activesock_t *asock, 2, listener->factory.obj_name, "incoming SIP TCP socket"); + /* Apply socket options, if specified */ + if (listener->sockopt_params.cnt) + status = pj_sock_setsockopt_params(sock, &listener->sockopt_params); + /* tcp_create() expect pj_sockaddr, so copy src_addr to temporary var, * just in case. */ diff --git a/pjsip/src/pjsip/sip_transport_tls.c b/pjsip/src/pjsip/sip_transport_tls.c index ac7b2840..a86b398c 100644 --- a/pjsip/src/pjsip/sip_transport_tls.c +++ b/pjsip/src/pjsip/sip_transport_tls.c @@ -349,6 +349,13 @@ PJ_DEF(pj_status_t) pjsip_tls_transport_start2( pjsip_endpoint *endpt, pj_memcpy(&ssock_param.qos_params, &listener->tls_setting.qos_params, sizeof(ssock_param.qos_params)); + ssock_param.sockopt_ignore_error = + listener->tls_setting.sockopt_ignore_error; + /* Copy the sockopt */ + pj_memcpy(&ssock_param.sockopt_params, + &listener->tls_setting.sockopt_params, + sizeof(listener->tls_setting.sockopt_params)); + has_listener = PJ_FALSE; switch(listener->tls_setting.method) { @@ -953,6 +960,13 @@ static pj_status_t lis_create_transport(pjsip_tpfactory *factory, pj_memcpy(&ssock_param.qos_params, &listener->tls_setting.qos_params, sizeof(ssock_param.qos_params)); + ssock_param.sockopt_ignore_error = + listener->tls_setting.sockopt_ignore_error; + /* Copy the sockopt */ + pj_memcpy(&ssock_param.sockopt_params, + &listener->tls_setting.sockopt_params, + sizeof(listener->tls_setting.sockopt_params)); + switch(listener->tls_setting.method) { case PJSIP_TLSV1_METHOD: ssock_param.proto = PJ_SSL_SOCK_PROTO_TLS1; diff --git a/pjsip/src/pjsua-lib/pjsua_core.c b/pjsip/src/pjsua-lib/pjsua_core.c index 79c69b3e..f76bc5e7 100644 --- a/pjsip/src/pjsua-lib/pjsua_core.c +++ b/pjsip/src/pjsua-lib/pjsua_core.c @@ -1964,6 +1964,10 @@ static pj_status_t create_sip_udp_sock(int af, &cfg->qos_params, 2, THIS_FILE, "SIP UDP socket"); + /* Apply sockopt, if specified */ + if (cfg->sockopt_params.cnt) + status = pj_sock_setsockopt_params(sock, &cfg->sockopt_params); + /* Bind socket */ status = pj_sock_bind(sock, &bind_addr, pj_sockaddr_get_len(&bind_addr)); if (status != PJ_SUCCESS) { @@ -2186,6 +2190,10 @@ PJ_DEF(pj_status_t) pjsua_transport_create( pjsip_transport_type_e type, pj_memcpy(&tcp_cfg.qos_params, &cfg->qos_params, sizeof(cfg->qos_params)); + /* Copy the sockopt */ + pj_memcpy(&tcp_cfg.sockopt_params, &cfg->sockopt_params, + sizeof(tcp_cfg.sockopt_params)); + /* Create the TCP transport */ status = pjsip_tcp_transport_start3(pjsua_var.endpt, &tcp_cfg, &tcp); diff --git a/pjsip/src/pjsua-lib/pjsua_media.c b/pjsip/src/pjsua-lib/pjsua_media.c index 62de7668..af0799aa 100644 --- a/pjsip/src/pjsua-lib/pjsua_media.c +++ b/pjsip/src/pjsua-lib/pjsua_media.c @@ -298,6 +298,10 @@ static pj_status_t create_rtp_rtcp_sock(pjsua_call_media *call_med, &cfg->qos_params, 2, THIS_FILE, "RTP socket"); + /* Apply sockopt, if specified */ + if (cfg->sockopt_params.cnt) + status = pj_sock_setsockopt_params(sock[0], &cfg->sockopt_params); + /* Bind RTP socket */ pj_sockaddr_set_port(&bound_addr, acc->next_rtp_port); status=pj_sock_bind(sock[0], &bound_addr, @@ -321,6 +325,10 @@ static pj_status_t create_rtp_rtcp_sock(pjsua_call_media *call_med, &cfg->qos_params, 2, THIS_FILE, "RTCP socket"); + /* Apply sockopt, if specified */ + if (cfg->sockopt_params.cnt) + status = pj_sock_setsockopt_params(sock[1], &cfg->sockopt_params); + /* Bind RTCP socket */ pj_sockaddr_set_port(&bound_addr, (pj_uint16_t)(acc->next_rtp_port+1)); status=pj_sock_bind(sock[1], &bound_addr, -- cgit v1.2.3