/* Start Session Timers */ static void start_timer(pjsip_inv_session *inv) { const pj_str_t UPDATE = { "UPDATE", 6 }; pjsip_timer *timer = inv->timer; pj_time_val delay = {0}; pj_assert(inv->timer->active == PJ_TRUE); stop_timer(inv); inv->timer->use_update = (pjsip_dlg_remote_has_cap(inv->dlg, PJSIP_H_ALLOW, NULL, &UPDATE) == PJSIP_DIALOG_CAP_SUPPORTED); if (!inv->timer->use_update) { /* INVITE always needs SDP */ inv->timer->with_sdp = PJ_TRUE; } pj_timer_entry_init(&timer->timer, 1, /* id */ inv, /* user data */ timer_cb); /* callback */ /* Set delay based on role, refresher or refreshee */ if ((timer->refresher == TR_UAC && inv->timer->role == PJSIP_ROLE_UAC) || (timer->refresher == TR_UAS && inv->timer->role == PJSIP_ROLE_UAS)) { /* Add refresher expire timer */ pj_timer_entry_init(&timer->expire_timer, REFRESHER_EXPIRE_TIMER_ID, /* id */ inv, /* user data */ timer_cb); /* callback */ delay.sec = timer->setting.sess_expires; /* Schedule the timer */ pjsip_endpt_schedule_timer(inv->dlg->endpt, &timer->expire_timer, &delay); /* Next refresh, the delay is half of session expire */ delay.sec = timer->setting.sess_expires / 2; } else { /* Send BYE if no refresh received until this timer fired, delay * is the minimum of 32 seconds and one third of the session interval * before session expiration. */ delay.sec = timer->setting.sess_expires - timer->setting.sess_expires/3; delay.sec = PJ_MAX((long)timer->setting.sess_expires-32, delay.sec); } /* Schedule the timer */ pjsip_endpt_schedule_timer(inv->dlg->endpt, &timer->timer, &delay); /* Update last refresh time */ pj_gettimeofday(&timer->last_refresh); }
static int32_t zrtp_activateTimer(ZrtpContext* ctx, int32_t time) { pj_time_val timeout; struct tp_zrtp *zrtp = (struct tp_zrtp*)ctx->userData; timeout.sec = time / 1000; timeout.msec = time % 1000; pj_timer_entry_init(&zrtp->timeoutEntry, 0, zrtp, &timer_callback); timer_add_entry(&zrtp->timeoutEntry, &timeout); return 1; }
static int32_t zrtp_activateTimer(ZrtpContext* ctx, int32_t time) { pj_time_val timeout; struct tp_zrtp *zrtp = (struct tp_zrtp*)ctx->userData; timeout.sec = time / 1000; timeout.msec = time % 1000; pj_timer_entry_init(&zrtp->timeoutEntry, 0, zrtp, &timer_callback); #ifndef DYNAMIC_TIMER timer_add_entry(&zrtp->timeoutEntry, &timeout); #else if(zrtp->timer_heap != NULL){ pj_timer_heap_schedule(zrtp->timer_heap, &zrtp->timeoutEntry, &timeout); } #endif return 1; }
Flow::Flow(FlowTable* flow_table, pjsip_transport* transport, const pj_sockaddr* remote_addr) : _flow_table(flow_table), _transport(transport), _tp_state_listener_key(NULL), _remote_addr(*remote_addr), _token(), _authorized_ids(), _default_id(), _refs(1), _dialogs(0) { // Create the lock for protecting the authorized_ids and default_id. pthread_mutex_init(&_flow_lock, NULL); // Create a random base64 encoded token for the flow. Utils::create_random_token(Flow::TOKEN_LENGTH, _token); if (PJSIP_TRANSPORT_IS_RELIABLE(_transport)) { // We're adding a new reliable transport, so make sure it stays around // until we remove it from the map. pjsip_transport_add_ref(_transport); // Add a state listener so we find out when the flow is destroyed. pjsip_transport_add_state_listener(_transport, &on_transport_state_changed, this, &_tp_state_listener_key); LOG_DEBUG("Added transport listener for flow %p", this); } // Initialize the timer. pj_timer_entry_init(&_timer, PJ_FALSE, (void*)this, &on_timer_expiry); _timer.id = 0; // Start the timer as an idle timer. restart_timer(IDLE_TIMER, IDLE_TIMEOUT); }
/* Start Session Timers */ static void start_timer(pjsip_inv_session *inv) { pjsip_timer *timer = inv->timer; pj_time_val delay = {0}; pj_assert(inv->timer->active == PJ_TRUE); stop_timer(inv); pj_timer_entry_init(&timer->timer, 1, /* id */ inv, /* user data */ timer_cb); /* callback */ /* Set delay based on role, refresher or refreshee */ if ((timer->refresher == TR_UAC && inv->timer->role == PJSIP_ROLE_UAC) || (timer->refresher == TR_UAS && inv->timer->role == PJSIP_ROLE_UAS)) { /* Next refresh, the delay is half of session expire */ delay.sec = timer->setting.sess_expires / 2; } else { /* Send BYE if no refresh received until this timer fired, delay * is the minimum of 32 seconds and one third of the session interval * before session expiration. */ delay.sec = timer->setting.sess_expires - timer->setting.sess_expires/3; delay.sec = PJ_MAX((long)timer->setting.sess_expires-32, delay.sec); } /* Schedule the timer */ pjsip_endpt_schedule_timer(inv->dlg->endpt, &timer->timer, &delay); /* Update last refresh time */ pj_gettimeofday(&timer->last_refresh); }
/* * Create relay. */ static pj_status_t create_relay(pj_turn_srv *srv, pj_turn_allocation *alloc, const pj_stun_msg *msg, const alloc_request *req, pj_turn_relay_res *relay) { enum { RETRY = 40 }; pj_pool_t *pool = alloc->pool; int retry, retry_max, sock_type; pj_ioqueue_callback icb; int af, namelen; pj_stun_string_attr *sa; pj_status_t status; pj_bzero(relay, sizeof(*relay)); relay->allocation = alloc; relay->tp.sock = PJ_INVALID_SOCKET; /* TODO: get the requested address family from somewhere */ af = alloc->transport->listener->addr.addr.sa_family; /* Save realm */ sa = (pj_stun_string_attr*) pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_REALM, 0); PJ_ASSERT_RETURN(sa, PJ_EINVALIDOP); pj_strdup(pool, &relay->realm, &sa->value); /* Save username */ sa = (pj_stun_string_attr*) pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_USERNAME, 0); PJ_ASSERT_RETURN(sa, PJ_EINVALIDOP); pj_strdup(pool, &relay->user, &sa->value); /* Lifetime and timeout */ relay->lifetime = req->lifetime; pj_timer_entry_init(&relay->timer, TIMER_ID_NONE, relay, &relay_timeout_cb); resched_timeout(alloc); /* Transport type */ relay->hkey.tp_type = req->tp_type; /* Create the socket */ if (req->tp_type == PJ_TURN_TP_UDP) { sock_type = pj_SOCK_DGRAM(); } else if (req->tp_type == PJ_TURN_TP_TCP) { sock_type = pj_SOCK_STREAM(); } else { pj_assert(!"Unknown transport"); return PJ_EINVALIDOP; } status = pj_sock_socket(af, sock_type, 0, &relay->tp.sock); if (status != PJ_SUCCESS) { pj_bzero(relay, sizeof(*relay)); return status; } /* Find suitable port for this allocation */ if (req->rpp_port) { retry_max = 1; } else { retry_max = RETRY; } for (retry=0; retry<retry_max; ++retry) { pj_uint16_t port; pj_sockaddr bound_addr; pj_lock_acquire(srv->core.lock); if (req->rpp_port) { port = (pj_uint16_t) req->rpp_port; } else if (req->tp_type == PJ_TURN_TP_UDP) { port = (pj_uint16_t) srv->ports.next_udp++; if (srv->ports.next_udp > srv->ports.max_udp) srv->ports.next_udp = srv->ports.min_udp; } else if (req->tp_type == PJ_TURN_TP_TCP) { port = (pj_uint16_t) srv->ports.next_tcp++; if (srv->ports.next_tcp > srv->ports.max_tcp) srv->ports.next_tcp = srv->ports.min_tcp; } else { pj_assert(!"Invalid transport"); port = 0; } pj_lock_release(srv->core.lock); pj_sockaddr_init(af, &bound_addr, NULL, port); status = pj_sock_bind(relay->tp.sock, &bound_addr, pj_sockaddr_get_len(&bound_addr)); if (status == PJ_SUCCESS) break; } if (status != PJ_SUCCESS) { /* Unable to allocate port */ PJ_LOG(4,(THIS_FILE, "Unable to allocate relay, giving up: err %d", status)); pj_sock_close(relay->tp.sock); relay->tp.sock = PJ_INVALID_SOCKET; return status; } /* Init relay key */ namelen = sizeof(relay->hkey.addr); status = pj_sock_getsockname(relay->tp.sock, &relay->hkey.addr, &namelen); if (status != PJ_SUCCESS) { PJ_LOG(4,(THIS_FILE, "pj_sock_getsockname() failed: err %d", status)); pj_sock_close(relay->tp.sock); relay->tp.sock = PJ_INVALID_SOCKET; return status; } if (!pj_sockaddr_has_addr(&relay->hkey.addr)) { pj_sockaddr_copy_addr(&relay->hkey.addr, &alloc->transport->listener->addr); } if (!pj_sockaddr_has_addr(&relay->hkey.addr)) { pj_sockaddr tmp_addr; pj_gethostip(af, &tmp_addr); pj_sockaddr_copy_addr(&relay->hkey.addr, &tmp_addr); } /* Init ioqueue */ pj_bzero(&icb, sizeof(icb)); icb.on_read_complete = &on_rx_from_peer; status = pj_ioqueue_register_sock(pool, srv->core.ioqueue, relay->tp.sock, relay, &icb, &relay->tp.key); if (status != PJ_SUCCESS) { PJ_LOG(4,(THIS_FILE, "pj_ioqueue_register_sock() failed: err %d", status)); pj_sock_close(relay->tp.sock); relay->tp.sock = PJ_INVALID_SOCKET; return status; } /* Kick off pending read operation */ pj_ioqueue_op_key_init(&relay->tp.read_key, sizeof(relay->tp.read_key)); on_rx_from_peer(relay->tp.key, &relay->tp.read_key, 0); /* Done */ return PJ_SUCCESS; }
/* * Create. */ PJ_DEF(pj_status_t) pj_turn_sock_create(pj_stun_config *cfg, int af, pj_turn_tp_type conn_type, const pj_turn_sock_cb *cb, const pj_turn_sock_cfg *setting, void *user_data, pj_turn_sock **p_turn_sock) { pj_turn_sock *turn_sock; pj_turn_session_cb sess_cb; pj_turn_sock_cfg default_setting; pj_pool_t *pool; const char *name_tmpl; pj_status_t status; PJ_ASSERT_RETURN(cfg && p_turn_sock, PJ_EINVAL); PJ_ASSERT_RETURN(af==pj_AF_INET() || af==pj_AF_INET6(), PJ_EINVAL); PJ_ASSERT_RETURN(conn_type!=PJ_TURN_TP_TCP || PJ_HAS_TCP, PJ_EINVAL); if (!setting) { pj_turn_sock_cfg_default(&default_setting); setting = &default_setting; } switch (conn_type) { case PJ_TURN_TP_UDP: name_tmpl = "udprel%p"; break; case PJ_TURN_TP_TCP: name_tmpl = "tcprel%p"; break; default: PJ_ASSERT_RETURN(!"Invalid TURN conn_type", PJ_EINVAL); name_tmpl = "tcprel%p"; break; } /* Create and init basic data structure */ pool = pj_pool_create(cfg->pf, name_tmpl, PJNATH_POOL_LEN_TURN_SOCK, PJNATH_POOL_INC_TURN_SOCK, NULL); turn_sock = PJ_POOL_ZALLOC_T(pool, pj_turn_sock); turn_sock->pool = pool; turn_sock->obj_name = pool->obj_name; turn_sock->user_data = user_data; turn_sock->af = af; turn_sock->conn_type = conn_type; /* Copy STUN config (this contains ioqueue, timer heap, etc.) */ pj_memcpy(&turn_sock->cfg, cfg, sizeof(*cfg)); /* Copy setting (QoS parameters etc */ pj_memcpy(&turn_sock->setting, setting, sizeof(*setting)); /* Set callback */ if (cb) { pj_memcpy(&turn_sock->cb, cb, sizeof(*cb)); } /* Session lock */ if (setting && setting->grp_lock) { turn_sock->grp_lock = setting->grp_lock; } else { status = pj_grp_lock_create(pool, NULL, &turn_sock->grp_lock); if (status != PJ_SUCCESS) { pj_pool_release(pool); return status; } } pj_grp_lock_add_ref(turn_sock->grp_lock); pj_grp_lock_add_handler(turn_sock->grp_lock, pool, turn_sock, &turn_sock_on_destroy); /* Init timer */ pj_timer_entry_init(&turn_sock->timer, TIMER_NONE, turn_sock, &timer_cb); /* Init TURN session */ pj_bzero(&sess_cb, sizeof(sess_cb)); sess_cb.on_send_pkt = &turn_on_send_pkt; sess_cb.on_channel_bound = &turn_on_channel_bound; sess_cb.on_rx_data = &turn_on_rx_data; sess_cb.on_state = &turn_on_state; status = pj_turn_session_create(cfg, pool->obj_name, af, conn_type, turn_sock->grp_lock, &sess_cb, 0, turn_sock, &turn_sock->sess); if (status != PJ_SUCCESS) { destroy(turn_sock); return status; } /* Note: socket and ioqueue will be created later once the TURN server * has been resolved. */ *p_turn_sock = turn_sock; return PJ_SUCCESS; }
/* * Create TCP client session. */ PJ_DEF(pj_status_t) pj_tcp_session_create( const pj_stun_config *cfg, const char *name, int af, const pj_tcp_session_cb *cb, unsigned options, void *user_data, pj_stun_session *default_stun, pj_tcp_session **p_sess, int sess_idx, int check_idx) { pj_pool_t *pool; pj_tcp_session *sess; pj_stun_session_cb stun_cb; pj_lock_t *null_lock; pj_status_t status; PJ_ASSERT_RETURN(cfg && cfg->pf && cb && p_sess, PJ_EINVAL); PJ_ASSERT_RETURN(cb->on_send_pkt, PJ_EINVAL); PJ_UNUSED_ARG(options); if (name == NULL) name = "tcp%p"; /* Allocate and create TCP session */ pool = pj_pool_create(cfg->pf, name, PJNATH_POOL_LEN_TCP_SESS, PJNATH_POOL_INC_TCP_SESS, NULL); sess = PJ_POOL_ZALLOC_T(pool, pj_tcp_session); sess->pool = pool; sess->obj_name = pool->obj_name; sess->timer_heap = cfg->timer_heap; sess->af = (pj_uint16_t)af; sess->ka_interval = PJ_TCP_KEEP_ALIVE_SEC; sess->user_data = user_data; sess->sess_idx = sess_idx; sess->check_idx = check_idx; /* Copy STUN session */ pj_memcpy(&sess->stun_cfg, cfg, sizeof(pj_stun_config)); /* Copy callback */ pj_memcpy(&sess->cb, cb, sizeof(*cb)); /* Session lock */ status = pj_lock_create_recursive_mutex(pool, sess->obj_name, &sess->lock); if (status != PJ_SUCCESS) { do_destroy(sess); return status; } /* Timer */ pj_timer_entry_init(&sess->timer, TIMER_NONE, sess, &on_timer_event); //DEAN if (default_stun) { sess->stun = default_stun; } else { /* Create STUN session */ pj_bzero(&stun_cb, sizeof(stun_cb)); stun_cb.on_send_msg = &stun_on_send_msg; #if 0 stun_cb.on_request_complete = &stun_on_request_complete; #else stun_cb.on_request_complete = &on_stun_request_complete; #endif stun_cb.on_rx_request = &on_stun_rx_request; stun_cb.on_rx_indication = &on_stun_rx_indication; status = pj_stun_session_create2(&sess->stun_cfg, sess->obj_name, &stun_cb, PJ_FALSE, NULL, &sess->stun, PJ_TRUE, sess); if (status != PJ_SUCCESS) { do_destroy(sess); return status; } } /* Attach ourself to STUN session */ pj_stun_session_set_user_data(sess->stun, pj_tcp_sock_get_tsd(user_data)); /* Replace mutex in STUN session with a NULL mutex, since access to * STUN session is serialized. */ status = pj_lock_create_null_mutex(pool, name, &null_lock); if (status != PJ_SUCCESS) { do_destroy(sess); return status; } pj_stun_session_set_lock(sess->stun, null_lock, PJ_TRUE); /* Done */ PJ_LOG(4,(sess->obj_name, "TCP client session created")); *p_sess = sess; return PJ_SUCCESS; }