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