Skip to content

Commit 5daf06c

Browse files
authored
Add pjsip_tls_transport_restart2() and pjsua_transport_lis_restart() for runtime transport settings update (#4631)
1 parent 2776fe3 commit 5daf06c

File tree

4 files changed

+214
-0
lines changed

4 files changed

+214
-0
lines changed

pjsip/include/pjsip/sip_transport_tls.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -651,6 +651,39 @@ PJ_DECL(pj_status_t) pjsip_tls_transport_restart(pjsip_tpfactory *factory,
651651
const pj_sockaddr *local,
652652
const pjsip_host_port *a_name);
653653

654+
/**
655+
* Restart the TLS listener with optional updated TLS settings. This will
656+
* close the listener socket and recreate the socket. If new TLS settings
657+
* are provided, they will be applied before creating the new socket,
658+
* allowing runtime updates of certificates, keys, and other TLS parameters.
659+
*
660+
* @param factory The SIP TLS transport factory.
661+
*
662+
* @param opt Optional new TLS settings to be applied during restart.
663+
* If NULL, the existing settings will be used (equivalent
664+
* to calling pjsip_tls_transport_restart()).
665+
*
666+
* @param local The address where the listener should be bound to.
667+
* Both IP interface address and port fields are optional.
668+
* If IP interface address is not specified, socket
669+
* will be bound to PJ_INADDR_ANY. If port is not
670+
* specified, socket will be bound to any port
671+
* selected by the operating system.
672+
*
673+
* @param a_name The published address for the listener.
674+
* It can be set using IP address or hostname.
675+
* If this argument is NULL, then the bound address will
676+
* be used as the published address.
677+
*
678+
* @return PJ_SUCCESS when the listener has been successfully
679+
* restarted.
680+
*
681+
*/
682+
PJ_DECL(pj_status_t) pjsip_tls_transport_restart2(pjsip_tpfactory *factory,
683+
const pjsip_tls_setting *opt,
684+
const pj_sockaddr *local,
685+
const pjsip_host_port *a_name);
686+
654687
PJ_END_DECL
655688

656689
/**

pjsip/include/pjsua-lib/pjsua.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3594,6 +3594,24 @@ PJ_DECL(pj_status_t) pjsua_transport_lis_start( pjsua_transport_id id,
35943594
const pjsua_transport_config *cfg);
35953595

35963596

3597+
/**
3598+
* Restart the listener of the transport. This will close the listener socket
3599+
* and recreate it. For TLS transports, TLS settings can be specified in the
3600+
* transport config to update certificates, keys, and other TLS parameters
3601+
* during runtime. For UDP transports, this will restart the transport with
3602+
* new settings.
3603+
*
3604+
* @param id Transport ID.
3605+
* @param cfg The new transport config used by the listener.
3606+
* For TCP/TLS: port, public_addr, bound_addr, and tls_setting
3607+
* are used. For UDP: port, public_addr, and bound_addr are used.
3608+
*
3609+
* @return PJ_SUCCESS on success, or the appropriate error code.
3610+
*/
3611+
PJ_DECL(pj_status_t) pjsua_transport_lis_restart( pjsua_transport_id id,
3612+
const pjsua_transport_config *cfg);
3613+
3614+
35973615
/**
35983616
* @}
35993617
*/

pjsip/src/pjsip/sip_transport_tls.c

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -765,6 +765,15 @@ static pj_status_t lis_destroy(pjsip_tpfactory *factory)
765765
PJ_DEF(pj_status_t) pjsip_tls_transport_restart(pjsip_tpfactory *factory,
766766
const pj_sockaddr *local,
767767
const pjsip_host_port *a_name)
768+
{
769+
return pjsip_tls_transport_restart2(factory, NULL, local, a_name);
770+
}
771+
772+
773+
PJ_DEF(pj_status_t) pjsip_tls_transport_restart2(pjsip_tpfactory *factory,
774+
const pjsip_tls_setting *opt,
775+
const pj_sockaddr *local,
776+
const pjsip_host_port *a_name)
768777
{
769778
pj_status_t status = PJ_SUCCESS;
770779
struct tls_listener *listener = (struct tls_listener *)factory;
@@ -775,6 +784,15 @@ PJ_DEF(pj_status_t) pjsip_tls_transport_restart(pjsip_tpfactory *factory,
775784
"TLS restart requested while no listener created, "
776785
"update the published address only"));
777786

787+
/* Update TLS settings if provided */
788+
if (opt) {
789+
/* Wipe old certificate keys for security */
790+
pjsip_tls_setting_wipe_keys(&listener->tls_setting);
791+
792+
/* Copy new settings */
793+
pjsip_tls_setting_copy(listener->factory.pool, &listener->tls_setting, opt);
794+
}
795+
778796
status = update_factory_addr(listener, a_name);
779797
if (status != PJ_SUCCESS)
780798
return status;
@@ -787,6 +805,69 @@ PJ_DEF(pj_status_t) pjsip_tls_transport_restart(pjsip_tpfactory *factory,
787805

788806
lis_close(listener);
789807

808+
/* Update TLS settings if provided */
809+
if (opt) {
810+
/* Wipe old certificate keys for security */
811+
pjsip_tls_setting_wipe_keys(&listener->tls_setting);
812+
813+
/* Copy new settings */
814+
pjsip_tls_setting_copy(listener->factory.pool, &listener->tls_setting, opt);
815+
816+
/* Free old certificate if present */
817+
if (listener->cert) {
818+
pj_ssl_cert_wipe_keys(listener->cert);
819+
listener->cert = NULL;
820+
}
821+
822+
/* Load new certificate based on updated settings */
823+
if (listener->tls_setting.cert_file.slen ||
824+
listener->tls_setting.ca_list_file.slen ||
825+
listener->tls_setting.ca_list_path.slen ||
826+
listener->tls_setting.privkey_file.slen)
827+
{
828+
status = pj_ssl_cert_load_from_files2(listener->factory.pool,
829+
&listener->tls_setting.ca_list_file,
830+
&listener->tls_setting.ca_list_path,
831+
&listener->tls_setting.cert_file,
832+
&listener->tls_setting.privkey_file,
833+
&listener->tls_setting.password,
834+
&listener->cert);
835+
if (status != PJ_SUCCESS) {
836+
tls_perror(listener->factory.obj_name,
837+
"Failed to load certificate from files", status, NULL);
838+
return status;
839+
}
840+
} else if (listener->tls_setting.ca_buf.slen ||
841+
listener->tls_setting.cert_buf.slen ||
842+
listener->tls_setting.privkey_buf.slen)
843+
{
844+
status = pj_ssl_cert_load_from_buffer(listener->factory.pool,
845+
&listener->tls_setting.ca_buf,
846+
&listener->tls_setting.cert_buf,
847+
&listener->tls_setting.privkey_buf,
848+
&listener->tls_setting.password,
849+
&listener->cert);
850+
if (status != PJ_SUCCESS) {
851+
tls_perror(listener->factory.obj_name,
852+
"Failed to load certificate from buffer", status, NULL);
853+
return status;
854+
}
855+
} else if (listener->tls_setting.cert_lookup.type !=
856+
PJ_SSL_CERT_LOOKUP_NONE &&
857+
listener->tls_setting.cert_lookup.keyword.slen)
858+
{
859+
status = pj_ssl_cert_load_from_store(
860+
listener->factory.pool,
861+
&listener->tls_setting.cert_lookup,
862+
&listener->cert);
863+
if (status != PJ_SUCCESS) {
864+
tls_perror(listener->factory.obj_name,
865+
"Failed to load certificate from store", status, NULL);
866+
return status;
867+
}
868+
}
869+
}
870+
790871
status = pjsip_tls_transport_lis_start(factory, local, a_name);
791872
if (status != PJ_SUCCESS) {
792873
tls_perror(listener->factory.obj_name,

pjsip/src/pjsua-lib/pjsua_core.c

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3139,6 +3139,88 @@ PJ_DEF(pj_status_t) pjsua_transport_lis_start(pjsua_transport_id id,
31393139
}
31403140

31413141

3142+
PJ_DEF(pj_status_t) pjsua_transport_lis_restart(pjsua_transport_id id,
3143+
const pjsua_transport_config *cfg)
3144+
{
3145+
pj_status_t status = PJ_SUCCESS;
3146+
pjsip_transport_type_e tp_type;
3147+
/* Common variables used by all transport types */
3148+
pj_sockaddr bind_addr;
3149+
pjsip_host_port addr_name;
3150+
int af;
3151+
3152+
/* Make sure id is in range. */
3153+
PJ_ASSERT_RETURN(id>=0 && id<(int)PJ_ARRAY_SIZE(pjsua_var.tpdata),
3154+
PJ_EINVAL);
3155+
3156+
/* Make sure that transport exists */
3157+
PJ_ASSERT_RETURN(pjsua_var.tpdata[id].data.ptr != NULL, PJ_EINVAL);
3158+
3159+
tp_type = pjsua_var.tpdata[id].type & ~PJSIP_TRANSPORT_IPV6;
3160+
3161+
if ((tp_type == PJSIP_TRANSPORT_TLS) || (tp_type == PJSIP_TRANSPORT_TCP)) {
3162+
pjsip_tpfactory *factory = pjsua_var.tpdata[id].data.factory;
3163+
af = pjsip_transport_type_get_af(factory->type);
3164+
} else if (tp_type == PJSIP_TRANSPORT_UDP) {
3165+
pjsip_transport *transport = pjsua_var.tpdata[id].data.tp;
3166+
af = pjsip_transport_type_get_af(transport->key.type);
3167+
} else {
3168+
return PJ_EINVAL;
3169+
}
3170+
3171+
/* Initialize bind address */
3172+
pj_sockaddr_init(af, &bind_addr, NULL, 0);
3173+
3174+
if (cfg->port)
3175+
pj_sockaddr_set_port(&bind_addr, (pj_uint16_t)cfg->port);
3176+
3177+
if (cfg->bound_addr.slen) {
3178+
status = pj_sockaddr_set_str_addr(af,
3179+
&bind_addr,
3180+
&cfg->bound_addr);
3181+
if (status != PJ_SUCCESS) {
3182+
pjsua_perror(THIS_FILE,
3183+
"Unable to resolve transport bound address",
3184+
status);
3185+
return status;
3186+
}
3187+
}
3188+
3189+
/* Set published name */
3190+
pj_bzero(&addr_name, sizeof(pjsip_host_port));
3191+
if (cfg->public_addr.slen)
3192+
addr_name.host = cfg->public_addr;
3193+
3194+
/* Restart transport based on type */
3195+
if ((tp_type == PJSIP_TRANSPORT_TLS) || (tp_type == PJSIP_TRANSPORT_TCP)) {
3196+
pjsip_tpfactory *factory = pjsua_var.tpdata[id].data.factory;
3197+
3198+
if (tp_type == PJSIP_TRANSPORT_TCP) {
3199+
status = pjsip_tcp_transport_restart(factory, &bind_addr,
3200+
&addr_name);
3201+
}
3202+
#if defined(PJSIP_HAS_TLS_TRANSPORT) && PJSIP_HAS_TLS_TRANSPORT!=0
3203+
else {
3204+
/* Use the new restart2 function for TLS to support settings update */
3205+
status = pjsip_tls_transport_restart2(factory, &cfg->tls_setting, &bind_addr,
3206+
&addr_name);
3207+
}
3208+
#endif
3209+
} else if (tp_type == PJSIP_TRANSPORT_UDP) {
3210+
pjsip_transport *transport = pjsua_var.tpdata[id].data.tp;
3211+
3212+
/* Restart UDP transport using restart2 function */
3213+
status = pjsip_udp_transport_restart2(transport,
3214+
PJSIP_UDP_TRANSPORT_DESTROY_SOCKET,
3215+
PJ_INVALID_SOCKET,
3216+
&bind_addr,
3217+
cfg->public_addr.slen ? &addr_name : NULL);
3218+
}
3219+
3220+
return status;
3221+
}
3222+
3223+
31423224
/*
31433225
* Add additional headers etc in msg_data specified by application
31443226
* when sending requests.

0 commit comments

Comments
 (0)