added support for SIP Outbound (RFC 5626)
This commit is contained in:
parent
4fc13c7f6b
commit
41c825ed0c
14 changed files with 559 additions and 14 deletions
|
@ -95,6 +95,7 @@ Features:
|
|||
* RFC 5118 - SIP Torture Test Messages for IPv6
|
||||
* RFC 5245 - Interactive Connectivity Establishment (ICE)
|
||||
* RFC 5389 - Session Traversal Utilities for NAT (STUN)
|
||||
* RFC 5626 - Managing Client-Initiated Connections in SIP
|
||||
* RFC 5761 - Multiplexing RTP Data and Control Packets on a Single Port
|
||||
* RFC 5766 - Traversal Using Relays around NAT (TURN)
|
||||
* RFC 5768 - Indicating Support for ICE in SIP
|
||||
|
|
|
@ -3,7 +3,6 @@ TODO
|
|||
-------------------------------------------------------------------------------
|
||||
Version v0.1.1
|
||||
|
||||
SIP Outbound support - client+server
|
||||
tmr: scaling using binary heap or hash
|
||||
Add support for SIP SUBSCRIBE/NOTIFY
|
||||
Add support for Call-Transfer in SIP Session
|
||||
|
|
|
@ -45,6 +45,7 @@ enum sip_hdrid {
|
|||
SIP_HDR_ERROR_INFO = 21,
|
||||
SIP_HDR_EVENT = 3286,
|
||||
SIP_HDR_EXPIRES = 1983,
|
||||
SIP_HDR_FLOW_TIMER = 584,
|
||||
SIP_HDR_FROM = 1963,
|
||||
SIP_HDR_HIDE = 283,
|
||||
SIP_HDR_HISTORY_INFO = 2582,
|
||||
|
@ -210,6 +211,7 @@ struct sip_request;
|
|||
struct sip_strans;
|
||||
struct sip_auth;
|
||||
struct sip_dialog;
|
||||
struct sip_keepalive;
|
||||
struct dnsc;
|
||||
|
||||
typedef bool(sip_msg_h)(const struct sip_msg *msg, void *arg);
|
||||
|
@ -222,6 +224,7 @@ typedef int(sip_auth_h)(char **username, char **password, const char *realm,
|
|||
void *arg);
|
||||
typedef bool(sip_hdr_h)(const struct sip_hdr *hdr, const struct sip_msg *msg,
|
||||
void *arg);
|
||||
typedef void(sip_keepalive_h)(int err, void *arg);
|
||||
|
||||
|
||||
/* sip */
|
||||
|
@ -312,6 +315,10 @@ const struct sip_hdr *sip_msg_xhdr_apply(const struct sip_msg *msg,
|
|||
sip_hdr_h *h, void *arg);
|
||||
uint32_t sip_msg_hdr_count(const struct sip_msg *msg, enum sip_hdrid id);
|
||||
uint32_t sip_msg_xhdr_count(const struct sip_msg *msg, const char *name);
|
||||
bool sip_msg_hdr_has_value(const struct sip_msg *msg, enum sip_hdrid id,
|
||||
const char *value);
|
||||
bool sip_msg_xhdr_has_value(const struct sip_msg *msg, const char *name,
|
||||
const char *value);
|
||||
struct tcp_conn *sip_msg_tcpconn(const struct sip_msg *msg);
|
||||
void sip_msg_dump(const struct sip_msg *msg);
|
||||
|
||||
|
@ -320,3 +327,9 @@ int sip_via_decode(struct sip_via *via, const struct pl *pl);
|
|||
int sip_cseq_decode(struct sip_cseq *cseq, const struct pl *pl);
|
||||
int sip_param_decode(const struct pl *pl, const char *name, struct pl *val);
|
||||
int sip_param_exists(const struct pl *pl, const char *name, struct pl *end);
|
||||
|
||||
|
||||
/* keepalive */
|
||||
int sip_keepalive_start(struct sip_keepalive **kap, struct sip *sip,
|
||||
const struct sip_msg *msg, uint32_t interval,
|
||||
sip_keepalive_h *kah, void *arg);
|
||||
|
|
|
@ -10,6 +10,6 @@ struct sipreg;
|
|||
int sipreg_register(struct sipreg **regp, struct sip *sip, const char *reg_uri,
|
||||
const char *to_uri, const char *from_uri, uint32_t expires,
|
||||
const char *cuser, const char *routev[], uint32_t routec,
|
||||
sip_auth_h *authh, void *aarg, bool ref,
|
||||
int regid, sip_auth_h *authh, void *aarg, bool aref,
|
||||
sip_resp_h *resph, void *arg,
|
||||
const char *params, const char *fmt, ...);
|
||||
|
|
|
@ -26,6 +26,8 @@ SOURCE auth.c
|
|||
SOURCE cseq.c
|
||||
SOURCE ctrans.c
|
||||
SOURCE dialog.c
|
||||
SOURCE keepalive.c
|
||||
SOURCE keepalive_udp.c
|
||||
SOURCE msg.c
|
||||
SOURCE param.c
|
||||
SOURCE reply.c
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <re_sys.h>
|
||||
#include <re_md5.h>
|
||||
#include <re_httpauth.h>
|
||||
#include <re_udp.h>
|
||||
#include <re_sip.h>
|
||||
#include "sip.h"
|
||||
|
||||
|
|
102
src/sip/keepalive.c
Normal file
102
src/sip/keepalive.c
Normal file
|
@ -0,0 +1,102 @@
|
|||
/**
|
||||
* @file keepalive.c SIP Keepalive
|
||||
*
|
||||
* Copyright (C) 2010 Creytiv.com
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <re_types.h>
|
||||
#include <re_fmt.h>
|
||||
#include <re_mem.h>
|
||||
#include <re_mbuf.h>
|
||||
#include <re_sa.h>
|
||||
#include <re_list.h>
|
||||
#include <re_sys.h>
|
||||
#include <re_uri.h>
|
||||
#include <re_udp.h>
|
||||
#include <re_sip.h>
|
||||
#include "sip.h"
|
||||
|
||||
|
||||
static void destructor(void *arg)
|
||||
{
|
||||
struct sip_keepalive *ka = arg;
|
||||
|
||||
if (ka->kap)
|
||||
*ka->kap = NULL;
|
||||
|
||||
list_unlink(&ka->le);
|
||||
}
|
||||
|
||||
|
||||
void sip_keepalive_signal(struct list *kal, int err)
|
||||
{
|
||||
struct le *le = list_head(kal);
|
||||
|
||||
while (le) {
|
||||
|
||||
struct sip_keepalive *ka = le->data;
|
||||
sip_keepalive_h *kah = ka->kah;
|
||||
void *arg = ka->arg;
|
||||
|
||||
le = le->next;
|
||||
|
||||
list_unlink(&ka->le);
|
||||
mem_deref(ka);
|
||||
|
||||
kah(err, arg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint64_t sip_keepalive_wait(uint32_t interval)
|
||||
{
|
||||
return interval * (800 + rand_u16() % 201);
|
||||
}
|
||||
|
||||
|
||||
int sip_keepalive_start(struct sip_keepalive **kap, struct sip *sip,
|
||||
const struct sip_msg *msg, uint32_t interval,
|
||||
sip_keepalive_h *kah, void *arg)
|
||||
{
|
||||
struct sip_keepalive *ka;
|
||||
int err;
|
||||
|
||||
if (!kap || !sip || !msg || !kah)
|
||||
return EINVAL;
|
||||
|
||||
ka = mem_zalloc(sizeof(*ka), destructor);
|
||||
if (!ka)
|
||||
return ENOMEM;
|
||||
|
||||
ka->kah = kah;
|
||||
ka->arg = arg;
|
||||
|
||||
switch (msg->tp) {
|
||||
|
||||
case SIP_TRANSP_UDP:
|
||||
err = sip_keepalive_udp(ka, sip, (struct udp_sock *)msg->sock,
|
||||
&msg->src, interval);
|
||||
break;
|
||||
|
||||
case SIP_TRANSP_TCP:
|
||||
case SIP_TRANSP_TLS:
|
||||
err = sip_keepalive_tcp(ka, (struct sip_conn *)msg->sock,
|
||||
interval);
|
||||
break;
|
||||
|
||||
default:
|
||||
err = EPROTONOSUPPORT;
|
||||
break;
|
||||
}
|
||||
|
||||
if (err) {
|
||||
mem_deref(ka);
|
||||
}
|
||||
else {
|
||||
ka->kap = kap;
|
||||
*kap = ka;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
187
src/sip/keepalive_udp.c
Normal file
187
src/sip/keepalive_udp.c
Normal file
|
@ -0,0 +1,187 @@
|
|||
/**
|
||||
* @file keepalive_udp.c SIP UDP Keepalive
|
||||
*
|
||||
* Copyright (C) 2010 Creytiv.com
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#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"
|
||||
|
||||
|
||||
enum {
|
||||
UDP_KEEPALIVE_INTVAL = 29,
|
||||
};
|
||||
|
||||
|
||||
struct sip_udpconn {
|
||||
struct le he;
|
||||
struct list kal;
|
||||
struct tmr tmr_ka;
|
||||
struct sa maddr;
|
||||
struct sa paddr;
|
||||
struct udp_sock *us;
|
||||
struct stun_ctrans *ct;
|
||||
struct stun *stun;
|
||||
uint32_t ka_interval;
|
||||
};
|
||||
|
||||
|
||||
static void udpconn_keepalive_handler(void *arg);
|
||||
|
||||
|
||||
static void destructor(void *arg)
|
||||
{
|
||||
struct sip_udpconn *uc = arg;
|
||||
|
||||
list_flush(&uc->kal);
|
||||
hash_unlink(&uc->he);
|
||||
tmr_cancel(&uc->tmr_ka);
|
||||
mem_deref(uc->ct);
|
||||
mem_deref(uc->us);
|
||||
mem_deref(uc->stun);
|
||||
}
|
||||
|
||||
|
||||
static void udpconn_close(struct sip_udpconn *uc, int err)
|
||||
{
|
||||
sip_keepalive_signal(&uc->kal, err);
|
||||
hash_unlink(&uc->he);
|
||||
tmr_cancel(&uc->tmr_ka);
|
||||
uc->ct = mem_deref(uc->ct);
|
||||
uc->us = mem_deref(uc->us);
|
||||
uc->stun = mem_deref(uc->stun);
|
||||
}
|
||||
|
||||
|
||||
static void stun_response_handler(int err, uint16_t scode, const char *reason,
|
||||
const struct stun_msg *msg, void *arg)
|
||||
{
|
||||
struct sip_udpconn *uc = arg;
|
||||
struct stun_attr *attr;
|
||||
(void)reason;
|
||||
|
||||
if (err || scode) {
|
||||
err = err ? err : EPROTO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
attr = stun_msg_attr(msg, STUN_ATTR_XOR_MAPPED_ADDR);
|
||||
if (!attr) {
|
||||
attr = stun_msg_attr(msg, STUN_ATTR_MAPPED_ADDR);
|
||||
if (!attr) {
|
||||
err = EPROTO;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (!sa_isset(&uc->maddr, SA_ALL)) {
|
||||
uc->maddr = attr->v.sa;
|
||||
}
|
||||
else if (!sa_cmp(&uc->maddr, &attr->v.sa, SA_ALL)) {
|
||||
err = ENOTCONN;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
if (err) {
|
||||
udpconn_close(uc, err);
|
||||
mem_deref(uc);
|
||||
}
|
||||
else {
|
||||
tmr_start(&uc->tmr_ka, sip_keepalive_wait(uc->ka_interval),
|
||||
udpconn_keepalive_handler, uc);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void udpconn_keepalive_handler(void *arg)
|
||||
{
|
||||
struct sip_udpconn *uc = arg;
|
||||
int err;
|
||||
|
||||
if (!uc->kal.head) {
|
||||
/* no need for us anymore */
|
||||
udpconn_close(uc, 0);
|
||||
mem_deref(uc);
|
||||
return;
|
||||
}
|
||||
|
||||
err = stun_request(&uc->ct, uc->stun, IPPROTO_UDP, uc->us,
|
||||
&uc->paddr, 0, STUN_METHOD_BINDING, NULL, 0,
|
||||
false, stun_response_handler, uc, 1,
|
||||
STUN_ATTR_SOFTWARE, stun_software);
|
||||
if (err) {
|
||||
udpconn_close(uc, err);
|
||||
mem_deref(uc);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static struct sip_udpconn *udpconn_find(struct sip *sip, struct udp_sock *us,
|
||||
const struct sa *paddr)
|
||||
{
|
||||
struct le *le;
|
||||
|
||||
le = list_head(hash_list(sip->ht_udpconn, sa_hash(paddr, SA_ALL)));
|
||||
|
||||
for (; le; le = le->next) {
|
||||
|
||||
struct sip_udpconn *uc = le->data;
|
||||
|
||||
if (!sa_cmp(&uc->paddr, paddr, SA_ALL))
|
||||
continue;
|
||||
|
||||
if (uc->us != us)
|
||||
continue;
|
||||
|
||||
return uc;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int sip_keepalive_udp(struct sip_keepalive *ka, struct sip *sip,
|
||||
struct udp_sock *us, const struct sa *paddr,
|
||||
uint32_t interval)
|
||||
{
|
||||
struct sip_udpconn *uc;
|
||||
|
||||
if (!ka || !sip || !us || !paddr)
|
||||
return EINVAL;
|
||||
|
||||
uc = udpconn_find(sip, us, paddr);
|
||||
if (!uc) {
|
||||
uc = mem_zalloc(sizeof(*uc), destructor);
|
||||
if (!uc)
|
||||
return ENOMEM;
|
||||
|
||||
hash_append(sip->ht_udpconn, sa_hash(paddr, SA_ALL),
|
||||
&uc->he, uc);
|
||||
|
||||
uc->paddr = *paddr;
|
||||
uc->stun = mem_ref(sip->stun);
|
||||
uc->us = mem_ref(us);
|
||||
uc->ka_interval = interval ? interval : UDP_KEEPALIVE_INTVAL;
|
||||
|
||||
/* learn mapped address immediately */
|
||||
tmr_start(&uc->tmr_ka, 0, udpconn_keepalive_handler, uc);
|
||||
}
|
||||
|
||||
list_append(&uc->kal, &ka->le, ka);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -8,6 +8,8 @@ SRCS += sip/auth.c
|
|||
SRCS += sip/cseq.c
|
||||
SRCS += sip/ctrans.c
|
||||
SRCS += sip/dialog.c
|
||||
SRCS += sip/keepalive.c
|
||||
SRCS += sip/keepalive_udp.c
|
||||
SRCS += sip/msg.c
|
||||
SRCS += sip/param.c
|
||||
SRCS += sip/reply.c
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <re_hash.h>
|
||||
#include <re_fmt.h>
|
||||
#include <re_uri.h>
|
||||
#include <re_udp.h>
|
||||
#include <re_sip.h>
|
||||
#include "sip.h"
|
||||
|
||||
|
@ -534,6 +535,31 @@ uint32_t sip_msg_xhdr_count(const struct sip_msg *msg, const char *name)
|
|||
}
|
||||
|
||||
|
||||
static bool value_handler(const struct sip_hdr *hdr, const struct sip_msg *msg,
|
||||
void *arg)
|
||||
{
|
||||
(void)msg;
|
||||
|
||||
return 0 == pl_strcasecmp(&hdr->val, (const char *)arg);
|
||||
}
|
||||
|
||||
|
||||
bool sip_msg_hdr_has_value(const struct sip_msg *msg, enum sip_hdrid id,
|
||||
const char *value)
|
||||
{
|
||||
return NULL != sip_msg_hdr_apply(msg, true, id, value_handler,
|
||||
(void *)value);
|
||||
}
|
||||
|
||||
|
||||
bool sip_msg_xhdr_has_value(const struct sip_msg *msg, const char *name,
|
||||
const char *value)
|
||||
{
|
||||
return NULL != sip_msg_xhdr_apply(msg, true, name, value_handler,
|
||||
(void *)value);
|
||||
}
|
||||
|
||||
|
||||
void sip_msg_dump(const struct sip_msg *msg)
|
||||
{
|
||||
struct le *le;
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <re_sys.h>
|
||||
#include <re_tmr.h>
|
||||
#include <re_udp.h>
|
||||
#include <re_stun.h>
|
||||
#include <re_sip.h>
|
||||
#include "sip.h"
|
||||
|
||||
|
@ -42,11 +43,15 @@ static void destructor(void *arg)
|
|||
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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -87,6 +92,14 @@ int sip_alloc(struct sip **sipp, struct dnsc *dnsc, uint32_t ctsz,
|
|||
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)
|
||||
|
|
|
@ -12,7 +12,9 @@ struct sip {
|
|||
struct hash *ht_ctrans;
|
||||
struct hash *ht_strans;
|
||||
struct hash *ht_conn;
|
||||
struct hash *ht_udpconn;
|
||||
struct dnsc *dnsc;
|
||||
struct stun *stun;
|
||||
char *software;
|
||||
sip_exit_h *exith;
|
||||
void *arg;
|
||||
|
@ -29,6 +31,14 @@ struct sip_lsnr {
|
|||
};
|
||||
|
||||
|
||||
struct sip_keepalive {
|
||||
struct le le;
|
||||
struct sip_keepalive **kap;
|
||||
sip_keepalive_h *kah;
|
||||
void *arg;
|
||||
};
|
||||
|
||||
|
||||
/* request */
|
||||
void sip_request_close(struct sip *sip);
|
||||
|
||||
|
@ -78,3 +88,15 @@ int sip_dialog_encode(struct mbuf *mb, struct sip_dialog *dlg, uint32_t cseq,
|
|||
const char *met);
|
||||
const char *sip_dialog_uri(const struct sip_dialog *dlg);
|
||||
const struct uri *sip_dialog_route(const struct sip_dialog *dlg);
|
||||
|
||||
|
||||
/* keepalive */
|
||||
struct sip_conn;
|
||||
|
||||
void sip_keepalive_signal(struct list *kal, int err);
|
||||
uint64_t sip_keepalive_wait(uint32_t interval);
|
||||
int sip_keepalive_tcp(struct sip_keepalive *ka, struct sip_conn *conn,
|
||||
uint32_t interval);
|
||||
int sip_keepalive_udp(struct sip_keepalive *ka, struct sip *sip,
|
||||
struct udp_sock *us, const struct sa *paddr,
|
||||
uint32_t interval);
|
||||
|
|
122
src/sip/transp.c
122
src/sip/transp.c
|
@ -15,6 +15,7 @@
|
|||
#include <re_sys.h>
|
||||
#include <re_tmr.h>
|
||||
#include <re_udp.h>
|
||||
#include <re_stun.h>
|
||||
#include <re_tcp.h>
|
||||
#include <re_tls.h>
|
||||
#include <re_sip.h>
|
||||
|
@ -22,7 +23,9 @@
|
|||
|
||||
|
||||
enum {
|
||||
TCP_ACCEPT_TIMEOUT = 32000,
|
||||
TCP_ACCEPT_TIMEOUT = 32,
|
||||
TCP_KEEPALIVE_TIMEOUT = 10,
|
||||
TCP_KEEPALIVE_INTVAL = 120,
|
||||
};
|
||||
|
||||
|
||||
|
@ -39,13 +42,16 @@ struct sip_transport {
|
|||
struct sip_conn {
|
||||
struct le he;
|
||||
struct list ql;
|
||||
struct list kal;
|
||||
struct tmr tmr;
|
||||
struct tmr tmr_ka;
|
||||
struct sa laddr;
|
||||
struct sa paddr;
|
||||
struct tls_conn *sc;
|
||||
struct tcp_conn *tc;
|
||||
struct mbuf *mb;
|
||||
struct sip *sip;
|
||||
uint32_t ka_interval;
|
||||
bool established;
|
||||
};
|
||||
|
||||
|
@ -59,6 +65,9 @@ struct sip_connqent {
|
|||
};
|
||||
|
||||
|
||||
static uint8_t crlfcrlf[4] = {0x0d, 0x0a, 0x0d, 0x0a};
|
||||
|
||||
|
||||
static void internal_transport_handler(int err, void *arg)
|
||||
{
|
||||
(void)err;
|
||||
|
@ -70,6 +79,9 @@ static void transp_destructor(void *arg)
|
|||
{
|
||||
struct sip_transport *transp = arg;
|
||||
|
||||
if (transp->tp == SIP_TRANSP_UDP)
|
||||
udp_handler_set(transp->sock, NULL, NULL);
|
||||
|
||||
list_unlink(&transp->le);
|
||||
mem_deref(transp->sock);
|
||||
mem_deref(transp->tls);
|
||||
|
@ -80,7 +92,9 @@ static void conn_destructor(void *arg)
|
|||
{
|
||||
struct sip_conn *conn = arg;
|
||||
|
||||
tmr_cancel(&conn->tmr_ka);
|
||||
tmr_cancel(&conn->tmr);
|
||||
list_flush(&conn->kal);
|
||||
list_flush(&conn->ql);
|
||||
hash_unlink(&conn->he);
|
||||
mem_deref(conn->sc);
|
||||
|
@ -155,6 +169,7 @@ static void conn_close(struct sip_conn *conn, int err)
|
|||
|
||||
conn->sc = mem_deref(conn->sc);
|
||||
conn->tc = mem_deref(conn->tc);
|
||||
tmr_cancel(&conn->tmr_ka);
|
||||
tmr_cancel(&conn->tmr);
|
||||
hash_unlink(&conn->he);
|
||||
|
||||
|
@ -174,6 +189,8 @@ static void conn_close(struct sip_conn *conn, int err)
|
|||
list_unlink(&qent->le);
|
||||
mem_deref(qent);
|
||||
}
|
||||
|
||||
sip_keepalive_signal(&conn->kal, err);
|
||||
}
|
||||
|
||||
|
||||
|
@ -186,6 +203,31 @@ static void conn_tmr_handler(void *arg)
|
|||
}
|
||||
|
||||
|
||||
static void conn_keepalive_handler(void *arg)
|
||||
{
|
||||
struct sip_conn *conn = arg;
|
||||
struct mbuf mb;
|
||||
int err;
|
||||
|
||||
mb.buf = crlfcrlf;
|
||||
mb.size = sizeof(crlfcrlf);
|
||||
mb.pos = 0;
|
||||
mb.end = 4;
|
||||
|
||||
err = tcp_send(conn->tc, &mb);
|
||||
if (err) {
|
||||
conn_close(conn, err);
|
||||
mem_deref(conn);
|
||||
return;
|
||||
}
|
||||
|
||||
tmr_start(&conn->tmr, TCP_KEEPALIVE_TIMEOUT * 1000,
|
||||
conn_tmr_handler, conn);
|
||||
tmr_start(&conn->tmr_ka, sip_keepalive_wait(conn->ka_interval),
|
||||
conn_keepalive_handler, conn);
|
||||
}
|
||||
|
||||
|
||||
static void sip_recv(struct sip *sip, const struct sip_msg *msg)
|
||||
{
|
||||
struct le *le = sip->lsnrl.head;
|
||||
|
@ -224,12 +266,42 @@ static void sip_recv(struct sip *sip, const struct sip_msg *msg)
|
|||
static void udp_recv_handler(const struct sa *src, struct mbuf *mb, void *arg)
|
||||
{
|
||||
struct sip_transport *transp = arg;
|
||||
struct stun_unknown_attr ua;
|
||||
struct stun_msg *stun_msg;
|
||||
struct sip_msg *msg;
|
||||
int err;
|
||||
|
||||
if (mb->end <= 4)
|
||||
return;
|
||||
|
||||
if (!stun_msg_decode(&stun_msg, mb, &ua)) {
|
||||
|
||||
if (stun_msg_method(stun_msg) == STUN_METHOD_BINDING) {
|
||||
|
||||
switch (stun_msg_class(stun_msg)) {
|
||||
|
||||
case STUN_CLASS_REQUEST:
|
||||
(void)stun_reply(IPPROTO_UDP, transp->sock,
|
||||
src, 0, stun_msg,
|
||||
NULL, 0, false, 2,
|
||||
STUN_ATTR_XOR_MAPPED_ADDR,
|
||||
src,
|
||||
STUN_ATTR_SOFTWARE,
|
||||
transp->sip->software);
|
||||
break;
|
||||
|
||||
default:
|
||||
(void)stun_ctrans_recv(transp->sip->stun,
|
||||
stun_msg, &ua);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mem_deref(stun_msg);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
err = sip_msg_decode(&msg, mb);
|
||||
if (err) {
|
||||
(void)re_fprintf(stderr, "sip: msg decode err: %s\n",
|
||||
|
@ -281,7 +353,26 @@ static void tcp_recv_handler(struct mbuf *mb, void *arg)
|
|||
break;
|
||||
|
||||
if (!memcmp(mbuf_buf(conn->mb), "\r\n", 2)) {
|
||||
|
||||
conn->mb->pos += 2;
|
||||
|
||||
if (mbuf_get_left(conn->mb) >= 2 &&
|
||||
!memcmp(mbuf_buf(conn->mb), "\r\n", 2)) {
|
||||
|
||||
struct mbuf mbr;
|
||||
|
||||
conn->mb->pos += 2;
|
||||
|
||||
mbr.buf = crlfcrlf;
|
||||
mbr.size = sizeof(crlfcrlf);
|
||||
mbr.pos = 0;
|
||||
mbr.end = 2;
|
||||
|
||||
err = tcp_send(conn->tc, &mbr);
|
||||
if (err)
|
||||
break;
|
||||
}
|
||||
|
||||
if (mbuf_get_left(conn->mb))
|
||||
continue;
|
||||
|
||||
|
@ -436,7 +527,8 @@ static void tcp_connect_handler(const struct sa *paddr, void *arg)
|
|||
}
|
||||
#endif
|
||||
|
||||
tmr_start(&conn->tmr, TCP_ACCEPT_TIMEOUT, conn_tmr_handler, conn);
|
||||
tmr_start(&conn->tmr, TCP_ACCEPT_TIMEOUT * 1000,
|
||||
conn_tmr_handler, conn);
|
||||
|
||||
out:
|
||||
if (err) {
|
||||
|
@ -781,3 +873,29 @@ struct tcp_conn *sip_msg_tcpconn(const struct sip_msg *msg)
|
|||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int sip_keepalive_tcp(struct sip_keepalive *ka, struct sip_conn *conn,
|
||||
uint32_t interval)
|
||||
{
|
||||
if (!ka || !conn)
|
||||
return EINVAL;
|
||||
|
||||
if (!conn->tc || !conn->established)
|
||||
return ENOTCONN;
|
||||
|
||||
list_append(&conn->kal, &ka->le, ka);
|
||||
|
||||
if (!tmr_isrunning(&conn->tmr_ka)) {
|
||||
|
||||
interval = MAX(interval ? interval : TCP_KEEPALIVE_INTVAL,
|
||||
TCP_KEEPALIVE_TIMEOUT * 2);
|
||||
|
||||
conn->ka_interval = interval;
|
||||
|
||||
tmr_start(&conn->tmr_ka, sip_keepalive_wait(conn->ka_interval),
|
||||
conn_keepalive_handler, conn);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <re_hash.h>
|
||||
#include <re_fmt.h>
|
||||
#include <re_uri.h>
|
||||
#include <re_sys.h>
|
||||
#include <re_tmr.h>
|
||||
#include <re_sip.h>
|
||||
#include <re_sipreg.h>
|
||||
|
@ -18,7 +19,6 @@
|
|||
|
||||
enum {
|
||||
DEFAULT_EXPIRES = 3600,
|
||||
FAIL_WAIT = 60 * 1000,
|
||||
};
|
||||
|
||||
|
||||
|
@ -27,6 +27,7 @@ struct sipreg {
|
|||
struct sa laddr;
|
||||
struct tmr tmr;
|
||||
struct sip *sip;
|
||||
struct sip_keepalive *ka;
|
||||
struct sip_request *req;
|
||||
struct sip_dialog *dlg;
|
||||
struct sip_auth *auth;
|
||||
|
@ -35,11 +36,13 @@ struct sipreg {
|
|||
sip_resp_h *resph;
|
||||
void *arg;
|
||||
uint32_t expires;
|
||||
uint32_t failc;
|
||||
uint32_t wait;
|
||||
enum sip_transp tp;
|
||||
bool registered;
|
||||
bool terminated;
|
||||
char *params;
|
||||
int regid;
|
||||
};
|
||||
|
||||
|
||||
|
@ -76,6 +79,7 @@ static void destructor(void *arg)
|
|||
}
|
||||
}
|
||||
|
||||
mem_deref(reg->ka);
|
||||
mem_deref(reg->dlg);
|
||||
mem_deref(reg->auth);
|
||||
mem_deref(reg->cuser);
|
||||
|
@ -85,6 +89,12 @@ static void destructor(void *arg)
|
|||
}
|
||||
|
||||
|
||||
static uint32_t failwait(uint32_t failc)
|
||||
{
|
||||
return min(1800, (30 * (1<<failc))) * (500 + rand_u16() % 501);
|
||||
}
|
||||
|
||||
|
||||
static void tmr_handler(void *arg)
|
||||
{
|
||||
struct sipreg *reg = arg;
|
||||
|
@ -92,12 +102,40 @@ static void tmr_handler(void *arg)
|
|||
|
||||
err = request(reg, true);
|
||||
if (err) {
|
||||
tmr_start(®->tmr, FAIL_WAIT, tmr_handler, reg);
|
||||
tmr_start(®->tmr, failwait(++reg->failc), tmr_handler, reg);
|
||||
reg->resph(err, NULL, reg->arg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void keepalive_handler(int err, void *arg)
|
||||
{
|
||||
struct sipreg *reg = arg;
|
||||
|
||||
/* failure will be handled in response handler */
|
||||
if (reg->req || reg->terminated)
|
||||
return;
|
||||
|
||||
tmr_start(®->tmr, failwait(++reg->failc), tmr_handler, reg);
|
||||
reg->resph(err, NULL, reg->arg);
|
||||
}
|
||||
|
||||
|
||||
static void start_outbound(struct sipreg *reg, const struct sip_msg *msg)
|
||||
{
|
||||
const struct sip_hdr *flowtimer;
|
||||
|
||||
if (!sip_msg_hdr_has_value(msg, SIP_HDR_REQUIRE, "outbound"))
|
||||
return;
|
||||
|
||||
flowtimer = sip_msg_hdr(msg, SIP_HDR_FLOW_TIMER);
|
||||
|
||||
(void)sip_keepalive_start(®->ka, reg->sip, msg,
|
||||
flowtimer ? pl_u32(&flowtimer->val) : 0,
|
||||
keepalive_handler, reg);
|
||||
}
|
||||
|
||||
|
||||
static bool contact_handler(const struct sip_hdr *hdr,
|
||||
const struct sip_msg *msg, void *arg)
|
||||
{
|
||||
|
@ -133,10 +171,12 @@ static void response_handler(int err, const struct sip_msg *msg, void *arg)
|
|||
const struct sip_hdr *minexp;
|
||||
struct sipreg *reg = arg;
|
||||
|
||||
reg->wait = FAIL_WAIT;
|
||||
reg->wait = failwait(reg->failc + 1);
|
||||
|
||||
if (err || sip_request_loops(®->ls, msg->scode))
|
||||
if (err || sip_request_loops(®->ls, msg->scode)) {
|
||||
reg->failc++;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (msg->scode < 200) {
|
||||
return;
|
||||
|
@ -147,6 +187,10 @@ static void response_handler(int err, const struct sip_msg *msg, void *arg)
|
|||
sip_msg_hdr_apply(msg, true, SIP_HDR_CONTACT, contact_handler,
|
||||
reg);
|
||||
reg->wait *= 900;
|
||||
reg->failc = 0;
|
||||
|
||||
if (reg->regid > 0 && !reg->terminated && !reg->ka)
|
||||
start_outbound(reg, msg);
|
||||
}
|
||||
else {
|
||||
if (reg->terminated && !reg->registered)
|
||||
|
@ -185,6 +229,8 @@ static void response_handler(int err, const struct sip_msg *msg, void *arg)
|
|||
|
||||
return;
|
||||
}
|
||||
|
||||
++reg->failc;
|
||||
}
|
||||
|
||||
out:
|
||||
|
@ -206,6 +252,8 @@ static int send_handler(enum sip_transp tp, const struct sa *src,
|
|||
const struct sa *dst, struct mbuf *mb, void *arg)
|
||||
{
|
||||
struct sipreg *reg = arg;
|
||||
int err;
|
||||
|
||||
(void)dst;
|
||||
|
||||
if (reg->expires > 0) {
|
||||
|
@ -213,11 +261,18 @@ static int send_handler(enum sip_transp tp, const struct sa *src,
|
|||
reg->tp = tp;
|
||||
}
|
||||
|
||||
return mbuf_printf(mb, "Contact: <sip:%s@%J%s>;expires=%u%s%s\r\n",
|
||||
reg->cuser, ®->laddr, sip_transp_param(reg->tp),
|
||||
reg->expires,
|
||||
reg->params ? ";" : "",
|
||||
reg->params ? reg->params : "");
|
||||
err = mbuf_printf(mb, "Contact: <sip:%s@%J%s>;expires=%u%s%s",
|
||||
reg->cuser, ®->laddr, sip_transp_param(reg->tp),
|
||||
reg->expires,
|
||||
reg->params ? ";" : "",
|
||||
reg->params ? reg->params : "");
|
||||
|
||||
if (reg->regid > 0)
|
||||
err |= mbuf_printf(mb, ";reg-id=%d", reg->regid);
|
||||
|
||||
err |= mbuf_printf(mb, "\r\n");
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
@ -231,9 +286,12 @@ static int request(struct sipreg *reg, bool reset_ls)
|
|||
|
||||
return sip_drequestf(®->req, reg->sip, true, "REGISTER", reg->dlg,
|
||||
0, reg->auth, send_handler, response_handler, reg,
|
||||
"%s"
|
||||
"%b"
|
||||
"Content-Length: 0\r\n"
|
||||
"\r\n",
|
||||
reg->regid > 0
|
||||
? "Supported: outbound, path\r\n" : "",
|
||||
reg->hdrs ? mbuf_buf(reg->hdrs) : NULL,
|
||||
reg->hdrs ? mbuf_get_left(reg->hdrs) : 0);
|
||||
}
|
||||
|
@ -242,7 +300,7 @@ static int request(struct sipreg *reg, bool reset_ls)
|
|||
int sipreg_register(struct sipreg **regp, struct sip *sip, const char *reg_uri,
|
||||
const char *to_uri, const char *from_uri, uint32_t expires,
|
||||
const char *cuser, const char *routev[], uint32_t routec,
|
||||
sip_auth_h *authh, void *aarg, bool aref,
|
||||
int regid, sip_auth_h *authh, void *aarg, bool aref,
|
||||
sip_resp_h *resph, void *arg,
|
||||
const char *params, const char *fmt, ...)
|
||||
{
|
||||
|
@ -295,6 +353,7 @@ int sipreg_register(struct sipreg **regp, struct sip *sip, const char *reg_uri,
|
|||
reg->expires = expires;
|
||||
reg->resph = resph ? resph : dummy_handler;
|
||||
reg->arg = arg;
|
||||
reg->regid = regid;
|
||||
|
||||
err = request(reg, true);
|
||||
if (err)
|
||||
|
|
Loading…
Add table
Reference in a new issue