From 5f9f9eac4b32212fbe1d38b55be7c2a9b77d68c0 Mon Sep 17 00:00:00 2001 From: "Alfred E. Heggestad" Date: Fri, 22 Feb 2013 22:07:12 +0000 Subject: [PATCH] merge from re/branches/bfcp2 --- include/re_bfcp.h | 322 +++++++++-------- src/bfcp/attr.c | 880 ++++++++++++++++++++++----------------------- src/bfcp/bfcp.h | 68 ++-- src/bfcp/conn.c | 148 ++++++++ src/bfcp/hdr.c | 57 --- src/bfcp/mod.mk | 8 +- src/bfcp/msg.c | 293 ++++++--------- src/bfcp/rep.c | 89 ----- src/bfcp/reply.c | 124 +++++++ src/bfcp/req.c | 171 --------- src/bfcp/request.c | 255 +++++++++++++ src/bfcp/sock.c | 352 ------------------ src/bfcp/transp.c | 52 --- 13 files changed, 1256 insertions(+), 1563 deletions(-) create mode 100644 src/bfcp/conn.c delete mode 100644 src/bfcp/hdr.c delete mode 100644 src/bfcp/rep.c create mode 100644 src/bfcp/reply.c delete mode 100644 src/bfcp/req.c create mode 100644 src/bfcp/request.c delete mode 100644 src/bfcp/sock.c delete mode 100644 src/bfcp/transp.c diff --git a/include/re_bfcp.h b/include/re_bfcp.h index c6591f1..13086eb 100644 --- a/include/re_bfcp.h +++ b/include/re_bfcp.h @@ -5,51 +5,57 @@ */ -/** BFCP Version */ -enum {BFCP_VERSION = 1}; - /** BFCP Primitives */ enum bfcp_prim { - BFCP_FLOOR_REQUEST = 1, - BFCP_FLOOR_RELEASE = 2, - BFCP_FLOOR_REQUEST_QUERY = 3, - BFCP_FLOOR_REQUEST_STAT = 4, - BFCP_USER_QUERY = 5, - BFCP_USER_STATUS = 6, - BFCP_FLOOR_QUERY = 7, - BFCP_FLOOR_STATUS = 8, - BFCP_CHAIR_ACTION = 9, - BFCP_CHAIR_ACTION_ACK = 10, - BFCP_HELLO = 11, - BFCP_HELLO_ACK = 12, - BFCP_ERROR = 13, + BFCP_FLOOR_REQUEST = 1, + BFCP_FLOOR_RELEASE = 2, + BFCP_FLOOR_REQUEST_QUERY = 3, + BFCP_FLOOR_REQUEST_STATUS = 4, + BFCP_USER_QUERY = 5, + BFCP_USER_STATUS = 6, + BFCP_FLOOR_QUERY = 7, + BFCP_FLOOR_STATUS = 8, + BFCP_CHAIR_ACTION = 9, + BFCP_CHAIR_ACTION_ACK = 10, + BFCP_HELLO = 11, + BFCP_HELLO_ACK = 12, + BFCP_ERROR = 13, + BFCP_FLOOR_REQ_STATUS_ACK = 14, + BFCP_FLOOR_STATUS_ACK = 15, + BFCP_GOODBYE = 16, + BFCP_GOODBYE_ACK = 17, }; /** BFCP Attributes */ enum bfcp_attrib { - BFCP_BENEFICIARY_ID = 1, - BFCP_FLOOR_ID = 2, - BFCP_FLOOR_REQUEST_ID = 3, - BFCP_PRIORITY = 4, - BFCP_REQUEST_STATUS = 5, - BFCP_ERROR_CODE = 6, - BFCP_ERROR_INFO = 7, - BFCP_PARTICIPANT_PROV_INFO = 8, - BFCP_STATUS_INFO = 9, - BFCP_SUPPORTED_ATTRIBUTES = 10, - BFCP_SUPPORTED_PRIMITIVES = 11, - BFCP_USER_DISPLAY_NAME = 12, - BFCP_USER_URI = 13, + BFCP_BENEFICIARY_ID = 1, + BFCP_FLOOR_ID = 2, + BFCP_FLOOR_REQUEST_ID = 3, + BFCP_PRIORITY = 4, + BFCP_REQUEST_STATUS = 5, + BFCP_ERROR_CODE = 6, + BFCP_ERROR_INFO = 7, + BFCP_PART_PROV_INFO = 8, + BFCP_STATUS_INFO = 9, + BFCP_SUPPORTED_ATTRS = 10, + BFCP_SUPPORTED_PRIMS = 11, + BFCP_USER_DISP_NAME = 12, + BFCP_USER_URI = 13, /* grouped: */ - BFCP_BENEFICIARY_INFO = 14, - BFCP_FLOOR_REQUEST_INFO = 15, - BFCP_REQUESTED_BY_INFO = 16, - BFCP_FLOOR_REQUEST_STATUS = 17, - BFCP_OVERALL_REQUEST_STATUS = 18, + BFCP_BENEFICIARY_INFO = 14, + BFCP_FLOOR_REQ_INFO = 15, + BFCP_REQUESTED_BY_INFO = 16, + BFCP_FLOOR_REQ_STATUS = 17, + BFCP_OVERALL_REQ_STATUS = 18, + + /** Mandatory Attribute */ + BFCP_MANDATORY = 1<<7, + /** Encode Handler */ + BFCP_ENCODE_HANDLER = 1<<8, }; /** BFCP Request Status */ -enum bfcp_rstat { +enum bfcp_reqstat { BFCP_PENDING = 1, BFCP_ACCEPTED = 2, BFCP_GRANTED = 3, @@ -61,19 +67,24 @@ enum bfcp_rstat { /** BFCP Error Codes */ enum bfcp_err { - BFCP_ERR_CONF_NOT_EXIST = 1, - BFCP_ERR_USER_NOT_EXIST = 2, - BFCP_ERR_UNKNOWN_PRIM = 3, - BFCP_ERR_UNKNOWN_MAND_ATTR = 4, - BFCP_ERR_UNAUTH_OPERATION = 5, - BFCP_ERR_INVALID_FLOOR_ID = 6, - BFCP_ERR_FLOOR_REQ_ID_NOT_EXIST = 7, - BFCP_ERR_MAX_FLOOR_REQ_REACHED = 8, - BFCP_ERR_USE_TLS = 9 + BFCP_CONF_NOT_EXIST = 1, + BFCP_USER_NOT_EXIST = 2, + BFCP_UNKNOWN_PRIM = 3, + BFCP_UNKNOWN_MAND_ATTR = 4, + BFCP_UNAUTH_OPERATION = 5, + BFCP_INVALID_FLOOR_ID = 6, + BFCP_FLOOR_REQ_ID_NOT_EXIST = 7, + BFCP_MAX_FLOOR_REQ_REACHED = 8, + BFCP_USE_TLS = 9, + BFCP_PARSE_ERROR = 10, + BFCP_USE_DTLS = 11, + BFCP_UNSUPPORTED_VERSION = 12, + BFCP_BAD_LENGTH = 13, + BFCP_GENERIC_ERROR = 14, }; /** BFCP Priority */ -enum bfcp_prio { +enum bfcp_priority { BFCP_PRIO_LOWEST = 0, BFCP_PRIO_LOW = 1, BFCP_PRIO_NORMAL = 2, @@ -81,74 +92,40 @@ enum bfcp_prio { BFCP_PRIO_HIGHEST = 4 }; -/** BFCP Request status */ -struct bfcp_reqstat { - enum bfcp_rstat stat; +/** BFCP Transport */ +enum bfcp_transp { + BFCP_UDP, +}; + +/** BFCP Request Status */ +struct bfcp_reqstatus { + enum bfcp_reqstat status; uint8_t qpos; }; -/** BFCP Error code */ +/** BFCP Error Code */ struct bfcp_errcode { enum bfcp_err code; uint8_t *details; /* optional */ size_t len; }; -/** BFCP supported attributes */ +/** BFCP Supported Attributes */ struct bfcp_supattr { enum bfcp_attrib *attrv; size_t attrc; }; -/** BFCP supported primitives */ +/** BFCP Supported Primitives */ struct bfcp_supprim { enum bfcp_prim *primv; size_t primc; }; -/** BFCP overall request status */ -struct bfcp_overall_reqstat { - uint16_t freqid; - struct bfcp_reqstat reqstat; - char *statinfo; -}; - -/** BFCP beneficiary information */ -struct bfcp_beneficiary_info { - uint16_t bfid; - char *dname; - char *uri; -}; - -/** BFCP requested by information */ -struct bfcp_reqby_info { - uint16_t rbid; - char *dname; - char *uri; -}; - -/** BFCP floor request status */ -struct bfcp_floor_reqstat { - uint16_t floorid; - struct bfcp_reqstat reqstat; - char *statinfo; -}; - -/** BFCP floor request info */ -struct bfcp_floor_reqinfo { - uint16_t freqid; - struct bfcp_overall_reqstat ors; - struct bfcp_floor_reqstat *frsv; - size_t frsc; - struct bfcp_beneficiary_info bfi; - struct bfcp_reqby_info rbi; - enum bfcp_prio prio; - char *ppi; -}; - /** BFCP Attribute */ struct bfcp_attr { struct le le; + struct list attrl; enum bfcp_attrib type; bool mand; union bfcp_union { @@ -157,39 +134,63 @@ struct bfcp_attr { uint16_t u16; /* actual attributes */ - uint16_t bfid; + uint16_t beneficiaryid; uint16_t floorid; - uint16_t freqid; - enum bfcp_prio prio; - struct bfcp_reqstat reqstat; + uint16_t floorreqid; + enum bfcp_priority priority; + struct bfcp_reqstatus reqstatus; struct bfcp_errcode errcode; char *errinfo; - char *ppi; - char *statinfo; + char *partprovinfo; + char *statusinfo; struct bfcp_supattr supattr; struct bfcp_supprim supprim; char *userdname; char *useruri; - - /* grouped attributes */ - struct bfcp_beneficiary_info bfi; - struct bfcp_floor_reqinfo fri; - struct bfcp_reqby_info rbi; - struct bfcp_floor_reqstat frs; - struct bfcp_overall_reqstat ors; + uint16_t reqbyid; } v; }; -/** BFCP Transport */ -enum bfcp_transp { - BFCP_TRANSP_TCP = 0, - BFCP_TRANSP_TLS = 1 +/** BFCP unknown attributes */ +struct bfcp_unknown_attr { + uint8_t typev[16]; + size_t typec; }; +/** BFCP Message */ +struct bfcp_msg { + struct bfcp_unknown_attr uma; + struct sa src; + uint8_t ver; + unsigned r:1; + unsigned f:1; + enum bfcp_prim prim; + uint16_t len; + uint32_t confid; + uint16_t tid; + uint16_t userid; + struct list attrl; +}; -/* BFCP Message */ +struct bfcp_conn; + + +/** + * Defines the BFCP encode handler + * + * @param mb Mbuf to encode into + * @param arg Handler argument + * + * @return 0 if success, otherwise errorcode + */ +typedef int (bfcp_encode_h)(struct mbuf *mb, void *arg); + +/** BFCP Encode */ +struct bfcp_encode { + bfcp_encode_h *ench; + void *arg; +}; -struct bfcp_msg; /** * Defines the BFCP attribute handler @@ -201,52 +202,15 @@ struct bfcp_msg; */ typedef bool (bfcp_attr_h)(const struct bfcp_attr *attr, void *arg); -int bfcp_msg_vencode(struct mbuf *mb, enum bfcp_prim prim, - uint32_t confid, uint16_t tid, uint16_t userid, - uint32_t attrc, va_list ap); -int bfcp_msg_encode(struct mbuf *mb, enum bfcp_prim prim, uint32_t confid, - uint16_t tid, uint16_t userid, uint32_t attrc, ...); -int bfcp_msg_decode(struct bfcp_msg **msgp, struct mbuf *mb, - const struct sa *src); -struct bfcp_attr *bfcp_msg_attr(const struct bfcp_msg *msg, - enum bfcp_attrib type); -struct bfcp_attr *bfcp_msg_attr_apply(const struct bfcp_msg *msg, - bfcp_attr_h *h, void *arg); -int bfcp_msg_print(struct re_printf *pf, const struct bfcp_msg *msg); -enum bfcp_prim bfcp_msg_prim(const struct bfcp_msg *msg); -uint32_t bfcp_msg_confid(const struct bfcp_msg *msg); -uint16_t bfcp_msg_tid(const struct bfcp_msg *msg); -uint16_t bfcp_msg_userid(const struct bfcp_msg *msg); -const struct sa *bfcp_msg_src(const struct bfcp_msg *msg); - - -/* BFCP supplement */ - -const char *bfcp_prim_name(enum bfcp_prim prim); -const char *bfcp_attr_name(enum bfcp_attrib attr); -const char *bfcp_reqstat_name(enum bfcp_rstat rstat); -const char *bfcp_errcode_name(enum bfcp_err code); - - -/* BFCP Transport */ - -bool bfcp_transp_reliable(enum bfcp_transp tp); -const char *bfcp_transp_proto(enum bfcp_transp tp); - - -/* BFCP Socket */ - -struct tls; -struct bfcp_sock; -struct bfcp_ctrans; /** - * Defines the BFCP message handler + * Defines the BFCP receive handler * * @param msg BFCP message * @param arg Handler argument */ -typedef void (bfcp_msg_h)(const struct bfcp_msg *msg, void *arg); +typedef void (bfcp_recv_h)(const struct bfcp_msg *msg, void *arg); + /** * Defines the BFCP response handler @@ -258,14 +222,56 @@ typedef void (bfcp_msg_h)(const struct bfcp_msg *msg, void *arg); typedef void (bfcp_resp_h)(int err, const struct bfcp_msg *msg, void *arg); -int bfcp_listen(struct bfcp_sock **sockp, enum bfcp_transp transp, - struct tls *tls, const struct sa *laddr, - bfcp_msg_h *msgh, void *arg); -int bfcp_request(struct bfcp_ctrans **ctp, struct bfcp_sock *sock, - const struct sa *dst, +/* attr */ +int bfcp_attrs_vencode(struct mbuf *mb, unsigned attrc, va_list ap); +int bfcp_attrs_encode(struct mbuf *mb, unsigned attrc, ...); +struct bfcp_attr *bfcp_attr_subattr(const struct bfcp_attr *attr, + enum bfcp_attrib type); +struct bfcp_attr *bfcp_attr_subattr_apply(const struct bfcp_attr *attr, + bfcp_attr_h *h, void *arg); +int bfcp_attr_print(struct re_printf *pf, const struct bfcp_attr *attr); +const char *bfcp_attr_name(enum bfcp_attrib type); +const char *bfcp_reqstatus_name(enum bfcp_reqstat status); +const char *bfcp_errcode_name(enum bfcp_err code); + + +/* msg */ +int 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); +int 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, ...); +int bfcp_msg_decode(struct bfcp_msg **msgp, struct mbuf *mb); +struct bfcp_attr *bfcp_msg_attr(const struct bfcp_msg *msg, + enum bfcp_attrib type); +struct bfcp_attr *bfcp_msg_attr_apply(const struct bfcp_msg *msg, + bfcp_attr_h *h, void *arg); +int bfcp_msg_print(struct re_printf *pf, const struct bfcp_msg *msg); +const char *bfcp_prim_name(enum bfcp_prim prim); + + +/* conn */ +int bfcp_listen(struct bfcp_conn **bcp, enum bfcp_transp tp, struct sa *laddr, + bfcp_recv_h *recvh, void *arg); + + +/* request */ +int bfcp_request(struct bfcp_conn *bc, const struct sa *dst, enum bfcp_prim prim, uint32_t confid, uint16_t userid, bfcp_resp_h *resph, void *arg, uint32_t attrc, ...); -int bfcp_reply(struct bfcp_sock *sock, const struct bfcp_msg *req, + + +/* notify */ +int bfcp_notify(struct bfcp_conn *bc, const struct sa *dst, + enum bfcp_prim prim, uint32_t confid, uint16_t userid, + uint32_t attrc, ...); + + +/* reply */ +int bfcp_reply(struct bfcp_conn *bc, const struct bfcp_msg *req, enum bfcp_prim prim, uint32_t attrc, ...); -int bfcp_ereply(struct bfcp_sock *sock, const struct bfcp_msg *req, - enum bfcp_err code, ...); +int bfcp_edreply(struct bfcp_conn *bc, const struct bfcp_msg *req, + enum bfcp_err code, const uint8_t *details, size_t len); +int bfcp_ereply(struct bfcp_conn *bc, const struct bfcp_msg *req, + enum bfcp_err code); diff --git a/src/bfcp/attr.c b/src/bfcp/attr.c index bbf496e..4878403 100644 --- a/src/bfcp/attr.c +++ b/src/bfcp/attr.c @@ -10,229 +10,111 @@ #include #include #include +#include #include #include "bfcp.h" -static int attr_decode(struct bfcp_attr *attr, union bfcp_union *v, - struct mbuf *mb); +enum { + BFCP_ATTR_HDR_SIZE = 2, +}; static void destructor(void *arg) { struct bfcp_attr *attr = arg; - size_t i; switch (attr->type) { - case BFCP_ERROR_INFO: - case BFCP_PARTICIPANT_PROV_INFO: - case BFCP_STATUS_INFO: - case BFCP_USER_DISPLAY_NAME: - case BFCP_USER_URI: - mem_deref(attr->v.str); - break; - - case BFCP_SUPPORTED_ATTRIBUTES: - mem_deref(attr->v.supattr.attrv); - break; - - case BFCP_SUPPORTED_PRIMITIVES: - mem_deref(attr->v.supprim.primv); - break; - case BFCP_ERROR_CODE: mem_deref(attr->v.errcode.details); break; - /* grouped */ - - case BFCP_BENEFICIARY_INFO: - mem_deref(attr->v.bfi.dname); - mem_deref(attr->v.bfi.uri); + case BFCP_ERROR_INFO: + case BFCP_PART_PROV_INFO: + case BFCP_STATUS_INFO: + case BFCP_USER_DISP_NAME: + case BFCP_USER_URI: + mem_deref(attr->v.str); break; - case BFCP_FLOOR_REQUEST_INFO: - mem_deref(attr->v.fri.ors.statinfo); - for (i=0; iv.fri.frsc; i++) - mem_deref(attr->v.fri.frsv[i].statinfo); - mem_deref(attr->v.fri.frsv); - mem_deref(attr->v.fri.bfi.dname); - mem_deref(attr->v.fri.bfi.uri); - mem_deref(attr->v.fri.rbi.dname); - mem_deref(attr->v.fri.rbi.uri); - mem_deref(attr->v.fri.ppi); + case BFCP_SUPPORTED_ATTRS: + mem_deref(attr->v.supattr.attrv); break; - case BFCP_REQUESTED_BY_INFO: - mem_deref(attr->v.rbi.dname); - mem_deref(attr->v.rbi.uri); - break; - - case BFCP_FLOOR_REQUEST_STATUS: - mem_deref(attr->v.frs.statinfo); - break; - - case BFCP_OVERALL_REQUEST_STATUS: - mem_deref(attr->v.ors.statinfo); + case BFCP_SUPPORTED_PRIMS: + mem_deref(attr->v.supprim.primv); break; default: - /* nothing allocated */ break; } + + list_flush(&attr->attrl); } -int bfcp_attr_encode(struct mbuf *mb, bool mand, enum bfcp_attrib type, - const void *v) +static int attr_encode(struct mbuf *mb, bool mand, enum bfcp_attrib type, + const void *v) { - const struct bfcp_errcode *ec = v; - const struct bfcp_supattr *sa = v; - const struct bfcp_supprim *sp = v; - const struct bfcp_reqstat *rs = v; - const struct bfcp_beneficiary_info *bfi = v; - const struct bfcp_floor_reqinfo *fri = v; - const struct bfcp_reqby_info *rbi = v; - const struct bfcp_floor_reqstat *frs = v; - const struct bfcp_overall_reqstat *ors = v; + const struct bfcp_reqstatus *reqstatus = v; + const struct bfcp_errcode *errcode = v; + const struct bfcp_supattr *supattr = v; + const struct bfcp_supprim *supprim = v; + const enum bfcp_priority *priority = v; const uint16_t *u16 = v; - const enum bfcp_prio *prio = v; size_t start, len, i; - int err = 0; - - if (!mb || !v) - return EINVAL; + int err; start = mb->pos; - mb->pos += ATTR_HDR_SIZE; + mb->pos += BFCP_ATTR_HDR_SIZE; switch (type) { case BFCP_BENEFICIARY_ID: case BFCP_FLOOR_ID: case BFCP_FLOOR_REQUEST_ID: - err |= mbuf_write_u16(mb, htons(*u16)); + case BFCP_BENEFICIARY_INFO: + case BFCP_FLOOR_REQ_INFO: + case BFCP_REQUESTED_BY_INFO: + case BFCP_FLOOR_REQ_STATUS: + case BFCP_OVERALL_REQ_STATUS: + err = mbuf_write_u16(mb, htons(*u16)); break; case BFCP_PRIORITY: - err |= mbuf_write_u8(mb, *prio << 5); + err = mbuf_write_u8(mb, *priority << 5); err |= mbuf_write_u8(mb, 0x00); break; case BFCP_REQUEST_STATUS: - err |= mbuf_write_u8(mb, rs->stat); - err |= mbuf_write_u8(mb, rs->qpos); + err = mbuf_write_u8(mb, reqstatus->status); + err |= mbuf_write_u8(mb, reqstatus->qpos); break; case BFCP_ERROR_CODE: - err |= mbuf_write_u8(mb, ec->code); - if (ec->details && ec->len) - err |= mbuf_write_mem(mb, ec->details, ec->len); + err = mbuf_write_u8(mb, errcode->code); + if (errcode->details && errcode->len) + err |= mbuf_write_mem(mb, errcode->details, + errcode->len); break; case BFCP_ERROR_INFO: - case BFCP_PARTICIPANT_PROV_INFO: + case BFCP_PART_PROV_INFO: case BFCP_STATUS_INFO: - case BFCP_USER_DISPLAY_NAME: + case BFCP_USER_DISP_NAME: case BFCP_USER_URI: - err |= mbuf_write_str(mb, v); + err = mbuf_write_str(mb, v); break; - case BFCP_SUPPORTED_ATTRIBUTES: - for (i=0; iattrc; i++) - err |= mbuf_write_u8(mb, sa->attrv[i] << 1); + case BFCP_SUPPORTED_ATTRS: + for (i=0, err=0; iattrc; i++) + err |= mbuf_write_u8(mb, supattr->attrv[i] << 1); break; - case BFCP_SUPPORTED_PRIMITIVES: - for (i=0; iprimc; i++) - err |= mbuf_write_u8(mb, sp->primv[i]); - break; - - /* grouped attributes: */ - - case BFCP_BENEFICIARY_INFO: - err |= mbuf_write_u16(mb, htons(bfi->bfid)); - - if (bfi->dname) - err |= bfcp_attr_encode(mb, mand, - BFCP_USER_DISPLAY_NAME, - bfi->dname); - if (bfi->uri) - err |= bfcp_attr_encode(mb, mand, - BFCP_USER_URI, - bfi->uri); - break; - - case BFCP_FLOOR_REQUEST_INFO: - err |= mbuf_write_u16(mb, htons(fri->freqid)); - - if (fri->ors.freqid) - err |= bfcp_attr_encode(mb, mand, - BFCP_OVERALL_REQUEST_STATUS, - &fri->ors); - - for (i=0; ifrsc; i++) { - err |= bfcp_attr_encode(mb, mand, - BFCP_FLOOR_REQUEST_STATUS, - &fri->frsv[i]); - } - - if (fri->bfi.bfid) - err |= bfcp_attr_encode(mb, mand, - BFCP_BENEFICIARY_INFO, - &fri->bfi); - - if (fri->rbi.rbid) - err |= bfcp_attr_encode(mb, mand, - BFCP_REQUESTED_BY_INFO, - &fri->rbi); - - err |= bfcp_attr_encode(mb, mand, BFCP_PRIORITY, &fri->prio); - - if (fri->ppi) - err |= bfcp_attr_encode(mb, mand, - BFCP_PARTICIPANT_PROV_INFO, - fri->ppi); - break; - - case BFCP_REQUESTED_BY_INFO: - err |= mbuf_write_u16(mb, htons(rbi->rbid)); - - if (rbi->dname) - err |= bfcp_attr_encode(mb, mand, - BFCP_USER_DISPLAY_NAME, - rbi->dname); - if (rbi->uri) - err |= bfcp_attr_encode(mb, mand, - BFCP_USER_URI, - rbi->uri); - break; - - case BFCP_FLOOR_REQUEST_STATUS: - err |= mbuf_write_u16(mb, htons(frs->floorid)); - - if (frs->reqstat.stat) - err |= bfcp_attr_encode(mb, mand, - BFCP_REQUEST_STATUS, - &frs->reqstat); - if (frs->statinfo) - err |= bfcp_attr_encode(mb, mand, - BFCP_STATUS_INFO, - frs->statinfo); - break; - - case BFCP_OVERALL_REQUEST_STATUS: - err |= mbuf_write_u16(mb, htons(ors->freqid)); - - if (ors->reqstat.stat) - err |= bfcp_attr_encode(mb, mand, - BFCP_REQUEST_STATUS, - &ors->reqstat); - if (ors->statinfo) - err |= bfcp_attr_encode(mb, mand, - BFCP_STATUS_INFO, - ors->statinfo); + case BFCP_SUPPORTED_PRIMS: + for (i=0, err=0; iprimc; i++) + err |= mbuf_write_u8(mb, supprim->primv[i]); break; default: @@ -240,121 +122,144 @@ int bfcp_attr_encode(struct mbuf *mb, bool mand, enum bfcp_attrib type, break; } - if (err) - return err; - + /* header */ len = mb->pos - start; + mb->pos = start; + err |= mbuf_write_u8(mb, (type<<1) | (mand&1)); + err |= mbuf_write_u8(mb, len); + mb->pos += (len - BFCP_ATTR_HDR_SIZE); + /* padding */ while ((mb->pos - start) & 0x03) err |= mbuf_write_u8(mb, 0x00); - if (bfcp_attr_isgrouped(type)) + return err; +} + + +/** + * Encode BFCP Attributes with variable arguments + * + * @param mb Mbuf to encode into + * @param attrc Number of attributes + * @param ap Variable argument of attributes + * + * @return 0 if success, otherwise errorcode + */ +int bfcp_attrs_vencode(struct mbuf *mb, unsigned attrc, va_list ap) +{ + unsigned i; + + if (!mb) + return EINVAL; + + for (i=0; ipos; + + if (type == BFCP_ENCODE_HANDLER) { + + const struct bfcp_encode *enc = v; + + if (enc->ench) { + err = enc->ench(mb, enc->arg); + if (err) + return err; + } + + continue; + } + + err = attr_encode(mb, type>>7, type & 0x7f, v); + if (err) + return err; + + if (subc == 0) + continue; + + err = bfcp_attrs_vencode(mb, subc, ap); + if (err) + return err; + + /* update total length for grouped attributes */ len = mb->pos - start; - /* header */ - mb->pos = start; - err |= mbuf_write_u8(mb, (type<<1) | (mand&1)); - err |= mbuf_write_u8(mb, len); - mb->pos = mb->end; - - return err; -} - - -static int decv(struct mbuf *mb, uint8_t type, void **vp, - size_t elemsz, size_t *count) -{ - size_t n = 0; - void *v = NULL; - int err = 0; - - while (mbuf_get_left(mb) >= ATTR_HDR_SIZE) { - - struct bfcp_attr attr; - uint8_t *bp; - - if (type != (mbuf_buf(mb)[0] >> 1)) - break; - - ++n; - - if (v) { - void *v2 = mem_realloc(v, n * elemsz); - if (!v2) { - err = ENOMEM; - break; - } - - v = v2; - } - else { - v = mem_zalloc(1 * elemsz, NULL); - if (!v) { - err = ENOMEM; - break; - } - } - - bp = ((uint8_t *)v) + (n-1) * elemsz; - - err = attr_decode(&attr, (void *)bp, mb); + mb->pos = start + 1; + err = mbuf_write_u8(mb, (uint8_t)len); if (err) - break; + return err; + + mb->pos += (len - BFCP_ATTR_HDR_SIZE); } - if (err) - mem_deref(v); - else { - *vp = v; - *count = n; - } - - return err; -} - - -/* Decode a Nested attribute */ -static int decn(struct mbuf *mb, uint8_t type, void *p) -{ - struct bfcp_attr attr; - int err; - - /* sanity check of attribute type */ - if (mbuf_get_left(mb) < 1 || type != (mbuf_buf(mb)[0] >> 1)) - return 0; - - err = attr_decode(&attr, p, mb); - if (err) - return err; - return 0; } -static int attr_decode(struct bfcp_attr *attr, union bfcp_union *v, - struct mbuf *mb) +/** + * Encode BFCP Attributes + * + * @param mb Mbuf to encode into + * @param attrc Number of attributes + * + * @return 0 if success, otherwise errorcode + */ +int bfcp_attrs_encode(struct mbuf *mb, unsigned attrc, ...) { + va_list ap; + int err; + + va_start(ap, attrc); + err = bfcp_attrs_vencode(mb, attrc, ap); + va_end(ap); + + return err; +} + + +static int attr_decode(struct bfcp_attr **attrp, struct mbuf *mb, + struct bfcp_unknown_attr *uma) +{ + struct bfcp_attr *attr; + union bfcp_union *v; size_t i, start, len; - uint8_t u8; int err = 0; + uint8_t b; - if (!attr || !v || !mb) - return EINVAL; - - if (mbuf_get_left(mb) < ATTR_HDR_SIZE) + if (mbuf_get_left(mb) < BFCP_ATTR_HDR_SIZE) return EBADMSG; + attr = mem_zalloc(sizeof(*attr), destructor); + if (!attr) + return ENOMEM; + start = mb->pos; - u8 = mbuf_read_u8(mb); - attr->type = u8 >> 1; - attr->mand = u8 & 1; - len = mbuf_read_u8(mb) - ATTR_HDR_SIZE; + b = mbuf_read_u8(mb); + attr->type = b >> 1; + attr->mand = b & 1; + len = mbuf_read_u8(mb); + + if (len < BFCP_ATTR_HDR_SIZE) + goto badmsg; + + len -= BFCP_ATTR_HDR_SIZE; if (mbuf_get_left(mb) < len) goto badmsg; + v = &attr->v; + switch (attr->type) { case BFCP_BENEFICIARY_ID: @@ -363,14 +268,14 @@ static int attr_decode(struct bfcp_attr *attr, union bfcp_union *v, if (len < 2) goto badmsg; - v->u16 = ntohs(mbuf_read_u16(mb)); + v->u16 = ntohs(mbuf_read_u16(mb)); break; case BFCP_PRIORITY: if (len < 2) goto badmsg; - v->prio = mbuf_read_u8(mb) >> 5; + v->priority = mbuf_read_u8(mb) >> 5; (void)mbuf_read_u8(mb); break; @@ -378,52 +283,53 @@ static int attr_decode(struct bfcp_attr *attr, union bfcp_union *v, if (len < 2) goto badmsg; - v->reqstat.stat = mbuf_read_u8(mb); - v->reqstat.qpos = mbuf_read_u8(mb); + v->reqstatus.status = mbuf_read_u8(mb); + v->reqstatus.qpos = mbuf_read_u8(mb); break; case BFCP_ERROR_CODE: if (len < 1) goto badmsg; - v->errcode.len = len - 1; v->errcode.code = mbuf_read_u8(mb); + v->errcode.len = len - 1; - if (v->errcode.len > 0) { + if (v->errcode.len == 0) + break; - v->errcode.details = mem_alloc(v->errcode.len, NULL); - if (!v->errcode.details) { - err = ENOMEM; - goto error; - } - - (void)mbuf_read_mem(mb, v->errcode.details, - v->errcode.len); + v->errcode.details = mem_alloc(v->errcode.len, NULL); + if (!v->errcode.details) { + err = ENOMEM; + goto error; } + + (void)mbuf_read_mem(mb, v->errcode.details, + v->errcode.len); break; case BFCP_ERROR_INFO: - case BFCP_PARTICIPANT_PROV_INFO: + case BFCP_PART_PROV_INFO: case BFCP_STATUS_INFO: - case BFCP_USER_DISPLAY_NAME: + case BFCP_USER_DISP_NAME: case BFCP_USER_URI: err = mbuf_strdup(mb, &v->str, len); break; - case BFCP_SUPPORTED_ATTRIBUTES: - v->supattr.attrv = mem_alloc(len * sizeof(*v->supattr.attrv), + case BFCP_SUPPORTED_ATTRS: + v->supattr.attrc = len; + v->supattr.attrv = mem_alloc(len*sizeof(*v->supattr.attrv), NULL); if (!v->supattr.attrv) { err = ENOMEM; goto error; } - v->supattr.attrc = (uint32_t)len; for (i=0; isupattr.attrv[i] = mbuf_read_u8(mb) >> 1; break; - case BFCP_SUPPORTED_PRIMITIVES: + case BFCP_SUPPORTED_PRIMS: + v->supprim.primc = len; v->supprim.primv = mem_alloc(len * sizeof(*v->supprim.primv), NULL); if (!v->supprim.primv) { @@ -431,7 +337,6 @@ static int attr_decode(struct bfcp_attr *attr, union bfcp_union *v, goto error; } - v->supprim.primc = (uint32_t)len; for (i=0; isupprim.primv[i] = mbuf_read_u8(mb); break; @@ -439,60 +344,25 @@ static int attr_decode(struct bfcp_attr *attr, union bfcp_union *v, /* grouped attributes */ case BFCP_BENEFICIARY_INFO: - if (len < 2) - goto badmsg; - - v->bfi.bfid = ntohs(mbuf_read_u16(mb)); - err |= decn(mb, BFCP_USER_DISPLAY_NAME, &v->bfi.dname); - err |= decn(mb, BFCP_USER_URI, &v->bfi.uri); - break; - - case BFCP_FLOOR_REQUEST_INFO: - if (len < 2) - goto badmsg; - - v->fri.freqid = ntohs(mbuf_read_u16(mb)); - err |= decn(mb, BFCP_OVERALL_REQUEST_STATUS, &v->fri.ors); - err |= decv(mb, BFCP_FLOOR_REQUEST_STATUS, - (void *)&v->fri.frsv, sizeof(*v->fri.frsv), - &v->fri.frsc); - err |= decn(mb, BFCP_BENEFICIARY_INFO, &v->fri.bfi); - err |= decn(mb, BFCP_REQUESTED_BY_INFO, &v->fri.rbi); - err |= decn(mb, BFCP_PRIORITY, &v->fri.prio); - err |= decn(mb, BFCP_PARTICIPANT_PROV_INFO, &v->fri.ppi); - break; - + case BFCP_FLOOR_REQ_INFO: case BFCP_REQUESTED_BY_INFO: + case BFCP_FLOOR_REQ_STATUS: + case BFCP_OVERALL_REQ_STATUS: if (len < 2) goto badmsg; - v->rbi.rbid = ntohs(mbuf_read_u16(mb)); - err |= decn(mb, BFCP_USER_DISPLAY_NAME, &v->rbi.dname); - err |= decn(mb, BFCP_USER_URI, &v->rbi.uri); - break; - - case BFCP_FLOOR_REQUEST_STATUS: - if (len < 2) - goto badmsg; - - v->frs.floorid = ntohs(mbuf_read_u16(mb)); - err |= decn(mb, BFCP_REQUEST_STATUS, &v->frs.reqstat); - err |= decn(mb, BFCP_STATUS_INFO, &v->frs.statinfo); - break; - - case BFCP_OVERALL_REQUEST_STATUS: - if (len < 2) - goto badmsg; - - v->ors.freqid = ntohs(mbuf_read_u16(mb)); - err |= decn(mb, BFCP_REQUEST_STATUS, &v->ors.reqstat); - err |= decn(mb, BFCP_STATUS_INFO, &v->ors.statinfo); + v->u16 = ntohs(mbuf_read_u16(mb)); + err = bfcp_attrs_decode(&attr->attrl, mb, len - 2, uma); break; default: mb->pos += len; - (void)re_fprintf(stderr, "bfcp decode: unknown attribute %d\n", - attr->type); + + if (!attr->mand) + break; + + if (uma && uma->typec < ARRAY_SIZE(uma->typev)) + uma->typev[uma->typec++] = attr->type<<1; break; } @@ -503,105 +373,144 @@ static int attr_decode(struct bfcp_attr *attr, union bfcp_union *v, while (((mb->pos - start) & 0x03) && mbuf_get_left(mb)) ++mb->pos; + *attrp = attr; + return 0; badmsg: err = EBADMSG; error: + mem_deref(attr); + return err; } -int bfcp_attr_decode(struct bfcp_attr **attrp, struct mbuf *mb) +int bfcp_attrs_decode(struct list *attrl, struct mbuf *mb, size_t len, + struct bfcp_unknown_attr *uma) { - struct bfcp_attr *attr; - int err; + int err = 0; + size_t end; - if (!attrp || !mb) + if (!attrl || !mb || mbuf_get_left(mb) < len) return EINVAL; - attr = mem_zalloc(sizeof(*attr), destructor); - if (!attr) - return ENOMEM; + end = mb->end; + mb->end = mb->pos + len; - err = attr_decode(attr, &attr->v, mb); + while (mbuf_get_left(mb) >= BFCP_ATTR_HDR_SIZE) { - if (err) - mem_deref(attr); - else - *attrp = attr; + struct bfcp_attr *attr; + + err = attr_decode(&attr, mb, uma); + if (err) + break; + + list_append(attrl, &attr->le, attr); + } + + mb->end = end; return err; } +struct bfcp_attr *bfcp_attrs_find(const struct list *attrl, + enum bfcp_attrib type) +{ + struct le *le = list_head(attrl); + + while (le) { + struct bfcp_attr *attr = le->data; + + le = le->next; + + if (attr->type == type) + return attr; + } + + return NULL; +} + + +struct bfcp_attr *bfcp_attrs_apply(const struct list *attrl, + bfcp_attr_h *h, void *arg) +{ + struct le *le = list_head(attrl); + + while (le) { + struct bfcp_attr *attr = le->data; + + le = le->next; + + if (h && h(attr, arg)) + return attr; + } + + return NULL; +} + + /** - * Get the BFCP attribute name + * Get a BFCP sub-attribute from a BFCP attribute * * @param attr BFCP attribute + * @param type Attribute type * - * @return String with BFCP attribute name + * @return Matching BFCP attribute if found, otherwise NULL */ -const char *bfcp_attr_name(enum bfcp_attrib attr) +struct bfcp_attr *bfcp_attr_subattr(const struct bfcp_attr *attr, + enum bfcp_attrib type) { - switch (attr) { + if (!attr) + return NULL; - case BFCP_BENEFICIARY_ID: return "BENEFICIARY-ID"; - case BFCP_FLOOR_ID: return "FLOOR-ID"; - case BFCP_FLOOR_REQUEST_ID: return "FLOOR-REQUEST-ID"; - case BFCP_PRIORITY: return "PRIORITY"; - case BFCP_REQUEST_STATUS: return "REQUEST-STATUS"; - case BFCP_ERROR_CODE: return "ERROR-CODE"; - case BFCP_ERROR_INFO: return "ERROR-INFO"; - case BFCP_PARTICIPANT_PROV_INFO: return "PARTICIPANT-PROVIDED-INFO"; - case BFCP_STATUS_INFO: return "STATUS-INFO"; - case BFCP_SUPPORTED_ATTRIBUTES: return "SUPPORTED-ATTRIBUTES"; - case BFCP_SUPPORTED_PRIMITIVES: return "SUPPORTED-PRIMITIVES"; - case BFCP_USER_DISPLAY_NAME: return "USER-DISPLAY-NAME"; - case BFCP_USER_URI: return "USER-URI"; - case BFCP_BENEFICIARY_INFO: return "BENEFICIARY-INFORMATION"; - case BFCP_FLOOR_REQUEST_INFO: return "FLOOR-REQUEST-INFORMATION"; - case BFCP_REQUESTED_BY_INFO: return "REQUESTED-BY-INFORMATION"; - case BFCP_FLOOR_REQUEST_STATUS: return "FLOOR-REQUEST-STATUS"; - case BFCP_OVERALL_REQUEST_STATUS: return "OVERALL-REQUEST-STATUS"; - default: return "???"; - } + return bfcp_attrs_find(&attr->attrl, type); } -static int leadh(struct re_printf *pf, void *arg) +/** + * Apply a function handler to all sub-attributes in a BFCP attribute + * + * @param attr BFCP attribute + * @param h Handler + * @param arg Handler argument + * + * @return BFCP attribute returned by handler, or NULL + */ +struct bfcp_attr *bfcp_attr_subattr_apply(const struct bfcp_attr *attr, + bfcp_attr_h *h, void *arg) { - int16_t level = *(int16_t *)arg; - int err = 0; + if (!attr) + return NULL; - while (level--) - err |= re_hprintf(pf, " "); - - return err; + return bfcp_attrs_apply(&attr->attrl, h, arg); } -static int attr_print(int16_t level, struct re_printf *pf, - enum bfcp_attrib type, const void *p) +/** + * Print a BFCP attribute + * + * @param pf Print function + * @param attr BFCP attribute + * + * @return 0 if success, otherwise errorcode + */ +int bfcp_attr_print(struct re_printf *pf, const struct bfcp_attr *attr) { - const union bfcp_union *v = p; - uint32_t i; - int err = 0; + const union bfcp_union *v; + size_t i; + int err; - if (!v) - return EINVAL; + if (!attr) + return 0; - ++level; + err = re_hprintf(pf, "%c%-28s", attr->mand ? '*' : ' ', + bfcp_attr_name(attr->type)); - err |= re_hprintf(pf, "%H%-28s", leadh, &level, bfcp_attr_name(type)); + v = &attr->v; - if (bfcp_attr_isgrouped(type)) { - const uint16_t level2 = level + 1; - err |= re_hprintf(pf, "\n%H{\n%H", leadh, &level, - leadh, &level2); - } - - switch (type) { + switch (attr->type) { case BFCP_BENEFICIARY_ID: case BFCP_FLOOR_ID: @@ -610,48 +519,58 @@ static int attr_print(int16_t level, struct re_printf *pf, break; case BFCP_PRIORITY: - err |= re_hprintf(pf, "%d", v->prio); + err |= re_hprintf(pf, "%d", v->priority); break; case BFCP_REQUEST_STATUS: err |= re_hprintf(pf, "%s (%d), qpos=%u", - bfcp_reqstat_name(v->reqstat.stat), - v->reqstat.stat, - v->reqstat.qpos); + bfcp_reqstatus_name(v->reqstatus.status), + v->reqstatus.status, + v->reqstatus.qpos); break; case BFCP_ERROR_CODE: err |= re_hprintf(pf, "%u (%s)", v->errcode.code, bfcp_errcode_name(v->errcode.code)); - if (v->errcode.code == BFCP_ERR_UNKNOWN_MAND_ATTR) { + + if (v->errcode.code == BFCP_UNKNOWN_MAND_ATTR) { + for (i=0; ierrcode.len; i++) { - uint8_t t = v->errcode.details[i] >> 1; + + uint8_t type = v->errcode.details[i] >> 1; + err |= re_hprintf(pf, " %s", - bfcp_attr_name(t)); + bfcp_attr_name(type)); } } break; case BFCP_ERROR_INFO: - case BFCP_PARTICIPANT_PROV_INFO: + case BFCP_PART_PROV_INFO: case BFCP_STATUS_INFO: - case BFCP_USER_DISPLAY_NAME: + case BFCP_USER_DISP_NAME: case BFCP_USER_URI: err |= re_hprintf(pf, "\"%s\"", v->str); break; - case BFCP_SUPPORTED_ATTRIBUTES: + case BFCP_SUPPORTED_ATTRS: err |= re_hprintf(pf, "%u:", v->supattr.attrc); + for (i=0; isupattr.attrc; i++) { - const enum bfcp_attrib attr = v->supattr.attrv[i]; - err |= re_hprintf(pf, " %s", bfcp_attr_name(attr)); + + const enum bfcp_attrib type = v->supattr.attrv[i]; + + err |= re_hprintf(pf, " %s", bfcp_attr_name(type)); } break; - case BFCP_SUPPORTED_PRIMITIVES: + case BFCP_SUPPORTED_PRIMS: err |= re_hprintf(pf, "%u:", v->supprim.primc); + for (i=0; isupprim.primc; i++) { + const enum bfcp_prim prim = v->supprim.primv[i]; + err |= re_hprintf(pf, " %s", bfcp_prim_name(prim)); } break; @@ -659,88 +578,109 @@ static int attr_print(int16_t level, struct re_printf *pf, /* Grouped Attributes */ case BFCP_BENEFICIARY_INFO: - err |= re_hprintf(pf, "bfid=%u\n", v->bfi.bfid); - err |= attr_print(level, pf, BFCP_USER_DISPLAY_NAME, - &v->bfi.dname); - err |= attr_print(level, pf, BFCP_USER_URI, &v->bfi.uri); + err |= re_hprintf(pf, "beneficiary-id=%u", v->beneficiaryid); break; - case BFCP_FLOOR_REQUEST_INFO: - err |= re_hprintf(pf, "freqid=%u\n", v->fri.freqid); - err |= attr_print(level, pf, BFCP_OVERALL_REQUEST_STATUS, - &v->fri.ors); - for (i=0; ifri.frsc; i++) { - err |= attr_print(level, pf, BFCP_FLOOR_REQUEST_STATUS, - &v->fri.frsv[i]); - } - err |= attr_print(level, pf, BFCP_BENEFICIARY_INFO, - &v->fri.bfi); - err |= attr_print(level, pf, BFCP_REQUESTED_BY_INFO, - &v->fri.rbi); - err |= attr_print(level, pf, BFCP_PRIORITY, &v->fri.prio); - err |= attr_print(level, pf, BFCP_PARTICIPANT_PROV_INFO, - &v->fri.ppi); + case BFCP_FLOOR_REQ_INFO: + err |= re_hprintf(pf, "floor-request-id=%u", v->floorreqid); break; case BFCP_REQUESTED_BY_INFO: - err |= re_hprintf(pf, "rbid=%u\n", v->rbi.rbid); - err |= attr_print(level, pf, BFCP_USER_DISPLAY_NAME, - &v->rbi.dname); - err |= attr_print(level, pf, BFCP_USER_URI, &v->rbi.uri); + err |= re_hprintf(pf, "requested-by-id=%u", v->reqbyid); break; - case BFCP_FLOOR_REQUEST_STATUS: - err |= re_hprintf(pf, "floorid=%u\n", v->frs.floorid); - err |= attr_print(level, pf, BFCP_REQUEST_STATUS, - &v->frs.reqstat); - err |= attr_print(level, pf, BFCP_STATUS_INFO, - &v->frs.statinfo); + case BFCP_FLOOR_REQ_STATUS: + err |= re_hprintf(pf, "floor-id=%u", v->floorid); break; - case BFCP_OVERALL_REQUEST_STATUS: - err |= re_hprintf(pf, "freqid=%u\n", v->ors.freqid); - err |= attr_print(level, pf, BFCP_REQUEST_STATUS, - &v->ors.reqstat); - err |= attr_print(level, pf, BFCP_STATUS_INFO, - &v->ors.statinfo); + case BFCP_OVERALL_REQ_STATUS: + err |= re_hprintf(pf, "floor-request-id=%u", v->floorreqid); break; default: - err |= re_hprintf(pf, "?"); + err |= re_hprintf(pf, "???"); break; } - if (bfcp_attr_isgrouped(type)) - err |= re_hprintf(pf, "%H}", leadh, &level); - - err |= re_hprintf(pf, "\n"); - return err; } -int bfcp_attr_print(struct re_printf *pf, const struct bfcp_attr *a) +int bfcp_attrs_print(struct re_printf *pf, const struct list *attrl, + unsigned level) { - if (!a) - return 0; + struct le *le; + int err = 0; - return attr_print(0, pf, a->type, &a->v); + for (le=list_head(attrl); le; le=le->next) { + + const struct bfcp_attr *attr = le->data; + unsigned i; + + for (i=0; iattrl, level + 1); + } + + return err; } -bool bfcp_attr_isgrouped(enum bfcp_attrib attr) +/** + * Get the BFCP attribute name + * + * @param type BFCP attribute type + * + * @return String with BFCP attribute name + */ +const char *bfcp_attr_name(enum bfcp_attrib type) { - switch (attr) { + switch (type) { - case BFCP_BENEFICIARY_INFO: - case BFCP_FLOOR_REQUEST_INFO: - case BFCP_REQUESTED_BY_INFO: - case BFCP_FLOOR_REQUEST_STATUS: - case BFCP_OVERALL_REQUEST_STATUS: - return true; + case BFCP_BENEFICIARY_ID: return "BENEFICIARY-ID"; + case BFCP_FLOOR_ID: return "FLOOR-ID"; + case BFCP_FLOOR_REQUEST_ID: return "FLOOR-REQUEST-ID"; + case BFCP_PRIORITY: return "PRIORITY"; + case BFCP_REQUEST_STATUS: return "REQUEST-STATUS"; + case BFCP_ERROR_CODE: return "ERROR-CODE"; + case BFCP_ERROR_INFO: return "ERROR-INFO"; + case BFCP_PART_PROV_INFO: return "PARTICIPANT-PROVIDED-INFO"; + case BFCP_STATUS_INFO: return "STATUS-INFO"; + case BFCP_SUPPORTED_ATTRS: return "SUPPORTED-ATTRIBUTES"; + case BFCP_SUPPORTED_PRIMS: return "SUPPORTED-PRIMITIVES"; + case BFCP_USER_DISP_NAME: return "USER-DISPLAY-NAME"; + case BFCP_USER_URI: return "USER-URI"; + case BFCP_BENEFICIARY_INFO: return "BENEFICIARY-INFORMATION"; + case BFCP_FLOOR_REQ_INFO: return "FLOOR-REQUEST-INFORMATION"; + case BFCP_REQUESTED_BY_INFO: return "REQUESTED-BY-INFORMATION"; + case BFCP_FLOOR_REQ_STATUS: return "FLOOR-REQUEST-STATUS"; + case BFCP_OVERALL_REQ_STATUS: return "OVERALL-REQUEST-STATUS"; + default: return "???"; + } +} - default: - return false; + +/** + * Get the BFCP Request status name + * + * @param status Request status + * + * @return String with BFCP Request status name + */ +const char *bfcp_reqstatus_name(enum bfcp_reqstat status) +{ + switch (status) { + + case BFCP_PENDING: return "Pending"; + case BFCP_ACCEPTED: return "Accepted"; + case BFCP_GRANTED: return "Granted"; + case BFCP_DENIED: return "Denied"; + case BFCP_CANCELLED: return "Cancelled"; + case BFCP_RELEASED: return "Released"; + case BFCP_REVOKED: return "Revoked"; + default: return "???"; } } @@ -756,25 +696,49 @@ const char *bfcp_errcode_name(enum bfcp_err code) { switch (code) { - case BFCP_ERR_CONF_NOT_EXIST: + case BFCP_CONF_NOT_EXIST: return "Conference does not Exist"; - case BFCP_ERR_USER_NOT_EXIST: + + case BFCP_USER_NOT_EXIST: return "User does not Exist"; - case BFCP_ERR_UNKNOWN_PRIM: + + case BFCP_UNKNOWN_PRIM: return "Unknown Primitive"; - case BFCP_ERR_UNKNOWN_MAND_ATTR: + + case BFCP_UNKNOWN_MAND_ATTR: return "Unknown Mandatory Attribute"; - case BFCP_ERR_UNAUTH_OPERATION: + + case BFCP_UNAUTH_OPERATION: return "Unauthorized Operation"; - case BFCP_ERR_INVALID_FLOOR_ID: + + case BFCP_INVALID_FLOOR_ID: return "Invalid Floor ID"; - case BFCP_ERR_FLOOR_REQ_ID_NOT_EXIST: + + case BFCP_FLOOR_REQ_ID_NOT_EXIST: return "Floor Request ID Does Not Exist"; - case BFCP_ERR_MAX_FLOOR_REQ_REACHED: - return "You have Already Reached the Maximum Number" - " of Ongoing Floor Requests for this Floor"; - case BFCP_ERR_USE_TLS: + + case BFCP_MAX_FLOOR_REQ_REACHED: + return "You have Already Reached the Maximum Number " + "of Ongoing Floor Requests for this Floor"; + + case BFCP_USE_TLS: return "Use TLS"; + + case BFCP_PARSE_ERROR: + return "Unable to Parse Message"; + + case BFCP_USE_DTLS: + return "Use DTLS"; + + case BFCP_UNSUPPORTED_VERSION: + return "Unsupported Version"; + + case BFCP_BAD_LENGTH: + return "Incorrect Message Length"; + + case BFCP_GENERIC_ERROR: + return "Generic Error"; + default: return "???"; } diff --git a/src/bfcp/bfcp.h b/src/bfcp/bfcp.h index bc0cbed..34d3072 100644 --- a/src/bfcp/bfcp.h +++ b/src/bfcp/bfcp.h @@ -4,57 +4,51 @@ * Copyright (C) 2010 Creytiv.com */ - -/* header */ enum { - BFCP_HDR_SIZE = 12, - ATTR_HDR_SIZE = 2 + BFCP_VER1 = 1, + BFCP_VER2 = 2, }; -struct bfcp_hdr { - uint8_t ver; - unsigned i:1; +struct bfcp_strans { enum bfcp_prim prim; - uint16_t len; uint32_t confid; uint16_t tid; uint16_t userid; }; -int bfcp_hdr_encode(struct mbuf *mb, enum bfcp_prim prim, uint16_t len, - uint32_t confid, uint16_t tid, uint16_t userid); -int bfcp_hdr_decode(struct mbuf *mb, struct bfcp_hdr *hdr); - - -/* attributes */ -int bfcp_attr_encode(struct mbuf *mb, bool mand, enum bfcp_attrib type, - const void *v); -int bfcp_attr_decode(struct bfcp_attr **attrp, struct mbuf *mb); -int bfcp_attr_print(struct re_printf *pf, const struct bfcp_attr *a); -bool bfcp_attr_isgrouped(enum bfcp_attrib attr); - - -/* socket */ - -struct bfcp_sock { - struct list transl; - struct list connl; - struct tcp_sock *ts; - struct tls *tls; - enum bfcp_transp transp; - uint16_t tidc; - bool active; - bfcp_msg_h *msgh; +struct bfcp_conn { + struct bfcp_strans st; + struct list ctransl; + struct tmr tmr1; + struct tmr tmr2; + struct udp_sock *us; + struct mbuf *mb; + bfcp_recv_h *recvh; void *arg; + enum bfcp_transp tp; + unsigned txc; + uint16_t tid; }; -int bfcp_send(struct bfcp_sock *sock, const struct sa *dst, struct mbuf *mb); +/* attributes */ +int bfcp_attrs_decode(struct list *attrl, struct mbuf *mb, size_t len, + struct bfcp_unknown_attr *uma); +struct bfcp_attr *bfcp_attrs_find(const struct list *attrl, + enum bfcp_attrib type); +struct bfcp_attr *bfcp_attrs_apply(const struct list *attrl, + bfcp_attr_h *h, void *arg); +int bfcp_attrs_print(struct re_printf *pf, const struct list *attrl, + unsigned level); -/* ctrans request */ +/* connection */ +int bfcp_send(struct bfcp_conn *bc, const struct sa *dst, struct mbuf *mb); -void bfcp_ctrans_completed(struct bfcp_ctrans *ct, int err, - const struct bfcp_msg *msg); -struct bfcp_ctrans *bfcp_ctrans_find(struct bfcp_sock *sock, uint16_t tid); + +/* request */ +bool bfcp_handle_response(struct bfcp_conn *bc, const struct bfcp_msg *msg); +int bfcp_vrequest(struct bfcp_conn *bc, const struct sa *dst, + enum bfcp_prim prim, uint32_t confid, uint16_t userid, + bfcp_resp_h *resph, void *arg, uint32_t attrc, va_list ap); diff --git a/src/bfcp/conn.c b/src/bfcp/conn.c new file mode 100644 index 0000000..9875e2c --- /dev/null +++ b/src/bfcp/conn.c @@ -0,0 +1,148 @@ +/** + * @file bfcp/conn.c BFCP Connection + * + * Copyright (C) 2010 Creytiv.com + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "bfcp.h" + + +static void destructor(void *arg) +{ + struct bfcp_conn *bc = arg; + + list_flush(&bc->ctransl); + tmr_cancel(&bc->tmr1); + tmr_cancel(&bc->tmr2); + mem_deref(bc->us); + mem_deref(bc->mb); +} + + +static bool strans_cmp(const struct bfcp_strans *st, + const struct bfcp_msg *msg) +{ + if (st->tid != msg->tid) + return false; + + if (st->prim != msg->prim) + return false; + + if (st->confid != msg->confid) + return false; + + if (st->userid != msg->userid) + return false; + + return true; +} + + +static void udp_recv_handler(const struct sa *src, struct mbuf *mb, void *arg) +{ + struct bfcp_conn *bc = arg; + struct bfcp_msg *msg; + int err; + + err = bfcp_msg_decode(&msg, mb); + if (err) + return; + + msg->src = *src; + + if (bfcp_handle_response(bc, msg)) + goto out; + + if (bc->mb && strans_cmp(&bc->st, msg)) { + (void)bfcp_send(bc, &msg->src, bc->mb); + goto out; + } + + if (bc->recvh) + bc->recvh(msg, bc->arg); + +out: + mem_deref(msg); +} + + +/** + * Create BFCP connection + * + * @param bcp Pointer to BFCP connection + * @param tp BFCP Transport type + * @param laddr Optional listening address/port + * @param recvh Receive handler + * @param arg Receive handler argument + * + * @return 0 if success, otherwise errorcode + */ +int bfcp_listen(struct bfcp_conn **bcp, enum bfcp_transp tp, struct sa *laddr, + bfcp_recv_h *recvh, void *arg) +{ + struct bfcp_conn *bc; + int err; + + if (!bcp) + return EINVAL; + + bc = mem_zalloc(sizeof(*bc), destructor); + if (!bc) + return ENOMEM; + + bc->tp = tp; + bc->recvh = recvh; + bc->arg = arg; + + switch (bc->tp) { + + case BFCP_UDP: + err = udp_listen(&bc->us, laddr, udp_recv_handler, bc); + if (err) + goto out; + + if (laddr) { + err = udp_local_get(bc->us, laddr); + if (err) + goto out; + } + break; + + default: + err = ENOSYS; + goto out; + } + + out: + if (err) + mem_deref(bc); + else + *bcp = bc; + + return err; +} + + +int bfcp_send(struct bfcp_conn *bc, const struct sa *dst, struct mbuf *mb) +{ + if (!bc || !dst || !mb) + return EINVAL; + + switch (bc->tp) { + + case BFCP_UDP: + return udp_send(bc->us, dst, mb); + + default: + return ENOSYS; + } +} diff --git a/src/bfcp/hdr.c b/src/bfcp/hdr.c deleted file mode 100644 index 8ffb071..0000000 --- a/src/bfcp/hdr.c +++ /dev/null @@ -1,57 +0,0 @@ -/** - * @file bfcp/hdr.c BFCP Message header - * - * Copyright (C) 2010 Creytiv.com - */ -#include -#include -#include -#include -#include -#include -#include -#include "bfcp.h" - - -int bfcp_hdr_encode(struct mbuf *mb, enum bfcp_prim prim, uint16_t len, - uint32_t confid, uint16_t tid, uint16_t userid) -{ - int err; - - err = mbuf_write_u8(mb, BFCP_VERSION << 5); - err |= mbuf_write_u8(mb, prim); - err |= mbuf_write_u16(mb, htons(len)); - err |= mbuf_write_u32(mb, htonl(confid)); - err |= mbuf_write_u16(mb, htons(tid)); - err |= mbuf_write_u16(mb, htons(userid)); - - return err; -} - - -int bfcp_hdr_decode(struct mbuf *mb, struct bfcp_hdr *hdr) -{ - uint8_t b; - - if (mbuf_get_left(mb) < BFCP_HDR_SIZE) - return EBADMSG; - - b = mbuf_read_u8(mb); - hdr->ver = b >> 5; - hdr->i = (b >> 4) & 1; - hdr->prim = mbuf_read_u8(mb); - hdr->len = ntohs(mbuf_read_u16(mb)); - hdr->confid = ntohl(mbuf_read_u32(mb)); - hdr->tid = ntohs(mbuf_read_u16(mb)); - hdr->userid = ntohs(mbuf_read_u16(mb)); - - if (hdr->ver != BFCP_VERSION) - return EBADMSG; - - if (mbuf_get_left(mb) < (size_t)(hdr->len*4)) { - - return ENODATA; - } - - return 0; -} diff --git a/src/bfcp/mod.mk b/src/bfcp/mod.mk index f46e564..b533415 100644 --- a/src/bfcp/mod.mk +++ b/src/bfcp/mod.mk @@ -5,9 +5,7 @@ # SRCS += bfcp/attr.c -SRCS += bfcp/hdr.c +SRCS += bfcp/conn.c SRCS += bfcp/msg.c -SRCS += bfcp/rep.c -SRCS += bfcp/req.c -SRCS += bfcp/sock.c -SRCS += bfcp/transp.c +SRCS += bfcp/reply.c +SRCS += bfcp/request.c diff --git a/src/bfcp/msg.c b/src/bfcp/msg.c index 073f295..15500d2 100644 --- a/src/bfcp/msg.c +++ b/src/bfcp/msg.c @@ -10,14 +10,13 @@ #include #include #include +#include #include #include "bfcp.h" -struct bfcp_msg { - struct sa src; - struct bfcp_hdr hdr; - struct list attrl; +enum { + BFCP_HDR_SIZE = 12, }; @@ -29,10 +28,61 @@ static void destructor(void *arg) } +static int 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) +{ + int err; + + err = mbuf_write_u8(mb, (ver << 5) | ((r ? 1 : 0) << 4)); + err |= mbuf_write_u8(mb, prim); + err |= mbuf_write_u16(mb, htons(len)); + err |= mbuf_write_u32(mb, htonl(confid)); + err |= mbuf_write_u16(mb, htons(tid)); + err |= mbuf_write_u16(mb, htons(userid)); + + return err; +} + + +static int hdr_decode(struct bfcp_msg *msg, struct mbuf *mb) +{ + uint8_t b; + + if (mbuf_get_left(mb) < BFCP_HDR_SIZE) + return ENODATA; + + b = mbuf_read_u8(mb); + + msg->ver = b >> 5; + msg->r = (b >> 4) & 1; + msg->f = (b >> 3) & 1; + msg->prim = mbuf_read_u8(mb); + msg->len = ntohs(mbuf_read_u16(mb)); + msg->confid = ntohl(mbuf_read_u32(mb)); + msg->tid = ntohs(mbuf_read_u16(mb)); + msg->userid = ntohs(mbuf_read_u16(mb)); + + if (msg->ver != BFCP_VER1 && msg->ver != BFCP_VER2) + return EBADMSG; + + /* fragmentation not supported */ + if (msg->f) + return ENOSYS; + + if (mbuf_get_left(mb) < (size_t)(4*msg->len)) + return ENODATA; + + return 0; +} + + /** * Encode a BFCP message with variable arguments * * @param mb Mbuf to encode into + * @param ver Protocol version + * @param r Transaction responder flag * @param prim BFCP Primitive * @param confid Conference ID * @param tid Transaction ID @@ -42,14 +92,12 @@ static void destructor(void *arg) * * @return 0 if success, otherwise errorcode */ -int bfcp_msg_vencode(struct mbuf *mb, enum bfcp_prim prim, +int bfcp_msg_vencode(struct mbuf *mb, uint8_t ver, bool r, enum bfcp_prim prim, uint32_t confid, uint16_t tid, uint16_t userid, - uint32_t attrc, va_list ap) + unsigned attrc, va_list ap) { - size_t start; - uint32_t i; - uint16_t len; - int err = 0; + size_t start, len; + int err; if (!mb) return EINVAL; @@ -57,26 +105,16 @@ int bfcp_msg_vencode(struct mbuf *mb, enum bfcp_prim prim, start = mb->pos; mb->pos += BFCP_HDR_SIZE; - for (i=0; ipos - start - BFCP_HDR_SIZE) / 4; + len = mb->pos - start - BFCP_HDR_SIZE; mb->pos = start; - err = bfcp_hdr_encode(mb, prim, len, confid, tid, userid); - - mb->pos = mb->end; + err = hdr_encode(mb, ver, r, prim, (uint16_t)(len/4), confid, tid, + userid); + mb->pos += len; return err; } @@ -86,6 +124,8 @@ int bfcp_msg_vencode(struct mbuf *mb, enum bfcp_prim prim, * Encode a BFCP message * * @param mb Mbuf to encode into + * @param ver Protocol version + * @param r Transaction responder flag * @param prim BFCP Primitive * @param confid Conference ID * @param tid Transaction ID @@ -94,14 +134,16 @@ int bfcp_msg_vencode(struct mbuf *mb, enum bfcp_prim prim, * * @return 0 if success, otherwise errorcode */ -int bfcp_msg_encode(struct mbuf *mb, enum bfcp_prim prim, uint32_t confid, - uint16_t tid, uint16_t userid, uint32_t attrc, ...) +int 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, ...) { va_list ap; int err; va_start(ap, attrc); - err = bfcp_msg_vencode(mb, prim, confid, tid, userid, attrc, ap); + err = bfcp_msg_vencode(mb, ver, r, prim, confid, tid, userid, + attrc, ap); va_end(ap); return err; @@ -113,47 +155,33 @@ int bfcp_msg_encode(struct mbuf *mb, enum bfcp_prim prim, uint32_t confid, * * @param msgp Pointer to allocated and decoded BFCP message * @param mb Mbuf to decode from - * @param src Source network address (optional) * * @return 0 if success, otherwise errorcode */ -int bfcp_msg_decode(struct bfcp_msg **msgp, struct mbuf *mb, - const struct sa *src) +int bfcp_msg_decode(struct bfcp_msg **msgp, struct mbuf *mb) { struct bfcp_msg *msg; - size_t start, extra; + size_t start; int err; if (!msgp || !mb) return EINVAL; - start = mb->pos; - msg = mem_zalloc(sizeof(*msg), destructor); if (!msg) return ENOMEM; - err = bfcp_hdr_decode(mb, &msg->hdr); + start = mb->pos; + + err = hdr_decode(msg, mb); if (err) { mb->pos = start; goto out; } - extra = mbuf_get_left(mb) - 4*msg->hdr.len; - - while (mbuf_get_left(mb) - extra >= ATTR_HDR_SIZE) { - - struct bfcp_attr *attr; - - err = bfcp_attr_decode(&attr, mb); - if (err) - break; - - list_append(&msg->attrl, &attr->le, attr); - } - - if (src) - msg->src = *src; + err = bfcp_attrs_decode(&msg->attrl, mb, 4*msg->len, &msg->uma); + if (err) + goto out; out: if (err) @@ -165,12 +193,6 @@ int bfcp_msg_decode(struct bfcp_msg **msgp, struct mbuf *mb, } -static bool attr_match(const struct bfcp_attr *attr, void *arg) -{ - return attr->type == *(enum bfcp_attrib *)arg; -} - - /** * Get a BFCP attribute from a BFCP message * @@ -182,7 +204,10 @@ static bool attr_match(const struct bfcp_attr *attr, void *arg) struct bfcp_attr *bfcp_msg_attr(const struct bfcp_msg *msg, enum bfcp_attrib type) { - return bfcp_msg_attr_apply(msg, attr_match, &type); + if (!msg) + return NULL; + + return bfcp_attrs_find(&msg->attrl, type); } @@ -198,26 +223,10 @@ struct bfcp_attr *bfcp_msg_attr(const struct bfcp_msg *msg, struct bfcp_attr *bfcp_msg_attr_apply(const struct bfcp_msg *msg, bfcp_attr_h *h, void *arg) { - struct le *le = msg ? list_head(&msg->attrl) : NULL; + if (!msg) + return NULL; - while (le) { - struct bfcp_attr *attr = le->data; - - le = le->next; - - if (h && h(attr, arg)) - return attr; - } - - return NULL; -} - - -static bool attr_print(const struct bfcp_attr *attr, void *arg) -{ - struct re_printf *pf = arg; - - return 0 != bfcp_attr_print(pf, attr); + return bfcp_attrs_apply(&msg->attrl, h, arg); } @@ -236,91 +245,16 @@ int bfcp_msg_print(struct re_printf *pf, const struct bfcp_msg *msg) if (!msg) return 0; - err = re_hprintf(pf, "%s (len=%u confid=%u tid=%u userid=%u)\n", - bfcp_prim_name(msg->hdr.prim), msg->hdr.len, - msg->hdr.confid, msg->hdr.tid, msg->hdr.userid); + err = re_hprintf(pf, "%s (confid=%u tid=%u userid=%u)\n", + bfcp_prim_name(msg->prim), msg->confid, + msg->tid, msg->userid); - bfcp_msg_attr_apply(msg, attr_print, pf); + err |= bfcp_attrs_print(pf, &msg->attrl, 0); return err; } -/** - * Get the BFCP primitive of a BFCP message - * - * @param msg BFCP message - * - * @return The BFCP primitive - */ -enum bfcp_prim bfcp_msg_prim(const struct bfcp_msg *msg) -{ - return msg ? msg->hdr.prim : 0; -} - - -/** - * Get the Conference ID of a BFCP message - * - * @param msg BFCP message - * - * @return The Conference ID - */ -uint32_t bfcp_msg_confid(const struct bfcp_msg *msg) -{ - return msg ? msg->hdr.confid : 0; -} - - -/** - * Get the Transaction ID of a BFCP message - * - * @param msg BFCP message - * - * @return The Transaction ID - */ -uint16_t bfcp_msg_tid(const struct bfcp_msg *msg) -{ - return msg ? msg->hdr.tid : 0; -} - - -/** - * Get the User ID of a BFCP message - * - * @param msg BFCP message - * - * @return The User ID - */ -uint16_t bfcp_msg_userid(const struct bfcp_msg *msg) -{ - return msg ? msg->hdr.userid : 0; -} - - -/** - * Get the BFCP Request status name - * - * @param rstat Request status - * - * @return String with BFCP Request status name - */ -const char *bfcp_reqstat_name(enum bfcp_rstat rstat) -{ - switch (rstat) { - - case BFCP_PENDING: return "Pending"; - case BFCP_ACCEPTED: return "Accepted"; - case BFCP_GRANTED: return "Granted"; - case BFCP_DENIED: return "Denied"; - case BFCP_CANCELLED: return "Cancelled"; - case BFCP_RELEASED: return "Released"; - case BFCP_REVOKED: return "Revoked"; - default: return "???"; - } -} - - /** * Get the BFCP primitive name * @@ -332,32 +266,23 @@ const char *bfcp_prim_name(enum bfcp_prim prim) { switch (prim) { - case BFCP_FLOOR_REQUEST: return "FloorRequest"; - case BFCP_FLOOR_RELEASE: return "FloorRelease"; - case BFCP_FLOOR_REQUEST_QUERY: return "FloorRequestQuery"; - case BFCP_FLOOR_REQUEST_STAT: return "FloorRequestStatus"; - case BFCP_USER_QUERY: return "UserQuery"; - case BFCP_USER_STATUS: return "UserStatus"; - case BFCP_FLOOR_QUERY: return "FloorQuery"; - case BFCP_FLOOR_STATUS: return "FloorStatus"; - case BFCP_CHAIR_ACTION: return "ChairAction"; - case BFCP_CHAIR_ACTION_ACK: return "ChairActionAck"; - case BFCP_HELLO: return "Hello"; - case BFCP_HELLO_ACK: return "HelloAck"; - case BFCP_ERROR: return "Error"; - default: return "???"; + case BFCP_FLOOR_REQUEST: return "FloorRequest"; + case BFCP_FLOOR_RELEASE: return "FloorRelease"; + case BFCP_FLOOR_REQUEST_QUERY: return "FloorRequestQuery"; + case BFCP_FLOOR_REQUEST_STATUS: return "FloorRequestStatus"; + case BFCP_USER_QUERY: return "UserQuery"; + case BFCP_USER_STATUS: return "UserStatus"; + case BFCP_FLOOR_QUERY: return "FloorQuery"; + case BFCP_FLOOR_STATUS: return "FloorStatus"; + case BFCP_CHAIR_ACTION: return "ChairAction"; + case BFCP_CHAIR_ACTION_ACK: return "ChairActionAck"; + case BFCP_HELLO: return "Hello"; + case BFCP_HELLO_ACK: return "HelloAck"; + case BFCP_ERROR: return "Error"; + case BFCP_FLOOR_REQ_STATUS_ACK: return "FloorRequestStatusAck"; + case BFCP_FLOOR_STATUS_ACK: return "FloorStatusAck"; + case BFCP_GOODBYE: return "Goodbye"; + case BFCP_GOODBYE_ACK: return "GoodbyeAck"; + default: return "???"; } } - - -/** - * Get the source network address of a BFCP message - * - * @param msg BFCP message - * - * @return Source network address - */ -const struct sa *bfcp_msg_src(const struct bfcp_msg *msg) -{ - return msg ? &msg->src : NULL; -} diff --git a/src/bfcp/rep.c b/src/bfcp/rep.c deleted file mode 100644 index e36840a..0000000 --- a/src/bfcp/rep.c +++ /dev/null @@ -1,89 +0,0 @@ -/** - * @file bfcp/rep.c BFCP Reply - * - * Copyright (C) 2010 Creytiv.com - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include "bfcp.h" - - -/** - * Send BFCP reply - * - * @param sock BFCP socket - * @param req BFCP request to reply to - * @param prim BFCP primitive - * @param attrc Number of attributes - * - * @return 0 if success, otherwise errorcode - */ -int bfcp_reply(struct bfcp_sock *sock, const struct bfcp_msg *req, - enum bfcp_prim prim, uint32_t attrc, ...) -{ - struct mbuf *mb; - va_list ap; - int err; - - if (!sock || !req) - return EINVAL; - - mb = mbuf_alloc(64); - if (!mb) - return ENOMEM; - - va_start(ap, attrc); - err = bfcp_msg_vencode(mb, prim, bfcp_msg_confid(req), - bfcp_msg_tid(req), bfcp_msg_userid(req), - attrc, ap); - va_end(ap); - - if (err) - goto out; - - mb->pos = 0; - - err = bfcp_send(sock, bfcp_msg_src(req), mb); - - out: - mem_deref(mb); - - return err; -} - - -/** - * Send BFCP error reply - * - * @param sock BFCP socket - * @param req BFCP request to reply to - * @param code BFCP Error code - * - * @return 0 if success, otherwise errorcode - */ -int bfcp_ereply(struct bfcp_sock *sock, const struct bfcp_msg *req, - enum bfcp_err code, ...) -{ - struct bfcp_errcode ec; - va_list ap; - - va_start(ap, code); - - memset(&ec, 0, sizeof(ec)); - ec.code = code; - - if (code == BFCP_ERR_UNKNOWN_MAND_ATTR) { - ec.details = va_arg(ap, uint8_t *); - ec.len = va_arg(ap, size_t); - } - - va_end(ap); - - return bfcp_reply(sock, req, BFCP_ERROR, 1, BFCP_ERROR_CODE, &ec); -} diff --git a/src/bfcp/reply.c b/src/bfcp/reply.c new file mode 100644 index 0000000..35c1590 --- /dev/null +++ b/src/bfcp/reply.c @@ -0,0 +1,124 @@ +/** + * @file bfcp/reply.c BFCP Reply + * + * Copyright (C) 2010 Creytiv.com + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "bfcp.h" + + +enum { + BFCP_T2 = 10000, +}; + + +static void tmr_handler(void *arg) +{ + struct bfcp_conn *bc = arg; + + bc->mb = mem_deref(bc->mb); +} + + +/** + * Send a BFCP response + * + * @param bc BFCP connection + * @param req BFCP request message + * @param prim BFCP Primitive + * @param attrc Number of attributes + * + * @return 0 if success, otherwise errorcode + */ +int bfcp_reply(struct bfcp_conn *bc, const struct bfcp_msg *req, + enum bfcp_prim prim, uint32_t attrc, ...) +{ + va_list ap; + int err; + + if (!bc || !req) + return EINVAL; + + bc->mb = mem_deref(bc->mb); + tmr_cancel(&bc->tmr2); + + bc->mb = mbuf_alloc(64); + if (!bc->mb) + return ENOMEM; + + va_start(ap, attrc); + err = bfcp_msg_vencode(bc->mb, BFCP_VER2, true, prim, req->confid, + req->tid, req->userid, attrc, ap); + va_end(ap); + + if (err) + goto out; + + bc->mb->pos = 0; + + err = bfcp_send(bc, &req->src, bc->mb); + if (err) + goto out; + + bc->st.prim = req->prim; + bc->st.confid = req->confid; + bc->st.tid = req->tid; + bc->st.userid = req->userid; + + tmr_start(&bc->tmr2, BFCP_T2, tmr_handler, bc); + + out: + if (err) + bc->mb = mem_deref(bc->mb); + + return err; +} + + +/** + * Send a BFCP error response with details + * + * @param bc BFCP connection + * @param req BFCP request message + * @param code Error code + * @param details Error details + * @param len Details length + * + * @return 0 if success, otherwise errorcode + */ +int bfcp_edreply(struct bfcp_conn *bc, const struct bfcp_msg *req, + enum bfcp_err code, const uint8_t *details, size_t len) +{ + struct bfcp_errcode errcode; + + errcode.code = code; + errcode.details = (uint8_t *)details; + errcode.len = len; + + return bfcp_reply(bc, req, BFCP_ERROR, 1, + BFCP_ERROR_CODE, 0, &errcode); +} + + +/** + * Send a BFCP error response + * + * @param bc BFCP connection + * @param req BFCP request message + * @param code Error code + * + * @return 0 if success, otherwise errorcode + */ +int bfcp_ereply(struct bfcp_conn *bc, const struct bfcp_msg *req, + enum bfcp_err code) +{ + return bfcp_edreply(bc, req, code, NULL, 0); +} diff --git a/src/bfcp/req.c b/src/bfcp/req.c deleted file mode 100644 index 36a9a31..0000000 --- a/src/bfcp/req.c +++ /dev/null @@ -1,171 +0,0 @@ -/** - * @file bfcp/req.c BFCP Client request - * - * Copyright (C) 2010 Creytiv.com - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "bfcp.h" - - -struct bfcp_ctrans { - struct le le; - struct tmr tmr; - struct bfcp_ctrans **ctp; - uint16_t tid; - bfcp_resp_h *resph; - void *arg; -}; - - -static void destructor(void *arg) -{ - struct bfcp_ctrans *ct = arg; - - list_unlink(&ct->le); - tmr_cancel(&ct->tmr); -} - - -static void timeout(void *arg) -{ - struct bfcp_ctrans *ct = arg; - - bfcp_ctrans_completed(ct, ETIMEDOUT, NULL); -} - - -static struct bfcp_ctrans *ctrans_new(struct bfcp_sock *sock, - bfcp_resp_h *resph, void *arg) -{ - struct bfcp_ctrans *ct; - - ct = mem_zalloc(sizeof(*ct), destructor); - if (!ct) - return NULL; - - list_append(&sock->transl, &ct->le, ct); - - sock->tidc++; - - if (sock->tidc == 0) - sock->tidc++; - - ct->tid = sock->tidc; - ct->resph = resph; - ct->arg = arg; - - tmr_start(&ct->tmr, 10000, timeout, ct); - - return ct; -} - - -void bfcp_ctrans_completed(struct bfcp_ctrans *ct, int err, - const struct bfcp_msg *msg) -{ - bfcp_resp_h *resph = ct->resph; - void *arg = ct->arg; - - list_unlink(&ct->le); - tmr_cancel(&ct->tmr); - - if (ct->ctp) { - *ct->ctp = NULL; - ct->ctp = NULL; - } - - ct->resph = NULL; - - mem_deref(ct); - - if (resph) - resph(err, msg, arg); -} - - -struct bfcp_ctrans *bfcp_ctrans_find(struct bfcp_sock *sock, uint16_t tid) -{ - struct le *le; - - for (le = sock->transl.head; le; le = le->next) { - - struct bfcp_ctrans *ct = le->data; - - if (ct->tid == tid) - return ct; - } - - return NULL; -} - - -/** - * Send a BFCP request with variable number of attributes - * - * @param ctp Pointer to allocated transaction (optional) - * @param sock BFCP socket - * @param dst Destination network address - * @param prim BFCP primitive - * @param confid Conference ID - * @param userid User ID - * @param resph Response handler (optional) - * @param arg Handler argument - * @param attrc Number of BFCP attributes - * - * @return 0 if success, otherwise errorcode - */ -int bfcp_request(struct bfcp_ctrans **ctp, struct bfcp_sock *sock, - const struct sa *dst, - enum bfcp_prim prim, uint32_t confid, uint16_t userid, - bfcp_resp_h *resph, void *arg, uint32_t attrc, ...) -{ - struct bfcp_ctrans *ct; - struct mbuf *mb; - va_list ap; - int err; - - if (!sock || !dst || !confid || !userid) - return EINVAL; - - ct = ctrans_new(sock, resph, arg); - if (!ct) - return ENOMEM; - - mb = mbuf_alloc(512); - if (!mb) { - err = ENOMEM; - goto out; - } - - va_start(ap, attrc); - err = bfcp_msg_vencode(mb, prim, confid, ct->tid, userid, - attrc, ap); - va_end(ap); - if (err) - goto out; - - mb->pos = 0; - - err = bfcp_send(sock, dst, mb); - if (err) - goto out; - - out: - if (err) - mem_deref(ct); - else if (ctp) { - ct->ctp = ctp; - *ctp = ct; - } - - mem_deref(mb); - return err; -} diff --git a/src/bfcp/request.c b/src/bfcp/request.c new file mode 100644 index 0000000..b37bd1c --- /dev/null +++ b/src/bfcp/request.c @@ -0,0 +1,255 @@ +/** + * @file bfcp/request.c BFCP Request + * + * Copyright (C) 2010 Creytiv.com + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "bfcp.h" + + +enum { + BFCP_T1 = 500, + BFCP_TXC = 4, +}; + + +struct bfcp_ctrans { + struct le le; + struct sa dst; + struct mbuf *mb; + bfcp_resp_h *resph; + void *arg; + uint32_t confid; + uint16_t userid; + uint16_t tid; +}; + + +static void tmr_handler(void *arg); + + +static void dummy_resp_handler(int err, const struct bfcp_msg *msg, void *arg) +{ + (void)err; + (void)msg; + (void)arg; +} + + +static void destructor(void *arg) +{ + struct bfcp_ctrans *ct = arg; + + list_unlink(&ct->le); + mem_deref(ct->mb); +} + + +static void dispatch(struct bfcp_conn *bc) +{ + struct le *le = bc->ctransl.head; + + while (le) { + struct bfcp_ctrans *ct = le->data; + int err; + + le = le->next; + + err = bfcp_send(bc, &ct->dst, ct->mb); + if (err) { + ct->resph(err, NULL, ct->arg); + mem_deref(ct); + continue; + } + + tmr_start(&bc->tmr1, BFCP_T1, tmr_handler, bc); + bc->txc = 1; + break; + } +} + + +static void tmr_handler(void *arg) +{ + struct bfcp_conn *bc = arg; + struct bfcp_ctrans *ct; + uint32_t timeout; + int err; + + ct = list_ledata(bc->ctransl.head); + if (!ct) + return; + + timeout = BFCP_T1<txc; + + if (++bc->txc > BFCP_TXC) { + err = ETIMEDOUT; + goto out; + } + + err = bfcp_send(bc, &ct->dst, ct->mb); + if (err) + goto out; + + tmr_start(&bc->tmr1, timeout, tmr_handler, bc); + return; + + out: + ct->resph(err, NULL, ct->arg); + mem_deref(ct); + dispatch(bc); +} + + +bool bfcp_handle_response(struct bfcp_conn *bc, const struct bfcp_msg *msg) +{ + struct bfcp_ctrans *ct; + + if (!bc || !msg) + return false; + + ct = list_ledata(bc->ctransl.head); + if (!ct) + return false; + + if (msg->tid != ct->tid) + return false; + + if (msg->confid != ct->confid) + return false; + + if (msg->userid != ct->userid) + return false; + + tmr_cancel(&bc->tmr1); + + ct->resph(0, msg, ct->arg); + mem_deref(ct); + + dispatch(bc); + + return true; +} + + +int bfcp_vrequest(struct bfcp_conn *bc, const struct sa *dst, + enum bfcp_prim prim, uint32_t confid, uint16_t userid, + bfcp_resp_h *resph, void *arg, uint32_t attrc, va_list ap) +{ + struct bfcp_ctrans *ct; + int err; + + if (!bc || !dst) + return EINVAL; + + ct = mem_zalloc(sizeof(*ct), destructor); + if (!ct) + return ENOMEM; + + if (bc->tid == 0) + bc->tid = 1; + + ct->dst = *dst; + ct->confid = confid; + ct->userid = userid; + ct->tid = bc->tid++; + ct->resph = resph ? resph : dummy_resp_handler; + ct->arg = arg; + + ct->mb = mbuf_alloc(128); + if (!ct->mb) { + err = ENOMEM; + goto out; + } + + err = bfcp_msg_vencode(ct->mb, BFCP_VER2, false, prim, confid, ct->tid, + userid, attrc, ap); + if (err) + goto out; + + ct->mb->pos = 0; + + if (!bc->ctransl.head) { + + err = bfcp_send(bc, &ct->dst, ct->mb); + if (err) + goto out; + + tmr_start(&bc->tmr1, BFCP_T1, tmr_handler, bc); + bc->txc = 1; + } + + list_append(&bc->ctransl, &ct->le, ct); + + out: + if (err) + mem_deref(ct); + + return err; +} + + +/** + * Send a BFCP request + * + * @param bc BFCP connection + * @param dst Destination address + * @param prim BFCP Primitive + * @param confid Conference ID + * @param userid User ID + * @param resph Response handler + * @param arg Response handler argument + * @param attrc Number of attributes + * + * @return 0 if success, otherwise errorcode + */ +int bfcp_request(struct bfcp_conn *bc, const struct sa *dst, + enum bfcp_prim prim, uint32_t confid, uint16_t userid, + bfcp_resp_h *resph, void *arg, uint32_t attrc, ...) +{ + va_list ap; + int err; + + va_start(ap, attrc); + err = bfcp_vrequest(bc, dst, prim, confid, userid, resph, arg, + attrc, ap); + va_end(ap); + + return err; +} + + +/** + * Send a BFCP notification/subsequent response + * + * @param bc BFCP connection + * @param dst Destination address + * @param prim BFCP Primitive + * @param confid Conference ID + * @param userid User ID + * @param attrc Number of attributes + * + * @return 0 if success, otherwise errorcode + */ +int bfcp_notify(struct bfcp_conn *bc, const struct sa *dst, + enum bfcp_prim prim, uint32_t confid, uint16_t userid, + uint32_t attrc, ...) +{ + va_list ap; + int err; + + va_start(ap, attrc); + err = bfcp_vrequest(bc, dst, prim, confid, userid, NULL, NULL, + attrc, ap); + va_end(ap); + + return err; +} diff --git a/src/bfcp/sock.c b/src/bfcp/sock.c deleted file mode 100644 index 5ca29ad..0000000 --- a/src/bfcp/sock.c +++ /dev/null @@ -1,352 +0,0 @@ -/** - * @file bfcp/sock.c BFCP Socket - * - * Copyright (C) 2010 Creytiv.com - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "bfcp.h" - - -struct bfcp_conn { - struct le le; - struct sa paddr; - struct mbuf *mbtx; - struct mbuf *mbrx; - struct tcp_conn *tc; - struct tls_conn *sc; - struct bfcp_sock *bs; - bool established; -}; - - -static void destructor(void *arg) -{ - struct bfcp_sock *sock = arg; - - list_flush(&sock->transl); - list_flush(&sock->connl); - mem_deref(sock->tls); - mem_deref(sock->ts); -} - - -static void conn_destructor(void *arg) -{ - struct bfcp_conn *conn = arg; - - list_unlink(&conn->le); - mem_deref(conn->mbtx); - mem_deref(conn->mbrx); - mem_deref(conn->sc); - mem_deref(conn->tc); -} - - -static struct bfcp_conn *conn_add(struct bfcp_sock *bs, - const struct sa *paddr) -{ - struct bfcp_conn *bc = mem_zalloc(sizeof(*bc), conn_destructor); - if (!bc) - return NULL; - - list_append(&bs->connl, &bc->le, bc); - - bc->bs = bs; - bc->paddr = *paddr; - - return bc; -} - - -static void tcp_estab_handler(void *arg) -{ - struct bfcp_conn *conn = arg; - -#ifdef USE_TLS - if (conn->sc) { - char cn[256]; - int err; - - err = tls_verify_cert(conn->sc, cn, sizeof(cn)); - - (void)re_printf("CN: '%s' (%sverified)\n", - cn, err ? "not " : ""); - } -#endif - - conn->established = true; - - /* flush transmit buffer */ - if (conn->mbtx) { - - conn->mbtx->pos = 0; - if (tcp_send(conn->tc, conn->mbtx)) - return; - - conn->mbtx = mem_deref(conn->mbtx); - } -} - - -static void tcp_recv_handler(struct mbuf *mb, void *arg) -{ - struct bfcp_conn *conn = arg; - size_t pos; - int err = 0; - - if (conn->mbrx) { - pos = conn->mbrx->pos; - - conn->mbrx->pos = conn->mbrx->end; - - err = mbuf_write_mem(conn->mbrx, - mbuf_buf(mb), mbuf_get_left(mb)); - if (err) - goto out; - - conn->mbrx->pos = pos; - } - else { - conn->mbrx = mem_ref(mb); - } - - for (;;) { - struct bfcp_msg *msg; - struct bfcp_ctrans *ct; - - pos = conn->mbrx->pos; - - err = bfcp_msg_decode(&msg, conn->mbrx, &conn->paddr); - if (err) { - if (err == ENODATA) { - conn->mbrx->pos = pos; - err = 0; - } - break; - } - - ct = bfcp_ctrans_find(conn->bs, bfcp_msg_tid(msg)); - if (ct) { - bfcp_ctrans_completed(ct, 0, msg); - } - else { - if (conn->bs->msgh) - conn->bs->msgh(msg, conn->bs->arg); - } - - mem_deref(msg); - - if (0 == mbuf_get_left(conn->mbrx)) { - conn->mbrx = mem_deref(conn->mbrx); - break; - } - } - - out: - if (err) - mem_deref(conn); -} - - -static void tcp_close_handler(int err, void *arg) -{ - struct bfcp_conn *conn = arg; - - (void)re_printf("BFCP connection closed: %m\n", err); - - mem_deref(conn); -} - - -static void tcp_conn_handler(const struct sa *addr, void *arg) -{ - struct bfcp_sock *bs = arg; - struct bfcp_conn *conn; - - (void)re_printf("bfcpd: Connection from %J via %s\n", addr, - bs->transp == BFCP_TRANSP_TLS ? "TLS" : "TCP"); - - conn = conn_add(bs, addr); - if (conn) { - if (tcp_accept(&conn->tc, bs->ts, tcp_estab_handler, - tcp_recv_handler, tcp_close_handler, conn)) - goto error; - -#ifdef USE_TLS - if (bs->transp == BFCP_TRANSP_TLS) { - if (tls_start_tcp(&conn->sc, bs->tls, conn->tc, 0)) - goto error; - } -#endif - - return; - } - - error: - tcp_reject(bs->ts); - mem_deref(conn); -} - - -static struct bfcp_conn *findconn(const struct bfcp_sock *bs, - const struct sa *peer) -{ - struct le *le; - - for (le = bs->connl.head; le; le = le->next) { - - struct bfcp_conn *bc = le->data; - - if (sa_cmp(&bc->paddr, peer, SA_ALL)) - return bc; - } - - return NULL; -} - - -/** - * Listen on a BFCP socket - * - * @param sockp Pointer to allocated BFCP socket object - * @param transp BFCP transport - * @param tls TLS context, used for secure transport (optional) - * @param laddr Local network address (optional) - * @param msgh BFCP message handler (optional) - * @param arg Handler argument - * - * @return 0 if success, otherwise errorcode - */ -int bfcp_listen(struct bfcp_sock **sockp, enum bfcp_transp transp, - struct tls *tls, const struct sa *laddr, - bfcp_msg_h *msgh, void *arg) -{ - struct bfcp_sock *sock; - int err = 0; - - if (!sockp) - return EINVAL; - - sock = mem_zalloc(sizeof(*sock), destructor); - if (!sock) - return ENOMEM; - - sock->transp = transp; - sock->tls = mem_ref(tls); - sock->msgh = msgh; - sock->arg = arg; - - /* Server */ - if (laddr) { - switch (transp) { - - case BFCP_TRANSP_TLS: - if (!tls) { - err = EINVAL; - goto out; - } - /*@fallthrough@*/ - - case BFCP_TRANSP_TCP: - sock->active = false; - err = tcp_listen(&sock->ts, laddr, tcp_conn_handler, - sock); - break; - - default: - err = EPROTONOSUPPORT; - break; - } - } - else { - sock->active = true; - } - - out: - if (err) - mem_deref(sock); - else if (sockp) - *sockp = sock; - - return err; -} - - -int bfcp_send(struct bfcp_sock *sock, const struct sa *dst, struct mbuf *mb) -{ - struct bfcp_conn *conn = NULL; - int err = 0; - - if (!sock || !dst || !mb) - return EINVAL; - - switch (sock->transp) { - - case BFCP_TRANSP_TCP: - case BFCP_TRANSP_TLS: - - conn = findconn(sock, dst); - - if (!conn) { - - if (!sock->active) - return ENOTCONN; - - conn = conn_add(sock, dst); - if (!conn) { - err = ENOMEM; - goto out; - } - - err = tcp_connect(&conn->tc, dst, tcp_estab_handler, - tcp_recv_handler, - tcp_close_handler, conn); - if (err) - goto out; - -#ifdef USE_TLS - if (sock->transp == BFCP_TRANSP_TLS) { - - err = tls_start_tcp(&conn->sc, sock->tls, - conn->tc, 0); - if (err) - goto out; - } -#endif - } - - if (conn->established) { - err = tcp_send(conn->tc, mb); - } - else { - if (!conn->mbtx) { - conn->mbtx = mem_ref(mb); - } - else { - conn->mbtx->pos = conn->mbtx->end; - err = mbuf_write_mem(conn->mbtx, mbuf_buf(mb), - mbuf_get_left(mb)); - } - } - break; - - default: - err = EPROTONOSUPPORT; - break; - } - - out: - if (err) - mem_deref(conn); - - return err; -} diff --git a/src/bfcp/transp.c b/src/bfcp/transp.c deleted file mode 100644 index d4e555f..0000000 --- a/src/bfcp/transp.c +++ /dev/null @@ -1,52 +0,0 @@ -/** - * @file bfcp/transp.c BFCP Transport - * - * Copyright (C) 2010 Creytiv.com - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "bfcp.h" - - -/** - * Check if BFCP transport is reliable - * - * @param tp BFCP transport - * - * @return True if reliable, false if un-reliable - */ -bool bfcp_transp_reliable(enum bfcp_transp tp) -{ - switch (tp) { - - case BFCP_TRANSP_TCP: return true; - case BFCP_TRANSP_TLS: return true; - default: return false; - } -} - - -/** - * Get the BFCP Transport protocol, suitable for SDP - * - * @param tp BFCP transport - * - * @return String with BFCP transport protocol - */ -const char *bfcp_transp_proto(enum bfcp_transp tp) -{ - switch (tp) { - - case BFCP_TRANSP_TCP: return "TCP/BFCP"; - case BFCP_TRANSP_TLS: return "TCP/TLS/BFCP"; - default: return "???"; - } -}