added bfcp

This commit is contained in:
Richard Aas 2011-09-06 11:51:13 +00:00
parent 0b50778c33
commit 385203d8b1
16 changed files with 2069 additions and 0 deletions

View file

@ -28,6 +28,7 @@ MODULES += udp sa net tcp tls
MODULES += list mbuf hash
MODULES += fmt tmr main mem dbg sys lock mqueue
MODULES += mod conf
MODULES += bfcp
INSTALL := install
ifeq ($(DESTDIR),)

View file

@ -88,6 +88,7 @@ Features:
* RFC 3994 - Indication of Message Composition for Instant Messaging
* RFC 4346 - The TLS Protocol Version 1.1
* RFC 4566 - SDP: Session Description Protocol
* RFC 4582 - The Binary Floor Control Protocol (BFCP)
* RFC 4585 - Extended RTP Profile for RTCP-Based Feedback
* RFC 4733 - RTP Payload for DTMF Digits, Telephony Tones, and Teleph. Signals
* RFC 4961 - Symmetric RTP / RTP Control Protocol (RTCP)

View file

@ -17,6 +17,7 @@ extern "C" {
/* Library modules */
#include "re_base64.h"
#include "re_bfcp.h"
#include "re_conf.h"
#include "re_crc32.h"
#include "re_dns.h"

236
include/re_bfcp.h Normal file
View file

@ -0,0 +1,236 @@
/**
* @file re_bfcp.h Interface to Binary Floor Control Protocol (BFCP)
*
* Copyright (C) 2010 Creytiv.com
*/
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 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,
/* 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 Request Status */
enum bfcp_rstat {
BFCP_PENDING = 1,
BFCP_ACCEPTED = 2,
BFCP_GRANTED = 3,
BFCP_DENIED = 4,
BFCP_CANCELLED = 5,
BFCP_RELEASED = 6,
BFCP_REVOKED = 7
};
/** 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
};
enum bfcp_prio {
BFCP_PRIO_LOWEST = 0,
BFCP_PRIO_LOW = 1,
BFCP_PRIO_NORMAL = 2,
BFCP_PRIO_HIGH = 3,
BFCP_PRIO_HIGHEST = 4
};
struct bfcp_reqstat {
enum bfcp_rstat stat;
uint8_t qpos;
};
struct bfcp_errcode {
enum bfcp_err code;
uint8_t *details; /* optional */
size_t len;
};
struct bfcp_supattr {
enum bfcp_attrib *attrv;
size_t attrc;
};
struct bfcp_supprim {
enum bfcp_prim *primv;
size_t primc;
};
struct bfcp_overall_reqstat {
uint16_t freqid;
struct bfcp_reqstat reqstat;
char *statinfo;
};
struct bfcp_beneficiary_info {
uint16_t bfid;
char *dname;
char *uri;
};
struct bfcp_reqby_info {
uint16_t rbid;
char *dname;
char *uri;
};
struct bfcp_floor_reqstat {
uint16_t floorid;
struct bfcp_reqstat reqstat;
char *statinfo;
};
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;
uint8_t prio;
char *ppi;
};
struct bfcp_attr {
struct le le;
enum bfcp_attrib type;
bool mand;
union bfcp_union {
/* generic types */
char *str;
uint16_t u16;
/* actual attributes */
uint16_t bfid;
uint16_t floorid;
uint16_t freqid;
uint8_t prio;
struct bfcp_reqstat reqstat;
struct bfcp_errcode errcode;
char *errinfo;
char *ppi;
char *statinfo;
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;
} v;
};
enum bfcp_transp {
BFCP_TRANSP_TCP = 0,
BFCP_TRANSP_TLS = 1
};
/* BFCP Message */
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);
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);
void bfcp_msg_set_src(struct bfcp_msg *msg, const struct sa *src);
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 stat);
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;
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,
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,
enum bfcp_prim prim, uint32_t attrc, ...);
int bfcp_ereply(struct bfcp_sock *sock, const struct bfcp_msg *req,
enum bfcp_err code, ...);

View file

@ -8,6 +8,7 @@ PRJ_EXPORTS
..\..\include\re.h \epoc32\include\re\re.h
..\..\include\re_base64.h \epoc32\include\re\re_base64.h
..\..\include\re_bfcp.h \epoc32\include\re\re_bfcp.h
..\..\include\re_bitv.h \epoc32\include\re\re_bitv.h
..\..\include\re_conf.h \epoc32\include\re\re_conf.h
..\..\include\re_crc32.h \epoc32\include\re\re_crc32.h
@ -51,6 +52,7 @@ PRJ_EXPORTS
PRJ_MMPFILES
re.mmp
rebfcp.mmp
redns.mmp
resdp.mmp
resip.mmp

