1 /**
2 * @file bfcp/msg.c BFCP Message
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_HDR_SIZE = 12,
20 };
21
22
destructor(void * arg)23 static void destructor(void *arg)
24 {
25 struct bfcp_msg *msg = arg;
26
27 list_flush(&msg->attrl);
28 }
29
30
hdr_encode(struct mbuf * mb,uint8_t ver,bool r,enum bfcp_prim prim,uint16_t len,uint32_t confid,uint16_t tid,uint16_t userid)31 static int hdr_encode(struct mbuf *mb, uint8_t ver, bool r,
32 enum bfcp_prim prim, uint16_t len, uint32_t confid,
33 uint16_t tid, uint16_t userid)
34 {
35 int err;
36
37 err = mbuf_write_u8(mb, (ver << 5) | ((r ? 1 : 0) << 4));
38 err |= mbuf_write_u8(mb, prim);
39 err |= mbuf_write_u16(mb, htons(len));
40 err |= mbuf_write_u32(mb, htonl(confid));
41 err |= mbuf_write_u16(mb, htons(tid));
42 err |= mbuf_write_u16(mb, htons(userid));
43
44 return err;
45 }
46
47
hdr_decode(struct bfcp_msg * msg,struct mbuf * mb)48 static int hdr_decode(struct bfcp_msg *msg, struct mbuf *mb)
49 {
50 uint8_t b;
51
52 if (mbuf_get_left(mb) < BFCP_HDR_SIZE)
53 return ENODATA;
54
55 b = mbuf_read_u8(mb);
56
57 msg->ver = b >> 5;
58 msg->r = (b >> 4) & 1;
59 msg->f = (b >> 3) & 1;
60 msg->prim = mbuf_read_u8(mb);
61 msg->len = ntohs(mbuf_read_u16(mb));
62 msg->confid = ntohl(mbuf_read_u32(mb));
63 msg->tid = ntohs(mbuf_read_u16(mb));
64 msg->userid = ntohs(mbuf_read_u16(mb));
65
66 if (msg->ver != BFCP_VER1 && msg->ver != BFCP_VER2)
67 return EBADMSG;
68
69 /* fragmentation not supported */
70 if (msg->f)
71 return ENOSYS;
72
73 if (mbuf_get_left(mb) < (size_t)(4*msg->len))
74 return ENODATA;
75
76 return 0;
77 }
78
79
80 /**
81 * Encode a BFCP message with variable arguments
82 *
83 * @param mb Mbuf to encode into
84 * @param ver Protocol version
85 * @param r Transaction responder flag
86 * @param prim BFCP Primitive
87 * @param confid Conference ID
88 * @param tid Transaction ID
89 * @param userid User ID
90 * @param attrc Number of attributes
91 * @param ap Variable argument of attributes
92 *
93 * @return 0 if success, otherwise errorcode
94 */
bfcp_msg_vencode(struct mbuf * mb,uint8_t ver,bool r,enum bfcp_prim prim,uint32_t confid,uint16_t tid,uint16_t userid,unsigned attrc,va_list * ap)95 int bfcp_msg_vencode(struct mbuf *mb, uint8_t ver, bool r, enum bfcp_prim prim,
96 uint32_t confid, uint16_t tid, uint16_t userid,
97 unsigned attrc, va_list *ap)
98 {
99 size_t start, len;
100 int err;
101
102 if (!mb)
103 return EINVAL;
104
105 start = mb->pos;
106 mb->pos += BFCP_HDR_SIZE;
107
108 err = bfcp_attrs_vencode(mb, attrc, ap);
109 if (err)
110 return err;
111
112 /* header */
113 len = mb->pos - start - BFCP_HDR_SIZE;
114 mb->pos = start;
115 err = hdr_encode(mb, ver, r, prim, (uint16_t)(len/4), confid, tid,
116 userid);
117 mb->pos += len;
118
119 return err;
120 }
121
122
123 /**
124 * Encode a BFCP message
125 *
126 * @param mb Mbuf to encode into
127 * @param ver Protocol version
128 * @param r Transaction responder flag
129 * @param prim BFCP Primitive
130 * @param confid Conference ID
131 * @param tid Transaction ID
132 * @param userid User ID
133 * @param attrc Number of attributes
134 *
135 * @return 0 if success, otherwise errorcode
136 */
bfcp_msg_encode(struct mbuf * mb,uint8_t ver,bool r,enum bfcp_prim prim,uint32_t confid,uint16_t tid,uint16_t userid,unsigned attrc,...)137 int bfcp_msg_encode(struct mbuf *mb, uint8_t ver, bool r, enum bfcp_prim prim,
138 uint32_t confid, uint16_t tid, uint16_t userid,
139 unsigned attrc, ...)
140 {
141 va_list ap;
142 int err;
143
144 va_start(ap, attrc);
145 err = bfcp_msg_vencode(mb, ver, r, prim, confid, tid, userid,
146 attrc, &ap);
147 va_end(ap);
148
149 return err;
150 }
151
152
153 /**
154 * Decode a BFCP message from a buffer
155 *
156 * @param msgp Pointer to allocated and decoded BFCP message
157 * @param mb Mbuf to decode from
158 *
159 * @return 0 if success, otherwise errorcode
160 */
bfcp_msg_decode(struct bfcp_msg ** msgp,struct mbuf * mb)161 int bfcp_msg_decode(struct bfcp_msg **msgp, struct mbuf *mb)
162 {
163 struct bfcp_msg *msg;
164 size_t start;
165 int err;
166
167 if (!msgp || !mb)
168 return EINVAL;
169
170 msg = mem_zalloc(sizeof(*msg), destructor);
171 if (!msg)
172 return ENOMEM;
173
174 start = mb->pos;
175
176 err = hdr_decode(msg, mb);
177 if (err) {
178 mb->pos = start;
179 goto out;
180 }
181
182 err = bfcp_attrs_decode(&msg->attrl, mb, 4*msg->len, &msg->uma);
183 if (err)
184 goto out;
185
186 out:
187 if (err)
188 mem_deref(msg);
189 else
190 *msgp = msg;
191
192 return err;
193 }
194
195
196 /**
197 * Get a BFCP attribute from a BFCP message
198 *
199 * @param msg BFCP message
200 * @param type Attribute type
201 *
202 * @return Matching BFCP attribute if found, otherwise NULL
203 */
bfcp_msg_attr(const struct bfcp_msg * msg,enum bfcp_attrib type)204 struct bfcp_attr *bfcp_msg_attr(const struct bfcp_msg *msg,
205 enum bfcp_attrib type)
206 {
207 if (!msg)
208 return NULL;
209
210 return bfcp_attrs_find(&msg->attrl, type);
211 }
212
213
214 /**
215 * Apply a function handler to all attributes in a BFCP message
216 *
217 * @param msg BFCP message
218 * @param h Handler
219 * @param arg Handler argument
220 *
221 * @return BFCP attribute returned by handler, or NULL
222 */
bfcp_msg_attr_apply(const struct bfcp_msg * msg,bfcp_attr_h * h,void * arg)223 struct bfcp_attr *bfcp_msg_attr_apply(const struct bfcp_msg *msg,
224 bfcp_attr_h *h, void *arg)
225 {
226 if (!msg)
227 return NULL;
228
229 return bfcp_attrs_apply(&msg->attrl, h, arg);
230 }
231
232
233 /**
234 * Print a BFCP message
235 *
236 * @param pf Print function
237 * @param msg BFCP message
238 *
239 * @return 0 if success, otherwise errorcode
240 */
bfcp_msg_print(struct re_printf * pf,const struct bfcp_msg * msg)241 int bfcp_msg_print(struct re_printf *pf, const struct bfcp_msg *msg)
242 {
243 int err;
244
245 if (!msg)
246 return 0;
247
248 err = re_hprintf(pf, "%s (confid=%u tid=%u userid=%u)\n",
249 bfcp_prim_name(msg->prim), msg->confid,
250 msg->tid, msg->userid);
251
252 err |= bfcp_attrs_print(pf, &msg->attrl, 0);
253
254 return err;
255 }
256
257
258 /**
259 * Get the BFCP primitive name
260 *
261 * @param prim BFCP primitive
262 *
263 * @return String with BFCP primitive name
264 */
bfcp_prim_name(enum bfcp_prim prim)265 const char *bfcp_prim_name(enum bfcp_prim prim)
266 {
267 switch (prim) {
268
269 case BFCP_FLOOR_REQUEST: return "FloorRequest";
270 case BFCP_FLOOR_RELEASE: return "FloorRelease";
271 case BFCP_FLOOR_REQUEST_QUERY: return "FloorRequestQuery";
272 case BFCP_FLOOR_REQUEST_STATUS: return "FloorRequestStatus";
273 case BFCP_USER_QUERY: return "UserQuery";
274 case BFCP_USER_STATUS: return "UserStatus";
275 case BFCP_FLOOR_QUERY: return "FloorQuery";
276 case BFCP_FLOOR_STATUS: return "FloorStatus";
277 case BFCP_CHAIR_ACTION: return "ChairAction";
278 case BFCP_CHAIR_ACTION_ACK: return "ChairActionAck";
279 case BFCP_HELLO: return "Hello";
280 case BFCP_HELLO_ACK: return "HelloAck";
281 case BFCP_ERROR: return "Error";
282 case BFCP_FLOOR_REQ_STATUS_ACK: return "FloorRequestStatusAck";
283 case BFCP_FLOOR_STATUS_ACK: return "FloorStatusAck";
284 case BFCP_GOODBYE: return "Goodbye";
285 case BFCP_GOODBYE_ACK: return "GoodbyeAck";
286 default: return "???";
287 }
288 }
289