blob: cfe066eae4ee726444aea389db2aabef157ef7b0 [file] [log] [blame]
/**
* @file bfcp/request.c BFCP 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_sa.h>
#include <re_tmr.h>
#include <re_bfcp.h>
#include "bfcp.h"
enum {
BFCP_T1 = 500,
BFCP_TXC = 4,
};
struct bfcp_ctrans {
struct le le;
struct sa dst;
struct mbuf *mb;
bfcp_resp_h *resph;
void *arg;
uint32_t confid;
uint16_t userid;
uint16_t tid;
};
static void tmr_handler(void *arg);
static void dummy_resp_handler(int err, const struct bfcp_msg *msg, void *arg)
{
(void)err;
(void)msg;
(void)arg;
}
static void destructor(void *arg)
{
struct bfcp_ctrans *ct = arg;
list_unlink(&ct->le);
mem_deref(ct->mb);
}
static void dispatch(struct bfcp_conn *bc)
{
struct le *le = bc->ctransl.head;
while (le) {
struct bfcp_ctrans *ct = le->data;
int err;
le = le->next;
err = bfcp_send(bc, &ct->dst, ct->mb);
if (err) {
ct->resph(err, NULL, ct->arg);
mem_deref(ct);
continue;
}
tmr_start(&bc->tmr1, BFCP_T1, tmr_handler, bc);
bc->txc = 1;
break;
}
}
static void tmr_handler(void *arg)
{
struct bfcp_conn *bc = arg;
struct bfcp_ctrans *ct;
uint32_t timeout;
int err;
ct = list_ledata(bc->ctransl.head);
if (!ct)
return;
timeout = BFCP_T1<<bc->txc;
if (++bc->txc > BFCP_TXC) {
err = ETIMEDOUT;
goto out;
}
err = bfcp_send(bc, &ct->dst, ct->mb);
if (err)
goto out;
tmr_start(&bc->tmr1, timeout, tmr_handler, bc);
return;
out:
ct->resph(err, NULL, ct->arg);
mem_deref(ct);
dispatch(bc);
}
bool bfcp_handle_response(struct bfcp_conn *bc, const struct bfcp_msg *msg)
{
struct bfcp_ctrans *ct;
if (!bc || !msg)
return false;
ct = list_ledata(bc->ctransl.head);
if (!ct)
return false;
if (msg->tid != ct->tid)
return false;
if (msg->confid != ct->confid)
return false;
if (msg->userid != ct->userid)
return false;
tmr_cancel(&bc->tmr1);
ct->resph(0, msg, ct->arg);
mem_deref(ct);
dispatch(bc);
return true;
}
int bfcp_vrequest(struct bfcp_conn *bc, const struct sa *dst, uint8_t ver,
enum bfcp_prim prim, uint32_t confid, uint16_t userid,
bfcp_resp_h *resph, void *arg, unsigned attrc, va_list *ap)
{
struct bfcp_ctrans *ct;
int err;
if (!bc || !dst)
return EINVAL;
ct = mem_zalloc(sizeof(*ct), destructor);
if (!ct)
return ENOMEM;
if (bc->tid == 0)
bc->tid = 1;
ct->dst = *dst;
ct->confid = confid;
ct->userid = userid;
ct->tid = bc->tid++;
ct->resph = resph ? resph : dummy_resp_handler;
ct->arg = arg;
ct->mb = mbuf_alloc(128);
if (!ct->mb) {
err = ENOMEM;
goto out;
}
err = bfcp_msg_vencode(ct->mb, ver, false, prim, confid, ct->tid,
userid, attrc, ap);
if (err)
goto out;
ct->mb->pos = 0;
if (!bc->ctransl.head) {
err = bfcp_send(bc, &ct->dst, ct->mb);
if (err)
goto out;
tmr_start(&bc->tmr1, BFCP_T1, tmr_handler, bc);
bc->txc = 1;
}
list_append(&bc->ctransl, &ct->le, ct);
out:
if (err)
mem_deref(ct);
return err;
}
/**
* Send a BFCP request
*
* @param bc BFCP connection
* @param dst Destination address
* @param ver BFCP Version
* @param prim BFCP Primitive
* @param confid Conference ID
* @param userid User ID
* @param resph Response handler
* @param arg Response handler argument
* @param attrc Number of attributes
*
* @return 0 if success, otherwise errorcode
*/
int bfcp_request(struct bfcp_conn *bc, const struct sa *dst, uint8_t ver,
enum bfcp_prim prim, uint32_t confid, uint16_t userid,
bfcp_resp_h *resph, void *arg, unsigned attrc, ...)
{
va_list ap;
int err;
va_start(ap, attrc);
err = bfcp_vrequest(bc, dst, ver, prim, confid, userid, resph, arg,
attrc, &ap);
va_end(ap);
return err;
}
/**
* Send a BFCP notification/subsequent response
*
* @param bc BFCP connection
* @param dst Destination address
* @param ver BFCP Version
* @param prim BFCP Primitive
* @param confid Conference ID
* @param userid User ID
* @param attrc Number of attributes
*
* @return 0 if success, otherwise errorcode
*/
int bfcp_notify(struct bfcp_conn *bc, const struct sa *dst, uint8_t ver,
enum bfcp_prim prim, uint32_t confid, uint16_t userid,
unsigned attrc, ...)
{
va_list ap;
int err;
va_start(ap, attrc);
err = bfcp_vrequest(bc, dst, ver, prim, confid, userid, NULL, NULL,
attrc, &ap);
va_end(ap);
return err;
}