43
mk/symbian/rebfcp.mmp Normal file
View file

@ -0,0 +1,43 @@
/**
* @file rebfcp.mmp Symbian makefile for libre BFCP
*
* Copyright (C) 2010 Creytiv.com
*/
TARGET rebfcp.lib
TARGETTYPE lib
TARGETPATH system\libs
UID 0x10000fd3 0x20011308
#ifdef EKA2
VENDORID 0
CAPABILITY NetworkServices
#endif
MACRO HAVE_SYS_TIME_H
MACRO HAVE_UNISTD_H
MACRO HAVE_ACTSCHED
#ifndef EKA2
SOURCEPATH .
SOURCE dll.cpp
#endif
SOURCEPATH ..\..\src\bfcp
SOURCE attr.c
SOURCE hdr.c
SOURCE msg.c
SOURCE rep.c
SOURCE req.c
SOURCE sock.c
SOURCE transp.c
USERINCLUDE . ..\..\include
SYSTEMINCLUDE \epoc32\include
SYSTEMINCLUDE \epoc32\include\libc
SYSTEMINCLUDE ..\..\include
#ifndef EKA2
LIBRARY estlib.lib euser.lib
LIBRARY esock.lib insock.lib
#endif
EXPORTUNFROZEN

View file

@ -108,6 +108,31 @@
RelativePath="..\..\src\base64\b64.c">
</File>
</Filter>
<Filter
Name="bfcp"
Filter="">
<File
RelativePath="..\..\src\bfcp\attr.c">
</File>
<File
RelativePath="..\..\src\bfcp\hdr.c">
</File>
<File
RelativePath="..\..\src\bfcp\msg.c">
</File>
<File
RelativePath="..\..\src\bfcp\rep.c">
</File>
<File
RelativePath="..\..\src\bfcp\req.c">
</File>
<File
RelativePath="..\..\src\bfcp\sock.c">
</File>
<File
RelativePath="..\..\src\bfcp\transp.c">
</File>
</Filter>
<Filter
Name="conf"
Filter="">

763
src/bfcp/attr.c Normal file
View file

