Logo Search packages:      
Sourcecode: wengophone version File versions  Download package

osip.c

/*
  The oSIP library implements the Session Initiation Protocol (SIP -rfc3261-)
  Copyright (C) 2001,2002,2003  Aymeric MOIZARD jack@atosc.org
  
  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 <osip2/internal.h>
#include <osip2/osip.h>

#include "fsm.h"
#include "xixt.h"

#ifdef OSIP_MT
static struct osip_mutex *ict_fastmutex;
static struct osip_mutex *ist_fastmutex;
static struct osip_mutex *nict_fastmutex;
static struct osip_mutex *nist_fastmutex;
#endif

#ifdef OSIP_RETRANSMIT_2XX

#include <osip2/osip_dialog.h>
#ifdef OSIP_MT
static struct osip_mutex *ixt_fastmutex;
#endif

#endif

static int __osip_global_init (void);
static void __osip_global_free (void);
static int increase_ref_count (void);
static void decrease_ref_count (void);

static int
__osip_global_init ()
{
  /* load the fsm configuration */
  __ict_load_fsm ();
  __ist_load_fsm ();
  __nict_load_fsm ();
  __nist_load_fsm ();

  /* load the parser configuration */
  parser_init ();

#ifdef OSIP_MT
  ict_fastmutex = osip_mutex_init ();
  ist_fastmutex = osip_mutex_init ();
  nict_fastmutex = osip_mutex_init ();
  nist_fastmutex = osip_mutex_init ();

#ifdef OSIP_RETRANSMIT_2XX
  ixt_fastmutex = osip_mutex_init ();
#endif

#endif
  return 0;
}

static void
__osip_global_free ()
{
  __ict_unload_fsm ();
  __ist_unload_fsm ();
  __nict_unload_fsm ();
  __nist_unload_fsm ();

#ifdef OSIP_MT
  osip_mutex_destroy (ict_fastmutex);
  osip_mutex_destroy (ist_fastmutex);
  osip_mutex_destroy (nict_fastmutex);
  osip_mutex_destroy (nist_fastmutex);

#ifdef OSIP_RETRANSMIT_2XX
  osip_mutex_destroy (ixt_fastmutex);
#endif
#endif
}

#ifdef OSIP_RETRANSMIT_2XX

int
osip_ixt_lock (osip_t * osip)
{
#ifdef OSIP_MT
  return osip_mutex_lock (ixt_fastmutex);
#else
  return 0;
#endif
}

int
osip_ixt_unlock (osip_t * osip)
{
#ifdef OSIP_MT
  return osip_mutex_unlock (ixt_fastmutex);
#else
  return 0;
#endif
}

/* these are for transactions that would need retransmission not handled by state machines */
void
osip_add_ixt (osip_t * osip, ixt_t * ixt)
{
  /* ajout dans la liste de osip_t->ixt */
  osip_ixt_lock (osip);
  osip_list_add (osip->ixt_retransmissions, (void *) ixt, 0);
  osip_ixt_unlock (osip);
}

void
osip_remove_ixt (osip_t * osip, ixt_t * ixt)
{
  int i;
  int found = 0;
  ixt_t *tmp;
  /* ajout dans la liste de osip_t->ixt */
  osip_ixt_lock (osip);
  for (i = 0; !osip_list_eol (osip->ixt_retransmissions, i); i++)
    {
      tmp = (ixt_t *) osip_list_get (osip->ixt_retransmissions, i);
      if (tmp == ixt)
      {
        osip_list_remove (osip->ixt_retransmissions, i);
        found = 1;
        break;
      }
    }
  osip_ixt_unlock (osip);
}


void
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;
}


