/** Keepalive timer. */ void tport_keepalive_timer(tport_t *self, su_time_t now) { unsigned timeout = self->tp_params->tpp_pingpong; if (timeout != 0) { if (self->tp_ptime.tv_sec && !self->tp_recv_close && su_time_cmp(su_time_add(self->tp_ptime, timeout), now) < 0) { SU_DEBUG_3(("%s(%p): %s to " TPN_FORMAT "%s\n", __func__, (void *)self, "closing connection", TPN_ARGS(self->tp_name), " because of PONG timeout")); tport_error_report(self, EPIPE, NULL); if (!self->tp_closed) tport_close(self); return; } } timeout = self->tp_params->tpp_keepalive; if (timeout != 0 && timeout != UINT_MAX) { if (su_time_cmp(su_time_add(self->tp_ktime, timeout), now) < 0) { tport_tcp_ping(self, now); } } }
/** Calculate next timeout for keepalive */ int tport_next_keepalive(tport_t *self, su_time_t *return_target, char const **return_why) { /* Keepalive timer */ unsigned timeout = self->tp_params->tpp_keepalive; if (timeout != 0 && timeout != UINT_MAX) { if (!tport_has_queued(self)) { su_time_t ntime = su_time_add(self->tp_ktime, timeout); if (su_time_cmp(ntime, *return_target) < 0) *return_target = ntime, *return_why = "keepalive"; } } timeout = self->tp_params->tpp_pingpong; if (timeout != 0) { if (self->tp_ptime.tv_sec && !self->tp_recv_close) { su_time_t ntime = su_time_add(self->tp_ptime, timeout); if (su_time_cmp(ntime, *return_target) < 0) *return_target = ntime, *return_why = "waiting for pong"; } } return 0; }
/** Timeout timer if receive is incomplete */ void tport_recv_timeout_timer(tport_t *self, su_time_t now) { unsigned timeout = self->tp_params->tpp_timeout; if (timeout < INT_MAX) { if (self->tp_msg && su_time_cmp(su_time_add(self->tp_rtime, timeout), now) < 0) { msg_t *msg = self->tp_msg; msg_set_streaming(msg, (enum msg_streaming_status)0); msg_set_flags(msg, MSG_FLG_ERROR | MSG_FLG_TRUNC | MSG_FLG_TIMEOUT); tport_deliver(self, msg, NULL, NULL, now); self->tp_msg = NULL; } #if 0 /* Send timeout */ if (tport_has_queued(self) && su_time_cmp(su_time_add(self->tp_stime, timeout), now) < 0) { stime = su_time_add(self->tp_stime, self->tp_params->tpp_timeout); if (su_time_cmp(stime, target) < 0) target = stime; } #endif } }
/** Calculate timeout if receive is incomplete. */ int tport_next_recv_timeout(tport_t *self, su_time_t *return_target, char const **return_why) { unsigned timeout = self->tp_params->tpp_timeout; if (timeout < INT_MAX) { /* Recv timeout */ if (self->tp_msg) { su_time_t ntime = su_time_add(self->tp_rtime, timeout); if (su_time_cmp(ntime, *return_target) < 0) *return_target = ntime, *return_why = "recv timeout"; } #if 0 /* Send timeout */ if (tport_has_queued(self)) { su_time_t ntime = su_time_add(self->tp_stime, timeout); if (su_time_cmp(ntime, *return_target) < 0) *return_target = ntime, *return_why = "send timeout"; } #endif } return 0; }
TimerEventHandle TimerQueue::add( TimerFunc f, void* functionArgs, uint32_t milliseconds, su_time_t now ) { //self check assert( m_length == numberOfElements()) ; assert( 0 != m_length || (NULL == m_head && NULL == m_tail) ) ; assert( 1 != m_length || (m_head == m_tail)) ; assert( m_length < 2 || (m_head != m_tail)) ; assert( !(NULL == m_head && NULL != m_tail)) ; assert( !(NULL == m_tail && NULL != m_head)) ; su_time_t when = su_time_add(now, milliseconds) ; queueEntry_t* entry = new queueEntry_t(this, f, functionArgs, when) ; TimerEventHandle handle = entry ; assert(handle) ; int queueLength ; if( entry ) { #ifndef TEST DR_LOG(log_debug) << m_name << ": Adding entry to go off in " << std::dec << milliseconds << "ms" ; #endif //std::cout << "Adding entry to go off in " << milliseconds << "ms" << std::endl; if( NULL == m_head ) { assert( NULL == m_tail ) ; m_head = m_tail = entry; #ifndef TEST DR_LOG(log_debug) << m_name << ": Adding entry to the head (queue was empty), length: " << dec << m_length+1 ; #endif //std::cout << "Adding entry to the head of the queue (it was empty)" << std::endl ; } else if( NULL != m_tail && su_time_cmp( when, m_tail->m_when ) > 0) { //one class of timer queues will always be appending entries, so check the tail //before starting to iterate through #ifndef TEST DR_LOG(log_debug) << m_name << ": Adding entry to the tail of the queue: length " << dec << m_length+1; #endif //std::cout << "Adding entry to the tail of the queue" << std::endl ; entry->m_prev = m_tail ; m_tail->m_next = entry ; m_tail = entry ; } else { //iterate queueEntry_t* ptr = m_head ; int idx = 0 ; do { if( su_time_cmp( when, ptr->m_when ) < 0) { #ifndef TEST DR_LOG(log_debug) << m_name << ": Adding entry at position " << std::dec << idx << " of the queue, length: " << dec << m_length+1 ; #endif //std::cout << "Adding entry at position " << idx << " of the queue" << std::endl ; entry->m_next = ptr ; if( 0 == idx ) { m_head = entry ; } else { entry->m_prev = ptr->m_prev ; ptr->m_prev->m_next = entry ; } ptr->m_prev = entry ; break ; } idx++ ; } while( NULL != (ptr = ptr->m_next) ) ; assert( NULL != ptr ) ; /* if( NULL == ptr ) { #ifndef TEST DR_LOG(log_debug) << m_name << ": Adding entry to the tail of the queue: length " << dec << m_length+1; #endif //std::cout << "Adding entry to the tail of the queue" << std::endl ; entry->m_prev = m_tail ; m_tail->m_next = entry ; m_tail = entry ; } */ } queueLength = ++m_length ; } else { //DR_LOG(log_error) << "Error allocating queue entry" ; //std::cerr << "Error allocating queue entry" << std::endl ; return NULL ; } //only need to set the timer if we added to the front if( m_head == entry ) { //DR_LOG(log_debug) << "timer add: Setting timer for " << milliseconds << "ms" ; //std::cout << "timer add: Setting timer for " << milliseconds << "ms" << std::endl; int rc = su_timer_set_at(m_timer, timer_function, this, when); assert( 0 == rc ) ; } //DR_LOG(log_debug) << "timer add: queue length is now " << queueLength ; //std::cout << "timer add: queue length is now " << queueLength << std::endl; //self check assert( m_length == numberOfElements()) ; assert( 0 != m_length || (NULL == m_head && NULL == m_tail) ) ; assert( 1 != m_length || (m_head == m_tail)) ; assert( m_length < 2 || (m_head != m_tail)) ; assert( !(NULL == m_head && NULL != m_tail)) ; assert( !(NULL == m_tail && NULL != m_head)) ; return handle ; }
void TimerQueue::doTimer(su_timer_t* timer) { //self check assert( m_length == numberOfElements()) ; assert( 0 != m_length || (NULL == m_head && NULL == m_tail) ) ; assert( 1 != m_length || (m_head == m_tail)) ; assert( m_length < 2 || (m_head != m_tail)) ; assert( !(NULL == m_head && NULL != m_tail)) ; assert( !(NULL == m_tail && NULL != m_head)) ; #ifndef TEST DR_LOG(log_debug) << m_name << ": running timer function" ; #endif //std::cout << "doTimer: running timer function with " << m_length << " timers queued " << std::endl; if( m_in_timer ) return ; m_in_timer = 1 ; queueEntry_t* expired = NULL ; queueEntry_t* tailExpired = NULL ; su_time_t now = su_now() ; assert( NULL != m_head ) ; queueEntry_t* ptr = m_head ; while( ptr && su_time_cmp( ptr->m_when, now ) < 0 ) { //std::cout << "expiring a timer" << std::endl ; m_length-- ; m_head = ptr->m_next ; if( m_head ) m_head->m_prev = NULL ; else m_tail = NULL ; //detach and assemble them into a new queue temporarily if( !expired ) { expired = tailExpired = ptr ; ptr->m_prev = ptr->m_next = NULL ; } else { tailExpired->m_next = ptr ; ptr->m_prev = tailExpired ; tailExpired = ptr ; } ptr = ptr->m_next ; } if( NULL == m_head ) { #ifndef TEST DR_LOG(log_debug) << m_name << ": timer not set (queue is empty after processing expired timers), length: " << dec << m_length ; #endif //std::cout << "doTimer: timer not set (queue is empty after processing expired timers)" << std::endl; assert( 0 == m_length ) ; } else { //std::cout << "doTimer: Setting timer for " << su_duration( m_head->m_when, su_now() ) << "ms after processing expired timers" << std::endl; #ifndef TEST DR_LOG(log_debug) << m_name << ": Setting timer for " << su_duration( m_head->m_when, su_now() ) << "ms after processing expired timers, length: " << dec << m_length ; #endif int rc = su_timer_set_at(m_timer, timer_function, this, m_head->m_when); } m_in_timer = 0 ; while( NULL != expired ) { expired->m_function( expired->m_functionArgs ) ; queueEntry_t* p = expired ; expired = expired->m_next ; delete p ; } //self check assert( m_length == numberOfElements()) ; assert( 0 != m_length || (NULL == m_head && NULL == m_tail) ) ; assert( 1 != m_length || (m_head == m_tail)) ; assert( m_length < 2 || (m_head != m_tail)) ; assert( !(NULL == m_head && NULL != m_tail)) ; assert( !(NULL == m_tail && NULL != m_head)) ; }