@ -0,0 +1,763 @@
/**
* @file bfcp/attr.c BFCP Attributes
*
* Copyright (C) 2010 Creytiv.com
*/
#include <string.h>
#include <re_types.h>
#include <re_fmt.h>
#include <re_mem.h>
#include <re_mbuf.h>
#include <re_sa.h>
#include <re_list.h>
#include <re_bfcp.h>
#include "bfcp.h"
static int attr_decode(struct bfcp_attr *attr, union bfcp_union *v,
struct mbuf *mb);
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);
break;
case BFCP_FLOOR_REQUEST_INFO:
mem_deref(attr->v.fri.ors.statinfo);
for (i=0; i<attr->v.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);
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);
break;
default:
/* nothing allocated */
break;
}
}
int bfcp_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 unsigned int *num = v;
size_t start, len, i;
int err = 0;
if (!mb || !v)
return EINVAL;
start = mb->pos;
mb->pos += ATTR_HDR_SIZE;
switch (type) {
case BFCP_BENEFICIARY_ID:
case BFCP_FLOOR_ID:
case BFCP_FLOOR_REQUEST_ID:
err |= mbuf_write_u16(mb, htons(*num));
break;
case BFCP_PRIORITY:
err |= mbuf_write_u8(mb, *num << 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);
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);
break;
case BFCP_ERROR_INFO:
case BFCP_PARTICIPANT_PROV_INFO:
case BFCP_STATUS_INFO:
case BFCP_USER_DISPLAY_NAME:
case BFCP_USER_URI:
err |= mbuf_write_str(mb, v);
break;
case BFCP_SUPPORTED_ATTRIBUTES:
for (i=0; i<sa->attrc; i++)
err |= mbuf_write_u8(mb, sa->attrv[i] << 1);
break;
case BFCP_SUPPORTED_PRIMITIVES:
for (i=0; i<sp->primc; 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; i<fri->frsc; 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);
break;
default:
err = EINVAL;
break;
}
if (err)
return err;
len = mb->pos - start;
/* padding */
while ((mb->pos - start) & 0x03)
err |= mbuf_write_u8(mb, 0x00);
if (bfcp_attr_isgrouped(type))
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);
if (err)
break;
}
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)
{
size_t i, start, len;
uint8_t u8;
int err = 0;
if (!attr || !v || !mb)
return EINVAL;
if (mbuf_get_left(mb) < ATTR_HDR_SIZE)
return EBADMSG;
start = mb->pos;
u8 = mbuf_read_u8(mb);
attr->type = u8 >> 1;
attr->mand = u8 & 1;
len = mbuf_read_u8(mb) - ATTR_HDR_SIZE;
if (mbuf_get_left(mb) < len)
goto badmsg;
switch (attr->type) {
case BFCP_BENEFICIARY_ID:
case BFCP_FLOOR_ID:
case BFCP_FLOOR_REQUEST_ID:
if (len < 2)
goto badmsg;
v->u16 = ntohs(mbuf_read_u16(mb));
break;
case BFCP_PRIORITY:
if (len < 2)
goto badmsg;
v->prio = mbuf_read_u8(mb) >> 5;
(void)mbuf_read_u8(mb);
break;
case BFCP_REQUEST_STATUS:
if (len < 2)
goto badmsg;
v->reqstat.stat = mbuf_read_u8(mb);
v->reqstat.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);
if (v->errcode.len > 0) {
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_STATUS_INFO:
case BFCP_USER_DISPLAY_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),
NULL);
if (!v->supattr.attrv) {
err = ENOMEM;
goto error;
}
v->supattr.attrc = (uint32_t)len;
for (i=0; i<len; i++)
v->supattr.attrv[i] = mbuf_read_u8(mb) >> 1;
break;
case BFCP_SUPPORTED_PRIMITIVES:
v->supprim.primv = mem_alloc(len * sizeof(*v->supprim.primv),
NULL);
if (!v->supprim.primv) {
err = ENOMEM;
goto error;
}
v->supprim.primc = (uint32_t)len;
for (i=0; i<len; i++)
v->supprim.primv[i] = mbuf_read_u8(mb);
break;
/* 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_REQUESTED_BY_INFO:
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);
break;
default:
mb->pos += len;
(void)re_fprintf(stderr, "bfcp decode: unknown attribute %d\n",
attr->type);
break;
}
if (err)
goto error;
/* padding */
while (((mb->pos - start) & 0x03) && mbuf_get_left(mb))
++mb->pos;
return 0;
badmsg:
err = EBADMSG;
error:
return err;
}
int bfcp_attr_decode(struct bfcp_attr **attrp, struct mbuf *mb)
{
struct bfcp_attr *attr;
int err;
if (!attrp || !mb)
return EINVAL;
attr = mem_zalloc(sizeof(*attr), destructor);
if (!attr)
return ENOMEM;
err = attr_decode(attr, &attr->v, mb);
if (err)
mem_deref(attr);
else
*attrp = attr;
return err;
}
const char *bfcp_attr_name(enum bfcp_attrib attr)
{
switch (attr) {
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 "???";
}
}
static int leadh(struct re_printf *pf, void *arg)
{
int16_t level = *(int16_t *)arg;
int err = 0;
while (level--)
err |= re_hprintf(pf, " ");
return err;
}
static int attr_print(int16_t level, struct re_printf *pf,
uint8_t type, const void *p)
{
const union bfcp_union *v = p;
uint32_t i;
int err = 0;
if (!v)
return EINVAL;
++level;
err |= re_hprintf(pf, "%H%-28s", leadh, &level, bfcp_attr_name(type));
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) {
case BFCP_BENEFICIARY_ID:
case BFCP_FLOOR_ID:
case BFCP_FLOOR_REQUEST_ID:
case BFCP_PRIORITY:
err |= re_hprintf(pf, "%u", v->u16);
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);
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) {
for (i=0; i<v->errcode.len; i++) {
uint8_t t = v->errcode.details[i] >> 1;
err |= re_hprintf(pf, " %s",
bfcp_attr_name(t));
}
}
break;
case BFCP_ERROR_INFO:
case BFCP_PARTICIPANT_PROV_INFO:
case BFCP_STATUS_INFO:
case BFCP_USER_DISPLAY_NAME:
case BFCP_USER_URI:
err |= re_hprintf(pf, "\"%s\"", v->str);
break;
case BFCP_SUPPORTED_ATTRIBUTES:
err |= re_hprintf(pf, "%u:", v->supattr.attrc);
for (i=0; i<v->supattr.attrc; i++) {
const enum bfcp_attrib attr = v->supattr.attrv[i];
err |= re_hprintf(pf, " %s", bfcp_attr_name(attr));
}
break;
case BFCP_SUPPORTED_PRIMITIVES:
err |= re_hprintf(pf, "%u:", v->supprim.primc);
for (i=0; i<v->supprim.primc; i++) {
const enum bfcp_prim prim = v->supprim.primv[i];
err |= re_hprintf(pf, " %s", bfcp_prim_name(prim));
}
break;
/* 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);
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; i<v->fri.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);
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);
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);
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);
break;
default:
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)
{
if (!a)
return 0;
return attr_print(0, pf, a->type, &a->v);
}
bool bfcp_attr_isgrouped(enum bfcp_attrib attr)
{
switch (attr) {
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;
default:
return false;
}
}
const char *bfcp_errcode_name(enum bfcp_err code)
{
switch (code) {
case BFCP_ERR_CONF_NOT_EXIST:
return "Conference does not Exist";
case BFCP_ERR_USER_NOT_EXIST:
return "User does not Exist";
case BFCP_ERR_UNKNOWN_PRIM:
return "Unknown Primitive";
case BFCP_ERR_UNKNOWN_MAND_ATTR:
return "Unknown Mandatory Attribute";
case BFCP_ERR_UNAUTH_OPERATION:
return "Unauthorized Operation";
case BFCP_ERR_INVALID_FLOOR_ID:
return "Invalid Floor ID";
case BFCP_ERR_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:
return "Use TLS";
default:
return "???";
}
}

60
src/bfcp/bfcp.h Normal file
View file

@ -0,0 +1,60 @@
/**
* @file bfcp.h Internal interface to Binary Floor Control Protocol (BFCP)
*
* Copyright (C) 2010 Creytiv.com
*/
/* header */
enum {
BFCP_HDR_SIZE = 12,
ATTR_HDR_SIZE = 2
};
struct bfcp_hdr {
uint8_t ver;
unsigned i:1;
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;
void *arg;
};
int bfcp_send(struct bfcp_sock *sock, const struct sa *dst, struct mbuf *mb);
/* ctrans request */
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);

