Add initial code for channel & private structure allocation
This is early good but I think it's a good start. Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
This commit is contained in:
parent
a617200a54
commit
28eed215bd
145
chan_openbsc.c
145
chan_openbsc.c
|
@ -29,10 +29,30 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision: $")
|
||||||
#include <openbsc/talloc.h>
|
#include <openbsc/talloc.h>
|
||||||
|
|
||||||
#include "asterisk/channel.h"
|
#include "asterisk/channel.h"
|
||||||
|
#include "asterisk/linkedlists.h"
|
||||||
#include "asterisk/logger.h"
|
#include "asterisk/logger.h"
|
||||||
#include "asterisk/module.h"
|
#include "asterisk/module.h"
|
||||||
|
|
||||||
|
|
||||||
|
enum call_direction {
|
||||||
|
MOBILE_ORIGINATED,
|
||||||
|
MOBILE_TERMINATED,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Uses the owner lock, or g_openbsc_lock if owner==NULL */
|
||||||
|
struct openbsc_chan_priv {
|
||||||
|
struct ast_channel *owner;
|
||||||
|
|
||||||
|
u_int32_t callref;
|
||||||
|
enum call_direction dir;
|
||||||
|
|
||||||
|
AST_LIST_ENTRY(openbsc_chan_priv) _list;
|
||||||
|
};
|
||||||
|
|
||||||
|
static AST_RWLIST_HEAD_STATIC(g_privs, openbsc_chan_priv);
|
||||||
|
static u_int32_t g_nextcallref = 0x00000001; /* uses g_privs lock */
|
||||||
|
|
||||||
|
|
||||||
AST_MUTEX_DEFINE_STATIC(g_openbsc_lock);
|
AST_MUTEX_DEFINE_STATIC(g_openbsc_lock);
|
||||||
|
|
||||||
|
|
||||||
|
@ -182,10 +202,128 @@ openbsc_stop(void)
|
||||||
/* Channel driver */
|
/* Channel driver */
|
||||||
/* ---------------------------------------------------------------------{{{ */
|
/* ---------------------------------------------------------------------{{{ */
|
||||||
|
|
||||||
|
static const struct ast_channel_tech openbsc_tech;
|
||||||
|
|
||||||
|
|
||||||
|
/* Helpers */
|
||||||
|
|
||||||
|
static struct ast_channel *
|
||||||
|
_openbsc_chan_new(struct openbsc_chan_priv *p, int state)
|
||||||
|
{
|
||||||
|
struct ast_channel *chan = NULL;
|
||||||
|
|
||||||
|
chan = ast_channel_alloc(1, state, 0, NULL, "", "", "", 0, "OpenBSC/callref-%d", p->callref);
|
||||||
|
if (!chan)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
chan->tech = &openbsc_tech;
|
||||||
|
chan->nativeformats = AST_FORMAT_GSM;
|
||||||
|
chan->readformat = AST_FORMAT_GSM;
|
||||||
|
chan->writeformat = AST_FORMAT_GSM;
|
||||||
|
|
||||||
|
chan->tech_pvt = p;
|
||||||
|
p->owner = chan;
|
||||||
|
|
||||||
|
ast_module_ref(ast_module_info->self);
|
||||||
|
|
||||||
|
return chan;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_openbsc_chan_detach(struct ast_channel *chan)
|
||||||
|
{
|
||||||
|
struct openbsc_chan_priv *p = chan->tech_pvt;
|
||||||
|
|
||||||
|
chan->tech_pvt = NULL;
|
||||||
|
p->owner = NULL;
|
||||||
|
|
||||||
|
ast_module_unref(ast_module_info->self);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct openbsc_chan_priv *
|
||||||
|
_openbsc_chan_priv_new(u_int32_t callref, enum call_direction dir)
|
||||||
|
{
|
||||||
|
struct openbsc_chan_priv *p = NULL;
|
||||||
|
|
||||||
|
AST_RWLIST_WRLOCK(&g_privs);
|
||||||
|
|
||||||
|
/* Auto callref */
|
||||||
|
if (!callref) {
|
||||||
|
callref = g_nextcallref;
|
||||||
|
g_nextcallref = (g_nextcallref + 1) & 0x7fffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Alloc and init the structure */
|
||||||
|
p = ast_calloc(1, sizeof(*p));
|
||||||
|
if (!p) {
|
||||||
|
ast_log(LOG_ERROR, "Failed to allocate channel private structure\n");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
p->callref = callref;
|
||||||
|
p->dir = dir;
|
||||||
|
|
||||||
|
/* Finally add to the list */
|
||||||
|
AST_RWLIST_INSERT_HEAD(&g_privs, p, _list);
|
||||||
|
|
||||||
|
AST_RWLIST_UNLOCK(&g_privs);
|
||||||
|
|
||||||
|
return p;
|
||||||
|
|
||||||
|
error:
|
||||||
|
if (p)
|
||||||
|
ast_free(p);
|
||||||
|
AST_RWLIST_UNLOCK(&g_privs);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_openbsc_chan_priv_destroy(struct openbsc_chan_priv *p)
|
||||||
|
{
|
||||||
|
/* Remove entry from the list */
|
||||||
|
AST_RWLIST_WRLOCK(&g_privs);
|
||||||
|
AST_RWLIST_REMOVE(&g_privs, p, _list);
|
||||||
|
AST_RWLIST_UNLOCK(&g_privs);
|
||||||
|
|
||||||
|
/* Free memory */
|
||||||
|
ast_free(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct openbsc_chan_priv *
|
||||||
|
_openbsc_chan_priv_find(u_int32_t callref)
|
||||||
|
{
|
||||||
|
/* FIXME */
|
||||||
|
/* Also, what about race conditions ? I could find a channel with the
|
||||||
|
* given callref but then have it deleted under my nose ... */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Interface implementation */
|
||||||
|
|
||||||
static struct ast_channel *
|
static struct ast_channel *
|
||||||
openbsc_chan_requester(const char *type, int format, void *data, int *cause)
|
openbsc_chan_requester(const char *type, int format, void *data, int *cause)
|
||||||
{
|
{
|
||||||
return 0;
|
struct openbsc_chan_priv *p = NULL;
|
||||||
|
struct ast_channel *chan = NULL;
|
||||||
|
|
||||||
|
p = _openbsc_chan_priv_new(0, MOBILE_TERMINATED);
|
||||||
|
if (!p) {
|
||||||
|
ast_log(LOG_ERROR, "Failed to create channel private structure\n");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
chan = _openbsc_chan_new(p, AST_STATE_DOWN);
|
||||||
|
if (!chan) {
|
||||||
|
ast_log(LOG_ERROR, "Failed to create channel structure\n");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return chan;
|
||||||
|
|
||||||
|
error:
|
||||||
|
if (p)
|
||||||
|
_openbsc_chan_priv_destroy(p);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
|
@ -217,6 +355,11 @@ openbsc_chan_call(struct ast_channel *chan, char *addr, int timeout)
|
||||||
static int
|
static int
|
||||||
openbsc_chan_hangup(struct ast_channel *chan)
|
openbsc_chan_hangup(struct ast_channel *chan)
|
||||||
{
|
{
|
||||||
|
struct openbsc_chan_priv *p = chan->tech_pvt;
|
||||||
|
|
||||||
|
_openbsc_chan_detach(chan);
|
||||||
|
_openbsc_chan_priv_destroy(p); /* FIXME shouldn't be done here in the future */
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Reference in New Issue