1 /**
2  * @file bfcp/request.c BFCP Request
3  *
4  * Copyright (C) 2010 Creytiv.com
5  */
6 #include <string.h>
7 #include <re_types.h>
8 #include <re_fmt.h>
9 #include <re_mem.h>
10 #include <re_mbuf.h>
11 #include <re_list.h>
12 #include <re_sa.h>
13 #include <re_tmr.h>
14 #include <re_bfcp.h>
15 #include "bfcp.h"
16 
17 
18 enum {
19 	BFCP_T1  = 500,
20 	BFCP_TXC = 4,
21 };
22 
23 
24 struct bfcp_ctrans {
25 	struct le le;
26 	struct sa dst;
27 	struct mbuf *mb;
28 	bfcp_resp_h *resph;
29 	void *arg;
30 	uint32_t confid;
31 	uint16_t userid;
32 	uint16_t tid;
33 };
34 
35 
36 static void tmr_handler(void *arg);
37 
38 
dummy_resp_handler(int err,const struct bfcp_msg * msg,void * arg)39 static void dummy_resp_handler(int err, const struct bfcp_msg *msg, void *arg)
40 {
41 	(void)err;
42 	(void)msg;
43 	(void)arg;
44 }
45 
46 
destructor(void * arg)47 static void destructor(void *arg)
48 {
49 	struct bfcp_ctrans *ct = arg;
50 
51 	list_unlink(&ct->le);
52 	mem_deref(ct->mb);
53 }
54 
55 
dispatch(struct bfcp_conn * bc)56 static void dispatch(struct bfcp_conn *bc)
57 {
58 	struct le *le = bc->ctransl.head;
59 
60 	while (le) {
61 		struct bfcp_ctrans *ct = le->data;
62 		int err;
63 
64 		le = le->next;
65 
66 		err = bfcp_send(bc, &ct->dst, ct->mb);
67 		if (err) {
68 			ct->resph(err, NULL, ct->arg);
69 			mem_deref(ct);
70 			continue;
71 		}
72 
73 		tmr_start(&bc->tmr1, BFCP_T1, tmr_handler, bc);
74 		bc->txc = 1;
75 		break;
76 	}
77 }
78 
79 
tmr_handler(void * arg)80 static void tmr_handler(void *arg)
81 {
82 	struct bfcp_conn *bc = arg;
83 	struct bfcp_ctrans *ct;
84 	uint32_t timeout;
85 	int err;
86 
87 	ct = list_ledata(bc->ctransl.head);
88 	if (!ct)
89 		return;
90 
91 	timeout = BFCP_T1<<bc->txc;
92 
93 	if (++bc->txc > BFCP_TXC) {
94 		err = ETIMEDOUT;
95 		goto out;
96 	}
97 
98 	err = bfcp_send(bc, &ct->dst, ct->mb);
99 	if (err)
100 		goto out;
101 
102 	tmr_start(&bc->tmr1, timeout, tmr_handler, bc);
103 	return;
104 
105  out:
106 	ct->resph(err, NULL, ct->arg);
107 	mem_deref(ct);
108 	dispatch(bc);
109 }
110 
111 
bfcp_handle_response(struct bfcp_conn * bc,const struct bfcp_msg * msg)112 bool bfcp_handle_response(struct bfcp_conn *bc, const struct bfcp_msg *msg)
113 {
114 	struct bfcp_ctrans *ct;
115 
116 	if (!bc || !msg)
117 		return false;
118 
119 	ct = list_ledata(bc->ctransl.head);
120 	if (!ct)
121 		return false;
122 
123 	if (msg->tid != ct->tid)
124 		return false;
125 
126 	if (msg->confid != ct->confid)
127 		return false;
128 
129 	if (msg->userid != ct->userid)
130 		return false;
131 
132 	tmr_cancel(&bc->tmr1);
133 
134 	ct->resph(0, msg, ct->arg);
135 	mem_deref(ct);
136 
137 	dispatch(bc);
138 
139 	return true;
140 }
141 
142 
bfcp_vrequest(struct bfcp_conn * bc,const struct sa * dst,uint8_t ver,enum bfcp_prim prim,uint32_t confid,uint16_t userid,bfcp_resp_h * resph,void * arg,unsigned attrc,va_list * ap)143 int bfcp_vrequest(struct bfcp_conn *bc, const struct sa *dst, uint8_t ver,
144 		  enum bfcp_prim prim, uint32_t confid, uint16_t userid,
145 		  bfcp_resp_h *resph, void *arg, unsigned attrc, va_list *ap)
146 {
147 	struct bfcp_ctrans *ct;
148 	int err;
149 
150 	if (!bc || !dst)
151 		return EINVAL;
152 
153 	ct = mem_zalloc(sizeof(*ct), destructor);
154 	if (!ct)
155 		return ENOMEM;
156 
157 	if (bc->tid == 0)
158 		bc->tid = 1;
159 
160 	ct->dst    = *dst;
161 	ct->confid = confid;
162 	ct->userid = userid;
163 	ct->tid    = bc->tid++;
164 	ct->resph  = resph ? resph : dummy_resp_handler;
165 	ct->arg    = arg;
166 
167 	ct->mb = mbuf_alloc(128);
168 	if (!ct->mb) {
169 		err = ENOMEM;
170 		goto out;
171 	}
172 
173 	err = bfcp_msg_vencode(ct->mb, ver, false, prim, confid, ct->tid,
174 			       userid, attrc, ap);
175 	if (err)
176 		goto out;
177 
178 	ct->mb->pos = 0;
179 
180 	if (!bc->ctransl.head) {
181 
182 		err = bfcp_send(bc, &ct->dst, ct->mb);
183 		if (err)
184 			goto out;
185 
186 		tmr_start(&bc->tmr1, BFCP_T1, tmr_handler, bc);
187 		bc->txc = 1;
188 	}
189 
190 	list_append(&bc->ctransl, &ct->le, ct);
191 
192  out:
193 	if (err)
194 		mem_deref(ct);
195 
196 	return err;
197 }
198 
199 
200 /**
201  * Send a BFCP request
202  *
203  * @param bc      BFCP connection
204  * @param dst     Destination address
205  * @param ver     BFCP Version
206  * @param prim    BFCP Primitive
207  * @param confid  Conference ID
208  * @param userid  User ID
209  * @param resph   Response handler
210  * @param arg     Response handler argument
211  * @param attrc   Number of attributes
212  *
213  * @return 0 if success, otherwise errorcode
214  */
bfcp_request(struct bfcp_conn * bc,const struct sa * dst,uint8_t ver,enum bfcp_prim prim,uint32_t confid,uint16_t userid,bfcp_resp_h * resph,void * arg,unsigned attrc,...)215 int bfcp_request(struct bfcp_conn *bc, const struct sa *dst, uint8_t ver,
216 		 enum bfcp_prim prim, uint32_t confid, uint16_t userid,
217 		 bfcp_resp_h *resph, void *arg, unsigned attrc, ...)
218 {
219 	va_list ap;
220 	int err;
221 
222 	va_start(ap, attrc);
223 	err = bfcp_vrequest(bc, dst, ver, prim, confid, userid, resph, arg,
224 			    attrc, &ap);
225 	va_end(ap);
226 
227 	return err;
228 }
229 
230 
231 /**
232  * Send a BFCP notification/subsequent response
233  *
234  * @param bc      BFCP connection
235  * @param dst     Destination address
236  * @param ver     BFCP Version
237  * @param prim    BFCP Primitive
238  * @param confid  Conference ID
239  * @param userid  User ID
240  * @param attrc   Number of attributes
241  *
242  * @return 0 if success, otherwise errorcode
243  */
bfcp_notify(struct bfcp_conn * bc,const struct sa * dst,uint8_t ver,enum bfcp_prim prim,uint32_t confid,uint16_t userid,unsigned attrc,...)244 int bfcp_notify(struct bfcp_conn *bc, const struct sa *dst, uint8_t ver,
245 		enum bfcp_prim prim, uint32_t confid, uint16_t userid,
246 		unsigned attrc, ...)
247 {
248 	va_list ap;
249 	int err;
250 
251 	va_start(ap, attrc);
252 	err = bfcp_vrequest(bc, dst, ver, prim, confid, userid, NULL, NULL,
253 			    attrc, &ap);
254 	va_end(ap);
255 
256 	return err;
257 }
258