/* Copyright (C) 2005-2009 Michel de Boer This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include "events.h" #include "log.h" #include "userintf.h" #include "util.h" #include "audits/memman.h" string event_type2str(t_event_type t) { switch(t) { case EV_QUIT: return "EV_QUIT"; case EV_NETWORK: return "EV_NETWORK"; case EV_USER: return "EV_USER"; case EV_TIMEOUT: return "EV_TIMEOUT"; case EV_FAILURE: return "EV_FAILURE"; case EV_START_TIMER: return "EV_START_TIMER"; case EV_STOP_TIMER: return "EV_STOP_TIMER"; case EV_ABORT_TRANS: return "EV_ABORT_TRANS"; case EV_STUN_REQUEST: return "EV_STUN_REQUEST"; case EV_STUN_RESPONSE: return "EV_STUN_RESPONSE"; case EV_NAT_KEEPALIVE: return "EV_NAT_KEEPALIVE"; case EV_ICMP: return "EV_ICMP"; case EV_UI: return "EV_UI"; case EV_ASYNC_RESPONSE: return "EV_ASYNC_RESPONSE"; case EV_BROKEN_CONNECTION: return "EV_BROKEN_CONNECTION"; case EV_TCP_PING: return "EV_TCP_PING"; case EV_FN_CALL: return "EV_FN_CALL"; } return "UNKNOWN"; } /////////////////////////////////////////////////////////// // class t_event_network /////////////////////////////////////////////////////////// t_event_network::t_event_network(t_sip_message *m) : t_event() { msg = m->copy(); src_addr = 0; src_port = 0; dst_addr = 0; dst_port = 0; transport.clear(); } t_event_network::~t_event_network() { MEMMAN_DELETE(msg); delete msg; } t_event_type t_event_network::get_type(void) const { return EV_NETWORK; } t_sip_message *t_event_network::get_msg(void) const { return msg; } /////////////////////////////////////////////////////////// // class t_event_quit /////////////////////////////////////////////////////////// t_event_quit::~t_event_quit() {} t_event_type t_event_quit::get_type(void) const { return EV_QUIT; } /////////////////////////////////////////////////////////// // class t_event_user /////////////////////////////////////////////////////////// t_event_user::t_event_user(t_user *u, t_sip_message *m, unsigned short _tuid, unsigned short _tid) : t_event() { msg = m->copy(); tuid = _tuid; tid = _tid; tid_cancel_target = 0; if (u) { user_config = u->copy(); } else { user_config = NULL; } } t_event_user::t_event_user(t_user *u, t_sip_message *m, unsigned short _tuid, unsigned short _tid, unsigned short _tid_cancel_target) : t_event() { msg = m->copy(); tuid = _tuid; tid = _tid; tid_cancel_target = _tid_cancel_target; if (u) { user_config = u->copy(); } else { user_config = NULL; } } t_event_user::~t_event_user() { MEMMAN_DELETE(msg); delete msg; if (user_config) { MEMMAN_DELETE(user_config); delete user_config; } } t_event_type t_event_user::get_type(void) const { return EV_USER; } t_sip_message *t_event_user::get_msg(void) const { return msg; } unsigned short t_event_user::get_tuid(void) const { return tuid; } unsigned short t_event_user::get_tid(void) const { return tid; } unsigned short t_event_user::get_tid_cancel_target(void) const { return tid_cancel_target; } t_user *t_event_user::get_user_config(void) const { return user_config; } /////////////////////////////////////////////////////////// // class t_event_timeout /////////////////////////////////////////////////////////// t_event_timeout::t_event_timeout(t_timer *t) : t_event() { timer = t->copy(); } t_event_timeout::~t_event_timeout() { MEMMAN_DELETE(timer); delete timer; } t_event_type t_event_timeout::get_type(void) const { return EV_TIMEOUT; } t_timer *t_event_timeout::get_timer(void) const { return timer; } /////////////////////////////////////////////////////////// // class t_event_failure /////////////////////////////////////////////////////////// t_event_failure::t_event_failure(t_failure f, unsigned short _tid) : t_event(), failure(f), tid_populated(true), tid(_tid) {} t_event_failure::t_event_failure(t_failure f, const string &_branch, const t_method &_cseq_method) : failure(f), tid_populated(false), branch(_branch), cseq_method(_cseq_method) {} t_event_type t_event_failure::get_type(void) const { return EV_FAILURE; } t_failure t_event_failure::get_failure(void) const { return failure; } unsigned short t_event_failure::get_tid(void) const { return tid; } string t_event_failure::get_branch(void) const { return branch; } t_method t_event_failure::get_cseq_method(void) const { return cseq_method; } bool t_event_failure::is_tid_populated(void) const { return tid_populated; } /////////////////////////////////////////////////////////// // class t_event_start_timer /////////////////////////////////////////////////////////// t_event_start_timer::t_event_start_timer(t_timer *t) : t_event() { timer = t->copy(); } t_event_type t_event_start_timer::get_type(void) const { return EV_START_TIMER; } t_timer *t_event_start_timer::get_timer(void) const { return timer; } /////////////////////////////////////////////////////////// // class t_event_stop_timer /////////////////////////////////////////////////////////// t_event_stop_timer::t_event_stop_timer(unsigned short id) : t_event() { timer_id = id; } t_event_type t_event_stop_timer::get_type(void) const { return EV_STOP_TIMER; } unsigned short t_event_stop_timer::get_timer_id(void) const { return timer_id; } /////////////////////////////////////////////////////////// // class t_event_abort_trans /////////////////////////////////////////////////////////// t_event_abort_trans::t_event_abort_trans(unsigned short _tid) : t_event() { tid = _tid; } t_event_type t_event_abort_trans::get_type(void) const { return EV_ABORT_TRANS; } unsigned short t_event_abort_trans::get_tid(void) const { return tid; } /////////////////////////////////////////////////////////// // class t_event_stun_request /////////////////////////////////////////////////////////// t_event_stun_request::t_event_stun_request(t_user *u, StunMessage *m, t_stun_event_type ev_type, unsigned short _tuid, unsigned short _tid) : t_event() { msg = new StunMessage(*m); MEMMAN_NEW(msg); stun_event_type = ev_type; tuid = _tuid; tid = _tid; dst_addr = 0; dst_port = 0; user_config = u->copy(); } t_event_stun_request::~t_event_stun_request() { MEMMAN_DELETE(msg); delete msg; MEMMAN_DELETE(user_config); delete user_config; } t_event_type t_event_stun_request::get_type(void) const { return EV_STUN_REQUEST; } StunMessage *t_event_stun_request::get_msg(void) const { return msg; } unsigned short t_event_stun_request::get_tuid(void) const { return tuid; } unsigned short t_event_stun_request::get_tid(void) const { return tid; } t_stun_event_type t_event_stun_request::get_stun_event_type(void) const { return stun_event_type; } t_user *t_event_stun_request::get_user_config(void) const { return user_config; } /////////////////////////////////////////////////////////// // class t_event_stun_response /////////////////////////////////////////////////////////// t_event_stun_response::t_event_stun_response(StunMessage *m, unsigned short _tuid, unsigned short _tid) : t_event() { msg = new StunMessage(*m); MEMMAN_NEW(msg); tuid = _tuid; tid = _tid; } t_event_stun_response::~t_event_stun_response() { MEMMAN_DELETE(msg); delete(msg); } t_event_type t_event_stun_response::get_type(void) const { return EV_STUN_RESPONSE; } StunMessage *t_event_stun_response::get_msg(void) const { return msg; } unsigned short t_event_stun_response::get_tuid(void) const { return tuid; } unsigned short t_event_stun_response::get_tid(void) const { return tid; } /////////////////////////////////////////////////////////// // class t_event_nat_keepalive /////////////////////////////////////////////////////////// t_event_type t_event_nat_keepalive::get_type(void) const { return EV_NAT_KEEPALIVE; } /////////////////////////////////////////////////////////// // class t_event_icmp /////////////////////////////////////////////////////////// t_event_icmp::t_event_icmp(const t_icmp_msg &m) : icmp(m) {} t_event_type t_event_icmp::get_type(void) const { return EV_ICMP; } t_icmp_msg t_event_icmp::get_icmp(void) const { return icmp; } /////////////////////////////////////////////////////////// // class t_event_ui /////////////////////////////////////////////////////////// t_event_ui::t_event_ui(t_ui_event_type _type) : t_event(), type(_type) {} t_event_type t_event_ui::get_type(void) const { return EV_UI; } void t_event_ui::set_line(int _line) { line = _line; } void t_event_ui::set_codec(t_audio_codec _codec) { codec = _codec; } void t_event_ui::set_dtmf_event(t_dtmf_ev _dtmf_event) { dtmf_event = _dtmf_event; } void t_event_ui::set_encrypted(bool on) { encrypted = on; } void t_event_ui::set_cipher_mode(const string &_cipher_mode) { cipher_mode = _cipher_mode; } void t_event_ui::set_zrtp_sas(const string &sas) { zrtp_sas = sas; } void t_event_ui::set_display_msg(const string &_msg, t_msg_priority &_msg_priority) { msg = _msg; msg_priority = _msg_priority; } void t_event_ui::exec(t_userintf *user_intf) { switch (type) { case TYPE_UI_CB_DTMF_DETECTED: ui->cb_dtmf_detected(line, dtmf_event); break; case TYPE_UI_CB_SEND_DTMF: ui->cb_send_dtmf(line, dtmf_event); break; case TYPE_UI_CB_RECV_CODEC_CHANGED: ui->cb_recv_codec_changed(line, codec); break; case TYPE_UI_CB_LINE_STATE_CHANGED: ui->cb_line_state_changed(); break; case TYPE_UI_CB_LINE_ENCRYPTED: ui->cb_line_encrypted(line, encrypted, cipher_mode); break; case TYPE_UI_CB_SHOW_ZRTP_SAS: ui->cb_show_zrtp_sas(line, zrtp_sas); break; case TYPE_UI_CB_ZRTP_CONFIRM_GO_CLEAR: ui->cb_zrtp_confirm_go_clear(line); break; case TYPE_UI_CB_QUIT: ui->cmd_quit(); break; default: assert(false); } } /////////////////////////////////////////////////////////// // class t_event_async_response /////////////////////////////////////////////////////////// t_event_async_response::t_event_async_response(t_response_type type) : t_event(), response_type(type) {} t_event_type t_event_async_response::get_type(void) const { return EV_ASYNC_RESPONSE; } void t_event_async_response::set_bool_response(bool b) { bool_response = b; } t_event_async_response::t_response_type t_event_async_response::get_response_type(void) const { return response_type; } bool t_event_async_response::get_bool_response(void) const { return bool_response; } /////////////////////////////////////////////////////////// // class t_event_broken_connection /////////////////////////////////////////////////////////// t_event_broken_connection::t_event_broken_connection(const t_url &url) : t_event(), user_uri_(url) {} t_event_type t_event_broken_connection::get_type(void) const { return EV_BROKEN_CONNECTION; } t_url t_event_broken_connection::get_user_uri(void) const { return user_uri_; } /////////////////////////////////////////////////////////// // class t_event_tcp_ping /////////////////////////////////////////////////////////// t_event_tcp_ping::t_event_tcp_ping(const t_url &url, unsigned int dst_addr, unsigned short dst_port) : t_event(), user_uri_(url), dst_addr_(dst_addr), dst_port_(dst_port) {} t_event_type t_event_tcp_ping::get_type(void) const { return EV_TCP_PING; } t_url t_event_tcp_ping::get_user_uri(void) const { return user_uri_; } unsigned int t_event_tcp_ping::get_dst_addr(void) const { return dst_addr_; } unsigned short t_event_tcp_ping::get_dst_port(void) const { return dst_port_; } /////////////////////////////////////////////////////////// // class t_event_fncall /////////////////////////////////////////////////////////// t_event_fncall::t_event_fncall(std::function fn) : m_fn(fn) { } void t_event_fncall::invoke() { m_fn(); } t_event_type t_event_fncall::get_type(void) const { return EV_FN_CALL; } /////////////////////////////////////////////////////////// // class t_event_queue /////////////////////////////////////////////////////////// t_event_queue::t_event_queue() : sema_evq(0), sema_caught_interrupt(0) {} t_event_queue::~t_event_queue() { log_file->write_header("t_event_queue::~t_event_queue", LOG_NORMAL, LOG_INFO); log_file->write_raw("Clean up event queue.\n"); while (!ev_queue.empty()) { t_event *e = ev_queue.front(); ev_queue.pop(); log_file->write_raw("\nDeleting unprocessed event: \n"); log_file->write_raw("Type: "); log_file->write_raw(event_type2str(e->get_type())); log_file->write_raw(", Pointer: "); log_file->write_raw(ptr2str(e)); log_file->write_endl(); MEMMAN_DELETE(e); delete e; } log_file->write_footer(); } void t_event_queue::push(t_event *e) { mutex_evq.lock(); ev_queue.push(e); mutex_evq.unlock(); sema_evq.up(); } void t_event_queue::push_quit(void) { t_event_quit *event = new t_event_quit(); MEMMAN_NEW(event); push(event); } void t_event_queue::push_fncall(std::function fn) { t_event_fncall* event = new t_event_fncall(fn); MEMMAN_NEW(event); push(event); } void t_event_queue::push_network(t_sip_message *m, const t_ip_port &ip_port) { t_event_network *event = new t_event_network(m); MEMMAN_NEW(event); event->dst_addr = ip_port.ipaddr; event->dst_port = ip_port.port; event->transport = ip_port.transport; push(event); } void t_event_queue::push_user(t_user *user_config, t_sip_message *m, unsigned short tuid, unsigned short tid) { t_event_user *event = new t_event_user(user_config, m, tuid, tid); MEMMAN_NEW(event); push(event); } void t_event_queue::push_user(t_sip_message *m, unsigned short tuid, unsigned short tid) { push_user(NULL, m, tuid, tid); } void t_event_queue::push_user_cancel(t_user *user_config, t_sip_message *m, unsigned short tuid, unsigned short tid, unsigned short target_tid) { t_event_user *event = new t_event_user(user_config, m, tuid, tid, target_tid); MEMMAN_NEW(event); push(event); } void t_event_queue::push_user_cancel(t_sip_message *m, unsigned short tuid, unsigned short tid, unsigned short target_tid) { push_user_cancel(NULL, m, tuid, tid, target_tid); } void t_event_queue::push_timeout(t_timer *t) { t_event_timeout *event = new t_event_timeout(t); MEMMAN_NEW(event); push(event); } void t_event_queue::push_failure(t_failure f, unsigned short tid) { t_event_failure *event = new t_event_failure(f, tid); MEMMAN_NEW(event); push(event); } void t_event_queue::push_failure(t_failure f, const string &branch, const t_method &cseq_method) { t_event_failure *event = new t_event_failure(f, branch, cseq_method); MEMMAN_NEW(event); push(event); } void t_event_queue::push_start_timer(t_timer *t) { t_event_start_timer *event = new t_event_start_timer(t); MEMMAN_NEW(event); push(event); } void t_event_queue::push_stop_timer(unsigned short timer_id) { t_event_stop_timer *event = new t_event_stop_timer(timer_id); MEMMAN_NEW(event); push(event); } void t_event_queue::push_abort_trans(unsigned short tid) { t_event_abort_trans *event = new t_event_abort_trans(tid); MEMMAN_NEW(event); push(event); } void t_event_queue::push_stun_request(t_user *user_config, StunMessage *m, t_stun_event_type ev_type, unsigned short tuid, unsigned short tid, unsigned long ipaddr, unsigned short port, unsigned short src_port) { t_event_stun_request *event = new t_event_stun_request(user_config, m, ev_type, tuid, tid); MEMMAN_NEW(event); event->dst_addr = ipaddr; event->dst_port = port; event->src_port = src_port; push(event); } void t_event_queue::push_stun_response(StunMessage *m, unsigned short tuid, unsigned short tid) { t_event_stun_response *event = new t_event_stun_response(m, tuid, tid); MEMMAN_NEW(event); push(event); } void t_event_queue::push_nat_keepalive(unsigned long ipaddr, unsigned short port) { t_event_nat_keepalive *event = new t_event_nat_keepalive(); MEMMAN_NEW(event); event->dst_addr = ipaddr; event->dst_port = port; push(event); } void t_event_queue::push_icmp(const t_icmp_msg &m) { t_event_icmp *event = new t_event_icmp(m); MEMMAN_NEW(event); push(event); } void t_event_queue::push_refer_permission_response(bool permission) { t_event_async_response *event = new t_event_async_response( t_event_async_response::RESP_REFER_PERMISSION); MEMMAN_NEW(event); event->set_bool_response(permission); push(event); } void t_event_queue::push_broken_connection(const t_url &user_uri) { t_event_broken_connection *event = new t_event_broken_connection(user_uri); MEMMAN_NEW(event); push(event); } void t_event_queue::push_tcp_ping(const t_url &user_uri, unsigned int dst_addr, unsigned short dst_port) { t_event_tcp_ping *event = new t_event_tcp_ping(user_uri, dst_addr, dst_port); MEMMAN_NEW(event); push(event); } t_event *t_event_queue::pop(void) { t_event *e; bool interrupt; do { interrupt = false; sema_evq.down(); mutex_evq.lock(); if (sema_caught_interrupt.try_down()) { // This pop is non-interruptable, so ignore the interrupt interrupt = true; } else { e = ev_queue.front(); ev_queue.pop(); } mutex_evq.unlock(); } while (interrupt); return e; } t_event *t_event_queue::pop(bool &interrupted) { t_event *e; sema_evq.down(); mutex_evq.lock(); if (sema_caught_interrupt.try_down()) { interrupted = true; e = NULL; } else { interrupted = false; e = ev_queue.front(); ev_queue.pop(); } mutex_evq.unlock(); return e; } void t_event_queue::interrupt(void) { sema_caught_interrupt.up(); sema_evq.up(); }