int
ixt_init (ixt_t ** ixt)
{
  ixt_t *pixt;
  *ixt = pixt = (ixt_t *) osip_malloc (sizeof (ixt_t));
  if (pixt==NULL) return -1;
  pixt->dialog = NULL;
  pixt->msg2xx = NULL;
  pixt->ack = NULL;
  pixt->start = time (NULL);
  pixt->interval = 500;
  pixt->counter = 7;
  pixt->dest = NULL;
  pixt->port = 5060;
  pixt->sock = -1;
  return 0;
}

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)
{
  ixt_t *ixt;
  ixt_init (&ixt);
  ixt->dialog = dialog;
  osip_message_clone (msg200ok, &ixt->msg2xx);
  ixt->sock = sock;
  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 */
void
osip_stop_200ok_retransmissions (osip_t * osip, osip_message_t * ack)
{
  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 (osip_dialog_match_as_uas (ixt->dialog, ack) == 0)
      {
        osip_list_remove (osip->ixt_retransmissions, i);
        ixt_free (ixt);
        break;
      }
    }
  osip_ixt_unlock (osip);
}

/* 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);
}

void
ixt_retransmit (osip_t * osip, ixt_t * ixt, time_t current)
{
  if ((current - ixt->start) * 1000 > ixt->interval)
    {
      ixt->interval = ixt->interval * 2;
      ixt->start = current;
      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;
  time_t current;
  ixt_t *ixt;
  current = time (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, current);
      if (ixt->counter == 0)
      {
        /* remove it */
        osip_list_remove (osip->ixt_retransmissions, i);
        ixt_free (ixt);
        i--;
      }
    }
  osip_ixt_unlock (osip);
}

#endif

int
osip_ict_lock (osip_t * osip)
{
#ifdef OSIP_MT
  return osip_mutex_lock (ict_fastmutex);
#else
  return 0;
#endif
}

int
osip_ict_unlock (osip_t * osip)
{
#ifdef OSIP_MT
  return osip_mutex_unlock (ict_fastmutex);
#else
  return 0;
#endif
}

int
osip_ist_lock (osip_t * osip)
{
#ifdef OSIP_MT
  return osip_mutex_lock (ist_fastmutex);
#else
  return 0;
#endif
}

int
osip_ist_unlock (osip_t * osip)
{
#ifdef OSIP_MT
  return osip_mutex_unlock (ist_fastmutex);
#else
  return 0;
#endif
}

int
osip_nict_lock (osip_t * osip)
{
#ifdef OSIP_MT
  return osip_mutex_lock (nict_fastmutex);
#else
  return 0;
#endif
}

int
osip_nict_unlock (osip_t * osip)
{
#ifdef OSIP_MT
  return osip_mutex_unlock (nict_fastmutex);
#else
  return 0;
#endif
}

int
osip_nist_lock (osip_t * osip)
{
#ifdef OSIP_MT
  return osip_mutex_lock (nist_fastmutex);
#else
  return 0;
#endif
}

int
osip_nist_unlock (osip_t * osip)
{
#ifdef OSIP_MT
  return osip_mutex_unlock (nist_fastmutex);
#else
  return 0;
#endif
}

int
__osip_add_ict (osip_t * osip, osip_transaction_t * ict)
{
#ifdef OSIP_MT
  osip_mutex_lock (ict_fastmutex);
#endif
  osip_list_add (osip->osip_ict_transactions, ict, -1);
#ifdef OSIP_MT
  osip_mutex_unlock (ict_fastmutex);
#endif
  return 0;
}

int
__osip_add_ist (osip_t * osip, osip_transaction_t * ist)
{
#ifdef OSIP_MT
  osip_mutex_lock (ist_fastmutex);
#endif
  osip_list_add (osip->osip_ist_transactions, ist, -1);
#ifdef OSIP_MT
  osip_mutex_unlock (ist_fastmutex);
#endif
  return 0;
}

int
__osip_add_nict (osip_t * osip, osip_transaction_t * nict)
{
#ifdef OSIP_MT
  osip_mutex_lock (nict_fastmutex);
#endif
  osip_list_add (osip->osip_nict_transactions, nict, -1);
#ifdef OSIP_MT
  osip_mutex_unlock (nict_fastmutex);
#endif
  return 0;
}