57
src/bfcp/hdr.c Normal file
View file

@ -0,0 +1,57 @@
/**
* @file hdr.c BFCP Message header
*
* Copyright (C) 2010 Creytiv.com
*/
#include <re_types.h>
#include <re_fmt.h>
#include <re_mem.h>
#include <re_mbuf.h>
#include <re_sa.h>
#include <re_list.h>
#include <re_bfcp.h>
#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;
}

13
src/bfcp/mod.mk Normal file
View file

@ -0,0 +1,13 @@
#
# mod.mk
#
# Copyright (C) 2010 Creytiv.com
#
SRCS += bfcp/attr.c
SRCS += bfcp/hdr.c
SRCS += bfcp/msg.c
SRCS += bfcp/rep.c
SRCS += bfcp/req.c
SRCS += bfcp/sock.c
SRCS += bfcp/transp.c

260
src/bfcp/msg.c Normal file
View file

@ -0,0 +1,260 @@
/**
* @file bfcp/msg.c BFCP Message
*
* Copyright (C) 2010 Creytiv.com
*/
#include <string.h>
#include <re_types.h>
#include <re_fmt.h>
#include <re_mem.h>
#include <re_mbuf.h>
#include <re_list.h>
#include <re_sa.h>
#include <re_bfcp.h>
#include "bfcp.h"
struct bfcp_msg {
struct sa src;
struct bfcp_hdr hdr;
struct list attrl;
};
static void destructor(void *arg)
{
struct bfcp_msg *msg = arg;
list_flush(&msg->attrl);
}
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)
{
size_t start;
uint32_t i;
uint16_t len;
int err = 0;
if (!mb)
return EINVAL;
start = mb->pos;
mb->pos += BFCP_HDR_SIZE;
for (i=0; i<attrc; i++) {
uint16_t type = va_arg(ap, int);
const void *v = va_arg(ap, const void *);
bool mand = false;
if (!v)
continue;
err = bfcp_attr_encode(mb, mand, type, v);
if (err)
return err;
}
/* header */
len = (mb->pos - start - BFCP_HDR_SIZE) / 4;
mb->pos = start;
err = bfcp_hdr_encode(mb, prim, len, confid, tid, userid);
mb->pos = mb->end;
return err;
}
int bfcp_msg_encode(struct mbuf *mb, enum bfcp_prim prim, uint32_t confid,
uint16_t tid, uint16_t userid, uint32_t attrc, ...)
{
va_list ap;
int err;
va_start(ap, attrc);
err = bfcp_msg_vencode(mb, prim, confid, tid, userid, attrc, ap);
va_end(ap);
return err;
}
int bfcp_msg_decode(struct bfcp_msg **msgp, struct mbuf *mb)
{
struct bfcp_msg *msg;
size_t start, extra;
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);
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);
}
out:
if (err)
mem_deref(msg);
else
*msgp = msg;
return err;
}
static bool attr_match(const struct bfcp_attr *attr, void *arg)
{
return attr->type == *(uint8_t *)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);
}
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;
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);
}
int bfcp_msg_print(struct re_printf *pf, const struct bfcp_msg *msg)
{
int err;
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);
bfcp_msg_attr_apply(msg, attr_print, pf);
return err;
}
enum bfcp_prim bfcp_msg_prim(const struct bfcp_msg *msg)
{
return msg ? msg->hdr.prim : 0;
}
uint32_t bfcp_msg_confid(const struct bfcp_msg *msg)
{
return msg ? msg->hdr.confid : 0;
}
uint16_t bfcp_msg_tid(const struct bfcp_msg *msg)
{
return msg ? msg->hdr.tid : 0;
}
uint16_t bfcp_msg_userid(const struct bfcp_msg *msg)
{
return msg ? msg->hdr.userid : 0;
}
const char *bfcp_reqstat_name(enum bfcp_rstat stat)
{
switch (stat) {
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 "???";
}
}
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 "???";
}
}
void bfcp_msg_set_src(struct bfcp_msg *msg, const struct sa *src)
{
if (!msg || !src)
return;
msg->src = *src;
}
const struct sa *bfcp_msg_src(const struct bfcp_msg *msg)
{
return msg ? &msg->src : NULL;
}

