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