int
__osip_add_nist (osip_t * osip, osip_transaction_t * nist)
{
#ifdef OSIP_MT
  osip_mutex_lock (nist_fastmutex);
#endif
  osip_list_add (osip->osip_nist_transactions, nist, -1);
#ifdef OSIP_MT
  osip_mutex_unlock (nist_fastmutex);
#endif
  return 0;
}

int
00472 osip_remove_transaction (osip_t * osip, osip_transaction_t * tr)
{
  int i = -1;
  if (tr == NULL)
    return -1;
  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 -1;
  return i;
}

int
__osip_remove_ict_transaction (osip_t * osip, osip_transaction_t * ict)
{
  int pos = 0;
  osip_transaction_t *tmp;

#ifdef OSIP_MT
  osip_mutex_lock (ict_fastmutex);
#endif
  while (!osip_list_eol (osip->osip_ict_transactions, pos))
    {
      tmp = osip_list_get (osip->osip_ict_transactions, pos);
      if (tmp->transactionid == ict->transactionid)
      {
        osip_list_remove (osip->osip_ict_transactions, pos);
#ifdef OSIP_MT
        osip_mutex_unlock (ict_fastmutex);
#endif
        return 0;
      }
      pos++;
    }
#ifdef OSIP_MT
  osip_mutex_unlock (ict_fastmutex);
#endif
  return -1;
}

int
__osip_remove_ist_transaction (osip_t * osip, osip_transaction_t * ist)
{
  int pos = 0;
  osip_transaction_t *tmp;

#ifdef OSIP_MT
  osip_mutex_lock (ist_fastmutex);
#endif
  while (!osip_list_eol (osip->osip_ist_transactions, pos))
    {
      tmp = osip_list_get (osip->osip_ist_transactions, pos);
      if (tmp->transactionid == ist->transactionid)
      {
        osip_list_remove (osip->osip_ist_transactions, pos);
#ifdef OSIP_MT
        osip_mutex_unlock (ist_fastmutex);
#endif
        return 0;
      }
      pos++;
    }
#ifdef OSIP_MT
  osip_mutex_unlock (ist_fastmutex);
#endif
  return -1;
}

int
__osip_remove_nict_transaction (osip_t * osip, osip_transaction_t * nict)
{
  int pos = 0;
  osip_transaction_t *tmp;

#ifdef OSIP_MT
  osip_mutex_lock (nict_fastmutex);
#endif
  while (!osip_list_eol (osip->osip_nict_transactions, pos))
    {
      tmp = osip_list_get (osip->osip_nict_transactions, pos);
      if (tmp->transactionid == nict->transactionid)
      {
        osip_list_remove (osip->osip_nict_transactions, pos);
#ifdef OSIP_MT
        osip_mutex_unlock (nict_fastmutex);
#endif
        return 0;
      }
      pos++;
    }
#ifdef OSIP_MT
  osip_mutex_unlock (nict_fastmutex);
#endif
  return -1;
}

int
__osip_remove_nist_transaction (osip_t * osip, osip_transaction_t * nist)
{
  int pos = 0;
  osip_transaction_t *tmp;

#ifdef OSIP_MT
  osip_mutex_lock (nist_fastmutex);
#endif
  while (!osip_list_eol (osip->osip_nist_transactions, pos))
    {
      tmp = osip_list_get (osip->osip_nist_transactions, pos);
      if (tmp->transactionid == nist->transactionid)
      {
        osip_list_remove (osip->osip_nist_transactions, pos);
#ifdef OSIP_MT
        osip_mutex_unlock (nist_fastmutex);
#endif
        return 0;
      }
      pos++;
    }
#ifdef OSIP_MT
  osip_mutex_unlock (nist_fastmutex);
#endif
  return -1;
}

