/* The oSIP library implements the Session Initiation Protocol (SIP -rfc3261-) Copyright (C) 2001-2020 Aymeric MOIZARD amoizard@antisip.com This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include "fsm.h" #include "xixt.h" #include #if defined(HAVE_DICT_DICT_H) #include #endif void osip_response_get_destination(osip_message_t *response, char **address, int *portnum) { osip_via_t *via; char *host = NULL; int port = 0; via = (osip_via_t *) osip_list_get(&response->vias, 0); if (via) { osip_generic_param_t *maddr; osip_generic_param_t *received; osip_generic_param_t *rport; osip_via_param_get_byname(via, "maddr", &maddr); osip_via_param_get_byname(via, "received", &received); osip_via_param_get_byname(via, "rport", &rport); /* 1: user should not use the provided information (host and port) if they are using a reliable transport. Instead, they should use the already open socket attached to this transaction. */ /* 2: check maddr and multicast usage */ if (maddr != NULL) host = maddr->gvalue; /* we should check if this is a multicast address and use set the "ttl" in this case. (this must be done in the UDP message (not at the SIP layer) */ else if (received != NULL) host = received->gvalue; else host = via->host; if (rport == NULL || rport->gvalue == NULL) { if (via->port != NULL) port = osip_atoi(via->port); else port = 5060; } else port = osip_atoi(rport->gvalue); } *portnum = port; if (host != NULL) *address = osip_strdup(host); else *address = NULL; } static int osip_ixt_lock(osip_t *osip) { #ifndef OSIP_MONOTHREAD return osip_mutex_lock(osip->ixt_fastmutex); #else return OSIP_SUCCESS; #endif } static int osip_ixt_unlock(osip_t *osip) { #ifndef OSIP_MONOTHREAD return osip_mutex_unlock(osip->ixt_fastmutex); #else return OSIP_SUCCESS; #endif } int osip_id_mutex_lock(osip_t *osip); int osip_id_mutex_unlock(osip_t *osip); int osip_id_mutex_lock(osip_t *osip) { #ifndef OSIP_MONOTHREAD return osip_mutex_lock(osip->id_mutex); #else return OSIP_SUCCESS; #endif } int osip_id_mutex_unlock(osip_t *osip) { #ifndef OSIP_MONOTHREAD return osip_mutex_unlock(osip->id_mutex); #else return OSIP_SUCCESS; #endif } /* these are for transactions that would need retransmission not handled by state machines */ static void osip_add_ixt(osip_t *osip, ixt_t *ixt) { /* add in list osip_t->ixt */ osip_ixt_lock(osip); osip_list_add(&osip->ixt_retransmissions, (void *) ixt, 0); osip_ixt_unlock(osip); } static int ixt_init(ixt_t **ixt) { ixt_t *pixt; *ixt = pixt = (ixt_t *) osip_malloc(sizeof(ixt_t)); if (pixt == NULL) return OSIP_NOMEM; pixt->dialog = NULL; pixt->msg2xx = NULL; pixt->ack = NULL; pixt->interval = DEFAULT_T1; osip_gettimeofday(&pixt->start, NULL); add_gettimeofday(&pixt->start, pixt->interval + 10); pixt->counter = 10; pixt->dest = NULL; pixt->port = 5060; pixt->sock = -1; return OSIP_SUCCESS; } static void ixt_free(ixt_t *ixt) { osip_message_free(ixt->ack); osip_message_free(ixt->msg2xx); osip_free(ixt->dest); osip_free(ixt); } /* usefull for UAs */ void osip_start_200ok_retransmissions(osip_t *osip, osip_dialog_t *dialog, osip_message_t *msg200ok, int sock) { int i; ixt_t *ixt; i = ixt_init(&ixt); if (i != 0) return; ixt->dialog = dialog; osip_message_clone(msg200ok, &ixt->msg2xx); ixt->sock = sock; osip_response_get_destination(msg200ok, &ixt->dest, &ixt->port); osip_add_ixt(osip, ixt); } void osip_start_ack_retransmissions(osip_t *osip, osip_dialog_t *dialog, osip_message_t *ack, char *dest, int port, int sock) { int i; ixt_t *ixt; i = ixt_init(&ixt); if (i != 0) return; ixt->dialog = dialog; osip_message_clone(ack, &ixt->ack); ixt->dest = osip_strdup(dest); ixt->port = port; ixt->sock = sock; osip_add_ixt(osip, ixt); } /* we stop the 200ok when receiving the corresponding ack */ struct osip_dialog *osip_stop_200ok_retransmissions(osip_t *osip, osip_message_t *ack) { osip_dialog_t *dialog = NULL; int i; ixt_t *ixt; if (ack == NULL || ack->cseq == NULL || ack->cseq->number == NULL) return NULL; osip_ixt_lock(osip); for (i = 0; !osip_list_eol(&osip->ixt_retransmissions, i); i++) { ixt = (ixt_t *) osip_list_get(&osip->ixt_retransmissions, i); if (ixt->msg2xx == NULL || ixt->msg2xx->cseq == NULL || ixt->msg2xx->cseq->number == NULL) continue; if (osip_dialog_match_as_uas(ixt->dialog, ack) == 0 && strcmp(ixt->msg2xx->cseq->number, ack->cseq->number) == 0) { osip_list_remove(&osip->ixt_retransmissions, i); dialog = ixt->dialog; ixt_free(ixt); break; } } osip_ixt_unlock(osip); return dialog; } /* when a dialog is destroyed by the application, it is safer to remove all ixt that are related to it */ void osip_stop_retransmissions_from_dialog(osip_t *osip, osip_dialog_t *dialog) { int i; ixt_t *ixt; osip_ixt_lock(osip); for (i = 0; !osip_list_eol(&osip->ixt_retransmissions, i); i++) { ixt = (ixt_t *) osip_list_get(&osip->ixt_retransmissions, i); if (ixt->dialog == dialog) { osip_list_remove(&osip->ixt_retransmissions, i); ixt_free(ixt); i--; } } osip_ixt_unlock(osip); } static void ixt_retransmit(osip_t *osip, ixt_t *ixt, struct timeval *current) { if (osip_timercmp(current, &ixt->start, >=)) { ixt->interval = ixt->interval * 2; if (ixt->interval > DEFAULT_T2) ixt->interval = DEFAULT_T2; add_gettimeofday(&ixt->start, ixt->interval); if (ixt->ack != NULL) osip->cb_send_message(NULL, ixt->ack, ixt->dest, ixt->port, ixt->sock); else if (ixt->msg2xx != NULL) osip->cb_send_message(NULL, ixt->msg2xx, ixt->dest, ixt->port, ixt->sock); ixt->counter--; } } void osip_retransmissions_execute(osip_t *osip) { int i; ixt_t *ixt; struct timeval current; osip_gettimeofday(¤t, NULL); osip_ixt_lock(osip); for (i = 0; !osip_list_eol(&osip->ixt_retransmissions, i); i++) { ixt = (ixt_t *) osip_list_get(&osip->ixt_retransmissions, i); ixt_retransmit(osip, ixt, ¤t); if (ixt->counter == 0) { /* remove it */ osip_list_remove(&osip->ixt_retransmissions, i); ixt_free(ixt); i--; } } osip_ixt_unlock(osip); } int osip_ict_lock(osip_t *osip) { #ifndef OSIP_MONOTHREAD return osip_mutex_lock(osip->ict_fastmutex); #else return OSIP_SUCCESS; #endif } int osip_ict_unlock(osip_t *osip) { #ifndef OSIP_MONOTHREAD return osip_mutex_unlock(osip->ict_fastmutex); #else return OSIP_SUCCESS; #endif } int osip_ist_lock(osip_t *osip) { #ifndef OSIP_MONOTHREAD return osip_mutex_lock(osip->ist_fastmutex); #else return OSIP_SUCCESS; #endif } int osip_ist_unlock(osip_t *osip) { #ifndef OSIP_MONOTHREAD return osip_mutex_unlock(osip->ist_fastmutex); #else return OSIP_SUCCESS; #endif } int osip_nict_lock(osip_t *osip) { #ifndef OSIP_MONOTHREAD return osip_mutex_lock(osip->nict_fastmutex); #else return OSIP_SUCCESS; #endif } int osip_nict_unlock(osip_t *osip) { #ifndef OSIP_MONOTHREAD return osip_mutex_unlock(osip->nict_fastmutex); #else return OSIP_SUCCESS; #endif } int osip_nist_lock(osip_t *osip) { #ifndef OSIP_MONOTHREAD return osip_mutex_lock(osip->nist_fastmutex); #else return OSIP_SUCCESS; #endif } int osip_nist_unlock(osip_t *osip) { #ifndef OSIP_MONOTHREAD return osip_mutex_unlock(osip->nist_fastmutex); #else return OSIP_SUCCESS; #endif } #if defined(HAVE_DICT_DICT_H) #define HSIZE 200 unsigned s_hash(const unsigned char *p); unsigned s_hash(const unsigned char *p) { unsigned hash = 0; while (*p) { hash *= 31; hash ^= *p++; } return hash; } #endif int __osip_add_ict(osip_t *osip, osip_transaction_t *ict) { #ifndef OSIP_MONOTHREAD osip_mutex_lock(osip->ict_fastmutex); #endif #if defined(HAVE_DICT_DICT_H) { osip_generic_param_t *b_request = NULL; int rv = -99; osip_via_param_get_byname(ict->topvia, "branch", &b_request); if (b_request != NULL && b_request->gvalue != NULL) rv = dict_insert((dict *) osip->osip_ict_hastable, b_request->gvalue, (void *) ict, FALSE); if (rv == 0) { OSIP_TRACE(osip_trace(__FILE__, __LINE__, OSIP_INFO1, NULL, "New key inserted in ict hastable `%s'\n", b_request->gvalue)); } else if (rv != -99) { OSIP_TRACE(osip_trace(__FILE__, __LINE__, OSIP_WARNING, NULL, "already inserted `%s'\n", b_request->gvalue)); } } #endif osip_list_add(&osip->osip_ict_transactions, ict, -1); #ifndef OSIP_MONOTHREAD osip_mutex_unlock(osip->ict_fastmutex); #endif return OSIP_SUCCESS; } int __osip_add_ist(osip_t *osip, osip_transaction_t *ist) { #ifndef OSIP_MONOTHREAD osip_mutex_lock(osip->ist_fastmutex); #endif #if defined(HAVE_DICT_DICT_H) { osip_generic_param_t *b_request = NULL; int rv = -99; osip_via_param_get_byname(ist->topvia, "branch", &b_request); if (b_request != NULL && b_request->gvalue != NULL) rv = dict_insert((dict *) osip->osip_ist_hastable, b_request->gvalue, (void *) ist, FALSE); if (rv == 0) { OSIP_TRACE(osip_trace(__FILE__, __LINE__, OSIP_INFO1, NULL, "New key inserted in ist hastable `%s'\n", b_request->gvalue)); } else if (rv != -99) { OSIP_TRACE(osip_trace(__FILE__, __LINE__, OSIP_WARNING, NULL, "already inserted `%s'\n", b_request->gvalue)); } } #endif osip_list_add(&osip->osip_ist_transactions, ist, -1); #ifndef OSIP_MONOTHREAD osip_mutex_unlock(osip->ist_fastmutex); #endif return OSIP_SUCCESS; } int __osip_add_nict(osip_t *osip, osip_transaction_t *nict) { #ifndef OSIP_MONOTHREAD osip_mutex_lock(osip->nict_fastmutex); #endif #if defined(HAVE_DICT_DICT_H) { osip_generic_param_t *b_request = NULL; int rv = -99; osip_via_param_get_byname(nict->topvia, "branch", &b_request); if (b_request != NULL && b_request->gvalue != NULL) rv = dict_insert((dict *) osip->osip_nict_hastable, b_request->gvalue, (void *) nict, FALSE); if (rv == 0) { OSIP_TRACE(osip_trace(__FILE__, __LINE__, OSIP_INFO1, NULL, "New key inserted in nict hastable `%s'\n", b_request->gvalue)); } else if (rv != -99) { OSIP_TRACE(osip_trace(__FILE__, __LINE__, OSIP_WARNING, NULL, "already inserted `%s'\n", b_request->gvalue)); } } #endif osip_list_add(&osip->osip_nict_transactions, nict, -1); #ifndef OSIP_MONOTHREAD osip_mutex_unlock(osip->nict_fastmutex); #endif return OSIP_SUCCESS; } int __osip_add_nist(osip_t *osip, osip_transaction_t *nist) { #ifndef OSIP_MONOTHREAD osip_mutex_lock(osip->nist_fastmutex); #endif #if defined(HAVE_DICT_DICT_H) { osip_generic_param_t *b_request = NULL; int rv = -99; osip_via_param_get_byname(nist->topvia, "branch", &b_request); if (b_request != NULL && b_request->gvalue != NULL) rv = dict_insert((dict *) osip->osip_nist_hastable, b_request->gvalue, (void *) nist, FALSE); if (rv == 0) { OSIP_TRACE(osip_trace(__FILE__, __LINE__, OSIP_INFO1, NULL, "New key inserted in ict hastable `%s'\n", b_request->gvalue)); } else if (rv != -99) { OSIP_TRACE(osip_trace(__FILE__, __LINE__, OSIP_WARNING, NULL, "already inserted `%s'\n", b_request->gvalue)); } } #endif osip_list_add(&osip->osip_nist_transactions, nist, -1); #ifndef OSIP_MONOTHREAD osip_mutex_unlock(osip->nist_fastmutex); #endif return OSIP_SUCCESS; } int osip_remove_transaction(osip_t *osip, osip_transaction_t *tr) { int i = -1; if (tr == NULL) return OSIP_BADPARAMETER; if (tr->ctx_type == ICT) i = __osip_remove_ict_transaction(osip, tr); else if (tr->ctx_type == IST) i = __osip_remove_ist_transaction(osip, tr); else if (tr->ctx_type == NICT) i = __osip_remove_nict_transaction(osip, tr); else if (tr->ctx_type == NIST) i = __osip_remove_nist_transaction(osip, tr); else return OSIP_BADPARAMETER; return i; } int __osip_remove_ict_transaction(osip_t *osip, osip_transaction_t *ict) { osip_list_iterator_t iterator; osip_transaction_t *tmp; #ifndef OSIP_MONOTHREAD osip_mutex_lock(osip->ict_fastmutex); #endif #if defined(HAVE_DICT_DICT_H) { osip_generic_param_t *b_request = NULL; int rv; osip_via_param_get_byname(ict->topvia, "branch", &b_request); if (b_request != NULL && b_request->gvalue != NULL) { rv = dict_remove((dict *) osip->osip_ict_hastable, b_request->gvalue, TRUE); if (rv == 0) { OSIP_TRACE(osip_trace(__FILE__, __LINE__, OSIP_INFO1, NULL, "New key deleted in ict hastable `%s'\n", b_request->gvalue)); } else { OSIP_TRACE(osip_trace(__FILE__, __LINE__, OSIP_WARNING, NULL, "key not removed `%s'\n", b_request->gvalue)); } } } #endif tmp = (osip_transaction_t *) osip_list_get_first(&osip->osip_ict_transactions, &iterator); while (osip_list_iterator_has_elem(iterator)) { if (tmp->transactionid == ict->transactionid) { osip_list_iterator_remove(&iterator); #ifndef OSIP_MONOTHREAD osip_mutex_unlock(osip->ict_fastmutex); #endif return OSIP_SUCCESS; } tmp = (osip_transaction_t *) osip_list_get_next(&iterator); } #ifndef OSIP_MONOTHREAD osip_mutex_unlock(osip->ict_fastmutex); #endif return OSIP_UNDEFINED_ERROR; } int __osip_remove_ist_transaction(osip_t *osip, osip_transaction_t *ist) { osip_list_iterator_t iterator; osip_transaction_t *tmp; #ifndef OSIP_MONOTHREAD osip_mutex_lock(osip->ist_fastmutex); #endif #if defined(HAVE_DICT_DICT_H) { osip_generic_param_t *b_request = NULL; int rv; osip_via_param_get_byname(ist->topvia, "branch", &b_request); if (b_request != NULL && b_request->gvalue != NULL) { rv = dict_remove((dict *) osip->osip_ist_hastable, b_request->gvalue, TRUE); if (rv == 0) { OSIP_TRACE(osip_trace(__FILE__, __LINE__, OSIP_INFO1, NULL, "New key deleted in ist hastable `%s'\n", b_request->gvalue)); } else { OSIP_TRACE(osip_trace(__FILE__, __LINE__, OSIP_WARNING, NULL, "key not removed `%s'\n", b_request->gvalue)); } } } #endif tmp = (osip_transaction_t *) osip_list_get_first(&osip->osip_ist_transactions, &iterator); while (osip_list_iterator_has_elem(iterator)) { if (tmp->transactionid == ist->transactionid) { osip_list_iterator_remove(&iterator); #ifndef OSIP_MONOTHREAD osip_mutex_unlock(osip->ist_fastmutex); #endif return OSIP_SUCCESS; } tmp = (osip_transaction_t *) osip_list_get_next(&iterator); } #ifndef OSIP_MONOTHREAD osip_mutex_unlock(osip->ist_fastmutex); #endif return OSIP_UNDEFINED_ERROR; } int __osip_remove_nict_transaction(osip_t *osip, osip_transaction_t *nict) { osip_list_iterator_t iterator; osip_transaction_t *tmp; #ifndef OSIP_MONOTHREAD osip_mutex_lock(osip->nict_fastmutex); #endif #if defined(HAVE_DICT_DICT_H) { osip_generic_param_t *b_request = NULL; int rv; osip_via_param_get_byname(nict->topvia, "branch", &b_request); if (b_request != NULL && b_request->gvalue != NULL) { rv = dict_remove((dict *) osip->osip_nict_hastable, b_request->gvalue, TRUE); if (rv == 0) { OSIP_TRACE(osip_trace(__FILE__, __LINE__, OSIP_INFO1, NULL, "New key deleted in nict hastable `%s'\n", b_request->gvalue)); } else { OSIP_TRACE(osip_trace(__FILE__, __LINE__, OSIP_WARNING, NULL, "key not removed `%s'\n", b_request->gvalue)); } } } #endif tmp = (osip_transaction_t *) osip_list_get_first(&osip->osip_nict_transactions, &iterator); while (osip_list_iterator_has_elem(iterator)) { if (tmp->transactionid == nict->transactionid) { osip_list_iterator_remove(&iterator); #ifndef OSIP_MONOTHREAD osip_mutex_unlock(osip->nict_fastmutex); #endif return OSIP_SUCCESS; } tmp = (osip_transaction_t *) osip_list_get_next(&iterator); } #ifndef OSIP_MONOTHREAD osip_mutex_unlock(osip->nict_fastmutex); #endif return OSIP_UNDEFINED_ERROR; } int __osip_remove_nist_transaction(osip_t *osip, osip_transaction_t *nist) { osip_list_iterator_t iterator; osip_transaction_t *tmp; #ifndef OSIP_MONOTHREAD osip_mutex_lock(osip->nist_fastmutex); #endif #if defined(HAVE_DICT_DICT_H) { osip_generic_param_t *b_request = NULL; int rv; osip_via_param_get_byname(nist->topvia, "branch", &b_request); if (b_request != NULL && b_request->gvalue != NULL) { rv = dict_remove((dict *) osip->osip_nist_hastable, b_request->gvalue, TRUE); if (rv == 0) { OSIP_TRACE(osip_trace(__FILE__, __LINE__, OSIP_INFO1, NULL, "New key deleted in ict hastable `%s'\n", b_request->gvalue)); } else { OSIP_TRACE(osip_trace(__FILE__, __LINE__, OSIP_WARNING, NULL, "key not removed `%s'\n", b_request->gvalue)); } } } #endif tmp = (osip_transaction_t *) osip_list_get_first(&osip->osip_nist_transactions, &iterator); while (osip_list_iterator_has_elem(iterator)) { if (tmp->transactionid == nist->transactionid) { osip_list_iterator_remove(&iterator); #ifndef OSIP_MONOTHREAD osip_mutex_unlock(osip->nist_fastmutex); #endif return OSIP_SUCCESS; } tmp = (osip_transaction_t *) osip_list_get_next(&iterator); } #ifndef OSIP_MONOTHREAD osip_mutex_unlock(osip->nist_fastmutex); #endif return OSIP_UNDEFINED_ERROR; } int osip_find_transaction_and_add_event(osip_t *osip, osip_event_t *evt) { osip_transaction_t *transaction = __osip_find_transaction(osip, evt, 1); if (transaction == NULL) return OSIP_UNDEFINED_ERROR; return OSIP_SUCCESS; } #ifdef OSIP_MONOTHREAD osip_transaction_t *osip_find_transaction(osip_t *osip, osip_event_t *evt) { return __osip_find_transaction(osip, evt, 0); } #endif osip_transaction_t *__osip_find_transaction(osip_t *osip, osip_event_t *evt, int consume) { osip_transaction_t *transaction = NULL; osip_list_t *transactions = NULL; #ifndef OSIP_MONOTHREAD struct osip_mutex *mut = NULL; #endif if (evt == NULL || evt->sip == NULL || evt->sip->cseq == NULL) return NULL; if (EVT_IS_INCOMINGMSG(evt)) { if (MSG_IS_REQUEST(evt->sip)) { if (0 == strcmp(evt->sip->cseq->method, "INVITE") || 0 == strcmp(evt->sip->cseq->method, "ACK")) { transactions = &osip->osip_ist_transactions; #ifndef OSIP_MONOTHREAD mut = osip->ist_fastmutex; #endif } else { transactions = &osip->osip_nist_transactions; #ifndef OSIP_MONOTHREAD mut = osip->nist_fastmutex; #endif } } else { if (0 == strcmp(evt->sip->cseq->method, "INVITE")) { transactions = &osip->osip_ict_transactions; #ifndef OSIP_MONOTHREAD mut = osip->ict_fastmutex; #endif } else { transactions = &osip->osip_nict_transactions; #ifndef OSIP_MONOTHREAD mut = osip->nict_fastmutex; #endif } } } else if (EVT_IS_OUTGOINGMSG(evt)) { if (MSG_IS_RESPONSE(evt->sip)) { if (0 == strcmp(evt->sip->cseq->method, "INVITE")) { transactions = &osip->osip_ist_transactions; #ifndef OSIP_MONOTHREAD mut = osip->ist_fastmutex; #endif } else { transactions = &osip->osip_nist_transactions; #ifndef OSIP_MONOTHREAD mut = osip->nist_fastmutex; #endif } } else { if (0 == strcmp(evt->sip->cseq->method, "INVITE") || 0 == strcmp(evt->sip->cseq->method, "ACK")) { transactions = &osip->osip_ict_transactions; #ifndef OSIP_MONOTHREAD mut = osip->ict_fastmutex; #endif } else { transactions = &osip->osip_nict_transactions; #ifndef OSIP_MONOTHREAD mut = osip->nict_fastmutex; #endif } } } if (transactions == NULL) return NULL; /* not a message??? */ #ifndef OSIP_MONOTHREAD osip_mutex_lock(mut); #endif transaction = osip_transaction_find(transactions, evt); if (consume == 1) { /* we add the event before releasing the mutex!! */ if (transaction != NULL) { osip_transaction_add_event(transaction, evt); #ifndef OSIP_MONOTHREAD osip_mutex_unlock(mut); #endif return transaction; } } #ifndef OSIP_MONOTHREAD osip_mutex_unlock(mut); #endif return transaction; } osip_transaction_t *osip_create_transaction(osip_t *osip, osip_event_t *evt) { osip_transaction_t *transaction; int i; osip_fsm_type_t ctx_type; if (evt == NULL) return NULL; if (evt->sip == NULL) return NULL; /* make sure the request's method reflect the cseq value. */ if (MSG_IS_REQUEST(evt->sip)) { /* delete request where cseq method does not match the method in request-line */ if (evt->sip->cseq == NULL || evt->sip->cseq->method == NULL || evt->sip->sip_method == NULL) { return NULL; } if (0 != strcmp(evt->sip->cseq->method, evt->sip->sip_method)) { OSIP_TRACE(osip_trace(__FILE__, __LINE__, OSIP_WARNING, NULL, "core module: Discard invalid message with method!=cseq!\n")); return NULL; } } if (MSG_IS_ACK(evt->sip)) /* ACK never create transactions */ return NULL; if (EVT_IS_INCOMINGREQ(evt)) { /* we create a new context for this incoming request */ if (0 == strcmp(evt->sip->cseq->method, "INVITE")) ctx_type = IST; else ctx_type = NIST; } else if (EVT_IS_OUTGOINGREQ(evt)) { if (0 == strcmp(evt->sip->cseq->method, "INVITE")) ctx_type = ICT; else ctx_type = NICT; } else { OSIP_TRACE(osip_trace(__FILE__, __LINE__, OSIP_ERROR, NULL, "Cannot build a transaction for this message!\n")); return NULL; } i = osip_transaction_init(&transaction, ctx_type, osip, evt->sip); if (i != 0) { return NULL; } evt->transactionid = transaction->transactionid; return transaction; } osip_transaction_t *osip_transaction_find(osip_list_t *transactions, osip_event_t *evt) { osip_list_iterator_t iterator; osip_transaction_t *transaction; osip_t *osip = NULL; transaction = (osip_transaction_t *) osip_list_get_first(transactions, &iterator); if (transaction != NULL) osip = (osip_t *) transaction->config; if (osip == NULL) return NULL; if (EVT_IS_INCOMINGREQ(evt)) { #ifdef HAVE_DICT_DICT_H /* search in hastable! */ osip_generic_param_t *b_request; osip_via_t *topvia_request; topvia_request = osip_list_get(&evt->sip->vias, 0); if (topvia_request == NULL) { OSIP_TRACE(osip_trace(__FILE__, __LINE__, OSIP_ERROR, NULL, "Remote UA is not compliant: missing a Via header!\n")); return NULL; } osip_via_param_get_byname(topvia_request, "branch", &b_request); if (b_request != NULL && b_request->gvalue != NULL) { if (MSG_IS_INVITE(evt->sip) || MSG_IS_ACK(evt->sip)) { transaction = (osip_transaction_t *) dict_search((dict *) osip->osip_ist_hastable, b_request->gvalue); OSIP_TRACE(osip_trace(__FILE__, __LINE__, OSIP_INFO2, NULL, "Find matching Via header for INVITE(ACK) REQUEST!\n")); if (transaction != NULL) return transaction; } else { transaction = (osip_transaction_t *) dict_search((dict *) osip->osip_nist_hastable, b_request->gvalue); OSIP_TRACE(osip_trace(__FILE__, __LINE__, OSIP_INFO2, NULL, "Find matching Via header for NON-INVITE REQUEST!\n")); if (transaction != NULL) return transaction; } } #endif transaction = (osip_transaction_t *) osip_list_get_first(transactions, &iterator); while (osip_list_iterator_has_elem(iterator)) { if (0 == __osip_transaction_matching_request_osip_to_xist_17_2_3(transaction, evt->sip)) return transaction; transaction = (osip_transaction_t *) osip_list_get_next(&iterator); } } else if (EVT_IS_INCOMINGRESP(evt)) { #ifdef HAVE_DICT_DICT_H /* search in hastable! */ osip_generic_param_t *b_request; osip_via_t *topvia_request; topvia_request = osip_list_get(&evt->sip->vias, 0); if (topvia_request == NULL) { OSIP_TRACE(osip_trace(__FILE__, __LINE__, OSIP_ERROR, NULL, "Remote UA is not compliant: missing a Via header!\n")); return NULL; } osip_via_param_get_byname(topvia_request, "branch", &b_request); if (b_request != NULL && b_request->gvalue != NULL) { if (MSG_IS_RESPONSE_FOR(evt->sip, "INVITE")) { transaction = (osip_transaction_t *) dict_search((dict *) osip->osip_ict_hastable, b_request->gvalue); OSIP_TRACE(osip_trace(__FILE__, __LINE__, OSIP_INFO2, NULL, "Find matching Via header for INVITE ANSWER!\n")); if (transaction != NULL) return transaction; } else { transaction = (osip_transaction_t *) dict_search((dict *) osip->osip_nict_hastable, b_request->gvalue); OSIP_TRACE(osip_trace(__FILE__, __LINE__, OSIP_INFO2, NULL, "Find matching Via header for NON-INVITE ANSWER!\n")); if (transaction != NULL) return transaction; } } #endif transaction = (osip_transaction_t *) osip_list_get_first(transactions, &iterator); while (osip_list_iterator_has_elem(iterator)) { if (0 == __osip_transaction_matching_response_osip_to_xict_17_1_3(transaction, evt->sip)) return transaction; transaction = (osip_transaction_t *) osip_list_get_next(&iterator); } } else { /* handle OUTGOING message */ /* THE TRANSACTION ID MUST BE SET */ transaction = (osip_transaction_t *) osip_list_get_first(transactions, &iterator); while (osip_list_iterator_has_elem(iterator)) { if (transaction->transactionid == evt->transactionid) return transaction; transaction = (osip_transaction_t *) osip_list_get_next(&iterator); } } return NULL; } int osip_init(osip_t **osip) { static int ref_count = 0; if (ref_count == 0) { ref_count++; /* load the parser configuration */ parser_init(); } *osip = (osip_t *) osip_malloc(sizeof(osip_t)); if (*osip == NULL) return OSIP_NOMEM; /* allocation failed */ memset(*osip, 0, sizeof(osip_t)); #ifndef OSIP_MONOTHREAD (*osip)->ict_fastmutex = osip_mutex_init(); (*osip)->ist_fastmutex = osip_mutex_init(); (*osip)->nict_fastmutex = osip_mutex_init(); (*osip)->nist_fastmutex = osip_mutex_init(); (*osip)->ixt_fastmutex = osip_mutex_init(); (*osip)->id_mutex = osip_mutex_init(); #endif osip_list_init(&(*osip)->osip_ict_transactions); osip_list_init(&(*osip)->osip_ist_transactions); osip_list_init(&(*osip)->osip_nict_transactions); osip_list_init(&(*osip)->osip_nist_transactions); osip_list_init(&(*osip)->ixt_retransmissions); (*osip)->transactionid = 1; #if defined(HAVE_DICT_DICT_H) (*osip)->osip_ict_hastable = (dict *) hashtable_dict_new((dict_cmp_func) strcmp, (dict_hsh_func) s_hash, NULL, NULL, HSIZE); (*osip)->osip_ist_hastable = (dict *) hashtable_dict_new((dict_cmp_func) strcmp, (dict_hsh_func) s_hash, NULL, NULL, HSIZE); (*osip)->osip_nict_hastable = (dict *) hashtable_dict_new((dict_cmp_func) strcmp, (dict_hsh_func) s_hash, NULL, NULL, HSIZE); (*osip)->osip_nist_hastable = (dict *) hashtable_dict_new((dict_cmp_func) strcmp, (dict_hsh_func) s_hash, NULL, NULL, HSIZE); #endif return OSIP_SUCCESS; } void osip_release(osip_t *osip) { #ifndef OSIP_MONOTHREAD osip_mutex_destroy(osip->ict_fastmutex); osip_mutex_destroy(osip->ist_fastmutex); osip_mutex_destroy(osip->nict_fastmutex); osip_mutex_destroy(osip->nist_fastmutex); osip_mutex_destroy(osip->ixt_fastmutex); osip_mutex_destroy(osip->id_mutex); #endif osip_free(osip); } void osip_set_application_context(osip_t *osip, void *pointer) { osip->application_context = pointer; } void *osip_get_application_context(osip_t *osip) { if (osip == NULL) return NULL; return osip->application_context; } int osip_ict_execute(osip_t *osip) { osip_transaction_t *transaction; osip_event_t *se; int more_event; osip_list_iterator_t iterator; void **array; int len; int index = 0; /* list must be copied because osip_transaction_execute() may change it */ #ifndef OSIP_MONOTHREAD osip_mutex_lock(osip->ict_fastmutex); #endif len = osip_list_size(&osip->osip_ict_transactions); if (0 >= len) { #ifndef OSIP_MONOTHREAD osip_mutex_unlock(osip->ict_fastmutex); #endif return OSIP_SUCCESS; } array = osip_malloc(sizeof(void *) * len); if (array == NULL) { #ifndef OSIP_MONOTHREAD osip_mutex_unlock(osip->ict_fastmutex); #endif return OSIP_NOMEM; /* OSIP_SUCCESS; */ } transaction = (osip_transaction_t *) osip_list_get_first(&osip->osip_ict_transactions, &iterator); while (osip_list_iterator_has_elem(iterator)) { array[index++] = transaction; transaction = (osip_transaction_t *) osip_list_get_next(&iterator); } #ifndef OSIP_MONOTHREAD osip_mutex_unlock(osip->ict_fastmutex); #endif for (index = 0; index < len; ++index) { transaction = (osip_transaction_t *) array[index]; more_event = 1; do { se = (osip_event_t *) osip_fifo_tryget(transaction->transactionff); if (se == NULL) /* no more event for this transaction */ more_event = 0; else osip_transaction_execute(transaction, se); } while (more_event == 1); } osip_free(array); return OSIP_SUCCESS; } int osip_ist_execute(osip_t *osip) { osip_transaction_t *transaction; osip_event_t *se; int more_event; osip_list_iterator_t iterator; void **array; int len; int index = 0; /* list must be copied because osip_transaction_execute() may change it */ #ifndef OSIP_MONOTHREAD osip_mutex_lock(osip->ist_fastmutex); #endif len = osip_list_size(&osip->osip_ist_transactions); if (0 >= len) { #ifndef OSIP_MONOTHREAD osip_mutex_unlock(osip->ist_fastmutex); #endif return OSIP_SUCCESS; } array = osip_malloc(sizeof(void *) * len); if (array == NULL) { #ifndef OSIP_MONOTHREAD osip_mutex_unlock(osip->ist_fastmutex); #endif return OSIP_NOMEM; /* OSIP_SUCCESS; */ } transaction = (osip_transaction_t *) osip_list_get_first(&osip->osip_ist_transactions, &iterator); while (osip_list_iterator_has_elem(iterator)) { array[index++] = transaction; transaction = (osip_transaction_t *) osip_list_get_next(&iterator); } #ifndef OSIP_MONOTHREAD osip_mutex_unlock(osip->ist_fastmutex); #endif for (index = 0; index < len; ++index) { transaction = (osip_transaction_t *) array[index]; more_event = 1; do { se = (osip_event_t *) osip_fifo_tryget(transaction->transactionff); if (se == NULL) /* no more event for this transaction */ more_event = 0; else osip_transaction_execute(transaction, se); } while (more_event == 1); } osip_free(array); return OSIP_SUCCESS; } int osip_nict_execute(osip_t *osip) { osip_transaction_t *transaction; osip_event_t *se; int more_event; osip_list_iterator_t iterator; void **array; int len; int index = 0; /* list must be copied because osip_transaction_execute() may change it */ #ifndef OSIP_MONOTHREAD osip_mutex_lock(osip->nict_fastmutex); #endif len = osip_list_size(&osip->osip_nict_transactions); if (0 >= len) { #ifndef OSIP_MONOTHREAD osip_mutex_unlock(osip->nict_fastmutex); #endif return OSIP_SUCCESS; } array = osip_malloc(sizeof(void *) * len); if (array == NULL) { #ifndef OSIP_MONOTHREAD osip_mutex_unlock(osip->nict_fastmutex); #endif return OSIP_NOMEM; /* OSIP_SUCCESS; */ } transaction = (osip_transaction_t *) osip_list_get_first(&osip->osip_nict_transactions, &iterator); while (osip_list_iterator_has_elem(iterator)) { array[index++] = transaction; transaction = (osip_transaction_t *) osip_list_get_next(&iterator); } #ifndef OSIP_MONOTHREAD osip_mutex_unlock(osip->nict_fastmutex); #endif for (index = 0; index < len; ++index) { transaction = (osip_transaction_t *) array[index]; more_event = 1; do { se = (osip_event_t *) osip_fifo_tryget(transaction->transactionff); if (se == NULL) /* no more event for this transaction */ more_event = 0; else osip_transaction_execute(transaction, se); } while (more_event == 1); } osip_free(array); return OSIP_SUCCESS; } int osip_nist_execute(osip_t *osip) { osip_transaction_t *transaction; osip_event_t *se; int more_event; osip_list_iterator_t iterator; void **array; int len; int index = 0; /* list must be copied because osip_transaction_execute() may change it */ #ifndef OSIP_MONOTHREAD osip_mutex_lock(osip->nist_fastmutex); #endif len = osip_list_size(&osip->osip_nist_transactions); if (0 >= len) { #ifndef OSIP_MONOTHREAD osip_mutex_unlock(osip->nist_fastmutex); #endif return OSIP_SUCCESS; } array = osip_malloc(sizeof(void *) * len); if (array == NULL) { #ifndef OSIP_MONOTHREAD osip_mutex_unlock(osip->nist_fastmutex); #endif return OSIP_NOMEM; /* OSIP_SUCCESS; */ } transaction = (osip_transaction_t *) osip_list_get_first(&osip->osip_nist_transactions, &iterator); while (osip_list_iterator_has_elem(iterator)) { array[index++] = transaction; transaction = (osip_transaction_t *) osip_list_get_next(&iterator); } #ifndef OSIP_MONOTHREAD osip_mutex_unlock(osip->nist_fastmutex); #endif for (index = 0; index < len; ++index) { transaction = (osip_transaction_t *) array[index]; more_event = 1; do { se = (osip_event_t *) osip_fifo_tryget(transaction->transactionff); if (se == NULL) /* no more event for this transaction */ more_event = 0; else osip_transaction_execute(transaction, se); } while (more_event == 1); } osip_free(array); return OSIP_SUCCESS; } void osip_timers_gettimeout(osip_t *osip, struct timeval *lower_tv) { struct timeval now; osip_transaction_t *tr; osip_list_iterator_t iterator; osip_gettimeofday(&now, NULL); lower_tv->tv_sec = now.tv_sec + 3600 * 24 * 365; /* wake up evry year :-) */ lower_tv->tv_usec = now.tv_usec; #ifndef OSIP_MONOTHREAD osip_mutex_lock(osip->ict_fastmutex); #endif /* handle ict timers */ tr = (osip_transaction_t *) osip_list_get_first(&osip->osip_ict_transactions, &iterator); while (osip_list_iterator_has_elem(iterator)) { if (1 <= osip_fifo_size(tr->transactionff)) { OSIP_TRACE(osip_trace(__FILE__, __LINE__, OSIP_INFO4, NULL, "1 Pending event already in transaction !\n")); lower_tv->tv_sec = 0; lower_tv->tv_usec = 0; #ifndef OSIP_MONOTHREAD osip_mutex_unlock(osip->ict_fastmutex); #endif return; } else { if (tr->state == ICT_CALLING) min_timercmp(lower_tv, &tr->ict_context->timer_b_start); if (tr->state == ICT_CALLING) min_timercmp(lower_tv, &tr->ict_context->timer_a_start); if (tr->state == ICT_COMPLETED) min_timercmp(lower_tv, &tr->ict_context->timer_d_start); if (osip_timercmp(&now, lower_tv, >=)) { lower_tv->tv_sec = 0; lower_tv->tv_usec = 0; #ifndef OSIP_MONOTHREAD osip_mutex_unlock(osip->ict_fastmutex); #endif return; } } tr = (osip_transaction_t *) osip_list_get_next(&iterator); } #ifndef OSIP_MONOTHREAD osip_mutex_unlock(osip->ict_fastmutex); #endif #ifndef OSIP_MONOTHREAD osip_mutex_lock(osip->ist_fastmutex); #endif /* handle ist timers */ tr = (osip_transaction_t *) osip_list_get_first(&osip->osip_ist_transactions, &iterator); while (osip_list_iterator_has_elem(iterator)) { if (tr->state == IST_CONFIRMED) min_timercmp(lower_tv, &tr->ist_context->timer_i_start); if (tr->state == IST_COMPLETED) min_timercmp(lower_tv, &tr->ist_context->timer_h_start); if (tr->state == IST_COMPLETED) min_timercmp(lower_tv, &tr->ist_context->timer_g_start); if (osip_timercmp(&now, lower_tv, >=)) { lower_tv->tv_sec = 0; lower_tv->tv_usec = 0; #ifndef OSIP_MONOTHREAD osip_mutex_unlock(osip->ist_fastmutex); #endif return; } tr = (osip_transaction_t *) osip_list_get_next(&iterator); } #ifndef OSIP_MONOTHREAD osip_mutex_unlock(osip->ist_fastmutex); #endif #ifndef OSIP_MONOTHREAD osip_mutex_lock(osip->nict_fastmutex); #endif /* handle nict timers */ tr = (osip_transaction_t *) osip_list_get_first(&osip->osip_nict_transactions, &iterator); while (osip_list_iterator_has_elem(iterator)) { if (tr->state == NICT_COMPLETED) min_timercmp(lower_tv, &tr->nict_context->timer_k_start); if (tr->state == NICT_PROCEEDING || tr->state == NICT_TRYING) min_timercmp(lower_tv, &tr->nict_context->timer_f_start); if (tr->state == NICT_PROCEEDING || tr->state == NICT_TRYING) min_timercmp(lower_tv, &tr->nict_context->timer_e_start); if (osip_timercmp(&now, lower_tv, >=)) { lower_tv->tv_sec = 0; lower_tv->tv_usec = 0; #ifndef OSIP_MONOTHREAD osip_mutex_unlock(osip->nict_fastmutex); #endif return; } tr = (osip_transaction_t *) osip_list_get_next(&iterator); } #ifndef OSIP_MONOTHREAD osip_mutex_unlock(osip->nict_fastmutex); #endif #ifndef OSIP_MONOTHREAD osip_mutex_lock(osip->nist_fastmutex); #endif /* handle nist timers */ tr = (osip_transaction_t *) osip_list_get_first(&osip->osip_nist_transactions, &iterator); while (osip_list_iterator_has_elem(iterator)) { if (tr->state == NIST_COMPLETED) min_timercmp(lower_tv, &tr->nist_context->timer_j_start); if (osip_timercmp(&now, lower_tv, >=)) { lower_tv->tv_sec = 0; lower_tv->tv_usec = 0; #ifndef OSIP_MONOTHREAD osip_mutex_unlock(osip->nist_fastmutex); #endif return; } tr = (osip_transaction_t *) osip_list_get_next(&iterator); } #ifndef OSIP_MONOTHREAD osip_mutex_unlock(osip->nist_fastmutex); #endif #ifndef OSIP_MONOTHREAD osip_mutex_lock(osip->ixt_fastmutex); #endif { ixt_t *ixt; ixt = (ixt_t *) osip_list_get_first(&osip->ixt_retransmissions, &iterator); while (osip_list_iterator_has_elem(iterator)) { min_timercmp(lower_tv, &ixt->start); if (osip_timercmp(&now, lower_tv, >=)) { lower_tv->tv_sec = 0; lower_tv->tv_usec = 0; #ifndef OSIP_MONOTHREAD osip_mutex_unlock(osip->ixt_fastmutex); #endif return; } ixt = (ixt_t *) osip_list_get_next(&iterator); } } #ifndef OSIP_MONOTHREAD osip_mutex_unlock(osip->ixt_fastmutex); #endif lower_tv->tv_sec = lower_tv->tv_sec - now.tv_sec; lower_tv->tv_usec = lower_tv->tv_usec - now.tv_usec; /* just make sure the value is correct! */ if (lower_tv->tv_usec < 0) { lower_tv->tv_usec = lower_tv->tv_usec + 1000000; lower_tv->tv_sec--; } if (lower_tv->tv_sec < 0) { lower_tv->tv_sec = 0; lower_tv->tv_usec = 0; } if (lower_tv->tv_usec > 1000000) { lower_tv->tv_usec = lower_tv->tv_usec - 1000000; lower_tv->tv_sec++; } return; } void osip_timers_ict_execute(osip_t *osip) { osip_transaction_t *tr; osip_list_iterator_t iterator; #ifndef OSIP_MONOTHREAD osip_mutex_lock(osip->ict_fastmutex); #endif /* handle ict timers */ tr = (osip_transaction_t *) osip_list_get_first(&osip->osip_ict_transactions, &iterator); while (osip_list_iterator_has_elem(iterator)) { osip_event_t *evt; if (1 <= osip_fifo_size(tr->transactionff)) { OSIP_TRACE(osip_trace(__FILE__, __LINE__, OSIP_INFO4, NULL, "1 Pending event already in transaction !\n")); } else { evt = __osip_ict_need_timer_b_event(tr->ict_context, tr->state, tr->transactionid); if (evt != NULL) osip_fifo_add(tr->transactionff, evt); else { evt = __osip_ict_need_timer_a_event(tr->ict_context, tr->state, tr->transactionid); if (evt != NULL) osip_fifo_add(tr->transactionff, evt); else { evt = __osip_ict_need_timer_d_event(tr->ict_context, tr->state, tr->transactionid); if (evt != NULL) osip_fifo_add(tr->transactionff, evt); } } } tr = (osip_transaction_t *) osip_list_get_next(&iterator); } #ifndef OSIP_MONOTHREAD osip_mutex_unlock(osip->ict_fastmutex); #endif } void osip_timers_ist_execute(osip_t *osip) { osip_transaction_t *tr; osip_list_iterator_t iterator; #ifndef OSIP_MONOTHREAD osip_mutex_lock(osip->ist_fastmutex); #endif /* handle ist timers */ tr = (osip_transaction_t *) osip_list_get_first(&osip->osip_ist_transactions, &iterator); while (osip_list_iterator_has_elem(iterator)) { osip_event_t *evt; evt = __osip_ist_need_timer_i_event(tr->ist_context, tr->state, tr->transactionid); if (evt != NULL) osip_fifo_add(tr->transactionff, evt); else { evt = __osip_ist_need_timer_h_event(tr->ist_context, tr->state, tr->transactionid); if (evt != NULL) osip_fifo_add(tr->transactionff, evt); else { evt = __osip_ist_need_timer_g_event(tr->ist_context, tr->state, tr->transactionid); if (evt != NULL) osip_fifo_add(tr->transactionff, evt); } } tr = (osip_transaction_t *) osip_list_get_next(&iterator); } #ifndef OSIP_MONOTHREAD osip_mutex_unlock(osip->ist_fastmutex); #endif } void osip_timers_nict_execute(osip_t *osip) { osip_transaction_t *tr; osip_list_iterator_t iterator; #ifndef OSIP_MONOTHREAD osip_mutex_lock(osip->nict_fastmutex); #endif /* handle nict timers */ tr = (osip_transaction_t *) osip_list_get_first(&osip->osip_nict_transactions, &iterator); while (osip_list_iterator_has_elem(iterator)) { osip_event_t *evt; evt = __osip_nict_need_timer_k_event(tr->nict_context, tr->state, tr->transactionid); if (evt != NULL) osip_fifo_add(tr->transactionff, evt); else { evt = __osip_nict_need_timer_f_event(tr->nict_context, tr->state, tr->transactionid); if (evt != NULL) osip_fifo_add(tr->transactionff, evt); else { evt = __osip_nict_need_timer_e_event(tr->nict_context, tr->state, tr->transactionid); if (evt != NULL) osip_fifo_add(tr->transactionff, evt); } } tr = (osip_transaction_t *) osip_list_get_next(&iterator); } #ifndef OSIP_MONOTHREAD osip_mutex_unlock(osip->nict_fastmutex); #endif } void osip_timers_nist_execute(osip_t *osip) { osip_transaction_t *tr; osip_list_iterator_t iterator; #ifndef OSIP_MONOTHREAD osip_mutex_lock(osip->nist_fastmutex); #endif /* handle nist timers */ tr = (osip_transaction_t *) osip_list_get_first(&osip->osip_nist_transactions, &iterator); while (osip_list_iterator_has_elem(iterator)) { osip_event_t *evt; evt = __osip_nist_need_timer_j_event(tr->nist_context, tr->state, tr->transactionid); if (evt != NULL) osip_fifo_add(tr->transactionff, evt); tr = (osip_transaction_t *) osip_list_get_next(&iterator); } #ifndef OSIP_MONOTHREAD osip_mutex_unlock(osip->nist_fastmutex); #endif } void osip_set_cb_send_message(osip_t *cf, int (*cb)(osip_transaction_t *, osip_message_t *, char *, int, int)) { cf->cb_send_message = cb; } void __osip_message_callback(int type, osip_transaction_t *tr, osip_message_t *msg) { osip_t *config = tr->config; if (type >= OSIP_MESSAGE_CALLBACK_COUNT) { OSIP_TRACE(osip_trace(__FILE__, __LINE__, OSIP_BUG, NULL, "invalid callback type %d\n", type)); return; } if (config->msg_callbacks[type] == NULL) return; config->msg_callbacks[type](type, tr, msg); } void __osip_kill_transaction_callback(int type, osip_transaction_t *tr) { osip_t *config = tr->config; if (type >= OSIP_KILL_CALLBACK_COUNT) { OSIP_TRACE(osip_trace(__FILE__, __LINE__, OSIP_BUG, NULL, "invalid callback type %d\n", type)); return; } tr->completed_time = osip_getsystemtime(NULL); osip_gettimeofday(&tr->destroyed_time, NULL); if (config->kill_callbacks[type] == NULL) return; config->kill_callbacks[type](type, tr); } void __osip_transport_error_callback(int type, osip_transaction_t *tr, int error) { osip_t *config = tr->config; if (type >= OSIP_TRANSPORT_ERROR_CALLBACK_COUNT) { OSIP_TRACE(osip_trace(__FILE__, __LINE__, OSIP_BUG, NULL, "invalid callback type %d\n", type)); return; } if (config->tp_error_callbacks[type] == NULL) return; config->tp_error_callbacks[type](type, tr, error); } int osip_set_message_callback(osip_t *config, int type, osip_message_cb_t cb) { if (type >= OSIP_MESSAGE_CALLBACK_COUNT) { OSIP_TRACE(osip_trace(__FILE__, __LINE__, OSIP_ERROR, NULL, "invalid callback type %d\n", type)); return OSIP_BADPARAMETER; } config->msg_callbacks[type] = cb; return OSIP_SUCCESS; } int osip_set_kill_transaction_callback(osip_t *config, int type, osip_kill_transaction_cb_t cb) { if (type >= OSIP_KILL_CALLBACK_COUNT) { OSIP_TRACE(osip_trace(__FILE__, __LINE__, OSIP_ERROR, NULL, "invalid callback type %d\n", type)); return OSIP_BADPARAMETER; } config->kill_callbacks[type] = cb; return OSIP_SUCCESS; } int osip_set_transport_error_callback(osip_t *config, int type, osip_transport_error_cb_t cb) { if (type >= OSIP_TRANSPORT_ERROR_CALLBACK_COUNT) { OSIP_TRACE(osip_trace(__FILE__, __LINE__, OSIP_ERROR, NULL, "invalid callback type %d\n", type)); return OSIP_BADPARAMETER; } config->tp_error_callbacks[type] = cb; return OSIP_SUCCESS; }