void SipTransportBroker::findLocalAddressFromTransport(pjsip_transport *transport, pjsip_transport_type_e transportType, const std::string &host, std::string &addr, pj_uint16_t &port) const { // Initialize the sip port with the default SIP port port = pjsip_transport_get_default_port_for_type(transportType); // Initialize the sip address with the hostname const pj_str_t *pjMachineName = pj_gethostname(); addr = std::string(pjMachineName->ptr, pjMachineName->slen); // Update address and port with active transport RETURN_IF_NULL(transport, "Transport is NULL in findLocalAddress, using local address %s :%d", addr.c_str(), port); // get the transport manager associated with the SIP enpoint pjsip_tpmgr *tpmgr = pjsip_endpt_get_tpmgr(endpt_); RETURN_IF_NULL(tpmgr, "Transport manager is NULL in findLocalAddress, using local address %s :%d", addr.c_str(), port); pj_str_t pjstring; pj_cstr(&pjstring, host.c_str()); pjsip_tpselector tp_sel = getTransportSelector(transport); pjsip_tpmgr_fla2_param param = {transportType, &tp_sel, pjstring, PJ_FALSE, {nullptr, 0}, 0, nullptr}; if (pjsip_tpmgr_find_local_addr2(tpmgr, &pool_, ¶m) != PJ_SUCCESS) { WARN("Could not retrieve local address and port from transport, using %s :%d", addr.c_str(), port); return; } // Update local address based on the transport type addr = std::string(param.ret_addr.ptr, param.ret_addr.slen); // Determine the local port based on transport information port = param.ret_port; }
static pj_bool_t logging_on_rx_msg(pjsip_rx_data *rdata) { char local_buf[256]; char remote_buf[256]; char *uuid; struct hepv3_capture_info *capture_info; pjsip_tpmgr_fla2_param prm; capture_info = hepv3_create_capture_info(&rdata->pkt_info.packet, rdata->pkt_info.len); if (!capture_info) { return PJ_SUCCESS; } if (!rdata->pkt_info.src_addr_len) { return PJ_SUCCESS; } pj_sockaddr_print(&rdata->pkt_info.src_addr, remote_buf, sizeof(remote_buf), 3); /* Attempt to determine what IP address we probably received this packet on */ pjsip_tpmgr_fla2_param_default(&prm); prm.tp_type = rdata->tp_info.transport->key.type; pj_strset2(&prm.dst_host, rdata->pkt_info.src_name); prm.local_if = PJ_TRUE; /* If we can't get the local address use what we have already */ if (pjsip_tpmgr_find_local_addr2(pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()), rdata->tp_info.pool, &prm) != PJ_SUCCESS) { pj_sockaddr_print(&rdata->tp_info.transport->local_addr, local_buf, sizeof(local_buf), 3); } else { if (prm.tp_type & PJSIP_TRANSPORT_IPV6) { snprintf(local_buf, sizeof(local_buf), "[%.*s]:%hu", (int)pj_strlen(&prm.ret_addr), pj_strbuf(&prm.ret_addr), prm.ret_port); } else { snprintf(local_buf, sizeof(local_buf), "%.*s:%hu", (int)pj_strlen(&prm.ret_addr), pj_strbuf(&prm.ret_addr), prm.ret_port); } } uuid = assign_uuid(&rdata->msg_info.cid->id, &rdata->msg_info.to->tag, &rdata->msg_info.from->tag); if (!uuid) { ao2_ref(capture_info, -1); return PJ_SUCCESS; } ast_sockaddr_parse(&capture_info->src_addr, remote_buf, PARSE_PORT_REQUIRE); ast_sockaddr_parse(&capture_info->dst_addr, local_buf, PARSE_PORT_REQUIRE); capture_info->capture_time.tv_sec = rdata->pkt_info.timestamp.sec; capture_info->capture_time.tv_usec = rdata->pkt_info.timestamp.msec * 1000; capture_info->capture_type = HEPV3_CAPTURE_TYPE_SIP; capture_info->uuid = uuid; capture_info->zipped = 0; hepv3_send_packet(capture_info); return PJ_FALSE; }
SipTransportBroker::SipTransportBroker(pjsip_endpoint *endpt, pj_caching_pool& cp, pj_pool_t& pool) : cp_(cp), pool_(pool), endpt_(endpt) { instance = this; auto status = pjsip_tpmgr_set_state_cb(pjsip_endpt_get_tpmgr(endpt_), SipTransportBroker::tp_state_callback); if (status != PJ_SUCCESS) { ERROR("Can't set transport callback"); sip_utils::sip_strerror(status); } }
/* * pjsip_udp_transport_attach() * * Attach UDP socket and start transport. */ static pj_status_t transport_attach( pjsip_endpoint *endpt, pjsip_transport_type_e type, pj_sock_t sock, const pjsip_host_port *a_name, unsigned async_cnt, pjsip_transport **p_transport) { pj_pool_t *pool; struct udp_transport *tp; const char *format, *ipv6_quoteb, *ipv6_quotee; unsigned i; pj_status_t status; PJ_ASSERT_RETURN(endpt && sock!=PJ_INVALID_SOCKET && a_name && async_cnt>0, PJ_EINVAL); /* Object name. */ if (type & PJSIP_TRANSPORT_IPV6) { format = "udpv6%p"; ipv6_quoteb = "["; ipv6_quotee = "]"; } else { format = "udp%p"; ipv6_quoteb = ipv6_quotee = ""; } /* Create pool. */ pool = pjsip_endpt_create_pool(endpt, format, PJSIP_POOL_LEN_TRANSPORT, PJSIP_POOL_INC_TRANSPORT); if (!pool) return PJ_ENOMEM; /* Create the UDP transport object. */ tp = PJ_POOL_ZALLOC_T(pool, struct udp_transport); /* Save pool. */ tp->base.pool = pool; pj_memcpy(tp->base.obj_name, pool->obj_name, PJ_MAX_OBJ_NAME); /* Init reference counter. */ status = pj_atomic_create(pool, 0, &tp->base.ref_cnt); if (status != PJ_SUCCESS) goto on_error; /* Init lock. */ status = pj_lock_create_recursive_mutex(pool, pool->obj_name, &tp->base.lock); if (status != PJ_SUCCESS) goto on_error; /* Set type. */ tp->base.key.type = type; /* Remote address is left zero (except the family) */ tp->base.key.rem_addr.addr.sa_family = (pj_uint16_t) ((type & PJSIP_TRANSPORT_IPV6) ? pj_AF_INET6() : pj_AF_INET()); /* Type name. */ tp->base.type_name = "UDP"; /* Transport flag */ tp->base.flag = pjsip_transport_get_flag_from_type(type); /* Length of addressess. */ tp->base.addr_len = sizeof(tp->base.local_addr); /* Init local address. */ status = pj_sock_getsockname(sock, &tp->base.local_addr, &tp->base.addr_len); if (status != PJ_SUCCESS) goto on_error; /* Init remote name. */ if (type == PJSIP_TRANSPORT_UDP) tp->base.remote_name.host = pj_str("0.0.0.0"); else tp->base.remote_name.host = pj_str("::0"); tp->base.remote_name.port = 0; /* Init direction */ tp->base.dir = PJSIP_TP_DIR_NONE; /* Set endpoint. */ tp->base.endpt = endpt; /* Transport manager and timer will be initialized by tpmgr */ /* Attach socket and assign name. */ udp_set_socket(tp, sock, a_name); /* Register to ioqueue */ status = register_to_ioqueue(tp); if (status != PJ_SUCCESS) goto on_error; /* Set functions. */ tp->base.send_msg = &udp_send_msg; tp->base.do_shutdown = &udp_shutdown; tp->base.destroy = &udp_destroy; /* This is a permanent transport, so we initialize the ref count * to one so that transport manager don't destroy this transport * when there's no user! */ pj_atomic_inc(tp->base.ref_cnt); /* Register to transport manager. */ tp->base.tpmgr = pjsip_endpt_get_tpmgr(endpt); status = pjsip_transport_register( tp->base.tpmgr, (pjsip_transport*)tp); if (status != PJ_SUCCESS) goto on_error; /* Create rdata and put it in the array. */ tp->rdata_cnt = 0; tp->rdata = (pjsip_rx_data**) pj_pool_calloc(tp->base.pool, async_cnt, sizeof(pjsip_rx_data*)); for (i=0; i<async_cnt; ++i) { pj_pool_t *rdata_pool = pjsip_endpt_create_pool(endpt, "rtd%p", PJSIP_POOL_RDATA_LEN, PJSIP_POOL_RDATA_INC); if (!rdata_pool) { pj_atomic_set(tp->base.ref_cnt, 0); pjsip_transport_destroy(&tp->base); return PJ_ENOMEM; } init_rdata(tp, i, rdata_pool, NULL); tp->rdata_cnt++; } /* Start reading the ioqueue. */ status = start_async_read(tp); if (status != PJ_SUCCESS) { pjsip_transport_destroy(&tp->base); return status; } /* Done. */ if (p_transport) *p_transport = &tp->base; PJ_LOG(4,(tp->base.obj_name, "SIP %s started, published address is %s%.*s%s:%d", pjsip_transport_get_type_desc((pjsip_transport_type_e)tp->base.key.type), ipv6_quoteb, (int)tp->base.local_name.host.slen, tp->base.local_name.host.ptr, ipv6_quotee, tp->base.local_name.port)); return PJ_SUCCESS; on_error: udp_destroy((pjsip_transport*)tp); return status; }
/* * 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; }
pj_status_t ConnectionPool::create_connection(int hash_slot) { // Resolve the target host to an IP address. pj_sockaddr remote_addr; pj_status_t status = resolve_host(&_target.host, _target.port, &remote_addr); if (status != PJ_SUCCESS) { TRC_ERROR("Failed to resolve %.*s to an IP address - %s", _target.host.slen, _target.host.ptr, PJUtils::pj_status_to_string(status).c_str()); return status; } // Call TPMGR to create a new transport connection. pjsip_transport* tp; pjsip_tpselector tp_sel; tp_sel.type = PJSIP_TPSELECTOR_LISTENER; tp_sel.u.listener = _tpfactory; status = pjsip_tpmgr_acquire_transport(pjsip_endpt_get_tpmgr(_endpt), (remote_addr.addr.sa_family == pj_AF_INET6()) ? PJSIP_TRANSPORT_TCP6 : PJSIP_TRANSPORT_TCP, &remote_addr, (remote_addr.addr.sa_family == pj_AF_INET6()) ? sizeof(pj_sockaddr_in6) : sizeof(pj_sockaddr_in), &tp_sel, &tp); if (status != PJ_SUCCESS) { return status; } // TPMGR will have already added a reference to the new transport to stop it // being destroyed while we have pointers referencing it. TRC_DEBUG("Created transport %s in slot %d (%.*s:%d to %.*s:%d)", tp->obj_name, hash_slot, (int)tp->local_name.host.slen, tp->local_name.host.ptr, tp->local_name.port, (int)tp->remote_name.host.slen, tp->remote_name.host.ptr, tp->remote_name.port); // Register for transport state callbacks. pjsip_tp_state_listener_key* key; status = pjsip_transport_add_state_listener(tp, &transport_state, (void*)this, &key); // Store the new transport in the hash slot, but marked as disconnected. pthread_mutex_lock(&_tp_hash_lock); _tp_hash[hash_slot].tp = tp; _tp_hash[hash_slot].listener_key = key; _tp_hash[hash_slot].connected = PJ_FALSE; _tp_map[tp] = hash_slot; // Don't increment the connection count here, wait until we get confirmation // that the transport is connected. pthread_mutex_unlock(&_tp_hash_lock); return PJ_SUCCESS; }
static pj_status_t multihomed_on_tx_message(pjsip_tx_data *tdata) { pjsip_tpmgr_fla2_param prm; pjsip_transport *transport = NULL; pjsip_cseq_hdr *cseq; pjsip_via_hdr *via; /* Use the destination information to determine what local interface this message will go out on */ pjsip_tpmgr_fla2_param_default(&prm); prm.tp_type = tdata->tp_info.transport->key.type; pj_strset2(&prm.dst_host, tdata->tp_info.dst_name); prm.local_if = PJ_TRUE; /* If we can't get the local address use best effort and let it pass */ if (pjsip_tpmgr_find_local_addr2(pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()), tdata->pool, &prm) != PJ_SUCCESS) { return PJ_SUCCESS; } /* If the transport it is going out on is different reflect it in the message */ if (tdata->tp_info.transport->key.type == PJSIP_TRANSPORT_UDP || tdata->tp_info.transport->key.type == PJSIP_TRANSPORT_UDP6) { transport = multihomed_get_udp_transport(&prm.ret_addr, prm.ret_port); } /* If no new transport use the one provided by the message */ if (!transport) { transport = tdata->tp_info.transport; } /* If the message should not be rewritten then abort early */ if (!multihomed_rewrite_header(&prm.ret_addr, transport)) { return PJ_SUCCESS; } /* Update the transport in case it has changed - we do this now in case we don't want to touch the message above */ tdata->tp_info.transport = transport; /* If the message needs to be updated with new address do so */ if (tdata->msg->type == PJSIP_REQUEST_MSG || !(cseq = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL)) || pj_strcmp2(&cseq->method.name, "REGISTER")) { pjsip_contact_hdr *contact = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CONTACT, NULL); if (contact && (PJSIP_URI_SCHEME_IS_SIP(contact->uri) || PJSIP_URI_SCHEME_IS_SIPS(contact->uri))) { pjsip_sip_uri *uri = pjsip_uri_get_uri(contact->uri); /* prm.ret_addr is allocated from the tdata pool so it is perfectly fine to just do an assignment like this */ pj_strassign(&uri->host, &prm.ret_addr); uri->port = prm.ret_port; pjsip_tx_data_invalidate_msg(tdata); } } if (tdata->msg->type == PJSIP_REQUEST_MSG && (via = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL))) { pj_strassign(&via->sent_by.host, &prm.ret_addr); via->sent_by.port = prm.ret_port; pjsip_tx_data_invalidate_msg(tdata); } /* Update the SDP if it is present */ if (tdata->msg->body && ast_sip_is_content_type(&tdata->msg->body->content_type, "application", "sdp") && multihomed_rewrite_sdp(tdata->msg->body->data)) { struct pjmedia_sdp_session *sdp = tdata->msg->body->data; int stream; pj_strassign(&sdp->conn->addr, &prm.ret_addr); for (stream = 0; stream < sdp->media_count; ++stream) { if (sdp->media[stream]->conn) { pj_strassign(&sdp->media[stream]->conn->addr, &prm.ret_addr); } } pjsip_tx_data_invalidate_msg(tdata); } return PJ_SUCCESS; }
/*! * \brief Create a pjsip transport. */ static int transport_create(void *data) { struct transport_create_data *create_data = data; struct ws_transport *newtransport = NULL; pjsip_endpoint *endpt = ast_sip_get_pjsip_endpoint(); struct pjsip_tpmgr *tpmgr = pjsip_endpt_get_tpmgr(endpt); pj_pool_t *pool; pj_str_t buf; pj_status_t status; newtransport = ao2_t_alloc_options(sizeof(*newtransport), transport_dtor, AO2_ALLOC_OPT_LOCK_NOLOCK, "pjsip websocket transport"); if (!newtransport) { ast_log(LOG_ERROR, "Failed to allocate WebSocket transport.\n"); goto on_error; } newtransport->transport.endpt = endpt; if (!(pool = pjsip_endpt_create_pool(endpt, "ws", 512, 512))) { ast_log(LOG_ERROR, "Failed to allocate WebSocket endpoint pool.\n"); goto on_error; } newtransport->transport.pool = pool; newtransport->ws_session = create_data->ws_session; /* Keep the session until transport dies */ ast_websocket_ref(newtransport->ws_session); status = pj_atomic_create(pool, 0, &newtransport->transport.ref_cnt); if (status != PJ_SUCCESS) { goto on_error; } status = pj_lock_create_recursive_mutex(pool, pool->obj_name, &newtransport->transport.lock); if (status != PJ_SUCCESS) { goto on_error; } pj_sockaddr_parse(pj_AF_UNSPEC(), 0, pj_cstr(&buf, ast_sockaddr_stringify(ast_websocket_remote_address(newtransport->ws_session))), &newtransport->transport.key.rem_addr); newtransport->transport.key.rem_addr.addr.sa_family = pj_AF_INET(); newtransport->transport.key.type = ast_websocket_is_secure(newtransport->ws_session) ? transport_type_wss : transport_type_ws; newtransport->transport.addr_len = pj_sockaddr_get_len(&newtransport->transport.key.rem_addr); pj_sockaddr_cp(&newtransport->transport.local_addr, &newtransport->transport.key.rem_addr); newtransport->transport.local_name.host.ptr = (char *)pj_pool_alloc(pool, newtransport->transport.addr_len+4); pj_sockaddr_print(&newtransport->transport.key.rem_addr, newtransport->transport.local_name.host.ptr, newtransport->transport.addr_len+4, 0); newtransport->transport.local_name.host.slen = pj_ansi_strlen(newtransport->transport.local_name.host.ptr); newtransport->transport.local_name.port = pj_sockaddr_get_port(&newtransport->transport.key.rem_addr); newtransport->transport.type_name = (char *)pjsip_transport_get_type_name(newtransport->transport.key.type); newtransport->transport.flag = pjsip_transport_get_flag_from_type((pjsip_transport_type_e)newtransport->transport.key.type); newtransport->transport.info = (char *)pj_pool_alloc(newtransport->transport.pool, 64); newtransport->transport.tpmgr = tpmgr; newtransport->transport.send_msg = &ws_send_msg; newtransport->transport.destroy = &ws_destroy; status = pjsip_transport_register(newtransport->transport.tpmgr, (pjsip_transport *)newtransport); if (status != PJ_SUCCESS) { goto on_error; } /* Add a reference for pjsip transport manager */ ao2_ref(newtransport, +1); newtransport->rdata.tp_info.transport = &newtransport->transport; newtransport->rdata.tp_info.pool = pjsip_endpt_create_pool(endpt, "rtd%p", PJSIP_POOL_RDATA_LEN, PJSIP_POOL_RDATA_INC); if (!newtransport->rdata.tp_info.pool) { ast_log(LOG_ERROR, "Failed to allocate WebSocket rdata.\n"); pjsip_transport_destroy((pjsip_transport *)newtransport); goto on_error; } create_data->transport = newtransport; return 0; on_error: ao2_cleanup(newtransport); return -1; }
pj_status_t ConnectionPool::create_connection(int hash_slot) { // Resolve the target host to an IP address. pj_sockaddr remote_addr; pj_status_t status = resolve_host(&_target.host, &remote_addr); if (status != PJ_SUCCESS) { LOG_ERROR("Failed to resolve %.*s to an IP address - %s", _target.host.slen, _target.host.ptr, PJUtils::pj_status_to_string(status).c_str()); return status; } pj_sockaddr_set_port(&remote_addr, _target.port); // Call the factory to create a new transport connection. pjsip_transport* tp; status = _tpfactory->create_transport(_tpfactory, pjsip_endpt_get_tpmgr(_endpt), _endpt, &remote_addr, sizeof(pj_sockaddr_in), &tp); if (status != PJ_SUCCESS) { return status; } // Add a reference to the new transport to stop it being destroyed while we // have pointers referencing it. pjsip_transport_add_ref(tp); LOG_DEBUG("Created transport %s in slot %d (%.*s:%d to %.*s:%d)", tp->obj_name, hash_slot, (int)tp->local_name.host.slen, tp->local_name.host.ptr, tp->local_name.port, (int)tp->remote_name.host.slen, tp->remote_name.host.ptr, tp->remote_name.port); // Register for transport state callbacks. pjsip_tp_state_listener_key* key; status = pjsip_transport_add_state_listener(tp, &transport_state, (void*)this, &key); // Store the new transport in the hash slot, but marked as disconnected. pthread_mutex_lock(&_tp_hash_lock); _tp_hash[hash_slot].tp = tp; _tp_hash[hash_slot].state = PJSIP_TP_STATE_DISCONNECTED; _tp_map[tp] = hash_slot; // Don't increment the connection count here, wait until we get confirmation // that the transport is connected. pthread_mutex_unlock(&_tp_hash_lock); return PJ_SUCCESS; }
SipTransportBroker::~SipTransportBroker() { instance = nullptr; pjsip_tpmgr_set_state_cb(pjsip_endpt_get_tpmgr(endpt_), nullptr); }
static pj_status_t multihomed_on_tx_message(pjsip_tx_data *tdata) { pjsip_tpmgr_fla2_param prm; pjsip_cseq_hdr *cseq; pjsip_via_hdr *via; /* Use the destination information to determine what local interface this message will go out on */ pjsip_tpmgr_fla2_param_default(&prm); prm.tp_type = tdata->tp_info.transport->key.type; pj_strset2(&prm.dst_host, tdata->tp_info.dst_name); prm.local_if = PJ_TRUE; /* If we can't get the local address use best effort and let it pass */ if (pjsip_tpmgr_find_local_addr2(pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()), tdata->pool, &prm) != PJ_SUCCESS) { return PJ_SUCCESS; } /* The port in the message should always be that of the original transport */ prm.ret_port = tdata->tp_info.transport->local_name.port; /* If the IP source differs from the existing transport see if we need to update it */ if (pj_strcmp(&prm.ret_addr, &tdata->tp_info.transport->local_name.host)) { /* If the transport it is going out on is different reflect it in the message */ if (tdata->tp_info.transport->key.type == PJSIP_TRANSPORT_UDP || tdata->tp_info.transport->key.type == PJSIP_TRANSPORT_UDP6) { pjsip_transport *transport; transport = multihomed_get_udp_transport(&prm.ret_addr, prm.ret_port); if (transport) { tdata->tp_info.transport = transport; } } /* If the chosen transport is not bound to any we can't use the source address as it won't get back to us */ if (!multihomed_bound_any(tdata->tp_info.transport)) { pj_strassign(&prm.ret_addr, &tdata->tp_info.transport->local_name.host); } } else { /* The transport chosen will deliver this but ensure it is updated with the right information */ pj_strassign(&prm.ret_addr, &tdata->tp_info.transport->local_name.host); } /* If the message needs to be updated with new address do so */ if (tdata->msg->type == PJSIP_REQUEST_MSG || !(cseq = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL)) || pj_strcmp2(&cseq->method.name, "REGISTER")) { pjsip_contact_hdr *contact = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CONTACT, NULL); if (contact && (PJSIP_URI_SCHEME_IS_SIP(contact->uri) || PJSIP_URI_SCHEME_IS_SIPS(contact->uri)) && !(tdata->msg->type == PJSIP_RESPONSE_MSG && tdata->msg->line.status.code / 100 == 3)) { pjsip_sip_uri *uri = pjsip_uri_get_uri(contact->uri); /* prm.ret_addr is allocated from the tdata pool OR the transport so it is perfectly fine to just do an assignment like this */ pj_strassign(&uri->host, &prm.ret_addr); uri->port = prm.ret_port; ast_debug(4, "Re-wrote Contact URI host/port to %.*s:%d\n", (int)pj_strlen(&uri->host), pj_strbuf(&uri->host), uri->port); pjsip_tx_data_invalidate_msg(tdata); } } if (tdata->msg->type == PJSIP_REQUEST_MSG && (via = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL))) { pj_strassign(&via->sent_by.host, &prm.ret_addr); via->sent_by.port = prm.ret_port; pjsip_tx_data_invalidate_msg(tdata); } /* Update the SDP if it is present */ if (tdata->msg->body && ast_sip_is_content_type(&tdata->msg->body->content_type, "application", "sdp") && multihomed_rewrite_sdp(tdata->msg->body->data)) { struct pjmedia_sdp_session *sdp = tdata->msg->body->data; int stream; pj_strassign(&sdp->conn->addr, &prm.ret_addr); for (stream = 0; stream < sdp->media_count; ++stream) { if (sdp->media[stream]->conn) { pj_strassign(&sdp->media[stream]->conn->addr, &prm.ret_addr); } } pjsip_tx_data_invalidate_msg(tdata); } return PJ_SUCCESS; }
/* * This is the public API to create, initialize, register, and start the * TCP listener. */ PJ_DEF(pj_status_t) pjsip_tcp_transport_start2(pjsip_endpoint *endpt, const pj_sockaddr_in *local, const pjsip_host_port *a_name, unsigned async_cnt, 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_in *listener_addr; int addr_len; pj_status_t status; /* Sanity check */ PJ_ASSERT_RETURN(endpt && async_cnt, PJ_EINVAL); /* Verify that address given in a_name (if any) is valid */ if (a_name && a_name->host.slen) { pj_sockaddr_in tmp; status = pj_sockaddr_in_init(&tmp, &a_name->host, (pj_uint16_t)a_name->port); if (status != PJ_SUCCESS || tmp.sin_addr.s_addr == PJ_INADDR_ANY || tmp.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 = PJSIP_TRANSPORT_TCP; listener->factory.type_name = "tcp"; listener->factory.flag = pjsip_transport_get_flag_from_type(PJSIP_TRANSPORT_TCP); pj_ansi_strcpy(listener->factory.obj_name, "tcplis"); status = pj_lock_create_recursive_mutex(pool, "tcplis", &listener->factory.lock); if (status != PJ_SUCCESS) goto on_error; /* Create and bind socket */ status = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0, &sock); if (status != PJ_SUCCESS) goto on_error; listener_addr = (pj_sockaddr_in*)&listener->factory.local_addr; if (local) { pj_memcpy(listener_addr, local, sizeof(pj_sockaddr_in)); } else { pj_sockaddr_in_init(listener_addr, NULL, 0); } status = pj_sock_bind(sock, listener_addr, sizeof(pj_sockaddr_in)); if (status != PJ_SUCCESS) goto on_error; /* Retrieve the bound address */ addr_len = sizeof(pj_sockaddr_in); 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 (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 (listener_addr->sin_addr.s_addr == 0) { pj_sockaddr hostip; status = pj_gethostip(pj_AF_INET(), &hostip); if (status != PJ_SUCCESS) goto on_error; listener_addr->sin_addr.s_addr = hostip.ipv4.sin_addr.s_addr; } /* 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_ntohs(listener_addr->sin_port); } 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 */ if (async_cnt > MAX_ASYNC_CNT) async_cnt = MAX_ASYNC_CNT; pj_activesock_cfg_default(&asock_cfg); asock_cfg.async_cnt = 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; }
SipIceTransport::SipIceTransport(pjsip_endpoint* endpt, pj_pool_t& /* pool */, long /* t_type */, const std::shared_ptr<IceTransport>& ice, int comp_id) : pool_(nullptr, pj_pool_release) , rxPool_(nullptr, pj_pool_release) , trData_() , rdata_() , ice_(ice) , comp_id_(comp_id) { trData_.self = this; if (not ice or not ice->isRunning()) throw std::logic_error("ice transport must exist and negotiation completed"); RING_DBG("SipIceTransport@%p {tr=%p}", this, &trData_.base); auto& base = trData_.base; pool_.reset(pjsip_endpt_create_pool(endpt, "SipIceTransport.pool", POOL_TP_INIT, POOL_TP_INC)); if (not pool_) throw std::bad_alloc(); auto pool = pool_.get(); pj_ansi_snprintf(base.obj_name, PJ_MAX_OBJ_NAME, "SipIceTransport"); base.endpt = endpt; base.tpmgr = pjsip_endpt_get_tpmgr(endpt); base.pool = pool; rdata_.tp_info.pool = pool; // FIXME: not destroyed in case of exception if (pj_atomic_create(pool, 0, &base.ref_cnt) != PJ_SUCCESS) throw std::runtime_error("Can't create PJSIP atomic."); // FIXME: not destroyed in case of exception if (pj_lock_create_recursive_mutex(pool, "SipIceTransport.mutex", &base.lock) != PJ_SUCCESS) throw std::runtime_error("Can't create PJSIP mutex."); auto remote = ice->getRemoteAddress(comp_id); RING_DBG("SipIceTransport: remote is %s", remote.toString(true).c_str()); pj_sockaddr_cp(&base.key.rem_addr, remote.pjPtr()); base.key.type = PJSIP_TRANSPORT_UDP;//t_type; base.type_name = (char*)pjsip_transport_get_type_name((pjsip_transport_type_e)base.key.type); base.flag = pjsip_transport_get_flag_from_type((pjsip_transport_type_e)base.key.type); base.info = (char*) pj_pool_alloc(pool, TRANSPORT_INFO_LENGTH); char print_addr[PJ_INET6_ADDRSTRLEN+10]; pj_ansi_snprintf(base.info, TRANSPORT_INFO_LENGTH, "%s to %s", base.type_name, pj_sockaddr_print(remote.pjPtr(), print_addr, sizeof(print_addr), 3)); base.addr_len = remote.getLength(); base.dir = PJSIP_TP_DIR_NONE;//is_server? PJSIP_TP_DIR_INCOMING : PJSIP_TP_DIR_OUTGOING; base.data = nullptr; /* Set initial local address */ auto local = ice->getDefaultLocalAddress(); pj_sockaddr_cp(&base.local_addr, local.pjPtr()); sockaddr_to_host_port(pool, &base.local_name, &base.local_addr); sockaddr_to_host_port(pool, &base.remote_name, remote.pjPtr()); base.send_msg = [](pjsip_transport *transport, pjsip_tx_data *tdata, const pj_sockaddr_t *rem_addr, int addr_len, void *token, pjsip_transport_callback callback) { auto& this_ = reinterpret_cast<TransportData*>(transport)->self; return this_->send(tdata, rem_addr, addr_len, token, callback); }; base.do_shutdown = [](pjsip_transport *transport) -> pj_status_t { auto& this_ = reinterpret_cast<TransportData*>(transport)->self; RING_WARN("SipIceTransport@%p: shutdown", this_); return PJ_SUCCESS; }; base.destroy = [](pjsip_transport *transport) -> pj_status_t { auto& this_ = reinterpret_cast<TransportData*>(transport)->self; RING_WARN("SipIceTransport@%p: destroy", this_); delete this_; return PJ_SUCCESS; }; /* Init rdata */ rxPool_.reset(pjsip_endpt_create_pool(base.endpt, "SipIceTransport.rtd%p", PJSIP_POOL_RDATA_LEN, PJSIP_POOL_RDATA_INC)); if (not rxPool_) throw std::bad_alloc(); auto rx_pool = rxPool_.get(); rdata_.tp_info.pool = rx_pool; rdata_.tp_info.transport = &base; rdata_.tp_info.tp_data = this; rdata_.tp_info.op_key.rdata = &rdata_; pj_ioqueue_op_key_init(&rdata_.tp_info.op_key.op_key, sizeof(pj_ioqueue_op_key_t)); rdata_.pkt_info.src_addr = base.key.rem_addr; rdata_.pkt_info.src_addr_len = sizeof(rdata_.pkt_info.src_addr); auto rem_addr = &base.key.rem_addr; pj_sockaddr_print(rem_addr, rdata_.pkt_info.src_name, sizeof(rdata_.pkt_info.src_name), 0); rdata_.pkt_info.src_port = pj_sockaddr_get_port(rem_addr); rdata_.pkt_info.len = 0; rdata_.pkt_info.zero = 0; if (pjsip_transport_register(base.tpmgr, &base) != PJ_SUCCESS) throw std::runtime_error("Can't register PJSIP transport."); is_registered_ = true; Manager::instance().registerEventHandler((uintptr_t)this, [this]{ loop(); }); }
/* * This is the public API to create, initialize, register, and start the * TLS listener. */ PJ_DEF(pj_status_t) pjsip_tls_transport_start (pjsip_endpoint *endpt, const pjsip_tls_setting *opt, const pj_sockaddr_in *local, const pjsip_host_port *a_name, unsigned async_cnt, pjsip_tpfactory **p_factory) { pj_pool_t *pool; struct tls_listener *listener; pj_ssl_sock_param ssock_param; pj_sockaddr_in *listener_addr; pj_bool_t has_listener; pj_status_t status; /* Sanity check */ PJ_ASSERT_RETURN(endpt && async_cnt, PJ_EINVAL); /* Verify that address given in a_name (if any) is valid */ if (a_name && a_name->host.slen) { pj_sockaddr_in tmp; status = pj_sockaddr_in_init(&tmp, &a_name->host, (pj_uint16_t)a_name->port); if (status != PJ_SUCCESS || tmp.sin_addr.s_addr == PJ_INADDR_ANY || tmp.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; listener->factory.type = PJSIP_TRANSPORT_TLS; listener->factory.type_name = "tls"; listener->factory.flag = pjsip_transport_get_flag_from_type(PJSIP_TRANSPORT_TLS); pj_ansi_strcpy(listener->factory.obj_name, "tlslis"); 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, "tlslis", &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.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.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; listener_addr = (pj_sockaddr_in*)&listener->factory.local_addr; if (local) { pj_sockaddr_cp((pj_sockaddr_t*)listener_addr, (const pj_sockaddr_t*)local); } else { pj_sockaddr_in_init(listener_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 (listener_addr->sin_addr.s_addr == 0) { pj_sockaddr hostip; status = pj_gethostip(pj_AF_INET(), &hostip); if (status != PJ_SUCCESS) goto on_error; listener_addr->sin_addr.s_addr = hostip.ipv4.sin_addr.s_addr; } /* 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_ntohs(listener_addr->sin_port); } 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; }
/* Start loop transport. */ PJ_DEF(pj_status_t) pjsip_loop_start( pjsip_endpoint *endpt, pjsip_transport **transport) { pj_pool_t *pool; struct loop_transport *loop; pj_status_t status; /* Create pool. */ pool = pjsip_endpt_create_pool(endpt, "loop", 4000, 4000); if (!pool) return PJ_ENOMEM; /* Create the loop structure. */ loop = pj_pool_zalloc(pool, sizeof(struct loop_transport)); /* Initialize transport properties. */ pj_ansi_snprintf(loop->base.obj_name, sizeof(loop->base.obj_name), "loop%p", loop); loop->base.pool = pool; status = pj_atomic_create(pool, 0, &loop->base.ref_cnt); if (status != PJ_SUCCESS) goto on_error; status = pj_lock_create_recursive_mutex(pool, "loop", &loop->base.lock); if (status != PJ_SUCCESS) goto on_error; loop->base.key.type = PJSIP_TRANSPORT_LOOP_DGRAM; //loop->base.key.rem_addr.sa_family = PJ_AF_INET; loop->base.type_name = "LOOP-DGRAM"; loop->base.info = "LOOP-DGRAM"; loop->base.flag = PJSIP_TRANSPORT_DATAGRAM; loop->base.local_name.host = pj_str(ADDR_LOOP_DGRAM); loop->base.local_name.port = pjsip_transport_get_default_port_for_type(loop->base.key.type); loop->base.addr_len = sizeof(pj_sockaddr_in); loop->base.endpt = endpt; loop->base.tpmgr = pjsip_endpt_get_tpmgr(endpt); loop->base.send_msg = &loop_send_msg; loop->base.destroy = &loop_destroy; pj_list_init(&loop->recv_list); pj_list_init(&loop->send_list); /* Create worker thread. */ status = pj_thread_create(pool, "loop", &loop_transport_worker_thread, loop, 0, PJ_THREAD_SUSPENDED, &loop->thread); if (status != PJ_SUCCESS) goto on_error; /* Register to transport manager. */ status = pjsip_transport_register( loop->base.tpmgr, &loop->base); if (status != PJ_SUCCESS) goto on_error; /* Start the thread. */ status = pj_thread_resume(loop->thread); if (status != PJ_SUCCESS) goto on_error; /* * Done. */ if (transport) *transport = &loop->base; return PJ_SUCCESS; on_error: if (loop->base.lock) pj_lock_destroy(loop->base.lock); if (loop->thread) pj_thread_destroy(loop->thread); if (loop->base.ref_cnt) pj_atomic_destroy(loop->base.ref_cnt); pjsip_endpt_release_pool(endpt, loop->pool); return status; }
static pj_status_t logging_on_tx_msg(pjsip_tx_data *tdata) { char local_buf[256]; char remote_buf[256]; char *uuid; struct hepv3_capture_info *capture_info; pjsip_cid_hdr *cid_hdr; pjsip_from_hdr *from_hdr; pjsip_to_hdr *to_hdr; capture_info = hepv3_create_capture_info(tdata->buf.start, (size_t)(tdata->buf.cur - tdata->buf.start)); if (!capture_info) { return PJ_SUCCESS; } if (!(tdata->tp_info.transport->flag & PJSIP_TRANSPORT_RELIABLE)) { pjsip_tpmgr_fla2_param prm; /* Attempt to determine what IP address will we send this packet out of */ pjsip_tpmgr_fla2_param_default(&prm); prm.tp_type = tdata->tp_info.transport->key.type; pj_strset2(&prm.dst_host, tdata->tp_info.dst_name); prm.local_if = PJ_TRUE; /* If we can't get the local address use what we have already */ if (pjsip_tpmgr_find_local_addr2(pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()), tdata->pool, &prm) != PJ_SUCCESS) { pj_sockaddr_print(&tdata->tp_info.transport->local_addr, local_buf, sizeof(local_buf), 3); } else { if (prm.tp_type & PJSIP_TRANSPORT_IPV6) { snprintf(local_buf, sizeof(local_buf), "[%.*s]:%hu", (int)pj_strlen(&prm.ret_addr), pj_strbuf(&prm.ret_addr), prm.ret_port); } else { snprintf(local_buf, sizeof(local_buf), "%.*s:%hu", (int)pj_strlen(&prm.ret_addr), pj_strbuf(&prm.ret_addr), prm.ret_port); } } } else { /* For reliable transports they can only ever come from the transport * local address. */ pj_sockaddr_print(&tdata->tp_info.transport->local_addr, local_buf, sizeof(local_buf), 3); } pj_sockaddr_print(&tdata->tp_info.dst_addr, remote_buf, sizeof(remote_buf), 3); cid_hdr = PJSIP_MSG_CID_HDR(tdata->msg); from_hdr = PJSIP_MSG_FROM_HDR(tdata->msg); to_hdr = PJSIP_MSG_TO_HDR(tdata->msg); uuid = assign_uuid(&cid_hdr->id, &to_hdr->tag, &from_hdr->tag); if (!uuid) { ao2_ref(capture_info, -1); return PJ_SUCCESS; } ast_sockaddr_parse(&capture_info->src_addr, local_buf, PARSE_PORT_REQUIRE); ast_sockaddr_parse(&capture_info->dst_addr, remote_buf, PARSE_PORT_REQUIRE); capture_info->protocol_id = transport_to_protocol_id(tdata->tp_info.transport); capture_info->capture_time = ast_tvnow(); capture_info->capture_type = HEPV3_CAPTURE_TYPE_SIP; capture_info->uuid = uuid; capture_info->zipped = 0; hepv3_send_packet(capture_info); return PJ_SUCCESS; }
int transport_tcp_test(void) { enum { SEND_RECV_LOOP = 8 }; pjsip_tpfactory *tpfactory; pjsip_transport *tcp; pj_sockaddr_in rem_addr; pj_status_t status; char url[PJSIP_MAX_URL_SIZE]; int rtt[SEND_RECV_LOOP], min_rtt; int i, pkt_lost; /* Start TCP listener on arbitrary port. */ status = pjsip_tcp_transport_start(endpt, NULL, 1, &tpfactory); if (status != PJ_SUCCESS) { app_perror(" Error: unable to start TCP transport", status); return -10; } /* Get the listener address */ status = pj_sockaddr_in_init(&rem_addr, &tpfactory->addr_name.host, (pj_uint16_t)tpfactory->addr_name.port); if (status != PJ_SUCCESS) { app_perror(" Error: possibly invalid TCP address name", status); return -14; } pj_ansi_sprintf(url, "sip:alice@%s:%d;transport=tcp", pj_inet_ntoa(rem_addr.sin_addr), pj_ntohs(rem_addr.sin_port)); /* Acquire one TCP transport. */ status = pjsip_endpt_acquire_transport(endpt, PJSIP_TRANSPORT_TCP, &rem_addr, sizeof(rem_addr), NULL, &tcp); if (status != PJ_SUCCESS || tcp == NULL) { app_perror(" Error: unable to acquire TCP transport", status); return -17; } /* After pjsip_endpt_acquire_transport, TCP transport must have * reference counter 1. */ if (pj_atomic_get(tcp->ref_cnt) != 1) return -20; /* Test basic transport attributes */ status = generic_transport_test(tcp); if (status != PJ_SUCCESS) return status; /* Check again that reference counter is 1. */ if (pj_atomic_get(tcp->ref_cnt) != 1) return -40; /* Load test */ if (transport_load_test(url) != 0) return -60; /* Basic transport's send/receive loopback test. */ for (i=0; i<SEND_RECV_LOOP; ++i) { status = transport_send_recv_test(PJSIP_TRANSPORT_TCP, tcp, url, &rtt[i]); if (status != 0) { pjsip_transport_dec_ref(tcp); flush_events(500); return -72; } } min_rtt = 0xFFFFFFF; for (i=0; i<SEND_RECV_LOOP; ++i) if (rtt[i] < min_rtt) min_rtt = rtt[i]; report_ival("tcp-rtt-usec", min_rtt, "usec", "Best TCP transport round trip time, in microseconds " "(time from sending request until response is received. " "Tests were performed on local machine only, and after " "TCP socket has been established by previous test)"); /* Multi-threaded round-trip test. */ status = transport_rt_test(PJSIP_TRANSPORT_TCP, tcp, url, &pkt_lost); if (status != 0) { pjsip_transport_dec_ref(tcp); return status; } if (pkt_lost != 0) PJ_LOG(3,(THIS_FILE, " note: %d packet(s) was lost", pkt_lost)); /* Check again that reference counter is still 1. */ if (pj_atomic_get(tcp->ref_cnt) != 1) return -80; /* Destroy this transport. */ pjsip_transport_dec_ref(tcp); /* Force destroy this transport. */ status = pjsip_transport_destroy(tcp); if (status != PJ_SUCCESS) return -90; /* Unregister factory */ status = pjsip_tpmgr_unregister_tpfactory(pjsip_endpt_get_tpmgr(endpt), tpfactory); if (status != PJ_SUCCESS) return -95; /* Flush events. */ PJ_LOG(3,(THIS_FILE, " Flushing events, 1 second...")); flush_events(1000); /* Done */ return 0; }