#if 0
/* this method is made obsolete because it contains bugs and is also
   too much limited.
   any call to this method should be replace this way:

   //osip_distribute(osip, evt);
   osip_transaction_t *transaction = osip_find_transaction_and_add_event(osip, evt);

   if (i!=0) // in case it's a new request
     {
        if (evt is an ACK)
            evt could be an ACK for INVITE (not handled by oSIP)
        else if ( evt is a 200 for INVITE)
           evt could be a retransmission of a 200 for INVITE (not handled by oSIP)
        else if (evt is a new request)  == not a ACK and not a response
        {
           transaction = osip_create_transaction(osip, evt);
           if (transaction==NULL)
             printf("failed to create a transaction\");
          }
    }
    else
    {
    // here, the message as been taken by the stack.
    }
*/


/* finds the transaction context and add the sipevent in its fifo. */
/* USED ONLY BY THE TRANSPORT LAYER.                               */
/* INPUT : osip_t *osip | osip. contains the list of tr. context*/
/* INPUT : osip_event_t* sipevent | event to dispatch.               */
osip_transaction_t *
osip_distribute_event (osip_t * osip, osip_event_t * evt)
{
  osip_transaction_t *transaction = NULL;
  int i;
  osip_fsm_type_t ctx_type;

  if (EVT_IS_INCOMINGMSG (evt))
    {
      /* event is for ict */
      if (MSG_IS_REQUEST (evt->sip))
      {
        if (0 == strcmp (evt->sip->cseq->method, "INVITE")
            || 0 == strcmp (evt->sip->cseq->method, "ACK"))
          {
#ifdef OSIP_MT
            osip_mutex_lock (ist_fastmutex);
#endif
            transaction =
            osip_transaction_find (osip->osip_ist_transactions, evt);
#ifdef OSIP_MT
            osip_mutex_unlock (ist_fastmutex);
#endif
          }
        else
          {
#ifdef OSIP_MT
            osip_mutex_lock (nist_fastmutex);
#endif
            transaction =
            osip_transaction_find (osip->osip_nist_transactions, evt);
#ifdef OSIP_MT
            osip_mutex_unlock (nist_fastmutex);
#endif
          }
      }
      else
      {
        if (0 == strcmp (evt->sip->cseq->method, "INVITE")
            || 0 == strcmp (evt->sip->cseq->method, "ACK"))
          {
#ifdef OSIP_MT
            osip_mutex_lock (ict_fastmutex);
#endif
            transaction =
            osip_transaction_find (osip->osip_ict_transactions, evt);
#ifdef OSIP_MT
            osip_mutex_unlock (ict_fastmutex);
#endif
          }
        else
          {
#ifdef OSIP_MT
            osip_mutex_lock (nict_fastmutex);
#endif
            transaction =
            osip_transaction_find (osip->osip_nict_transactions, evt);
#ifdef OSIP_MT
            osip_mutex_unlock (nict_fastmutex);
#endif
          }
      }
      if (transaction == NULL)
      {
        if (EVT_IS_RCV_STATUS_1XX (evt)
            || EVT_IS_RCV_STATUS_2XX (evt)
            || EVT_IS_RCV_STATUS_3456XX (evt) || EVT_IS_RCV_ACK (evt))
          {             /* event MUST be ignored! */
            /* EXCEPT FOR 2XX THAT MUST BE GIVEN TO THE CORE LAYER!!! */

            /* TODO */

            OSIP_TRACE (osip_trace
                    (__FILE__, __LINE__, OSIP_WARNING, NULL,
                     "transaction does not yet exist... %x callid:%s\n",
                     evt, evt->sip->call_id->number));
            osip_message_free (evt->sip);
            osip_free (evt);  /* transaction thread will not delete it */
            return NULL;
          }

        /* we create a new context for this incoming request */
        if (0 == strcmp (evt->sip->cseq->method, "INVITE"))
          ctx_type = IST;
        else
          ctx_type = NIST;

        i = osip_transaction_init (&transaction, ctx_type, osip, evt->sip);
        if (i == -1)
          {
            osip_message_free (evt->sip);
            osip_free (evt);  /* transaction thread will not delete it */
            return NULL;
          }
      }
      evt->transactionid = transaction->transactionid;

      evt->transactionid = transaction->transactionid;
      osip_fifo_add (transaction->transactionff, evt);
      return transaction;
    }
  else
    {
      OSIP_TRACE (osip_trace
              (__FILE__, __LINE__, OSIP_BUG, NULL,
               "wrong event type %x\n", evt));
      return NULL;
    }
}
#endif

