/* * Display program usage. */ static void icedemo_usage() { puts("Usage: icedemo [optons]"); printf("icedemo v%s by pjsip.org\n", pj_get_version()); puts(""); puts("General options:"); puts(" --comp-cnt, -c N Component count (default=1)"); puts(" --nameserver, -n IP Configure nameserver to activate DNS SRV"); puts(" resolution"); puts(" --max-host, -H N Set max number of host candidates to N"); puts(" --regular, -R Use regular nomination (default aggressive)"); puts(" --log-file, -L FILE Save output to log FILE"); puts(" --help, -h Display this screen."); puts(""); puts("STUN related options:"); puts(" --stun-srv, -s HOSTDOM Enable srflx candidate by resolving to STUN server."); puts(" HOSTDOM may be a \"host_or_ip[:port]\" or a domain"); puts(" name if DNS SRV resolution is used."); puts(""); puts("TURN related options:"); puts(" --turn-srv, -t HOSTDOM Enable relayed candidate by using this TURN server."); puts(" HOSTDOM may be a \"host_or_ip[:port]\" or a domain"); puts(" name if DNS SRV resolution is used."); puts(" --turn-tcp, -T Use TCP to connect to TURN server"); puts(" --turn-username, -u UID Set TURN username of the credential to UID"); puts(" --turn-password, -p PWD Set password of the credential to WPWD"); puts(" --turn-fingerprint, -F Use fingerprint for outgoing TURN requests"); puts(""); }
PJ_DEF(pj_status_t) pj_stun_session_create( pj_stun_config *cfg, const char *name, const pj_stun_session_cb *cb, pj_bool_t fingerprint, pj_stun_session **p_sess) { pj_pool_t *pool; pj_stun_session *sess; pj_status_t status; PJ_ASSERT_RETURN(cfg && cb && p_sess, PJ_EINVAL); if (name==NULL) name = "stuse%p"; pool = pj_pool_create(cfg->pf, name, PJNATH_POOL_LEN_STUN_SESS, PJNATH_POOL_INC_STUN_SESS, NULL); PJ_ASSERT_RETURN(pool, PJ_ENOMEM); sess = PJ_POOL_ZALLOC_T(pool, pj_stun_session); sess->cfg = cfg; sess->pool = pool; pj_memcpy(&sess->cb, cb, sizeof(*cb)); sess->use_fingerprint = fingerprint; sess->log_flag = 0xFFFF; sess->srv_name.ptr = (char*) pj_pool_alloc(pool, 32); sess->srv_name.slen = pj_ansi_snprintf(sess->srv_name.ptr, 32, "pjnath-%s", pj_get_version()); sess->rx_pool = pj_pool_create(sess->cfg->pf, name, PJNATH_POOL_LEN_STUN_TDATA, PJNATH_POOL_INC_STUN_TDATA, NULL); pj_list_init(&sess->pending_request_list); pj_list_init(&sess->cached_response_list); status = pj_lock_create_recursive_mutex(pool, name, &sess->lock); if (status != PJ_SUCCESS) { pj_pool_release(pool); return status; } sess->delete_lock = PJ_TRUE; status = pj_atomic_create(pool, 0, &sess->busy); if (status != PJ_SUCCESS) { pj_lock_destroy(sess->lock); pj_pool_release(pool); return status; } *p_sess = sess; return PJ_SUCCESS; }
static char *handle_pjsip_show_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { switch(cmd) { case CLI_INIT: e->command = "pjsip show version"; e->usage = "Usage: pjsip show version\n" " Show the version of pjproject that res_pjsip is running against\n"; return NULL; case CLI_GENERATE: return NULL; } ast_cli(a->fd, "PJPROJECT version currently running against: %s\n", pj_get_version()); return CLI_SUCCESS; }
/* Set default config. */ static void default_config(struct app_config *cfg) { char tmp[80]; unsigned i; pjsua_config_default(&cfg->cfg); pj_ansi_sprintf(tmp, "Sipek on PJSUA v%s/%s", pj_get_version(), PJ_OS_NAME); pj_strdup2_with_null(app_config.pool, &cfg->cfg.user_agent, tmp); pjsua_logging_config_default(&cfg->log_cfg); pjsua_media_config_default(&cfg->media_cfg); pjsua_transport_config_default(&cfg->udp_cfg); cfg->udp_cfg.port = 5060; pjsua_transport_config_default(&cfg->rtp_cfg); cfg->rtp_cfg.port = 4000; cfg->duration = NO_LIMIT; cfg->wav_id = PJSUA_INVALID_ID; cfg->rec_id = PJSUA_INVALID_ID; cfg->wav_port = PJSUA_INVALID_ID; cfg->rec_port = PJSUA_INVALID_ID; cfg->mic_level = cfg->speaker_level = 1.0; cfg->capture_dev = PJSUA_INVALID_ID; cfg->playback_dev = PJSUA_INVALID_ID; cfg->capture_lat = PJMEDIA_SND_DEFAULT_REC_LATENCY; cfg->playback_lat = PJMEDIA_SND_DEFAULT_PLAY_LATENCY; cfg->ringback_slot = PJSUA_INVALID_ID; cfg->ring_slot = PJSUA_INVALID_ID; for (i=0; i<PJ_ARRAY_SIZE(cfg->acc_cfg); ++i) pjsua_acc_config_default(&cfg->acc_cfg[i]); for (i=0; i<PJ_ARRAY_SIZE(cfg->buddy_cfg); ++i) pjsua_buddy_config_default(&cfg->buddy_cfg[i]); cfg->log_cfg.log_filename = pj_str("pjsip.log"); }
static void systest_display_settings(void) { pjmedia_aud_dev_info di; pj_size_t len = 0; enum gui_key key; test_item_t *ti; const char *title = "Audio Settings"; pj_status_t status; ti = systest_alloc_test_item(title); if (!ti) return; PJ_LOG(3,(THIS_FILE, "Running %s", title)); pj_ansi_snprintf(textbuf+len, sizeof(textbuf)-len, "Version: %s\r\n", pj_get_version()); len = strlen(textbuf); pj_ansi_snprintf(textbuf+len, sizeof(textbuf)-len, "Test clock rate: %d\r\n", systest.media_cfg.clock_rate); len = strlen(textbuf); pj_ansi_snprintf(textbuf+len, sizeof(textbuf)-len, "Device clock rate: %d\r\n", systest.media_cfg.snd_clock_rate); len = strlen(textbuf); pj_ansi_snprintf(textbuf+len, sizeof(textbuf)-len, "Aud frame ptime: %d\r\n", systest.media_cfg.audio_frame_ptime); len = strlen(textbuf); pj_ansi_snprintf(textbuf+len, sizeof(textbuf)-len, "Channel count: %d\r\n", systest.media_cfg.channel_count); len = strlen(textbuf); pj_ansi_snprintf(textbuf+len, sizeof(textbuf)-len, "Audio switching: %s\r\n", (PJMEDIA_CONF_USE_SWITCH_BOARD ? "Switchboard" : "Conf bridge")); len = strlen(textbuf); pj_ansi_snprintf(textbuf+len, sizeof(textbuf)-len, "Snd buff count: %d\r\n", PJMEDIA_SOUND_BUFFER_COUNT); len = strlen(textbuf); /* Capture device */ status = pjmedia_aud_dev_get_info(systest.rec_id, &di); if (status != PJ_SUCCESS) { systest_perror("Error querying device info", status); ti->success = PJ_FALSE; pj_strerror(status, ti->reason, sizeof(ti->reason)); return; } pj_ansi_snprintf(textbuf+len, sizeof(textbuf)-len, "Rec dev : %d (%s) [%s]\r\n", systest.rec_id, di.name, di.driver); len = strlen(textbuf); pj_ansi_snprintf(textbuf+len, sizeof(textbuf)-len, "Rec buf : %d msec\r\n", systest.media_cfg.snd_rec_latency); len = strlen(textbuf); /* Playback device */ status = pjmedia_aud_dev_get_info(systest.play_id, &di); if (status != PJ_SUCCESS) { systest_perror("Error querying device info", status); return; } pj_ansi_snprintf(textbuf+len, sizeof(textbuf)-len, "Play dev: %d (%s) [%s]\r\n", systest.play_id, di.name, di.driver); len = strlen(textbuf); pj_ansi_snprintf(textbuf+len, sizeof(textbuf)-len, "Play buf: %d msec\r\n", systest.media_cfg.snd_play_latency); len = strlen(textbuf); ti->success = PJ_TRUE; pj_ansi_strncpy(ti->reason, textbuf, sizeof(ti->reason)); ti->reason[sizeof(ti->reason)-1] = '\0'; key = gui_msgbox(title, textbuf, WITH_OK); PJ_UNUSED_ARG(key); /* Warning about unused var */ }
/*! \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; }
/* * Create server. */ PJ_DEF(pj_status_t) pj_turn_srv_create(pj_pool_factory *pf, pj_turn_srv **p_srv) { pj_pool_t *pool; pj_stun_session_cb sess_cb; pj_turn_srv *srv; unsigned i; pj_status_t status; PJ_ASSERT_RETURN(pf && p_srv, PJ_EINVAL); /* Create server and init core settings */ pool = pj_pool_create(pf, "srv%p", 1000, 1000, NULL); srv = PJ_POOL_ZALLOC_T(pool, pj_turn_srv); srv->obj_name = pool->obj_name; srv->core.pf = pf; srv->core.pool = pool; srv->core.tls_key = srv->core.tls_data = -1; /* Create ioqueue */ status = pj_ioqueue_create(pool, MAX_HANDLES, &srv->core.ioqueue); if (status != PJ_SUCCESS) goto on_error; /* Server mutex */ status = pj_lock_create_recursive_mutex(pool, srv->obj_name, &srv->core.lock); if (status != PJ_SUCCESS) goto on_error; /* Allocate TLS */ status = pj_thread_local_alloc(&srv->core.tls_key); if (status != PJ_SUCCESS) goto on_error; status = pj_thread_local_alloc(&srv->core.tls_data); if (status != PJ_SUCCESS) goto on_error; /* Create timer heap */ status = pj_timer_heap_create(pool, MAX_TIMER, &srv->core.timer_heap); if (status != PJ_SUCCESS) goto on_error; /* Configure lock for the timer heap */ pj_timer_heap_set_lock(srv->core.timer_heap, srv->core.lock, PJ_FALSE); /* Array of listeners */ srv->core.listener = (pj_turn_listener**) pj_pool_calloc(pool, MAX_LISTENERS, sizeof(srv->core.listener[0])); /* Create hash tables */ srv->tables.alloc = pj_hash_create(pool, MAX_CLIENTS); srv->tables.res = pj_hash_create(pool, MAX_CLIENTS); /* Init ports settings */ srv->ports.min_udp = srv->ports.next_udp = MIN_PORT; srv->ports.max_udp = MAX_PORT; srv->ports.min_tcp = srv->ports.next_tcp = MIN_PORT; srv->ports.max_tcp = MAX_PORT; /* Init STUN config */ pj_stun_config_init(&srv->core.stun_cfg, pf, 0, srv->core.ioqueue, srv->core.timer_heap); /* Init STUN credential */ srv->core.cred.type = PJ_STUN_AUTH_CRED_DYNAMIC; srv->core.cred.data.dyn_cred.user_data = srv; srv->core.cred.data.dyn_cred.get_auth = &pj_turn_get_auth; srv->core.cred.data.dyn_cred.get_password = &pj_turn_get_password; srv->core.cred.data.dyn_cred.verify_nonce = &pj_turn_verify_nonce; /* Create STUN session to handle new allocation */ pj_bzero(&sess_cb, sizeof(sess_cb)); sess_cb.on_rx_request = &on_rx_stun_request; sess_cb.on_send_msg = &on_tx_stun_msg; status = pj_stun_session_create(&srv->core.stun_cfg, srv->obj_name, &sess_cb, PJ_FALSE, NULL, &srv->core.stun_sess); if (status != PJ_SUCCESS) { goto on_error; } pj_stun_session_set_user_data(srv->core.stun_sess, srv); pj_stun_session_set_credential(srv->core.stun_sess, PJ_STUN_AUTH_LONG_TERM, &srv->core.cred); /* Array of worker threads */ srv->core.thread_cnt = MAX_THREADS; srv->core.thread = (pj_thread_t**) pj_pool_calloc(pool, srv->core.thread_cnt, sizeof(pj_thread_t*)); /* Start the worker threads */ for (i=0; i<srv->core.thread_cnt; ++i) { status = pj_thread_create(pool, srv->obj_name, &server_thread_proc, srv, 0, 0, &srv->core.thread[i]); if (status != PJ_SUCCESS) goto on_error; } /* We're done. Application should add listeners now */ PJ_LOG(4,(srv->obj_name, "TURN server v%s is running", pj_get_version())); *p_srv = srv; return PJ_SUCCESS; on_error: pj_turn_srv_destroy(srv); return status; }