PJ_DEF(pj_status_t) pj_sock_set_qos_type(pj_sock_t sock, pj_qos_type type) { pj_qos_params param; pj_status_t status; status = pj_qos_get_params(type, ¶m); if (status != PJ_SUCCESS) return status; return pj_sock_set_qos_params(sock, ¶m); }
/* Apply QoS */ PJ_DEF(pj_status_t) pj_sock_apply_qos( pj_sock_t sock, pj_qos_type qos_type, pj_qos_params *qos_params, unsigned log_level, const char *log_sender, const char *sock_name) { pj_status_t qos_type_rc = PJ_SUCCESS, qos_params_rc = PJ_SUCCESS; if (!log_sender) log_sender = THIS_FILE; if (!sock_name) sock_name = "socket"; if (qos_type != PJ_QOS_TYPE_BEST_EFFORT) { qos_type_rc = pj_sock_set_qos_type(sock, qos_type); if (qos_type_rc != PJ_SUCCESS) { pj_perror(log_level, log_sender, qos_type_rc, "Error setting QoS type %d to %s", qos_type, sock_name); } } if (qos_params && qos_params->flags) { qos_params_rc = pj_sock_set_qos_params(sock, qos_params); if (qos_params_rc != PJ_SUCCESS) { pj_perror(log_level, log_sender, qos_params_rc, "Error setting QoS params (flags=%d) to %s", qos_params->flags, sock_name); if (qos_type_rc != PJ_SUCCESS) return qos_params_rc; } } else if (qos_type_rc != PJ_SUCCESS) return qos_type_rc; return PJ_SUCCESS; }
/*! \brief Apply handler for transports */ static int transport_apply(const struct ast_sorcery *sorcery, void *obj) { struct ast_sip_transport *transport = obj; RAII_VAR(struct ast_sip_transport *, existing, ast_sorcery_retrieve_by_id(sorcery, "transport", ast_sorcery_object_get_id(obj)), ao2_cleanup); pj_status_t res = -1; if (!existing || !existing->state) { if (!(transport->state = ao2_alloc(sizeof(*transport->state), transport_state_destroy))) { ast_log(LOG_ERROR, "Transport state for '%s' could not be allocated\n", ast_sorcery_object_get_id(obj)); return -1; } } else { transport->state = existing->state; ao2_ref(transport->state, +1); } /* Once active a transport can not be reconfigured */ if (transport->state->transport || transport->state->factory) { return -1; } if (transport->host.addr.sa_family != PJ_AF_INET && transport->host.addr.sa_family != PJ_AF_INET6) { ast_log(LOG_ERROR, "Transport '%s' could not be started as binding not specified\n", ast_sorcery_object_get_id(obj)); return -1; } /* Set default port if not present */ if (!pj_sockaddr_get_port(&transport->host)) { pj_sockaddr_set_port(&transport->host, (transport->type == AST_TRANSPORT_TLS) ? 5061 : 5060); } /* Now that we know what address family we can set up a dnsmgr refresh for the external media address if present */ if (!ast_strlen_zero(transport->external_signaling_address)) { if (transport->host.addr.sa_family == pj_AF_INET()) { transport->external_address.ss.ss_family = AF_INET; } else if (transport->host.addr.sa_family == pj_AF_INET6()) { transport->external_address.ss.ss_family = AF_INET6; } else { ast_log(LOG_ERROR, "Unknown address family for transport '%s', could not get external signaling address\n", ast_sorcery_object_get_id(obj)); return -1; } if (ast_dnsmgr_lookup(transport->external_signaling_address, &transport->external_address, &transport->external_address_refresher, NULL) < 0) { ast_log(LOG_ERROR, "Could not create dnsmgr for external signaling address on '%s'\n", ast_sorcery_object_get_id(obj)); return -1; } } if (transport->type == AST_TRANSPORT_UDP) { if (transport->host.addr.sa_family == pj_AF_INET()) { res = pjsip_udp_transport_start(ast_sip_get_pjsip_endpoint(), &transport->host.ipv4, NULL, transport->async_operations, &transport->state->transport); } else if (transport->host.addr.sa_family == pj_AF_INET6()) { res = pjsip_udp_transport_start6(ast_sip_get_pjsip_endpoint(), &transport->host.ipv6, NULL, transport->async_operations, &transport->state->transport); } if (res == PJ_SUCCESS && (transport->tos || transport->cos)) { pj_sock_t sock; pj_qos_params qos_params; sock = pjsip_udp_transport_get_socket(transport->state->transport); pj_sock_get_qos_params(sock, &qos_params); set_qos(transport, &qos_params); pj_sock_set_qos_params(sock, &qos_params); } } else if (transport->type == AST_TRANSPORT_TCP) { pjsip_tcp_transport_cfg cfg; pjsip_tcp_transport_cfg_default(&cfg, transport->host.addr.sa_family); cfg.bind_addr = transport->host; cfg.async_cnt = transport->async_operations; set_qos(transport, &cfg.qos_params); res = pjsip_tcp_transport_start3(ast_sip_get_pjsip_endpoint(), &cfg, &transport->state->factory); } else if (transport->type == AST_TRANSPORT_TLS) { transport->tls.ca_list_file = pj_str((char*)transport->ca_list_file); transport->tls.cert_file = pj_str((char*)transport->cert_file); transport->tls.privkey_file = pj_str((char*)transport->privkey_file); transport->tls.password = pj_str((char*)transport->password); set_qos(transport, &transport->tls.qos_params); res = pjsip_tls_transport_start2(ast_sip_get_pjsip_endpoint(), &transport->tls, &transport->host, NULL, transport->async_operations, &transport->state->factory); } else if ((transport->type == AST_TRANSPORT_WS) || (transport->type == AST_TRANSPORT_WSS)) { if (transport->cos || transport->tos) { ast_log(LOG_WARNING, "TOS and COS values ignored for websocket transport\n"); } res = PJ_SUCCESS; } if (res != PJ_SUCCESS) { char msg[PJ_ERR_MSG_SIZE]; pjsip_strerror(res, msg, sizeof(msg)); ast_log(LOG_ERROR, "Transport '%s' could not be started: %s\n", ast_sorcery_object_get_id(obj), msg); return -1; } return 0; }
/*! \brief Apply handler for transports */ static int transport_apply(const struct ast_sorcery *sorcery, void *obj) { struct ast_sip_transport *transport = obj; const char *transport_id = ast_sorcery_object_get_id(obj); RAII_VAR(struct ao2_container *, states, transport_states, states_cleanup); RAII_VAR(struct internal_state *, temp_state, NULL, ao2_cleanup); RAII_VAR(struct internal_state *, perm_state, NULL, ao2_cleanup); RAII_VAR(struct ast_variable *, changes, NULL, ast_variables_destroy); pj_status_t res = -1; int i; #define BIND_TRIES 3 #define BIND_DELAY_US 100000 if (!states) { return -1; } /* * transport_apply gets called for EVERY retrieval of a transport when using realtime. * We need to prevent multiple threads from trying to mess with underlying transports * at the same time. The container is the only thing we have to lock on. */ ao2_wrlock(states); temp_state = internal_state_alloc(transport); if (!temp_state) { ast_log(LOG_ERROR, "Transport '%s' failed to allocate memory\n", transport_id); return -1; } perm_state = find_internal_state_by_transport(transport); if (perm_state) { ast_sorcery_diff(sorcery, perm_state->transport, transport, &changes); if (!changes && !has_state_changed(perm_state->state, temp_state->state)) { /* In case someone is using the deprecated fields, reset them */ transport->state = perm_state->state; copy_state_to_transport(transport); ao2_replace(perm_state->transport, transport); return 0; } if (!transport->allow_reload) { if (!perm_state->change_detected) { perm_state->change_detected = 1; ast_log(LOG_WARNING, "Transport '%s' is not reloadable, maintaining previous values\n", transport_id); } /* In case someone is using the deprecated fields, reset them */ transport->state = perm_state->state; copy_state_to_transport(transport); ao2_replace(perm_state->transport, transport); return 0; } } if (temp_state->state->host.addr.sa_family != PJ_AF_INET && temp_state->state->host.addr.sa_family != PJ_AF_INET6) { ast_log(LOG_ERROR, "Transport '%s' could not be started as binding not specified\n", transport_id); return -1; } /* Set default port if not present */ if (!pj_sockaddr_get_port(&temp_state->state->host)) { pj_sockaddr_set_port(&temp_state->state->host, (transport->type == AST_TRANSPORT_TLS) ? 5061 : 5060); } /* Now that we know what address family we can set up a dnsmgr refresh for the external media address if present */ if (!ast_strlen_zero(transport->external_signaling_address)) { if (temp_state->state->host.addr.sa_family == pj_AF_INET()) { temp_state->state->external_address.ss.ss_family = AF_INET; } else if (temp_state->state->host.addr.sa_family == pj_AF_INET6()) { temp_state->state->external_address.ss.ss_family = AF_INET6; } else { ast_log(LOG_ERROR, "Unknown address family for transport '%s', could not get external signaling address\n", transport_id); return -1; } if (ast_dnsmgr_lookup(transport->external_signaling_address, &temp_state->state->external_address, &temp_state->state->external_address_refresher, NULL) < 0) { ast_log(LOG_ERROR, "Could not create dnsmgr for external signaling address on '%s'\n", transport_id); return -1; } } if (transport->type == AST_TRANSPORT_UDP) { for (i = 0; i < BIND_TRIES && res != PJ_SUCCESS; i++) { if (perm_state && perm_state->state && perm_state->state->transport) { pjsip_udp_transport_pause(perm_state->state->transport, PJSIP_UDP_TRANSPORT_DESTROY_SOCKET); usleep(BIND_DELAY_US); } if (temp_state->state->host.addr.sa_family == pj_AF_INET()) { res = pjsip_udp_transport_start(ast_sip_get_pjsip_endpoint(), &temp_state->state->host.ipv4, NULL, transport->async_operations, &temp_state->state->transport); } else if (temp_state->state->host.addr.sa_family == pj_AF_INET6()) { res = pjsip_udp_transport_start6(ast_sip_get_pjsip_endpoint(), &temp_state->state->host.ipv6, NULL, transport->async_operations, &temp_state->state->transport); } } if (res == PJ_SUCCESS && (transport->tos || transport->cos)) { pj_sock_t sock; pj_qos_params qos_params; sock = pjsip_udp_transport_get_socket(temp_state->state->transport); pj_sock_get_qos_params(sock, &qos_params); set_qos(transport, &qos_params); pj_sock_set_qos_params(sock, &qos_params); } } else if (transport->type == AST_TRANSPORT_TCP) { pjsip_tcp_transport_cfg cfg; pjsip_tcp_transport_cfg_default(&cfg, temp_state->state->host.addr.sa_family); cfg.bind_addr = temp_state->state->host; cfg.async_cnt = transport->async_operations; set_qos(transport, &cfg.qos_params); for (i = 0; i < BIND_TRIES && res != PJ_SUCCESS; i++) { if (perm_state && perm_state->state && perm_state->state->factory && perm_state->state->factory->destroy) { perm_state->state->factory->destroy(perm_state->state->factory); usleep(BIND_DELAY_US); } res = pjsip_tcp_transport_start3(ast_sip_get_pjsip_endpoint(), &cfg, &temp_state->state->factory); } } else if (transport->type == AST_TRANSPORT_TLS) { if (transport->async_operations > 1 && ast_compare_versions(pj_get_version(), "2.5.0") < 0) { ast_log(LOG_ERROR, "Transport: %s: When protocol=tls and pjproject version < 2.5.0, async_operations can't be > 1\n", ast_sorcery_object_get_id(obj)); return -1; } temp_state->state->tls.password = pj_str((char*)transport->password); set_qos(transport, &temp_state->state->tls.qos_params); for (i = 0; i < BIND_TRIES && res != PJ_SUCCESS; i++) { if (perm_state && perm_state->state && perm_state->state->factory && perm_state->state->factory->destroy) { perm_state->state->factory->destroy(perm_state->state->factory); usleep(BIND_DELAY_US); } res = pjsip_tls_transport_start2(ast_sip_get_pjsip_endpoint(), &temp_state->state->tls, &temp_state->state->host, NULL, transport->async_operations, &temp_state->state->factory); } } else if ((transport->type == AST_TRANSPORT_WS) || (transport->type == AST_TRANSPORT_WSS)) { if (transport->cos || transport->tos) { ast_log(LOG_WARNING, "TOS and COS values ignored for websocket transport\n"); } res = PJ_SUCCESS; } if (res != PJ_SUCCESS) { char msg[PJ_ERR_MSG_SIZE]; pj_strerror(res, msg, sizeof(msg)); ast_log(LOG_ERROR, "Transport '%s' could not be started: %s\n", ast_sorcery_object_get_id(obj), msg); return -1; } copy_state_to_transport(transport); if (perm_state) { ao2_unlink_flags(states, perm_state, OBJ_NOLOCK); } ao2_link_flags(states, temp_state, OBJ_NOLOCK); return 0; }