int
00746 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 -1;
  return 0;
}

#ifndef OSIP_MT
osip_transaction_t *
00757 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;

#ifdef OSIP_MT
  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;
#ifdef OSIP_MT
            mut = ist_fastmutex;
#endif
          }
        else
          {
            transactions = osip->osip_nist_transactions;
#ifdef OSIP_MT
            mut = nist_fastmutex;
#endif
          }
      }
      else
      {
        if (0 == strcmp (evt->sip->cseq->method, "INVITE")
            || 0 == strcmp (evt->sip->cseq->method, "ACK"))
          {
            transactions = osip->osip_ict_transactions;
#ifdef OSIP_MT
            mut = ict_fastmutex;
#endif
          }
        else
          {
            transactions = osip->osip_nict_transactions;
#ifdef OSIP_MT
            mut = nict_fastmutex;
#endif
          }
      }
    }
  else if (EVT_IS_OUTGOINGMSG (evt))
    {
      if (MSG_IS_RESPONSE (evt->sip))
      {
        if (0 == strcmp (evt->sip->cseq->method, "INVITE")
            || 0 == strcmp (evt->sip->cseq->method, "ACK"))
          {
            transactions = osip->osip_ist_transactions;
#ifdef OSIP_MT
            mut = ist_fastmutex;
#endif
          }
        else
          {
            transactions = osip->osip_nist_transactions;
#ifdef OSIP_MT
            mut = nist_fastmutex;
#endif
          }
      }
      else
      {
        if (0 == strcmp (evt->sip->cseq->method, "INVITE")
            || 0 == strcmp (evt->sip->cseq->method, "ACK"))
          {
            transactions = osip->osip_ict_transactions;
#ifdef OSIP_MT
            mut = ict_fastmutex;
#endif
          }
        else
          {
            transactions = osip->osip_nict_transactions;
#ifdef OSIP_MT
            mut = nict_fastmutex;
#endif
          }
      }
    }
  if (transactions == NULL)
    return NULL;        /* not a message??? */

#ifdef OSIP_MT
  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);
#ifdef OSIP_MT
        osip_mutex_unlock (mut);
#endif
        return transaction;
      }
    }
#ifdef OSIP_MT
  osip_mutex_unlock (mut);
#endif

  return transaction;
}

osip_transaction_t *
00880 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 transction for this message!\n"));
      return NULL;
    }

  i = osip_transaction_init (&transaction, ctx_type, osip, evt->sip);
  if (i == -1)
    {
      return NULL;
    }
  evt->transactionid = transaction->transactionid;
  return transaction;
}

osip_transaction_t *
00946 osip_transaction_find (osip_list_t * transactions, osip_event_t * evt)
{
  int pos = 0;
  osip_transaction_t *transaction;

  if (EVT_IS_INCOMINGREQ (evt))
    {
      while (!osip_list_eol (transactions, pos))
      {
        transaction =
          (osip_transaction_t *) osip_list_get (transactions, pos);
        if (0 ==
            __osip_transaction_matching_request_osip_to_xist_17_2_3
            (transaction, evt->sip))
          return transaction;
        pos++;
      }
    }
  else if (EVT_IS_INCOMINGRESP (evt))
    {
      while (!osip_list_eol (transactions, pos))
      {
        transaction =
          (osip_transaction_t *) osip_list_get (transactions, pos);
        if (0 ==
            __osip_transaction_matching_response_osip_to_xict_17_1_3
            (transaction, evt->sip))
          return transaction;
        pos++;
      }
    }
  else                        /* handle OUTGOING message */
    {                   /* THE TRANSACTION ID MUST BE SET */
      while (!osip_list_eol (transactions, pos))
      {
        transaction =
          (osip_transaction_t *) osip_list_get (transactions, pos);
        if (transaction->transactionid == evt->transactionid)
          return transaction;
        pos++;
      }
    }
  return NULL;
}

