added bfcp
This commit is contained in:
parent
0b50778c33
commit
385203d8b1
16 changed files with 2069 additions and 0 deletions
1
Makefile
1
Makefile
|
@ -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),)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
236
include/re_bfcp.h
Normal 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, ...);
|
|
@ -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
43
mk/symbian/rebfcp.mmp
Normal 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
|
|
@ -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
763
src/bfcp/attr.c
Normal 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
60
src/bfcp/bfcp.h
Normal 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
57
src/bfcp/hdr.c
Normal 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
13
src/bfcp/mod.mk
Normal 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
260
src/bfcp/msg.c
Normal 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
70
src/bfcp/rep.c
Normal 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
156
src/bfcp/req.c
Normal 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
343
src/bfcp/sock.c
Normal 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
38
src/bfcp/transp.c
Normal 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 "???";
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue