2007-07-15 10:03:09 +00:00
|
|
|
|
/*****************************************************************************\
|
|
|
|
|
** **
|
2007-07-18 09:44:25 +00:00
|
|
|
|
** Linux Call Router **
|
2007-07-15 10:03:09 +00:00
|
|
|
|
** **
|
|
|
|
|
**---------------------------------------------------------------------------**
|
|
|
|
|
** Copyright: Andreas Eversberg **
|
|
|
|
|
** **
|
|
|
|
|
** Asterisk socket client **
|
|
|
|
|
** **
|
|
|
|
|
\*****************************************************************************/
|
|
|
|
|
|
2007-07-26 12:23:56 +00:00
|
|
|
|
/*
|
|
|
|
|
|
|
|
|
|
How does it work:
|
|
|
|
|
|
|
|
|
|
To connect, open a socket and send a MESSAGE_HELLO to admin socket with
|
|
|
|
|
the application name. This name is unique an can be used for routing calls.
|
|
|
|
|
|
|
|
|
|
To make a call, send a MESSAGE_NEWREF and a new reference is received.
|
|
|
|
|
When receiving a call, a new reference is received.
|
|
|
|
|
The reference is received with MESSAGE_NEWREF.
|
|
|
|
|
|
|
|
|
|
Make a MESSAGE_SETUP or receive a MESSAGE_SETUP with the reference.
|
|
|
|
|
|
|
|
|
|
To release call and reference, send or receive MESSAGE_RELEASE.
|
|
|
|
|
From that point on, the ref is not valid, so no other message may be sent
|
|
|
|
|
with that reference.
|
2007-08-12 08:16:19 +00:00
|
|
|
|
|
2007-07-26 12:23:56 +00:00
|
|
|
|
*/
|
|
|
|
|
|
2007-07-15 10:03:09 +00:00
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <stdarg.h>
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
#include <time.h>
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
|
#include <sys/socket.h>
|
|
|
|
|
#include <sys/un.h>
|
|
|
|
|
#include "extension.h"
|
|
|
|
|
#include "message.h"
|
2008-02-03 12:47:33 +00:00
|
|
|
|
#include "lcrsocket.h"
|
2007-08-12 09:16:45 +00:00
|
|
|
|
#include "cause.h"
|
2008-01-19 17:10:46 +00:00
|
|
|
|
#include "bchannel.h"
|
|
|
|
|
#include "chan_lcr.h"
|
2007-07-15 10:03:09 +00:00
|
|
|
|
|
2008-01-21 08:34:38 +00:00
|
|
|
|
int lcr_sock = -1;
|
2007-07-15 10:03:09 +00:00
|
|
|
|
|
|
|
|
|
struct admin_list {
|
|
|
|
|
struct admin_list *next;
|
|
|
|
|
struct admin_msg msg;
|
|
|
|
|
} *admin_first = NULL;
|
|
|
|
|
|
|
|
|
|
/*
|
2007-08-12 09:16:45 +00:00
|
|
|
|
* channel and call instances
|
|
|
|
|
*/
|
|
|
|
|
struct chan_call *call_first;
|
|
|
|
|
|
|
|
|
|
struct chan_call *find_call_ref(unsigned long ref)
|
|
|
|
|
{
|
|
|
|
|
struct chan_call *call = call_first;
|
|
|
|
|
|
|
|
|
|
while(call)
|
|
|
|
|
{
|
|
|
|
|
if (call->ref == ref)
|
|
|
|
|
break;
|
|
|
|
|
call = call->next;
|
|
|
|
|
}
|
|
|
|
|
return(call);
|
|
|
|
|
}
|
|
|
|
|
|
2008-01-19 17:10:46 +00:00
|
|
|
|
struct chan_call *find_call_handle(unsigned long handle)
|
2007-08-12 09:16:45 +00:00
|
|
|
|
{
|
|
|
|
|
struct chan_call *call = call_first;
|
|
|
|
|
|
|
|
|
|
while(call)
|
|
|
|
|
{
|
2008-01-19 17:10:46 +00:00
|
|
|
|
if (call->bchannel_handle == handle)
|
2007-08-12 09:16:45 +00:00
|
|
|
|
break;
|
|
|
|
|
call = call->next;
|
|
|
|
|
}
|
|
|
|
|
return(call);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct chan_call *alloc_call(void)
|
|
|
|
|
{
|
|
|
|
|
struct chan_call **callp = &call_first;
|
|
|
|
|
|
|
|
|
|
while(*callp)
|
|
|
|
|
callp = &((*callp)->next);
|
|
|
|
|
|
2008-01-19 17:44:26 +00:00
|
|
|
|
*callp = (struct chan_call *)malloc(sizeof(struct chan_call));
|
2007-08-12 09:16:45 +00:00
|
|
|
|
return(*callp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void free_call(struct chan_call *call)
|
|
|
|
|
{
|
|
|
|
|
struct chan_call **temp = &call_first;
|
|
|
|
|
|
|
|
|
|
while(*temp)
|
|
|
|
|
{
|
|
|
|
|
if (*temp == call)
|
|
|
|
|
{
|
|
|
|
|
*temp = (*temp)->next;
|
|
|
|
|
free(call);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
temp = &((*temp)->next);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-02-03 12:47:33 +00:00
|
|
|
|
unsigned short new_brige_id(void)
|
|
|
|
|
{
|
|
|
|
|
struct chan_call *call;
|
|
|
|
|
unsigned short id = 1;
|
|
|
|
|
|
|
|
|
|
/* search for lowest bridge id that is not in use and not 0 */
|
|
|
|
|
while(id)
|
|
|
|
|
{
|
|
|
|
|
call = call_first;
|
|
|
|
|
while(call)
|
|
|
|
|
{
|
|
|
|
|
if (call->bridge_id == id)
|
|
|
|
|
break;
|
|
|
|
|
call = call->next;
|
|
|
|
|
}
|
|
|
|
|
if (!call)
|
|
|
|
|
break;
|
|
|
|
|
id++;
|
|
|
|
|
}
|
|
|
|
|
return(id);
|
|
|
|
|
}
|
|
|
|
|
|
2007-08-12 09:16:45 +00:00
|
|
|
|
|
2008-01-19 17:10:46 +00:00
|
|
|
|
/*
|
|
|
|
|
* receive bchannel data
|
|
|
|
|
*/
|
|
|
|
|
void rx_data(struct bchannel *bchannel, unsigned char *data, int len)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void rx_dtmf(struct bchannel *bchannel, char tone)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2007-08-12 09:16:45 +00:00
|
|
|
|
/*
|
|
|
|
|
* enque message to LCR
|
2007-07-15 10:03:09 +00:00
|
|
|
|
*/
|
2007-08-12 08:16:19 +00:00
|
|
|
|
int send_message(int message_type, unsigned long ref, union parameter *param)
|
2007-07-15 10:03:09 +00:00
|
|
|
|
{
|
|
|
|
|
struct admin_list *admin, **adminp;
|
|
|
|
|
|
|
|
|
|
adminp = &admin_first;
|
|
|
|
|
while(*adminp)
|
|
|
|
|
adminp = &((*adminp)->next);
|
2008-01-19 17:44:26 +00:00
|
|
|
|
admin = (struct admin_list *)malloc(sizeof(struct admin_list));
|
2007-07-15 10:03:09 +00:00
|
|
|
|
*adminp = admin;
|
|
|
|
|
|
|
|
|
|
admin->msg.type = message_type;
|
2007-08-12 08:16:19 +00:00
|
|
|
|
admin->msg.ref = ref;
|
2007-07-15 10:03:09 +00:00
|
|
|
|
memcpy(&admin->msg.param, param, sizeof(union parameter));
|
|
|
|
|
|
|
|
|
|
return(0);
|
|
|
|
|
}
|
|
|
|
|
|
2007-08-12 08:16:19 +00:00
|
|
|
|
/*
|
|
|
|
|
* message received from LCR
|
|
|
|
|
*/
|
|
|
|
|
int receive_message(int message_type, unsigned long ref, union parameter *param)
|
|
|
|
|
{
|
|
|
|
|
union parameter newparam;
|
2008-01-19 17:10:46 +00:00
|
|
|
|
struct bchannel *bchannel;
|
2007-08-12 09:16:45 +00:00
|
|
|
|
struct chan_call *call;
|
2007-08-12 08:16:19 +00:00
|
|
|
|
|
|
|
|
|
memset(&newparam, 0, sizeof(union parameter));
|
|
|
|
|
|
|
|
|
|
/* handle bchannel message*/
|
|
|
|
|
if (message_type == MESSAGE_BCHANNEL)
|
|
|
|
|
{
|
2007-08-12 09:16:45 +00:00
|
|
|
|
switch(param->bchannel.type)
|
2007-08-12 08:16:19 +00:00
|
|
|
|
{
|
|
|
|
|
case BCHANNEL_ASSIGN:
|
2007-08-26 13:23:58 +00:00
|
|
|
|
if ((bchannel = find_bchannel_handle(param->bchannel.handle)))
|
2007-08-12 08:16:19 +00:00
|
|
|
|
{
|
2007-08-26 13:23:58 +00:00
|
|
|
|
fprintf(stderr, "error: bchannel handle %x already assigned.\n", param->bchannel.handle);
|
2007-08-12 08:16:19 +00:00
|
|
|
|
return(-1);
|
|
|
|
|
}
|
2007-08-12 09:16:45 +00:00
|
|
|
|
/* create bchannel */
|
2008-01-19 17:10:46 +00:00
|
|
|
|
bchannel = alloc_bchannel(param->bchannel.handle);
|
|
|
|
|
if (!bchannel)
|
|
|
|
|
{
|
|
|
|
|
fprintf(stderr, "error: alloc bchannel handle %x failed.\n", param->bchannel.handle);
|
|
|
|
|
return(-1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* configure channel */
|
|
|
|
|
bchannel->b_tx_gain = param->bchannel.tx_gain;
|
|
|
|
|
bchannel->b_rx_gain = param->bchannel.rx_gain;
|
|
|
|
|
strncpy(bchannel->b_pipeline, param->bchannel.pipeline, sizeof(bchannel->b_pipeline)-1);
|
|
|
|
|
if (param->bchannel.crypt_len)
|
|
|
|
|
{
|
|
|
|
|
bchannel->b_crypt_len = param->bchannel.crypt_len;
|
|
|
|
|
bchannel->b_crypt_type = param->bchannel.crypt_type;
|
|
|
|
|
memcpy(bchannel->b_crypt_key, param->bchannel.crypt, param->bchannel.crypt_len);
|
|
|
|
|
}
|
|
|
|
|
bchannel->b_txdata = 0;
|
|
|
|
|
bchannel->b_dtmf = 1;
|
|
|
|
|
bchannel->b_tx_dejitter = 1;
|
|
|
|
|
|
2007-08-12 09:16:45 +00:00
|
|
|
|
/* in case, ref is not set, this bchannel instance must
|
2007-08-12 08:16:19 +00:00
|
|
|
|
* be created until it is removed again by LCR */
|
|
|
|
|
/* link to call */
|
2007-08-12 09:16:45 +00:00
|
|
|
|
if ((call = find_call_ref(ref)))
|
2007-08-12 08:16:19 +00:00
|
|
|
|
{
|
2007-08-13 21:29:09 +00:00
|
|
|
|
bchannel->ref = ref;
|
2008-01-19 17:10:46 +00:00
|
|
|
|
call->bchannel_handle = param->bchannel.handle;
|
2008-02-03 12:47:33 +00:00
|
|
|
|
#warning hier muesen alle stati gesetzt werden falls sie vor dem b-kanal verf<72>gbar waren
|
|
|
|
|
bchannel_join(call->bridge_id);
|
2007-08-12 08:16:19 +00:00
|
|
|
|
}
|
2008-01-19 17:10:46 +00:00
|
|
|
|
if (bchannel_create(bchannel))
|
|
|
|
|
bchannel_activate(bchannel, 1);
|
2007-08-12 08:16:19 +00:00
|
|
|
|
|
|
|
|
|
/* acknowledge */
|
|
|
|
|
newparam.bchannel.type = BCHANNEL_ASSIGN_ACK;
|
2007-08-26 13:23:58 +00:00
|
|
|
|
newparam.bchannel.handle = param->bchannel.handle;
|
2007-08-12 08:16:19 +00:00
|
|
|
|
send_message(MESSAGE_BCHANNEL, 0, &newparam);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case BCHANNEL_REMOVE:
|
2007-08-26 13:23:58 +00:00
|
|
|
|
if (!(bchannel = find_bchannel_handle(param->bchannel.handle)))
|
2007-08-12 08:16:19 +00:00
|
|
|
|
{
|
2008-01-21 08:34:38 +00:00
|
|
|
|
alle fprintf nach ast_log
|
2007-08-26 13:23:58 +00:00
|
|
|
|
fprintf(stderr, "error: bchannel handle %x not assigned.\n", param->bchannel.handle);
|
2007-08-12 08:16:19 +00:00
|
|
|
|
return(-1);
|
|
|
|
|
}
|
|
|
|
|
/* unlink from call */
|
2007-08-12 09:16:45 +00:00
|
|
|
|
if ((call = find_call_ref(bchannel->ref)))
|
2007-08-12 08:16:19 +00:00
|
|
|
|
{
|
2008-01-19 17:10:46 +00:00
|
|
|
|
call->bchannel_handle = 0;
|
2007-08-12 08:16:19 +00:00
|
|
|
|
}
|
2008-01-19 17:10:46 +00:00
|
|
|
|
/* destroy and remove bchannel */
|
2007-08-12 09:16:45 +00:00
|
|
|
|
free_bchannel(bchannel);
|
2008-01-19 17:10:46 +00:00
|
|
|
|
|
2007-08-12 08:16:19 +00:00
|
|
|
|
/* acknowledge */
|
|
|
|
|
newparam.bchannel.type = BCHANNEL_REMOVE_ACK;
|
2007-08-26 13:23:58 +00:00
|
|
|
|
newparam.bchannel.handle = param->bchannel.handle;
|
2007-08-12 08:16:19 +00:00
|
|
|
|
send_message(MESSAGE_BCHANNEL, 0, &newparam);
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
2007-08-12 09:16:45 +00:00
|
|
|
|
fprintf(stderr, "received unknown bchannel message %d\n", param->bchannel.type);
|
|
|
|
|
}
|
|
|
|
|
return(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* handle new ref */
|
|
|
|
|
if (message_type == MESSAGE_NEWREF)
|
|
|
|
|
{
|
|
|
|
|
if (param->direction)
|
|
|
|
|
{
|
|
|
|
|
/* new ref from lcr */
|
|
|
|
|
if (!ref || find_call_ref(ref))
|
|
|
|
|
{
|
|
|
|
|
fprintf(stderr, "illegal new ref %d received\n", ref);
|
|
|
|
|
return(-1);
|
|
|
|
|
}
|
|
|
|
|
call = alloc_call();
|
|
|
|
|
call->ref = ref;
|
|
|
|
|
} else
|
|
|
|
|
{
|
|
|
|
|
/* new ref, as requested from this remote application */
|
|
|
|
|
call = find_call_ref(0);
|
|
|
|
|
if (!call)
|
|
|
|
|
{
|
|
|
|
|
/* send release, if ref does not exist */
|
|
|
|
|
newparam.disconnectinfo.cause = CAUSE_NORMAL;
|
|
|
|
|
newparam.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
|
|
|
|
|
send_message(MESSAGE_RELEASE, ref, &newparam);
|
|
|
|
|
return(0);
|
|
|
|
|
}
|
|
|
|
|
call->ref = ref;
|
|
|
|
|
#warning process call (send setup, if pending)
|
2007-08-12 08:16:19 +00:00
|
|
|
|
}
|
|
|
|
|
return(0);
|
|
|
|
|
}
|
2007-08-12 09:16:45 +00:00
|
|
|
|
|
|
|
|
|
/* check ref */
|
|
|
|
|
if (!ref)
|
|
|
|
|
{
|
|
|
|
|
fprintf(stderr, "received message %d without ref\n", message_type);
|
|
|
|
|
return(-1);
|
|
|
|
|
}
|
|
|
|
|
call = find_call_ref(ref);
|
|
|
|
|
if (!call)
|
|
|
|
|
{
|
|
|
|
|
/* ignore ref that is not used (anymore) */
|
|
|
|
|
return(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* handle messages */
|
2007-08-12 08:16:19 +00:00
|
|
|
|
switch(message_type)
|
2007-08-12 09:16:45 +00:00
|
|
|
|
{
|
2008-01-21 08:34:38 +00:00
|
|
|
|
case MESSAGE_SETUP:
|
|
|
|
|
todo
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case MESSAGE_OVERLAP:
|
|
|
|
|
todo
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case MESSAGE_PROCEEDING:
|
|
|
|
|
todo
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case MESSAGE_ALERTING:
|
|
|
|
|
todo
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case MESSAGE_CONNECT:
|
|
|
|
|
todo
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case MESSAGE_DISCONNECT:
|
|
|
|
|
todo
|
|
|
|
|
break;
|
|
|
|
|
|
2007-08-12 09:16:45 +00:00
|
|
|
|
case MESSAGE_RELEASE:
|
2008-01-21 08:34:38 +00:00
|
|
|
|
todo
|
2007-08-12 09:16:45 +00:00
|
|
|
|
free_call(call);
|
|
|
|
|
return(0);
|
|
|
|
|
|
2008-01-21 08:34:38 +00:00
|
|
|
|
case MESSAGE_INFORMATION:
|
|
|
|
|
todo
|
2007-08-12 09:16:45 +00:00
|
|
|
|
break;
|
2008-01-21 08:34:38 +00:00
|
|
|
|
|
|
|
|
|
case MESSAGE_FACILITY:
|
|
|
|
|
todo
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case MESSAGE_PATTERN:
|
|
|
|
|
todo
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case MESSAGE_NOPATTERN:
|
|
|
|
|
todo
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case MESSAGE_AUDIOPATH:
|
|
|
|
|
todo
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
unhandled
|
2007-08-12 09:16:45 +00:00
|
|
|
|
}
|
2007-08-12 08:16:19 +00:00
|
|
|
|
return(0);
|
|
|
|
|
}
|
|
|
|
|
|
2007-07-15 10:03:09 +00:00
|
|
|
|
|
|
|
|
|
/* asterisk handler
|
|
|
|
|
* warning! not thread safe
|
|
|
|
|
* returns -1 for socket error, 0 for no work, 1 for work
|
|
|
|
|
*/
|
|
|
|
|
int handle_socket(void)
|
|
|
|
|
{
|
|
|
|
|
int work = 0;
|
|
|
|
|
int len;
|
|
|
|
|
struct admin_message msg;
|
|
|
|
|
struct admin_list *admin;
|
|
|
|
|
|
|
|
|
|
/* read from socket */
|
|
|
|
|
len = read(sock, &msg, sizeof(msg));
|
|
|
|
|
if (len == 0)
|
|
|
|
|
{
|
|
|
|
|
printf("Socket closed\n");
|
|
|
|
|
return(-1); // socket closed
|
|
|
|
|
}
|
|
|
|
|
if (len > 0)
|
|
|
|
|
{
|
|
|
|
|
if (len != sizeof(msg))
|
|
|
|
|
{
|
|
|
|
|
fprintf(stderr, "Socket short read (%d)\n", len);
|
|
|
|
|
return(-1); // socket error
|
|
|
|
|
}
|
|
|
|
|
if (msg.message != ADMIN_MESSAGE)
|
|
|
|
|
{
|
|
|
|
|
fprintf(stderr, "Socket received illegal message %d\n", msg.message);
|
|
|
|
|
return(-1); // socket error
|
|
|
|
|
}
|
2007-08-12 09:16:45 +00:00
|
|
|
|
receive_message(msg.u.msg.type, msg.u.msg.ref, &msg.u.msg.param);
|
2007-07-15 10:03:09 +00:00
|
|
|
|
printf("message received %d\n", msg.u.msg.type);
|
|
|
|
|
work = 1;
|
|
|
|
|
} else
|
|
|
|
|
{
|
|
|
|
|
if (errno != EWOULDBLOCK)
|
|
|
|
|
{
|
|
|
|
|
fprintf(stderr, "Socket error %d\n", errno);
|
|
|
|
|
return(-1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* write to socket */
|
|
|
|
|
if (!admin_first)
|
|
|
|
|
return(work);
|
|
|
|
|
admin = admin_first;
|
|
|
|
|
len = write(sock, &admin->msg, sizeof(msg));
|
|
|
|
|
if (len == 0)
|
|
|
|
|
{
|
|
|
|
|
printf("Socket closed\n");
|
|
|
|
|
return(-1); // socket closed
|
|
|
|
|
}
|
|
|
|
|
if (len > 0)
|
|
|
|
|
{
|
|
|
|
|
if (len != sizeof(msg))
|
|
|
|
|
{
|
|
|
|
|
fprintf(stderr, "Socket short write (%d)\n", len);
|
|
|
|
|
return(-1); // socket error
|
|
|
|
|
}
|
|
|
|
|
/* free head */
|
|
|
|
|
admin_first = admin->next;
|
2008-01-19 17:44:26 +00:00
|
|
|
|
free(admin);
|
2007-07-15 10:03:09 +00:00
|
|
|
|
|
|
|
|
|
work = 1;
|
|
|
|
|
} else
|
|
|
|
|
{
|
|
|
|
|
if (errno != EWOULDBLOCK)
|
|
|
|
|
{
|
|
|
|
|
fprintf(stderr, "Socket error %d\n", errno);
|
|
|
|
|
return(-1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return(work);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2008-01-21 08:34:38 +00:00
|
|
|
|
* open and close socket
|
2007-07-15 10:03:09 +00:00
|
|
|
|
*/
|
2008-01-21 08:34:38 +00:00
|
|
|
|
int open_socket(void)
|
2007-07-15 10:03:09 +00:00
|
|
|
|
{
|
2008-01-21 08:34:38 +00:00
|
|
|
|
int ret;
|
|
|
|
|
int sock;
|
2007-07-15 10:03:09 +00:00
|
|
|
|
char *socket_name = SOCKET_NAME;
|
|
|
|
|
int conn;
|
|
|
|
|
struct sockaddr_un sock_address;
|
|
|
|
|
int ret;
|
|
|
|
|
unsigned long on = 1;
|
2007-07-26 12:23:56 +00:00
|
|
|
|
union parameter param;
|
2007-07-15 10:03:09 +00:00
|
|
|
|
|
|
|
|
|
/* open socket */
|
|
|
|
|
if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
|
|
|
|
|
{
|
2008-01-21 08:34:38 +00:00
|
|
|
|
ast_log(LOG_ERROR, "Failed to create socket.\n");
|
|
|
|
|
return(sock);
|
2007-07-15 10:03:09 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* set socket address and name */
|
|
|
|
|
memset(&sock_address, 0, sizeof(sock_address));
|
|
|
|
|
sock_address.sun_family = PF_UNIX;
|
2008-01-19 17:44:26 +00:00
|
|
|
|
strcpy(sock_address.sun_path, socket_name);
|
2007-07-15 10:03:09 +00:00
|
|
|
|
|
|
|
|
|
/* connect socket */
|
|
|
|
|
if ((conn = connect(sock, (struct sockaddr *)&sock_address, SUN_LEN(&sock_address))) < 0)
|
|
|
|
|
{
|
|
|
|
|
close(sock);
|
2008-01-21 08:34:38 +00:00
|
|
|
|
ast_log(LOG_ERROR, "Failed to connect to socket \"%s\". Is LCR running?\n", sock_address.sun_path);
|
|
|
|
|
return(conn);
|
2007-07-15 10:03:09 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* set non-blocking io */
|
2008-01-21 08:34:38 +00:00
|
|
|
|
if ((ret = ioctl(sock, FIONBIO, (unsigned char *)(&on))) < 0)
|
2007-07-15 10:03:09 +00:00
|
|
|
|
{
|
|
|
|
|
close(sock);
|
2008-01-21 08:34:38 +00:00
|
|
|
|
ast_log(LOG_ERROR, "Failed to set socket into non-blocking IO.\n");
|
|
|
|
|
return(ret);
|
2007-07-15 10:03:09 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* enque hello message */
|
2007-07-26 12:23:56 +00:00
|
|
|
|
memset(¶m, 0, sizeof(param));
|
2008-01-19 17:44:26 +00:00
|
|
|
|
strcpy(param.hello.application, "asterisk");
|
2007-08-12 09:16:45 +00:00
|
|
|
|
send_message(MESSAGE_HELLO, 0, ¶m);
|
2007-07-15 10:03:09 +00:00
|
|
|
|
|
2008-01-21 08:34:38 +00:00
|
|
|
|
return(sock);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void close_socket(int sock)
|
|
|
|
|
{
|
|
|
|
|
/* close socket */
|
|
|
|
|
if (socket >= 0)
|
|
|
|
|
close(sock);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void lcr_thread(void)
|
|
|
|
|
{
|
|
|
|
|
int work;
|
|
|
|
|
|
2007-07-15 10:03:09 +00:00
|
|
|
|
while(42)
|
|
|
|
|
{
|
2008-01-19 17:10:46 +00:00
|
|
|
|
work = 0;
|
|
|
|
|
|
|
|
|
|
/* handle socket */
|
2007-07-15 10:03:09 +00:00
|
|
|
|
ret = handle_socket();
|
|
|
|
|
if (ret < 0)
|
|
|
|
|
break;
|
2008-01-19 17:10:46 +00:00
|
|
|
|
if (ret)
|
|
|
|
|
work = 1;
|
|
|
|
|
|
|
|
|
|
/* handle mISDN */
|
|
|
|
|
ret = bchannel_handle();
|
|
|
|
|
if (ret)
|
|
|
|
|
work = 1;
|
|
|
|
|
|
|
|
|
|
if (!work)
|
2007-07-15 10:03:09 +00:00
|
|
|
|
usleep(30000);
|
|
|
|
|
}
|
2008-01-21 08:34:38 +00:00
|
|
|
|
}
|
|
|
|
|
|
2008-02-03 12:47:33 +00:00
|
|
|
|
/* call from asterisk (new instance) */
|
|
|
|
|
static int lcr_call(struct ast_channel *ast, char *dest, int timeout)
|
|
|
|
|
{
|
|
|
|
|
int port=0;
|
|
|
|
|
int r;
|
|
|
|
|
struct chan_list *ch=MISDN_ASTERISK_TECH_PVT(ast);
|
|
|
|
|
struct misdn_bchannel *newbc;
|
|
|
|
|
char *opts=NULL, *ext;
|
|
|
|
|
char dest_cp[256];
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
strncpy(dest_cp,dest,sizeof(dest_cp)-1);
|
|
|
|
|
dest_cp[sizeof(dest_cp)]=0;
|
|
|
|
|
|
|
|
|
|
ext=dest_cp;
|
|
|
|
|
strsep(&ext,"/");
|
|
|
|
|
if (ext) {
|
|
|
|
|
opts=ext;
|
|
|
|
|
strsep(&opts,"/");
|
|
|
|
|
} else {
|
|
|
|
|
ast_log(LOG_WARNING, "Malformed dialstring\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!ast) {
|
|
|
|
|
ast_log(LOG_WARNING, " --> ! misdn_call called on ast_channel *ast where ast == NULL\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) || !dest ) {
|
|
|
|
|
ast_log(LOG_WARNING, " --> ! misdn_call called on %s, neither down nor reserved (or dest==NULL)\n", ast->name);
|
|
|
|
|
ast->hangupcause=41;
|
|
|
|
|
ast_setstate(ast, AST_STATE_DOWN);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!ch) {
|
|
|
|
|
ast_log(LOG_WARNING, " --> ! misdn_call called on %s, neither down nor reserved (or dest==NULL)\n", ast->name);
|
|
|
|
|
ast->hangupcause=41;
|
|
|
|
|
ast_setstate(ast, AST_STATE_DOWN);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
newbc=ch->bc;
|
|
|
|
|
|
|
|
|
|
if (!newbc) {
|
|
|
|
|
ast_log(LOG_WARNING, " --> ! misdn_call called on %s, neither down nor reserved (or dest==NULL)\n", ast->name);
|
|
|
|
|
ast->hangupcause=41;
|
|
|
|
|
ast_setstate(ast, AST_STATE_DOWN);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
port=newbc->port;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
chan_misdn_log(1, port, "* CALL: %s\n",dest);
|
|
|
|
|
|
|
|
|
|
chan_misdn_log(2, port, " --> * dad:%s tech:%s ctx:%s\n",ast->exten,ast->name, ast->context);
|
|
|
|
|
|
|
|
|
|
chan_misdn_log(3, port, " --> * adding2newbc ext %s\n",ast->exten);
|
|
|
|
|
if (ast->exten) {
|
|
|
|
|
int l = sizeof(newbc->dad);
|
|
|
|
|
strncpy(ast->exten,ext,sizeof(ast->exten));
|
|
|
|
|
|
|
|
|
|
strncpy(newbc->dad,ext,l);
|
|
|
|
|
|
|
|
|
|
newbc->dad[l-1] = 0;
|
|
|
|
|
}
|
|
|
|
|
newbc->rad[0]=0;
|
|
|
|
|
chan_misdn_log(3, port, " --> * adding2newbc callerid %s\n",AST_CID_P(ast));
|
|
|
|
|
if (ast_strlen_zero(newbc->oad) && AST_CID_P(ast) ) {
|
|
|
|
|
|
|
|
|
|
if (AST_CID_P(ast)) {
|
|
|
|
|
int l = sizeof(newbc->oad);
|
|
|
|
|
strncpy(newbc->oad,AST_CID_P(ast), l);
|
|
|
|
|
newbc->oad[l-1] = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
struct chan_list *ch=MISDN_ASTERISK_TECH_PVT(ast);
|
|
|
|
|
if (!ch) { ast_verbose("No chan_list in misdn_call\n"); return -1;}
|
|
|
|
|
|
|
|
|
|
newbc->capability=ast->transfercapability;
|
|
|
|
|
pbx_builtin_setvar_helper(ast,"TRANSFERCAPABILITY",ast_transfercapability2str(newbc->capability));
|
|
|
|
|
if ( ast->transfercapability == INFO_CAPABILITY_DIGITAL_UNRESTRICTED) {
|
|
|
|
|
chan_misdn_log(2, port, " --> * Call with flag Digital\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* update screening and presentation */
|
|
|
|
|
update_config(ch,ORG_AST);
|
|
|
|
|
|
|
|
|
|
/* fill in some ies from channel vary*/
|
|
|
|
|
import_ch(ast, newbc, ch);
|
|
|
|
|
|
|
|
|
|
/* Finally The Options Override Everything */
|
|
|
|
|
if (opts)
|
|
|
|
|
misdn_set_opt_exec(ast,opts);
|
|
|
|
|
else
|
|
|
|
|
chan_misdn_log(2,port,"NO OPTS GIVEN\n");
|
|
|
|
|
|
|
|
|
|
/*check for bridging*/
|
|
|
|
|
int bridging;
|
|
|
|
|
misdn_cfg_get( 0, MISDN_GEN_BRIDGING, &bridging, sizeof(int));
|
|
|
|
|
if (bridging && ch->other_ch) {
|
|
|
|
|
chan_misdn_log(1, port, "Disabling EC (aka Pipeline) on both Sides\n");
|
|
|
|
|
*ch->bc->pipeline=0;
|
|
|
|
|
*ch->other_ch->bc->pipeline=0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
r=misdn_lib_send_event( newbc, EVENT_SETUP );
|
|
|
|
|
|
|
|
|
|
/** we should have l3id after sending setup **/
|
|
|
|
|
ch->l3id=newbc->l3_id;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( r == -ENOCHAN ) {
|
|
|
|
|
chan_misdn_log(0, port, " --> * Theres no Channel at the moment .. !\n");
|
|
|
|
|
chan_misdn_log(1, port, " --> * SEND: State Down pid:%d\n",newbc?newbc->pid:-1);
|
|
|
|
|
ast->hangupcause=34;
|
|
|
|
|
ast_setstate(ast, AST_STATE_DOWN);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
chan_misdn_log(2, port, " --> * SEND: State Dialing pid:%d\n",newbc?newbc->pid:1);
|
|
|
|
|
|
|
|
|
|
ast_setstate(ast, AST_STATE_DIALING);
|
|
|
|
|
ast->hangupcause=16;
|
|
|
|
|
|
|
|
|
|
wenn pattern available soll gestoppt werden, sonst nicht:
|
|
|
|
|
if (newbc->nt) stop_bc_tones(ch);
|
|
|
|
|
|
|
|
|
|
ch->state=MISDN_CALLING;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2008-01-21 08:34:38 +00:00
|
|
|
|
static struct ast_channel_tech misdn_tech = {
|
|
|
|
|
.type="lcr",
|
|
|
|
|
.description="Channel driver for connecting to Linux-Call-Router",
|
|
|
|
|
.capabilities= je nach option?AST_FORMAT_ALAW:AST_FORMAT_ULAW ,
|
|
|
|
|
.requester=lcr_request,
|
|
|
|
|
.send_digit=lcr_digit,
|
|
|
|
|
.call=lcr_call,
|
|
|
|
|
.bridge=lcr_bridge,
|
|
|
|
|
.hangup=lcr_hangup,
|
|
|
|
|
.answer=lcr_answer,
|
|
|
|
|
.read=lcr_read,
|
|
|
|
|
.write=lcr_write,
|
|
|
|
|
.indicate=lcr_indication,
|
|
|
|
|
.fixup=lcr_fixup,
|
|
|
|
|
.send_text=lcr_send_text,
|
|
|
|
|
.properties=0
|
|
|
|
|
};
|
|
|
|
|
|
2008-04-26 08:32:30 +00:00
|
|
|
|
/*
|
|
|
|
|
* cli
|
|
|
|
|
*/
|
|
|
|
|
static int cli_show_lcr (int fd, int argc, char *argv[])
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int cli_show_calls (int fd, int argc, char *argv[])
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int cli_reload_routing (int fd, int argc, char *argv[])
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int cli_reload_interfaces (int fd, int argc, char *argv[])
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int cli_port_block (int fd, int argc, char *argv[])
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int cli_port_unblock (int fd, int argc, char *argv[])
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int cli_port_unload (int fd, int argc, char *argv[])
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct ast_cli_entry cli_show_lcr =
|
|
|
|
|
{ {"lcr", "show", "lcr", NULL},
|
|
|
|
|
lcr_show_lcr,
|
|
|
|
|
"Shows current states of LCR core",
|
|
|
|
|
"Usage: lcr show lcr\n",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static struct ast_cli_entry cli_show_calls =
|
|
|
|
|
{ {"lcr", "show", "calls", NULL},
|
|
|
|
|
lcr_show_calls,
|
|
|
|
|
"Shows current calls made by LCR and Asterisk",
|
|
|
|
|
"Usage: lcr show calls\n",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static struct ast_cli_entry cli_reload_routing =
|
|
|
|
|
{ {"lcr", "reload", "routing", NULL},
|
|
|
|
|
lcr_reload_routing,
|
|
|
|
|
"Reloads routing conf of LCR, current uncomplete calls will be disconnected",
|
|
|
|
|
"Usage: lcr reload routing\n",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static struct ast_cli_entry cli_reload_interfaces =
|
|
|
|
|
{ {"lcr", "reload", "interfaces", NULL},
|
|
|
|
|
lcr_reload_interfaces,
|
|
|
|
|
"Reloads interfaces conf of LCR",
|
|
|
|
|
"Usage: lcr reload interfaces\n",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static struct ast_cli_entry cli_port_block =
|
|
|
|
|
{ {"lcr", "port", "block", NULL},
|
|
|
|
|
lcr_port_block,
|
|
|
|
|
"Blocks LCR port for further calls",
|
|
|
|
|
"Usage: lcr port block \"<port>\"\n",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static struct ast_cli_entry cli_port_unblock =
|
|
|
|
|
{ {"lcr", "port", "unblock", NULL},
|
|
|
|
|
lcr_port_unblock,
|
|
|
|
|
"Unblocks or loads LCR port, port is opened my mISDN",
|
|
|
|
|
"Usage: lcr port unblock \"<port>\"\n",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static struct ast_cli_entry cli_port_unload =
|
|
|
|
|
{ {"lcr", "port", "unload", NULL},
|
|
|
|
|
lcr_port_unload,
|
|
|
|
|
"Unloads LCR port, port is closes by mISDN",
|
|
|
|
|
"Usage: lcr port unload \"<port>\"\n",
|
|
|
|
|
};
|
|
|
|
|
|
2008-01-21 08:34:38 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* module loading and destruction
|
|
|
|
|
*/
|
|
|
|
|
int load_module(void)
|
|
|
|
|
{
|
|
|
|
|
// ast_mutex_init(&release_lock);
|
|
|
|
|
|
|
|
|
|
// lcr_cfg_update_ptp();
|
|
|
|
|
|
|
|
|
|
if (!(lcr_sock = open_socket())) {
|
|
|
|
|
ast_log(LOG_ERROR, "Unable to connect %s\n", misdn_type);
|
|
|
|
|
lcr_sock = -1;
|
|
|
|
|
/* continue with closed socket */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!bchannel_initialize()) {
|
|
|
|
|
ast_log(LOG_ERROR, "Unable to open mISDN device\n");
|
|
|
|
|
unload_module();
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
mISDN_created = 1;
|
|
|
|
|
|
|
|
|
|
if (ast_channel_register(&lcr_tech)) {
|
|
|
|
|
ast_log(LOG_ERROR, "Unable to register channel class %s\n", misdn_type);
|
|
|
|
|
unload_module();
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2008-02-03 12:47:33 +00:00
|
|
|
|
ast_cli_register(&cli_show_lcr);
|
|
|
|
|
ast_cli_register(&cli_show_calls);
|
2008-01-21 08:34:38 +00:00
|
|
|
|
|
2008-02-03 12:47:33 +00:00
|
|
|
|
ast_cli_register(&cli_reload_routing);
|
|
|
|
|
ast_cli_register(&cli_reload_interfaces);
|
|
|
|
|
ast_cli_register(&cli_port_block);
|
|
|
|
|
ast_cli_register(&cli_port_unblock);
|
2008-04-26 08:32:30 +00:00
|
|
|
|
ast_cli_register(&cli_port_unload);
|
2008-01-21 08:34:38 +00:00
|
|
|
|
|
|
|
|
|
ast_register_application("misdn_set_opt", misdn_set_opt_exec, "misdn_set_opt",
|
|
|
|
|
"misdn_set_opt(:<opt><optarg>:<opt><optarg>..):\n"
|
|
|
|
|
"Sets mISDN opts. and optargs\n"
|
|
|
|
|
"\n"
|
|
|
|
|
"The available options are:\n"
|
|
|
|
|
" d - Send display text on called phone, text is the optparam\n"
|
|
|
|
|
" n - don't detect dtmf tones on called channel\n"
|
|
|
|
|
" h - make digital outgoing call\n"
|
|
|
|
|
" c - make crypted outgoing call, param is keyindex\n"
|
|
|
|
|
" e - perform echo cancelation on this channel,\n"
|
|
|
|
|
" takes taps as arguments (32,64,128,256)\n"
|
|
|
|
|
" s - send Non Inband DTMF as inband\n"
|
|
|
|
|
" vr - rxgain control\n"
|
|
|
|
|
" vt - txgain control\n"
|
|
|
|
|
);
|
2008-01-19 17:10:46 +00:00
|
|
|
|
|
2007-07-15 10:03:09 +00:00
|
|
|
|
|
2008-01-21 08:34:38 +00:00
|
|
|
|
lcr_cfg_get( 0, LCR_GEN_TRACEFILE, global_tracefile, BUFFERSIZE);
|
|
|
|
|
|
|
|
|
|
chan_lcr_log(0, 0, "-- mISDN Channel Driver Registred -- (BE AWARE THIS DRIVER IS EXPERIMENTAL!)\n");
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int unload_module(void)
|
|
|
|
|
{
|
|
|
|
|
/* First, take us out of the channel loop */
|
|
|
|
|
ast_log(LOG_VERBOSE, "-- Unregistering mISDN Channel Driver --\n");
|
|
|
|
|
|
|
|
|
|
misdn_tasks_destroy();
|
|
|
|
|
|
|
|
|
|
if (!g_config_initialized) return 0;
|
|
|
|
|
|
2008-02-03 12:47:33 +00:00
|
|
|
|
ast_cli_unregister(&cli_show_lcr);
|
|
|
|
|
ast_cli_unregister(&cli_show_calls);
|
|
|
|
|
ast_cli_unregister(&cli_reload_routing);
|
|
|
|
|
ast_cli_unregister(&cli_reload_interfaces);
|
|
|
|
|
ast_cli_unregister(&cli_port_block);
|
|
|
|
|
ast_cli_unregister(&cli_port_unblock);
|
2008-01-21 08:34:38 +00:00
|
|
|
|
ast_unregister_application("misdn_set_opt");
|
|
|
|
|
|
|
|
|
|
ast_channel_unregister(&lcr_tech);
|
|
|
|
|
|
|
|
|
|
if (mISDN_created) {
|
|
|
|
|
bchannel_deinitialize();
|
|
|
|
|
mISDN_created = 0;
|
2007-07-15 10:03:09 +00:00
|
|
|
|
}
|
2008-01-21 08:34:38 +00:00
|
|
|
|
|
|
|
|
|
if (lcr_sock >= 0) {
|
|
|
|
|
close(lcr_sock);
|
|
|
|
|
lcr_sock = -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
was ist mit dem mutex
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int reload(void)
|
|
|
|
|
{
|
|
|
|
|
reload_config();
|
|
|
|
|
|
|
|
|
|
return 0;
|
2007-07-15 10:03:09 +00:00
|
|
|
|
}
|
|
|
|
|
|
2008-01-21 08:34:38 +00:00
|
|
|
|
int usecount(void)
|
|
|
|
|
{
|
|
|
|
|
int res;
|
|
|
|
|
ast_mutex_lock(&usecnt_lock);
|
|
|
|
|
res = usecnt;
|
|
|
|
|
ast_mutex_unlock(&usecnt_lock);
|
|
|
|
|
return res;
|
|
|
|
|
}
|
2007-07-15 10:03:09 +00:00
|
|
|
|
|
2008-01-21 08:34:38 +00:00
|
|
|
|
char *description(void)
|
|
|
|
|
{
|
|
|
|
|
return desc;
|
|
|
|
|
}
|
2007-07-15 10:03:09 +00:00
|
|
|
|
|
2008-01-21 08:34:38 +00:00
|
|
|
|
char *key(void)
|
|
|
|
|
{
|
|
|
|
|
return ASTERISK_GPL_KEY;
|
|
|
|
|
}
|
2007-07-15 10:03:09 +00:00
|
|
|
|
|
|
|
|
|
|