static int ref_count = 0;
#ifdef OSIP_MT
static struct osip_mutex *ref_mutex = NULL;
#endif

static int
increase_ref_count (void)
{
#ifdef OSIP_MT
  if (ref_count == 0)
    ref_mutex = osip_mutex_init ();
  /* Here we should assert() that the mutex was really generated. */
  osip_mutex_lock (ref_mutex);
#endif
  if (ref_count == 0)
    __osip_global_init ();
  ref_count++;
#ifdef OSIP_MT
  osip_mutex_unlock (ref_mutex);
#endif

  return 0;
}

static void
decrease_ref_count (void)
{
#ifdef OSIP_MT
  osip_mutex_lock (ref_mutex);
#endif
  /* assert (ref_count > 0); */
  ref_count--;
  if (ref_count == 0)
    {
#ifdef OSIP_MT
      osip_mutex_unlock (ref_mutex);
      osip_mutex_destroy (ref_mutex);
#endif
      __osip_global_free ();
      return;
    }
#ifdef OSIP_MT
  osip_mutex_unlock (ref_mutex);
#endif
}

int
01038 osip_init (osip_t ** osip)
{
  if (increase_ref_count () != 0)
    return -1;

  *osip = (osip_t *) osip_malloc (sizeof (osip_t));
  if (*osip == NULL)
    return -1;                /* allocation failed */

  memset (*osip, 0, sizeof (osip_t));

  (*osip)->osip_ict_transactions =
    (osip_list_t *) osip_malloc (sizeof (osip_list_t));
  osip_list_init ((*osip)->osip_ict_transactions);
  (*osip)->osip_ist_transactions =
    (osip_list_t *) osip_malloc (sizeof (osip_list_t));
  osip_list_init ((*osip)->osip_ist_transactions);
  (*osip)->osip_nict_transactions =
    (osip_list_t *) osip_malloc (sizeof (osip_list_t));
  osip_list_init ((*osip)->osip_nict_transactions);
  (*osip)->osip_nist_transactions =
    (osip_list_t *) osip_malloc (sizeof (osip_list_t));
  osip_list_init ((*osip)->osip_nist_transactions);

#ifdef OSIP_RETRANSMIT_2XX
  (*osip)->ixt_retransmissions =
    (osip_list_t *) osip_malloc (sizeof (osip_list_t));
  osip_list_init ((*osip)->ixt_retransmissions);
#else
  (*osip)->ixt_retransmissions = NULL;
#endif

  return 0;
}

void
01074 osip_release (osip_t * osip)
{
  osip_free (osip->osip_ict_transactions);
  osip_free (osip->osip_ist_transactions);
  osip_free (osip->osip_nict_transactions);
  osip_free (osip->osip_nist_transactions);

#ifdef OSIP_RETRANSMIT_2XX
  osip_free (osip->ixt_retransmissions);
#endif

  osip_free (osip);
  decrease_ref_count ();
}


void
01091 osip_set_application_context (osip_t * osip, void *pointer)
{
  osip->application_context = pointer;
}

void *
01097 osip_get_application_context (osip_t * osip)
{
  if (osip == NULL)
    return NULL;
  return osip->application_context;
}