70
src/bfcp/rep.c Normal file
View file

@ -0,0 +1,70 @@
/**
* @file bfcp/rep.c BFCP Reply
*
* Copyright (C) 2010 Creytiv.com
*/
#include <string.h>
#include <re_types.h>
#include <re_fmt.h>
#include <re_mem.h>
#include <re_mbuf.h>
#include <re_list.h>
#include <re_sa.h>
#include <re_bfcp.h>
#include "bfcp.h"
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;
}
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);
}

156
src/bfcp/req.c Normal file
View file

@ -0,0 +1,156 @@
/**
* @file bfcp/req.c BFCP Client request
*
* Copyright (C) 2010 Creytiv.com
*/
#include <string.h>
#include <re_types.h>
#include <re_fmt.h>
#include <re_mem.h>
#include <re_mbuf.h>
#include <re_list.h>
#include <re_tmr.h>
#include <re_sa.h>
#include <re_bfcp.h>
#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;
}
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;
}

343
src/bfcp/sock.c Normal file
View file

@ -0,0 +1,343 @@
/**
* @file bfcp/sock.c BFCP Socket
*
* Copyright (C) 2010 Creytiv.com
*/
#include <string.h>
#include <re_types.h>
#include <re_fmt.h>
#include <re_mem.h>
#include <re_mbuf.h>
#include <re_list.h>
#include <re_tmr.h>
#include <re_sa.h>
#include <re_tcp.h>
#include <re_tls.h>
#include <re_bfcp.h>
#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);
if (err) {
if (err == ENODATA) {
conn->mbrx->pos = pos;
err = 0;
}
break;
}
bfcp_msg_set_src(msg, &conn->paddr);
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: %s\n", strerror(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))
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;
}
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);
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;
}

38
src/bfcp/transp.c Normal file
View file

@ -0,0 +1,38 @@
/**
* @file transp.c BFCP Transport
*
* Copyright (C) 2010 Creytiv.com
*/
#include <string.h>
#include <re_types.h>
#include <re_fmt.h>
#include <re_mem.h>
#include <re_mbuf.h>
#include <re_list.h>
#include <re_tmr.h>
#include <re_sa.h>
#include <re_tcp.h>
#include <re_bfcp.h>
#include "bfcp.h"
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;
}
}
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 "???";
}
}