static int transport_shutdown(void *data) { pjsip_transport *transport = data; pjsip_transport_shutdown(transport); return 0; }
void ConnectionPool::quiesce_connection(int hash_slot) { pthread_mutex_lock(&_tp_hash_lock); pjsip_transport* tp = _tp_hash[hash_slot].tp; if (tp != NULL) { if (_tp_hash[hash_slot].state == PJSIP_TP_STATE_CONNECTED) { // Connection was established, so update statistics. --_active_connections; decrement_connection_count(tp); } // Remove the transport from the hash and the map. _tp_hash[hash_slot].tp = NULL; _tp_hash[hash_slot].state = PJSIP_TP_STATE_DISCONNECTED; _tp_map.erase(tp); // Release the lock now so we don't have a deadlock if pjsip_transport_shutdown // calls the transport state listener. pthread_mutex_unlock(&_tp_hash_lock); // Quiesce the transport. PJSIP will destroy the transport when there // are no further references to it. pjsip_transport_shutdown(tp); // Remove our reference to the transport. pjsip_transport_dec_ref(tp); } else { pthread_mutex_unlock(&_tp_hash_lock); } }
SipTransport::~SipTransport() { if (transport) { pjsip_transport_shutdown(transport); pjsip_transport_dec_ref(transport); // ?? DEBUG("Destroying transport (refcount: %u)", pj_atomic_get(transport->ref_cnt)); transport = nullptr; } }
void SipTransportBroker::shutdown() { std::unique_lock<std::mutex> lock(transportMapMutex_); for (auto& t : transports_) { if (auto transport = t.second.lock()) { pjsip_transport_shutdown(transport->get()); } } }
static void tls_init_shutdown(struct tls_transport *tls, pj_status_t status) { pjsip_tp_state_callback state_cb; if (tls->close_reason == PJ_SUCCESS) tls->close_reason = status; if (tls->base.is_shutdown || tls->base.is_destroying) return; /* Prevent immediate transport destroy by application, as transport * state notification callback may be stacked and transport instance * must remain valid at any point in the callback. */ pjsip_transport_add_ref(&tls->base); /* Notify application of transport disconnected state */ state_cb = pjsip_tpmgr_get_state_cb(tls->base.tpmgr); if (state_cb) { pjsip_transport_state_info state_info; pjsip_tls_state_info tls_info; pj_ssl_sock_info ssl_info; /* Init transport state info */ pj_bzero(&state_info, sizeof(state_info)); state_info.status = tls->close_reason; if (tls->ssock && pj_ssl_sock_get_info(tls->ssock, &ssl_info) == PJ_SUCCESS) { pj_bzero(&tls_info, sizeof(tls_info)); tls_info.ssl_sock_info = &ssl_info; state_info.ext_info = &tls_info; } (*state_cb)(&tls->base, PJSIP_TP_STATE_DISCONNECTED, &state_info); } /* check again */ if (tls->base.is_shutdown || tls->base.is_destroying) { pjsip_transport_dec_ref(&tls->base); return; } /* We can not destroy the transport since high level objects may * still keep reference to this transport. So we can only * instruct transport manager to gracefully start the shutdown * procedure for this transport. */ pjsip_transport_shutdown(&tls->base); /* Now, it is ok to destroy the transport. */ pjsip_transport_dec_ref(&tls->base); }
static int transport_shutdown(void *data) { RAII_VAR(struct ast_sip_contact_transport *, ct, NULL, ao2_cleanup); pjsip_transport *transport = data; if ((ct = ast_sip_location_retrieve_contact_transport_by_transport(transport))) { ast_sip_location_delete_contact_transport(ct); } pjsip_transport_shutdown(transport); return 0; }
static int transport_shutdown(void *data) { struct ws_transport *wstransport = data; if (!wstransport->transport.is_shutdown && !wstransport->transport.is_destroying) { pjsip_transport_shutdown(&wstransport->transport); } /* Note that the destructor calls PJSIP functions, * therefore it must be called in a PJSIP thread. */ ao2_ref(wstransport, -1); return 0; }
static int destroy_sip_transport_state(void *data) { struct ast_sip_transport_state *transport_state = data; ast_free(transport_state->id); ast_free_ha(transport_state->localnet); if (transport_state->external_address_refresher) { ast_dnsmgr_release(transport_state->external_address_refresher); } if (transport_state->transport) { pjsip_transport_shutdown(transport_state->transport); } return 0; }
/* * Callback from ioqueue when packet is sent. */ static pj_bool_t on_data_sent(pj_ssl_sock_t *ssock, pj_ioqueue_op_key_t *op_key, pj_ssize_t bytes_sent) { struct tls_transport *tls = (struct tls_transport*) pj_ssl_sock_get_user_data(ssock); pjsip_tx_data_op_key *tdata_op_key = (pjsip_tx_data_op_key*)op_key; /* Note that op_key may be the op_key from keep-alive, thus * it will not have tdata etc. */ tdata_op_key->tdata = NULL; if (tdata_op_key->callback) { /* * Notify sip_transport.c that packet has been sent. */ if (bytes_sent == 0) bytes_sent = -PJ_RETURN_OS_ERROR(OSERR_ENOTCONN); tdata_op_key->callback(&tls->base, tdata_op_key->token, bytes_sent); /* Mark last activity time */ pj_gettimeofday(&tls->last_activity); } /* Check for error/closure */ if (bytes_sent <= 0) { pj_status_t status; PJ_LOG(5,(tls->base.obj_name, "TLS send() error, sent=%d", bytes_sent)); status = (bytes_sent == 0) ? PJ_RETURN_OS_ERROR(OSERR_ENOTCONN) : -bytes_sent; if (tls->close_reason==PJ_SUCCESS) tls->close_reason = status; pjsip_transport_shutdown(&tls->base); return PJ_FALSE; } return PJ_TRUE; }
void ConnectionTracker::quiesce() { pj_bool_t quiesce_complete = PJ_FALSE; TRC_DEBUG("Start quiescing connections"); pthread_mutex_lock(&_lock); // Flag that we're now quiescing. It is illegal to call this method if we're // already quiescing. assert(!_quiescing); _quiescing = PJ_TRUE; if (_connection_listeners.empty()) { // There are no active connections, so quiescing is already complete. TRC_DEBUG("Connection quiescing complete"); quiesce_complete = PJ_TRUE; } else { // Call shutdown on each connection. PJSIP's reference counting means a // connection will be closed once all transactions that use it have // completed. for (std::map<pjsip_transport *, pjsip_tp_state_listener_key *>::iterator it = _connection_listeners.begin(); it != _connection_listeners.end(); ++it) { TRC_DEBUG("Shutdown connection %p", it->first); pjsip_transport_shutdown(it->first); } } pthread_mutex_unlock(&_lock); // If quiescing is now complete notify the quiescing manager. This is done // without holding the lock to avoid potential deadlocks. if (quiesce_complete) { _on_quiesced_handler->connections_quiesced(); } }
void ConnectionPool::quiesce_connection(int hash_slot) { pthread_mutex_lock(&_tp_hash_lock); pjsip_transport* tp = _tp_hash[hash_slot].tp; if (tp != NULL) { if (_tp_hash[hash_slot].connected) { // Connection was established, so update statistics. --_active_connections; decrement_connection_count(tp); } // Don't listen for any more state changes on this connection. pjsip_transport_remove_state_listener(tp, _tp_hash[hash_slot].listener_key, (void *)this); // Remove the transport from the hash and the map. _tp_hash[hash_slot].tp = NULL; _tp_hash[hash_slot].listener_key = NULL; _tp_hash[hash_slot].connected = PJ_FALSE; _tp_map.erase(tp); // Release the lock now so we don't have a deadlock if pjsip_transport_shutdown // calls the transport state listener. pthread_mutex_unlock(&_tp_hash_lock); // Quiesce the transport. PJSIP will destroy the transport when there // are no further references to it. pjsip_transport_shutdown(tp); // Remove our reference to the transport. pjsip_transport_dec_ref(tp); } else { pthread_mutex_unlock(&_tp_hash_lock); } }
void ConnectionTracker::connection_active(pjsip_transport *tp) { // We only track connection-oriented transports. if ((tp->flag & PJSIP_TRANSPORT_DATAGRAM) == 0) { pthread_mutex_lock(&_lock); if (_connection_listeners.find(tp) == _connection_listeners.end()) { // New connection. Register a state listener so we know when it gets // destroyed. pjsip_tp_state_listener_key *key; pjsip_transport_add_state_listener(tp, &connection_state, (void *)this, &key); // Record the listener. _connection_listeners[tp] = key; // If we're quiescing, shutdown the transport immediately. The connection // will be closed when all transactions that use it have ended. // // This catches cases where the connection was established before // quiescing started, but the first message was sent afterwards (so the // first time the connection tracker heard about it was after quiesing had // started). Trying to establish new connections after quiescing has // started should fail as the listening socket will have been closed. if (_quiescing) { pjsip_transport_shutdown(tp); } } pthread_mutex_unlock(&_lock); } }
/* * This callback is called by SSL socket when pending accept() operation * has completed. */ static pj_bool_t on_accept_complete(pj_ssl_sock_t *ssock, pj_ssl_sock_t *new_ssock, const pj_sockaddr_t *src_addr, int src_addr_len) { struct tls_listener *listener; struct tls_transport *tls; pj_ssl_sock_info ssl_info; char addr[PJ_INET6_ADDRSTRLEN+10]; pjsip_tp_state_callback state_cb; pj_bool_t is_shutdown; pj_status_t status; PJ_UNUSED_ARG(src_addr_len); listener = (struct tls_listener*) pj_ssl_sock_get_user_data(ssock); PJ_ASSERT_RETURN(new_ssock, PJ_TRUE); PJ_LOG(4,(listener->factory.obj_name, "TLS listener %.*s:%d: got incoming TLS connection " "from %s, sock=%d", (int)listener->factory.addr_name.host.slen, listener->factory.addr_name.host.ptr, listener->factory.addr_name.port, pj_sockaddr_print(src_addr, addr, sizeof(addr), 3), new_ssock)); /* Retrieve SSL socket info, close the socket if this is failed * as the SSL socket info availability is rather critical here. */ status = pj_ssl_sock_get_info(new_ssock, &ssl_info); if (status != PJ_SUCCESS) { pj_ssl_sock_close(new_ssock); return PJ_TRUE; } /* * Incoming connection! * Create TLS transport for the new socket. */ status = tls_create( listener, NULL, new_ssock, PJ_TRUE, (const pj_sockaddr_in*)&listener->factory.local_addr, (const pj_sockaddr_in*)src_addr, NULL, &tls); if (status != PJ_SUCCESS) return PJ_TRUE; /* Set the "pending" SSL socket user data */ pj_ssl_sock_set_user_data(new_ssock, tls); /* Prevent immediate transport destroy as application may access it * (getting info, etc) in transport state notification callback. */ pjsip_transport_add_ref(&tls->base); /* If there is verification error and verification is mandatory, shutdown * and destroy the transport. */ if (ssl_info.verify_status && listener->tls_setting.verify_client) { if (tls->close_reason == PJ_SUCCESS) tls->close_reason = PJSIP_TLS_ECERTVERIF; pjsip_transport_shutdown(&tls->base); } /* Notify transport state to application */ state_cb = pjsip_tpmgr_get_state_cb(tls->base.tpmgr); if (state_cb) { pjsip_transport_state_info state_info; pjsip_tls_state_info tls_info; pjsip_transport_state tp_state; /* Init transport state info */ pj_bzero(&tls_info, sizeof(tls_info)); pj_bzero(&state_info, sizeof(state_info)); tls_info.ssl_sock_info = &ssl_info; state_info.ext_info = &tls_info; /* Set transport state based on verification status */ if (ssl_info.verify_status && listener->tls_setting.verify_client) { tp_state = PJSIP_TP_STATE_DISCONNECTED; state_info.status = PJSIP_TLS_ECERTVERIF; } else { tp_state = PJSIP_TP_STATE_CONNECTED; state_info.status = PJ_SUCCESS; } (*state_cb)(&tls->base, tp_state, &state_info); } /* Release transport reference. If transport is shutting down, it may * get destroyed here. */ is_shutdown = tls->base.is_shutdown; pjsip_transport_dec_ref(&tls->base); if (is_shutdown) return PJ_TRUE; status = tls_start_read(tls); if (status != PJ_SUCCESS) { PJ_LOG(3,(tls->base.obj_name, "New transport cancelled")); tls_init_shutdown(tls, status); tls_destroy(&tls->base, status); } else { /* Start keep-alive timer */ if (PJSIP_TLS_KEEP_ALIVE_INTERVAL) { pj_time_val delay = {PJSIP_TLS_KEEP_ALIVE_INTERVAL, 0}; pjsip_endpt_schedule_timer(listener->endpt, &tls->ka_timer, &delay); tls->ka_timer.id = PJ_TRUE; pj_gettimeofday(&tls->last_activity); } } return PJ_TRUE; }
void SipTransport::deleteTransport(pjsip_transport* t) { pjsip_transport_shutdown(t); pjsip_transport_dec_ref(t); }