int
01105 osip_ict_execute (osip_t * osip)
{
  osip_transaction_t *transaction;
  osip_event_t *se;
  int more_event;
  int tr;

  tr = 0;
  while (!osip_list_eol (osip->osip_ict_transactions, tr))
    {
      transaction = osip_list_get (osip->osip_ict_transactions, tr);
      tr++;
      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);
    }
  return 0;
}

int
01132 osip_ist_execute (osip_t * osip)
{
  osip_transaction_t *transaction;
  osip_event_t *se;
  int more_event;
  int tr;

  tr = 0;
  while (!osip_list_eol (osip->osip_ist_transactions, tr))
    {
      transaction = osip_list_get (osip->osip_ist_transactions, tr);
      tr++;
      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);
    }
  return 0;
}

int
01159 osip_nict_execute (osip_t * osip)
{
  osip_transaction_t *transaction;
  osip_event_t *se;
  int more_event;
  int tr;

  tr = 0;
  while (!osip_list_eol (osip->osip_nict_transactions, tr))
    {
      transaction = osip_list_get (osip->osip_nict_transactions, tr);
      tr++;
      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);
    }
  return 0;
}

int
01186 osip_nist_execute (osip_t * osip)
{
  osip_transaction_t *transaction;
  osip_event_t *se;
  int more_event;
  int tr;

  tr = 0;
  while (!osip_list_eol (osip->osip_nist_transactions, tr))
    {
      transaction = osip_list_get (osip->osip_nist_transactions, tr);
      tr++;
      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);
    }
  return 0;
}

void
01213 osip_timers_gettimeout (osip_t * osip, struct timeval *lower_tv)
{
  struct timeval now;
  osip_transaction_t *tr;
  int pos = 0;

  gettimeofday (&now, NULL);
  lower_tv->tv_sec = now.tv_sec + 3600 * 24 * 265;    /* wake up evry year :-) */
  lower_tv->tv_usec = now.tv_usec;

#ifdef OSIP_MT
  osip_mutex_lock (ict_fastmutex);
#endif
  /* handle ict timers */
  while (!osip_list_eol (osip->osip_ict_transactions, pos))
    {
      tr =
      (osip_transaction_t *) osip_list_get (osip->osip_ict_transactions,
                                    pos);

      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;
#ifdef OSIP_MT
        osip_mutex_unlock (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 (timercmp (&now, lower_tv, >))
          {
            lower_tv->tv_sec = 0;
            lower_tv->tv_usec = 0;
#ifdef OSIP_MT
            osip_mutex_unlock (ict_fastmutex);
#endif
            return;
          }
      }
      pos++;
    }
#ifdef OSIP_MT
  osip_mutex_unlock (ict_fastmutex);
#endif

#ifdef OSIP_MT
  osip_mutex_lock (ist_fastmutex);
#endif
  /* handle ist timers */
  while (!osip_list_eol (osip->osip_ist_transactions, pos))
    {
      tr =
      (osip_transaction_t *) osip_list_get (osip->osip_ist_transactions,
                                    pos);

      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 (timercmp (&now, lower_tv, >))
      {
        lower_tv->tv_sec = 0;
        lower_tv->tv_usec = 0;
#ifdef OSIP_MT
        osip_mutex_unlock (ist_fastmutex);
#endif
        return;
      }
      pos++;
    }
#ifdef OSIP_MT
  osip_mutex_unlock (ist_fastmutex);
#endif

#ifdef OSIP_MT
  osip_mutex_lock (nict_fastmutex);
#endif
  /* handle nict timers */
  while (!osip_list_eol (osip->osip_nict_transactions, pos))
    {
      tr =
      (osip_transaction_t *) osip_list_get (osip->osip_nict_transactions,
                                    pos);

      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 (timercmp (&now, lower_tv, >))
      {
        lower_tv->tv_sec = 0;
        lower_tv->tv_usec = 0;
#ifdef OSIP_MT
        osip_mutex_unlock (nict_fastmutex);
#endif
        return;
      }
      pos++;
    }
#ifdef OSIP_MT
  osip_mutex_unlock (nict_fastmutex);
#endif

#ifdef OSIP_MT
  osip_mutex_lock (nist_fastmutex);
#endif
  /* handle nist timers */
  while (!osip_list_eol (osip->osip_nist_transactions, pos))
    {
      tr =
      (osip_transaction_t *) osip_list_get (osip->osip_nist_transactions,
                                    pos);

      if (tr->state == NIST_COMPLETED)
      min_timercmp (lower_tv, &tr->nist_context->timer_j_start);
      if (timercmp (&now, lower_tv, >))
      {
        lower_tv->tv_sec = 0;
        lower_tv->tv_usec = 0;
#ifdef OSIP_MT
        osip_mutex_unlock (nist_fastmutex);
#endif
        return;
      }
      pos++;
    }
#ifdef OSIP_MT
  osip_mutex_unlock (nist_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
01381 osip_timers_ict_execute (osip_t * osip)
{
  osip_transaction_t *tr;
  int pos = 0;

#ifdef OSIP_MT
  osip_mutex_lock (ict_fastmutex);
#endif
  /* handle ict timers */
  while (!osip_list_eol (osip->osip_ict_transactions, pos))
    {
      osip_event_t *evt;

      tr =
      (osip_transaction_t *) osip_list_get (osip->osip_ict_transactions,
                                    pos);

      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);
            }
          }
      }
      pos++;
    }
