1 /**
2  * @file sip/keepalive.c  SIP Keepalive
3  *
4  * Copyright (C) 2010 Creytiv.com
5  */
6 
7 #include <string.h>
8 #include <re_types.h>
9 #include <re_fmt.h>
10 #include <re_mem.h>
11 #include <re_mbuf.h>
12 #include <re_sa.h>
13 #include <re_list.h>
14 #include <re_sys.h>
15 #include <re_uri.h>
16 #include <re_udp.h>
17 #include <re_msg.h>
18 #include <re_sip.h>
19 #include "sip.h"
20 
21 
destructor(void * arg)22 static void destructor(void *arg)
23 {
24 	struct sip_keepalive *ka = arg;
25 
26 	if (ka->kap)
27 		*ka->kap = NULL;
28 
29 	list_unlink(&ka->le);
30 }
31 
32 
sip_keepalive_signal(struct list * kal,int err)33 void sip_keepalive_signal(struct list *kal, int err)
34 {
35 	struct le *le = list_head(kal);
36 
37 	while (le) {
38 
39 		struct sip_keepalive *ka = le->data;
40 		sip_keepalive_h *kah = ka->kah;
41 		void *arg = ka->arg;
42 
43 		le = le->next;
44 
45 		list_unlink(&ka->le);
46 		mem_deref(ka);
47 
48 		kah(err, arg);
49 	}
50 }
51 
52 
sip_keepalive_wait(uint32_t interval)53 uint64_t sip_keepalive_wait(uint32_t interval)
54 {
55 	return interval * (800 + rand_u16() % 201);
56 }
57 
58 
59 /**
60  * Start a keepalive handler on a SIP transport
61  *
62  * @param kap      Pointer to allocated keepalive object
63  * @param sip      SIP Stack instance
64  * @param msg      SIP Message
65  * @param interval Keepalive interval in seconds
66  * @param kah      Keepalive handler
67  * @param arg      Handler argument
68  *
69  * @return 0 if success, otherwise errorcode
70  */
sip_keepalive_start(struct sip_keepalive ** kap,struct sip * sip,const struct sip_msg * msg,uint32_t interval,sip_keepalive_h * kah,void * arg)71 int sip_keepalive_start(struct sip_keepalive **kap, struct sip *sip,
72 			const struct sip_msg *msg, uint32_t interval,
73 			sip_keepalive_h *kah, void *arg)
74 {
75 	struct sip_keepalive *ka;
76 	int err;
77 
78 	if (!kap || !sip || !msg || !kah)
79 		return EINVAL;
80 
81 	ka = mem_zalloc(sizeof(*ka), destructor);
82 	if (!ka)
83 		return ENOMEM;
84 
85 	ka->kah = kah;
86 	ka->arg = arg;
87 
88 	switch (msg->tp) {
89 
90 	case SIP_TRANSP_UDP:
91 		err = sip_keepalive_udp(ka, sip, (struct udp_sock *)msg->sock,
92 					&msg->src, interval);
93 		break;
94 
95 	case SIP_TRANSP_TCP:
96 	case SIP_TRANSP_TLS:
97 		err = sip_keepalive_tcp(ka, (struct sip_conn *)msg->sock,
98 					interval);
99 		break;
100 
101 	default:
102 		err = EPROTONOSUPPORT;
103 		break;
104 	}
105 
106 	if (err) {
107 		mem_deref(ka);
108 	}
109 	else {
110 		ka->kap = kap;
111 		*kap = ka;
112 	}
113 
114 	return err;
115 }
116