/* * List the ports in conference bridge */ static void ui_conf_list() { unsigned i, count; pjsua_conf_port_id id[PJSUA_MAX_CALLS]; printf("Conference ports:\n"); count = PJ_ARRAY_SIZE(id); pjsua_enum_conf_ports(id, &count); for (i=0; i<count; ++i) { char txlist[PJSUA_MAX_CALLS*4+10]; unsigned j; pjsua_conf_port_info info; pjsua_conf_get_port_info(id[i], &info); txlist[0] = '\0'; for (j=0; j<info.listener_cnt; ++j) { char s[10]; pj_ansi_snprintf(s, sizeof(s), "#%d ", info.listeners[j]); pj_ansi_strcat(txlist, s); } printf("Port #%02d[%2dKHz/%dms/%d] %20.*s transmitting to: %s\n", info.slot_id, info.clock_rate/1000, info.samples_per_frame*1000/info.channel_count/info.clock_rate, info.channel_count, (int)info.name.slen, info.name.ptr, txlist); } puts(""); }
/* * This is the public API to create, initialize, register, and start the * TCP listener. */ PJ_DEF(pj_status_t) pjsip_tcp_transport_start3( pjsip_endpoint *endpt, const pjsip_tcp_transport_cfg *cfg, pjsip_tpfactory **p_factory ) { pj_pool_t *pool; pj_sock_t sock = PJ_INVALID_SOCKET; struct tcp_listener *listener; pj_activesock_cfg asock_cfg; pj_activesock_cb listener_cb; pj_sockaddr *listener_addr; int addr_len; pj_status_t status; /* Sanity check */ PJ_ASSERT_RETURN(endpt && cfg->async_cnt, PJ_EINVAL); /* Verify that address given in a_name (if any) is valid */ if (cfg->addr_name.host.slen) { pj_sockaddr tmp; status = pj_sockaddr_init(cfg->af, &tmp, &cfg->addr_name.host, (pj_uint16_t)cfg->addr_name.port); if (status != PJ_SUCCESS || !pj_sockaddr_has_addr(&tmp) || (cfg->af==pj_AF_INET() && tmp.ipv4.sin_addr.s_addr==PJ_INADDR_NONE)) { /* Invalid address */ return PJ_EINVAL; } } pool = pjsip_endpt_create_pool(endpt, "tcplis", POOL_LIS_INIT, POOL_LIS_INC); PJ_ASSERT_RETURN(pool, PJ_ENOMEM); listener = PJ_POOL_ZALLOC_T(pool, struct tcp_listener); listener->factory.pool = pool; listener->factory.type = cfg->af==pj_AF_INET() ? PJSIP_TRANSPORT_TCP : PJSIP_TRANSPORT_TCP6; listener->factory.type_name = (char*) pjsip_transport_get_type_name(listener->factory.type); listener->factory.flag = pjsip_transport_get_flag_from_type(listener->factory.type); listener->qos_type = cfg->qos_type; pj_memcpy(&listener->qos_params, &cfg->qos_params, sizeof(cfg->qos_params)); pj_ansi_strcpy(listener->factory.obj_name, "tcplis"); if (listener->factory.type==PJSIP_TRANSPORT_TCP6) pj_ansi_strcat(listener->factory.obj_name, "6"); status = pj_lock_create_recursive_mutex(pool, listener->factory.obj_name, &listener->factory.lock); if (status != PJ_SUCCESS) goto on_error; /* Create socket */ status = pj_sock_socket(cfg->af, pj_SOCK_STREAM(), 0, &sock); if (status != PJ_SUCCESS) goto on_error; /* Apply QoS, if specified */ status = pj_sock_apply_qos2(sock, cfg->qos_type, &cfg->qos_params, 2, listener->factory.obj_name, "SIP TCP listener socket"); /* Bind address may be different than factory.local_addr because * factory.local_addr will be resolved below. */ pj_sockaddr_cp(&listener->bound_addr, &cfg->bind_addr); /* Bind socket */ listener_addr = &listener->factory.local_addr; pj_sockaddr_cp(listener_addr, &cfg->bind_addr); status = pj_sock_bind(sock, listener_addr, pj_sockaddr_get_len(listener_addr)); if (status != PJ_SUCCESS) goto on_error; /* Retrieve the bound address */ addr_len = pj_sockaddr_get_len(listener_addr); status = pj_sock_getsockname(sock, listener_addr, &addr_len); if (status != PJ_SUCCESS) goto on_error; /* If published host/IP is specified, then use that address as the * listener advertised address. */ if (cfg->addr_name.host.slen) { /* Copy the address */ listener->factory.addr_name = cfg->addr_name; pj_strdup(listener->factory.pool, &listener->factory.addr_name.host, &cfg->addr_name.host); listener->factory.addr_name.port = cfg->addr_name.port; } else { /* No published address is given, use the bound address */ /* If the address returns 0.0.0.0, use the default * interface address as the transport's address. */ if (!pj_sockaddr_has_addr(listener_addr)) { pj_sockaddr hostip; status = pj_gethostip(listener->bound_addr.addr.sa_family, &hostip); if (status != PJ_SUCCESS) goto on_error; pj_sockaddr_copy_addr(listener_addr, &hostip); } /* Save the address name */ sockaddr_to_host_port(listener->factory.pool, &listener->factory.addr_name, listener_addr); } /* If port is zero, get the bound port */ if (listener->factory.addr_name.port == 0) { listener->factory.addr_name.port = pj_sockaddr_get_port(listener_addr); } pj_ansi_snprintf(listener->factory.obj_name, sizeof(listener->factory.obj_name), "tcplis:%d", listener->factory.addr_name.port); /* Start listening to the address */ status = pj_sock_listen(sock, PJSIP_TCP_TRANSPORT_BACKLOG); if (status != PJ_SUCCESS) goto on_error; /* Create active socket */ pj_activesock_cfg_default(&asock_cfg); if (cfg->async_cnt > MAX_ASYNC_CNT) asock_cfg.async_cnt = MAX_ASYNC_CNT; else asock_cfg.async_cnt = cfg->async_cnt; pj_bzero(&listener_cb, sizeof(listener_cb)); listener_cb.on_accept_complete = &on_accept_complete; status = pj_activesock_create(pool, sock, pj_SOCK_STREAM(), &asock_cfg, pjsip_endpt_get_ioqueue(endpt), &listener_cb, listener, &listener->asock); /* Register to transport manager */ listener->endpt = endpt; listener->tpmgr = pjsip_endpt_get_tpmgr(endpt); listener->factory.create_transport = lis_create_transport; listener->factory.destroy = lis_destroy; listener->is_registered = PJ_TRUE; status = pjsip_tpmgr_register_tpfactory(listener->tpmgr, &listener->factory); if (status != PJ_SUCCESS) { listener->is_registered = PJ_FALSE; goto on_error; } /* Start pending accept() operations */ status = pj_activesock_start_accept(listener->asock, pool); if (status != PJ_SUCCESS) goto on_error; PJ_LOG(4,(listener->factory.obj_name, "SIP TCP listener ready for incoming connections at %.*s:%d", (int)listener->factory.addr_name.host.slen, listener->factory.addr_name.host.ptr, listener->factory.addr_name.port)); /* Return the pointer to user */ if (p_factory) *p_factory = &listener->factory; return PJ_SUCCESS; on_error: if (listener->asock==NULL && sock!=PJ_INVALID_SOCKET) pj_sock_close(sock); lis_destroy(&listener->factory); return status; }
/* * List the ports in conference bridge */ static void conf_list(pjmedia_conf *conf, int detail) { enum { MAX_PORTS = 32 }; unsigned i, count; pjmedia_conf_port_info info[MAX_PORTS]; printf("Conference ports:\n"); count = PJ_ARRAY_SIZE(info); pjmedia_conf_get_ports_info(conf, &count, info); for (i=0; i<count; ++i) { char txlist[4*MAX_PORTS]; unsigned j; pjmedia_conf_port_info *port_info = &info[i]; txlist[0] = '\0'; for (j=0; j<port_info->listener_cnt; ++j) { char s[10]; pj_ansi_sprintf(s, "#%d ", port_info->listener_slots[j]); pj_ansi_strcat(txlist, s); } if (txlist[0] == '\0') { txlist[0] = '-'; txlist[1] = '\0'; } if (!detail) { printf("Port #%02d %-25.*s transmitting to: %s\n", port_info->slot, (int)port_info->name.slen, port_info->name.ptr, txlist); } else { unsigned tx_level, rx_level; pjmedia_conf_get_signal_level(conf, port_info->slot, &tx_level, &rx_level); printf("Port #%02d:\n" " Name : %.*s\n" " Sampling rate : %d Hz\n" " Samples per frame : %d\n" " Frame time : %d ms\n" " Signal level adjustment : tx=%d, rx=%d\n" " Current signal level : tx=%u, rx=%u\n" " Transmitting to ports : %s\n\n", port_info->slot, (int)port_info->name.slen, port_info->name.ptr, port_info->clock_rate, port_info->samples_per_frame, port_info->samples_per_frame*1000/port_info->clock_rate, port_info->tx_adj_level, port_info->rx_adj_level, tx_level, rx_level, txlist); } } puts(""); }
PJ_DEF(pj_status_t) pjsip_tls_transport_start2( pjsip_endpoint *endpt, const pjsip_tls_setting *opt, const pj_sockaddr *local, const pjsip_host_port *a_name, unsigned async_cnt, pjsip_tpfactory **p_factory) { pj_pool_t *pool; pj_bool_t is_ipv6; int af; struct tls_listener *listener; pj_ssl_sock_param ssock_param; pj_sockaddr *listener_addr; pj_bool_t has_listener; pj_status_t status; /* Sanity check */ PJ_ASSERT_RETURN(endpt && async_cnt, PJ_EINVAL); is_ipv6 = (local && local->addr.sa_family == pj_AF_INET6()); af = is_ipv6 ? pj_AF_INET6() : pj_AF_INET(); /* Verify that address given in a_name (if any) is valid */ if (a_name && a_name->host.slen) { pj_sockaddr tmp; status = pj_sockaddr_init(af, &tmp, &a_name->host, (pj_uint16_t)a_name->port); if (status != PJ_SUCCESS || !pj_sockaddr_has_addr(&tmp) || (!is_ipv6 && tmp.ipv4.sin_addr.s_addr == PJ_INADDR_NONE)) { /* Invalid address */ return PJ_EINVAL; } } pool = pjsip_endpt_create_pool(endpt, "tlslis", POOL_LIS_INIT, POOL_LIS_INC); PJ_ASSERT_RETURN(pool, PJ_ENOMEM); listener = PJ_POOL_ZALLOC_T(pool, struct tls_listener); listener->factory.pool = pool; if (is_ipv6) listener->factory.type = PJSIP_TRANSPORT_TLS6; else listener->factory.type = PJSIP_TRANSPORT_TLS; listener->factory.type_name = (char*) pjsip_transport_get_type_name(listener->factory.type); listener->factory.flag = pjsip_transport_get_flag_from_type(listener->factory.type); pj_ansi_strcpy(listener->factory.obj_name, "tlslis"); if (is_ipv6) pj_ansi_strcat(listener->factory.obj_name, "6"); if (opt) pjsip_tls_setting_copy(pool, &listener->tls_setting, opt); else pjsip_tls_setting_default(&listener->tls_setting); status = pj_lock_create_recursive_mutex(pool, listener->factory.obj_name, &listener->factory.lock); if (status != PJ_SUCCESS) goto on_error; if (async_cnt > MAX_ASYNC_CNT) async_cnt = MAX_ASYNC_CNT; /* Build SSL socket param */ pj_ssl_sock_param_default(&ssock_param); ssock_param.sock_af = af; ssock_param.cb.on_accept_complete = &on_accept_complete; ssock_param.cb.on_data_read = &on_data_read; ssock_param.cb.on_data_sent = &on_data_sent; ssock_param.async_cnt = async_cnt; ssock_param.ioqueue = pjsip_endpt_get_ioqueue(endpt); ssock_param.require_client_cert = listener->tls_setting.require_client_cert; ssock_param.timeout = listener->tls_setting.timeout; ssock_param.user_data = listener; ssock_param.verify_peer = PJ_FALSE; /* avoid SSL socket closing the socket * due to verification error */ if (ssock_param.send_buffer_size < PJSIP_MAX_PKT_LEN) ssock_param.send_buffer_size = PJSIP_MAX_PKT_LEN; if (ssock_param.read_buffer_size < PJSIP_MAX_PKT_LEN) ssock_param.read_buffer_size = PJSIP_MAX_PKT_LEN; ssock_param.ciphers_num = listener->tls_setting.ciphers_num; ssock_param.ciphers = listener->tls_setting.ciphers; ssock_param.reuse_addr = listener->tls_setting.reuse_addr; ssock_param.qos_type = listener->tls_setting.qos_type; ssock_param.qos_ignore_error = listener->tls_setting.qos_ignore_error; pj_memcpy(&ssock_param.qos_params, &listener->tls_setting.qos_params, sizeof(ssock_param.qos_params)); has_listener = PJ_FALSE; switch(listener->tls_setting.method) { case PJSIP_TLSV1_METHOD: ssock_param.proto = PJ_SSL_SOCK_PROTO_TLS1; break; case PJSIP_SSLV2_METHOD: ssock_param.proto = PJ_SSL_SOCK_PROTO_SSL2; break; case PJSIP_SSLV3_METHOD: ssock_param.proto = PJ_SSL_SOCK_PROTO_SSL3; break; case PJSIP_SSLV23_METHOD: ssock_param.proto = PJ_SSL_SOCK_PROTO_SSL23; break; default: ssock_param.proto = PJ_SSL_SOCK_PROTO_DEFAULT; break; } /* Create SSL socket */ status = pj_ssl_sock_create(pool, &ssock_param, &listener->ssock); if (status != PJ_SUCCESS) goto on_error; /* Bind address may be different than factory.local_addr because * factory.local_addr will be resolved below. */ listener_addr = &listener->factory.local_addr; if (local) { pj_sockaddr_cp((pj_sockaddr_t*)listener_addr, (const pj_sockaddr_t*)local); pj_sockaddr_cp(&listener->bound_addr, local); } else { pj_sockaddr_init(af, listener_addr, NULL, 0); pj_sockaddr_init(af, &listener->bound_addr, NULL, 0); } /* Check if certificate/CA list for SSL socket is set */ if (listener->tls_setting.cert_file.slen || listener->tls_setting.ca_list_file.slen) { status = pj_ssl_cert_load_from_files(pool, &listener->tls_setting.ca_list_file, &listener->tls_setting.cert_file, &listener->tls_setting.privkey_file, &listener->tls_setting.password, &listener->cert); if (status != PJ_SUCCESS) goto on_error; status = pj_ssl_sock_set_certificate(listener->ssock, pool, listener->cert); if (status != PJ_SUCCESS) goto on_error; } /* Start accepting incoming connections. Note that some TLS/SSL backends * may not support for SSL socket server. */ has_listener = PJ_FALSE; status = pj_ssl_sock_start_accept(listener->ssock, pool, (pj_sockaddr_t*)listener_addr, pj_sockaddr_get_len((pj_sockaddr_t*)listener_addr)); if (status == PJ_SUCCESS || status == PJ_EPENDING) { pj_ssl_sock_info info; has_listener = PJ_TRUE; /* Retrieve the bound address */ status = pj_ssl_sock_get_info(listener->ssock, &info); if (status == PJ_SUCCESS) pj_sockaddr_cp(listener_addr, (pj_sockaddr_t*)&info.local_addr); } else if (status != PJ_ENOTSUP) { goto on_error; } /* If published host/IP is specified, then use that address as the * listener advertised address. */ if (a_name && a_name->host.slen) { /* Copy the address */ listener->factory.addr_name = *a_name; pj_strdup(listener->factory.pool, &listener->factory.addr_name.host, &a_name->host); listener->factory.addr_name.port = a_name->port; } else { /* No published address is given, use the bound address */ /* If the address returns 0.0.0.0, use the default * interface address as the transport's address. */ if (!pj_sockaddr_has_addr(listener_addr)) { pj_sockaddr hostip; status = pj_gethostip(af, &hostip); if (status != PJ_SUCCESS) goto on_error; pj_sockaddr_copy_addr(listener_addr, &hostip); } /* Save the address name */ sockaddr_to_host_port(listener->factory.pool, &listener->factory.addr_name, listener_addr); } /* If port is zero, get the bound port */ if (listener->factory.addr_name.port == 0) { listener->factory.addr_name.port = pj_sockaddr_get_port(listener_addr); } pj_ansi_snprintf(listener->factory.obj_name, sizeof(listener->factory.obj_name), "tlslis:%d", listener->factory.addr_name.port); /* Register to transport manager */ listener->endpt = endpt; listener->tpmgr = pjsip_endpt_get_tpmgr(endpt); listener->factory.create_transport2 = lis_create_transport; listener->factory.destroy = lis_destroy; listener->is_registered = PJ_TRUE; status = pjsip_tpmgr_register_tpfactory(listener->tpmgr, &listener->factory); if (status != PJ_SUCCESS) { listener->is_registered = PJ_FALSE; goto on_error; } if (has_listener) { PJ_LOG(4,(listener->factory.obj_name, "SIP TLS listener is ready for incoming connections " "at %.*s:%d", (int)listener->factory.addr_name.host.slen, listener->factory.addr_name.host.ptr, listener->factory.addr_name.port)); } else { PJ_LOG(4,(listener->factory.obj_name, "SIP TLS is ready " "(client only)")); } /* Return the pointer to user */ if (p_factory) *p_factory = &listener->factory; return PJ_SUCCESS; on_error: lis_destroy(&listener->factory); return status; }
static int init_options(int argc, char *argv[]) { struct pj_getopt_option long_options[] = { { "codec", 1, 0, OPT_CODEC }, { "input", 1, 0, OPT_INPUT }, { "output", 1, 0, OPT_OUTPUT }, { "duration", 1, 0, OPT_DURATION }, { "log-file", 1, 0, OPT_LOG_FILE}, { "loss", 1, 0, OPT_LOSS }, { "min-lost-burst", 1, 0, OPT_MIN_LOST_BURST}, { "max-lost-burst", 1, 0, OPT_MAX_LOST_BURST}, { "loss-corr", 1, 0, OPT_LOSS_CORR}, { "min-jitter", 1, 0, OPT_MIN_JITTER }, { "max-jitter", 1, 0, OPT_MAX_JITTER }, { "snd-burst", 1, 0, OPT_SND_BURST }, { "tx-ptime", 1, 0, OPT_TX_PTIME }, { "rx-ptime", 1, 0, OPT_RX_PTIME }, { "no-vad", 0, 0, OPT_NO_VAD }, { "no-plc", 0, 0, OPT_NO_PLC }, { "jb-prefetch", 0, 0, OPT_JB_PREFETCH }, { "jb-min-pre", 1, 0, OPT_JB_MIN_PRE }, { "jb-max-pre", 1, 0, OPT_JB_MAX_PRE }, { "jb-max", 1, 0, OPT_JB_MAX }, { "help", 0, 0, OPT_HELP}, { NULL, 0, 0, 0 }, }; int c; int option_index; char format[128]; /* Init default config */ g_app.cfg.codec = pj_str(CODEC); g_app.cfg.duration_msec = DURATION * 1000; g_app.cfg.silent = SILENT; g_app.cfg.log_file = LOG_FILE; g_app.cfg.tx_wav_in = WAV_REF; g_app.cfg.tx_ptime = 0; g_app.cfg.tx_min_jitter = 0; g_app.cfg.tx_max_jitter = 0; g_app.cfg.tx_dtx = DTX; g_app.cfg.tx_pct_avg_lost = 0; g_app.cfg.tx_min_lost_burst = MIN_LOST_BURST; g_app.cfg.tx_max_lost_burst = MAX_LOST_BURST; g_app.cfg.tx_pct_loss_corr = LOSS_CORR; g_app.cfg.rx_wav_out = WAV_OUT; g_app.cfg.rx_ptime = 0; g_app.cfg.rx_plc = PLC; g_app.cfg.rx_snd_burst = 1; g_app.cfg.rx_jb_init = -1; g_app.cfg.rx_jb_min_pre = -1; g_app.cfg.rx_jb_max_pre = -1; g_app.cfg.rx_jb_max = -1; /* Build format */ format[0] = '\0'; for (c=0; c<PJ_ARRAY_SIZE(long_options)-1; ++c) { if (long_options[c].has_arg) { char cmd[10]; pj_ansi_snprintf(cmd, sizeof(cmd), "%c:", long_options[c].val); pj_ansi_strcat(format, cmd); } } for (c=0; c<PJ_ARRAY_SIZE(long_options)-1; ++c) { if (long_options[c].has_arg == 0) { char cmd[10]; pj_ansi_snprintf(cmd, sizeof(cmd), "%c", long_options[c].val); pj_ansi_strcat(format, cmd); } } /* Parse options */ pj_optind = 0; while((c=pj_getopt_long(argc,argv, format, long_options, &option_index))!=-1) { switch (c) { case OPT_CODEC: g_app.cfg.codec = pj_str(pj_optarg); break; case OPT_INPUT: g_app.cfg.tx_wav_in = pj_optarg; break; case OPT_OUTPUT: g_app.cfg.rx_wav_out = pj_optarg; break; case OPT_DURATION: g_app.cfg.duration_msec = atoi(pj_optarg) * 1000; break; case OPT_LOG_FILE: g_app.cfg.log_file = pj_optarg; break; case OPT_LOSS: g_app.cfg.tx_pct_avg_lost = atoi(pj_optarg); if (g_app.cfg.tx_pct_avg_lost > 100) { puts("Error: Invalid loss value?"); return 1; } break; case OPT_MIN_LOST_BURST: g_app.cfg.tx_min_lost_burst = atoi(pj_optarg); break; case OPT_MAX_LOST_BURST: g_app.cfg.tx_max_lost_burst = atoi(pj_optarg); break; case OPT_LOSS_CORR: g_app.cfg.tx_pct_loss_corr = atoi(pj_optarg); if (g_app.cfg.tx_pct_avg_lost > 100) { puts("Error: Loss correlation is in percentage, value is not valid?"); return 1; } break; case OPT_MIN_JITTER: g_app.cfg.tx_min_jitter = atoi(pj_optarg); break; case OPT_MAX_JITTER: g_app.cfg.tx_max_jitter = atoi(pj_optarg); break; case OPT_SND_BURST: g_app.cfg.rx_snd_burst = atoi(pj_optarg); break; case OPT_TX_PTIME: g_app.cfg.tx_ptime = atoi(pj_optarg); break; case OPT_RX_PTIME: g_app.cfg.rx_ptime = atoi(pj_optarg); break; case OPT_NO_VAD: g_app.cfg.tx_dtx = PJ_FALSE; break; case OPT_NO_PLC: g_app.cfg.rx_plc = PJ_FALSE; break; case OPT_JB_PREFETCH: g_app.cfg.rx_jb_init = 1; break; case OPT_JB_MIN_PRE: g_app.cfg.rx_jb_min_pre = atoi(pj_optarg); break; case OPT_JB_MAX_PRE: g_app.cfg.rx_jb_max_pre = atoi(pj_optarg); break; case OPT_JB_MAX: g_app.cfg.rx_jb_max = atoi(pj_optarg); break; case OPT_HELP: usage(); return 1; default: usage(); return 1; } } /* Check for orphaned params */ if (pj_optind < argc) { usage(); return 1; } /* Normalize options */ if (g_app.cfg.rx_jb_init < g_app.cfg.rx_jb_min_pre) g_app.cfg.rx_jb_init = g_app.cfg.rx_jb_min_pre; else if (g_app.cfg.rx_jb_init > g_app.cfg.rx_jb_max_pre) g_app.cfg.rx_jb_init = g_app.cfg.rx_jb_max_pre; if (g_app.cfg.tx_max_jitter < g_app.cfg.tx_min_jitter) g_app.cfg.tx_max_jitter = g_app.cfg.tx_min_jitter; return 0; }