#ifdef OSIP_MT
  osip_mutex_unlock (ict_fastmutex);
#endif
}

void
01434 osip_timers_ist_execute (osip_t * osip)
{
  osip_transaction_t *tr;
  int pos = 0;

#ifdef OSIP_MT
  osip_mutex_lock (ist_fastmutex);
#endif
  /* handle ist timers */
  while (!osip_list_eol (osip->osip_ist_transactions, pos))
    {
      osip_event_t *evt;

      tr =
      (osip_transaction_t *) osip_list_get (osip->osip_ist_transactions,
                                    pos);

      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);
          }
      }
      pos++;
    }
#ifdef OSIP_MT
  osip_mutex_unlock (ist_fastmutex);
#endif
}

void
01477 osip_timers_nict_execute (osip_t * osip)
{
  osip_transaction_t *tr;
  int pos = 0;

#ifdef OSIP_MT
  osip_mutex_lock (nict_fastmutex);
#endif
  /* handle nict timers */
  while (!osip_list_eol (osip->osip_nict_transactions, pos))
    {
      osip_event_t *evt;

      tr =
      (osip_transaction_t *) osip_list_get (osip->osip_nict_transactions,
                                    pos);

      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);
          }
      }
      pos++;
    }
#ifdef OSIP_MT
  osip_mutex_unlock (nict_fastmutex);
#endif
}


void
01522 osip_timers_nist_execute (osip_t * osip)
{
  osip_transaction_t *tr;
  int pos = 0;

#ifdef OSIP_MT
  osip_mutex_lock (nist_fastmutex);
#endif
  /* handle nist timers */
  while (!osip_list_eol (osip->osip_nist_transactions, pos))
    {
      osip_event_t *evt;

      tr =
      (osip_transaction_t *) osip_list_get (osip->osip_nist_transactions,
                                    pos);

      evt = __osip_nist_need_timer_j_event (tr->nist_context, tr->state,
                                  tr->transactionid);
      if (evt != NULL)
      osip_fifo_add (tr->transactionff, evt);
      pos++;
    }
#ifdef OSIP_MT
  osip_mutex_unlock (nist_fastmutex);
#endif
}

void
01551 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;
    }
  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
01612 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 -1;
    }
  config->msg_callbacks[type] = cb;

  return 0;
}

int
01627 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 -1;
    }
  config->kill_callbacks[type] = cb;
  return 0;
}

int
01642 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 -1;
    }
  config->tp_error_callbacks[type] = cb;
  return 0;
}

Generated by  Doxygen 1.6.0   Back to index