237 lines
4.3 KiB
C
237 lines
4.3 KiB
C
/**
|
|
* @file sip.c SIP Core
|
|
*
|
|
* Copyright (C) 2010 Creytiv.com
|
|
*/
|
|
#include <re_types.h>
|
|
#include <re_mem.h>
|
|
#include <re_mbuf.h>
|
|
#include <re_sa.h>
|
|
#include <re_list.h>
|
|
#include <re_hash.h>
|
|
#include <re_fmt.h>
|
|
#include <re_uri.h>
|
|
#include <re_sys.h>
|
|
#include <re_tmr.h>
|
|
#include <re_udp.h>
|
|
#include <re_stun.h>
|
|
#include <re_sip.h>
|
|
#include "sip.h"
|
|
|
|
|
|
static void destructor(void *arg)
|
|
{
|
|
struct sip *sip = arg;
|
|
|
|
if (sip->closing) {
|
|
sip->closing = false;
|
|
mem_ref(sip);
|
|
if (sip->exith)
|
|
sip->exith(sip->arg);
|
|
return;
|
|
}
|
|
|
|
sip_request_close(sip);
|
|
sip_request_close(sip);
|
|
|
|
hash_flush(sip->ht_ctrans);
|
|
mem_deref(sip->ht_ctrans);
|
|
|
|
hash_flush(sip->ht_strans);
|
|
hash_clear(sip->ht_strans_mrg);
|
|
mem_deref(sip->ht_strans);
|
|
mem_deref(sip->ht_strans_mrg);
|
|
|
|
hash_flush(sip->ht_conn);
|
|
mem_deref(sip->ht_conn);
|
|
|
|
hash_flush(sip->ht_udpconn);
|
|
mem_deref(sip->ht_udpconn);
|
|
|
|
list_flush(&sip->transpl);
|
|
list_flush(&sip->lsnrl);
|
|
|
|
mem_deref(sip->software);
|
|
mem_deref(sip->dnsc);
|
|
mem_deref(sip->stun);
|
|
}
|
|
|
|
|
|
static void lsnr_destructor(void *arg)
|
|
{
|
|
struct sip_lsnr *lsnr = arg;
|
|
|
|
if (lsnr->lsnrp)
|
|
*lsnr->lsnrp = NULL;
|
|
|
|
list_unlink(&lsnr->le);
|
|
}
|
|
|
|
|
|
/**
|
|
* Allocate a SIP stack instance
|
|
*
|
|
* @param sipp Pointer to allocated SIP stack
|
|
* @param dnsc DNS Client (optional)
|
|
* @param ctsz Size of client transactions hashtable (power of 2)
|
|
* @param stsz Size of server transactions hashtable (power of 2)
|
|
* @param tcsz Size of SIP transport hashtable (power of 2)
|
|
* @param software Software identifier
|
|
* @param exith SIP-stack exit handler
|
|
* @param arg Handler argument
|
|
*
|
|
* @return 0 if success, otherwise errorcode
|
|
*/
|
|
int sip_alloc(struct sip **sipp, struct dnsc *dnsc, uint32_t ctsz,
|
|
uint32_t stsz, uint32_t tcsz, const char *software,
|
|
sip_exit_h *exith, void *arg)
|
|
{
|
|
struct sip *sip;
|
|
int err;
|
|
|
|
if (!sipp)
|
|
return EINVAL;
|
|
|
|
sip = mem_zalloc(sizeof(*sip), destructor);
|
|
if (!sip)
|
|
return ENOMEM;
|
|
|
|
err = sip_transp_init(sip, tcsz);
|
|
if (err)
|
|
goto out;
|
|
|
|
err = sip_ctrans_init(sip, ctsz);
|
|
if (err)
|
|
goto out;
|
|
|
|
err = sip_strans_init(sip, stsz);
|
|
if (err)
|
|
goto out;
|
|
|
|
err = hash_alloc(&sip->ht_udpconn, tcsz);
|
|
if (err)
|
|
goto out;
|
|
|
|
err = stun_alloc(&sip->stun, NULL, NULL, NULL);
|
|
if (err)
|
|
goto out;
|
|
|
|
if (software) {
|
|
err = str_dup(&sip->software, software);
|
|
if (err)
|
|
goto out;
|
|
}
|
|
|
|
sip->dnsc = mem_ref(dnsc);
|
|
sip->exith = exith;
|
|
sip->arg = arg;
|
|
|
|
out:
|
|
if (err)
|
|
mem_deref(sip);
|
|
else
|
|
*sipp = sip;
|
|
|
|
return err;
|
|
}
|
|
|
|
|
|
/**
|
|
* Close the SIP stack instance
|
|
*
|
|
* @param sip SIP stack instance
|
|
* @param force Don't wait for transactions to complete
|
|
*/
|
|
void sip_close(struct sip *sip, bool force)
|
|
{
|
|
if (!sip)
|
|
return;
|
|
|
|
if (force) {
|
|
sip_request_close(sip);
|
|
sip_request_close(sip);
|
|
}
|
|
else if (!sip->closing) {
|
|
sip->closing = true;
|
|
mem_deref(sip);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Send a SIP message
|
|
*
|
|
* @param sip SIP stack instance
|
|
* @param sock Optional socket to send from
|
|
* @param tp SIP transport
|
|
* @param dst Destination network address
|
|
* @param mb Buffer containing SIP message
|
|
*
|
|
* @return 0 if success, otherwise errorcode
|
|
*/
|
|
int sip_send(struct sip *sip, void *sock, enum sip_transp tp,
|
|
const struct sa *dst, struct mbuf *mb)
|
|
{
|
|
return sip_transp_send(NULL, sip, sock, tp, dst, mb, NULL, NULL);
|
|
}
|
|
|
|
|
|
/**
|
|
* Listen for incoming SIP Requests and SIP Responses
|
|
*
|
|
* @param lsnrp Pointer to allocated listener
|
|
* @param sip SIP stack instance
|
|
* @param req True for Request, false for Response
|
|
* @param msgh SIP message handler
|
|
* @param arg Handler argument
|
|
*
|
|
* @return 0 if success, otherwise errorcode
|
|
*/
|
|
int sip_listen(struct sip_lsnr **lsnrp, struct sip *sip, bool req,
|
|
sip_msg_h *msgh, void *arg)
|
|
{
|
|
struct sip_lsnr *lsnr;
|
|
|
|
if (!sip || !msgh)
|
|
return EINVAL;
|
|
|
|
lsnr = mem_zalloc(sizeof(*lsnr), lsnr_destructor);
|
|
if (!lsnr)
|
|
return ENOMEM;
|
|
|
|
list_append(&sip->lsnrl, &lsnr->le, lsnr);
|
|
|
|
lsnr->msgh = msgh;
|
|
lsnr->arg = arg;
|
|
lsnr->req = req;
|
|
|
|
if (lsnrp) {
|
|
lsnr->lsnrp = lsnrp;
|
|
*lsnrp = lsnr;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/**
|
|
* Print debug information about the SIP stack
|
|
*
|
|
* @param pf Print function for debug output
|
|
* @param sip SIP stack instance
|
|
*
|
|
* @return 0 if success, otherwise errorcode
|
|
*/
|
|
int sip_debug(struct re_printf *pf, const struct sip *sip)
|
|
{
|
|
int err;
|
|
|
|
if (!sip)
|
|
return 0;
|
|
|
|
err = sip_transp_debug(pf, sip);
|
|
err |= sip_ctrans_debug(pf, sip);
|
|
err |= sip_strans_debug(pf, sip);
|
|
|
|
return err;
|
|
}
|