Removed complete bchannel handling from chan_lcr

The remote application interface does not allow any bchannel to be
exported or imported. Audio traffic via socket interface is used instead.

The joinremote instance became obsolete and is removed.

The remote action (routing) became obsolete, use interface.conf instead.

The handling of loopback device became obsolete and was removed

The chan_lcr does not rely on mISDN anymore, that means:
- can be used with GSM and without mISDN at all.
- chan_lcr can be used as internal extension of LCR (e.g. SIP phone)
  (chan_lcr can be handled as any other interface)
- no loopback device to be used anymore.
This commit is contained in:
Andreas Eversberg 2012-07-27 17:20:43 +02:00
parent 6911e09b77
commit f6aea744f8
34 changed files with 490 additions and 2428 deletions

View File

@ -46,7 +46,7 @@ INSTALLATION_DEFINES = \
if ENABLE_MISDN
MISDN_INCLUDE = -DWITH_MISDN -DWITH_CRYPT
MISDN_SOURCE = mISDN.cpp dss1.cpp loop.c crypt.cpp remote.cpp joinremote.cpp
MISDN_SOURCE = mISDN.cpp dss1.cpp crypt.cpp
MISDN_LIB = -lmisdn
endif
@ -116,18 +116,15 @@ if ENABLE_ASTERISK_CHANNEL_DRIVER
noinst_PROGRAMS = chan_lcr.so
chan_lcr_so_SOURCES =
chan_lcr_so_LDFLAGS = -shared
chan_lcr_so_LDADD = chan_lcr.po bchannel.po options.po callerid.po select.po
chan_lcr_so_LDADD = chan_lcr.po options.po callerid.po select.po
# List chan_lcr specific sources for make dist
EXTRA_chan_lcr_so_SOURCES = chan_lcr.c chan_lcr.h bchannel.c bchannel.h
EXTRA_chan_lcr_so_SOURCES = chan_lcr.c chan_lcr.h
chan_lcr.po: chan_lcr.c chan_lcr.h
$(CC) $(INCLUDES) $(AST_CFLAGS) $(CPPFLAGS) $(CFLAGS) -D_GNU_SOURCE -fPIC -c $< -o $@
bchannel.po: bchannel.c bchannel.h
$(CC) $(INCLUDES) -D_GNU_SOURCE $(CPPFLAGS) $(CFLAGS) -fPIC -c $< -o $@
callerid.po: callerid.c callerid.h
$(CC) $(INCLUDES) -D_GNU_SOURCE $(CPPFLAGS) $(CFLAGS) -fPIC -c $< -o $@
@ -149,7 +146,7 @@ INCLUDES = $(all_includes) $(MISDN_INCLUDE) $(GSM_INCLUDE) $(SS5_INCLUDE) $(SIP_
lcr_SOURCES = \
main.c select.c trace.c options.c tones.c alawulaw.c cause.c interface.c message.c callerid.c socket_server.c \
port.cpp vbox.cpp \
port.cpp vbox.cpp remote.cpp \
$(MISDN_SOURCE) $(GSM_SOURCE) $(SS5_SOURCE) $(SIP_SOURCE) \
endpoint.cpp endpointapp.cpp \
appbridge.cpp apppbx.cpp route.c action.cpp action_efi.cpp action_vbox.cpp extension.c mail.c \
@ -168,7 +165,7 @@ noinst_HEADERS = \
message.h callerid.h socket_server.h port.h vbox.h endpoint.h endpointapp.h \
appbridge.h apppbx.h route.h extension.h join.h joinpbx.h lcrsocket.h
noinst_HEADERS += myisdn.h mISDN.h dss1.h loop.h crypt.h remote.h joinremote.h
noinst_HEADERS += myisdn.h mISDN.h dss1.h crypt.h remote.h
noinst_HEADERS += ss5.h ss5_encode.h ss5_decode.h
noinst_HEADERS += mncc.h gsm.h gsm_audio.h gsm_bs.h gsm_ms.h
noinst_HEADERS += ie.cpp sip.h
@ -184,7 +181,7 @@ EXTRA_DIST = default debian $(TONEDIRS)
install-data-hook:
@fns='strcpy strncpy strcat strncat sprintf snprintf' ; \
files=$$( find $(srcdir) -type f -name "*.c*" \
| $(GREP) -v -e chan_lcr.c -e bchannel.c -e callerid.c ) ; \
| $(GREP) -v -e chan_lcr.c -e callerid.c ) ; \
test -z "$$files" || { for fn in $$fns ; do \
$(GREP) -n $$fn $$files ; if test $$? = 0 ; then \
( echo "dont use $$fn, use makro instead." ; exit -1 ) ; \

View File

@ -15,9 +15,9 @@ extern char **environ;
/*
* process init 'internal' / 'external' / 'remote' / 'vbox-record' / 'partyline'...
* process init 'internal' / 'external' / 'vbox-record' / 'partyline'...
*/
int EndpointAppPBX::_action_init_call(char *remote)
void EndpointAppPBX::action_init_call(void)
{
class Join *join;
@ -25,47 +25,16 @@ int EndpointAppPBX::_action_init_call(char *remote)
if (ea_endpoint->ep_join_id) {
if (options.deb & DEBUG_EPOINT)
PERROR("EPOINT(%d): We already have a call instance, this should never happen!\n", ea_endpoint->ep_serial);
return(0);
return;
}
/* create join */
PDEBUG(DEBUG_EPOINT, "EPOINT(%d): Creating new join instance.\n", ea_endpoint->ep_serial);
#ifdef WITH_MISDN
if (remote) {
struct port_list *portlist = ea_endpoint->ep_portlist;
struct admin_list *admin;
admin = admin_first;
while(admin) {
if (admin->remote_name[0] && !strcmp(admin->remote_name, remote))
break;
admin = admin->next;
}
if (!admin) {
/* resource not available */
trace_header("ACTION remote (not available)", DIRECTION_NONE);
add_trace("application", NULL, "%s", remote);
end_trace();
message_disconnect_port(portlist, CAUSE_OUTOFORDER, LOCATION_PRIVATE_LOCAL, "");
new_state(EPOINT_STATE_OUT_DISCONNECT);
set_tone(portlist,"cause_1b");
return(0);
}
join = new JoinRemote(ea_endpoint->ep_serial, remote, admin->sock);
} else
#endif
join = new JoinPBX(ea_endpoint);
join = new JoinPBX(ea_endpoint);
if (!join)
FATAL("No memoy for Join instance.\n");
ea_endpoint->ep_join_id = join->j_serial;
return(1);
}
void EndpointAppPBX::action_init_call(void)
{
_action_init_call(NULL);
}
void EndpointAppPBX::action_init_remote(void)
{
return;
}
/*
@ -222,6 +191,9 @@ void EndpointAppPBX::action_dialing_external(void)
if ((rparam = routeparam(e_action, PARAM_PREFIX)))
SPRINT(dialinginfo.id, "%s%s", rparam->string_value, e_extdialing);
if ((rparam = routeparam(e_action, PARAM_CONTEXT)))
SCPY(dialinginfo.context, rparam->string_value);
/* process keypad */
if ((rparam = routeparam(e_action, PARAM_KEYPAD))) {
SCPY(dialinginfo.keypad, dialinginfo.id);
@ -333,78 +305,6 @@ void EndpointAppPBX::action_dialing_external(void)
}
void EndpointAppPBX::action_dialing_remote(void)
{
struct route_param *rparam;
struct port_list *portlist = ea_endpoint->ep_portlist;
struct lcr_msg *message;
struct capa_info capainfo;
struct caller_info callerinfo;
struct redir_info redirinfo;
struct dialing_info dialinginfo;
char context[128] = "";
char remote[32];
if (!ea_endpoint->ep_join_id) {
/* no join yet, sending setup */
if (!(rparam = routeparam(e_action, PARAM_APPLICATION))) {
trace_header("ACTION remote (no application given)", DIRECTION_NONE);
end_trace();
new_state(EPOINT_STATE_OUT_DISCONNECT);
message_disconnect_port(portlist, CAUSE_SERVICEUNAVAIL, LOCATION_PRIVATE_LOCAL, "");
set_tone(portlist, "cause_3f");
return;
}
SCPY(remote, rparam->string_value);
if (!_action_init_call(remote))
return;
/* create bearer/caller/dialinginfo */
memcpy(&capainfo, &e_capainfo, sizeof(capainfo));
memcpy(&callerinfo, &e_callerinfo, sizeof(callerinfo));
memcpy(&redirinfo, &e_redirinfo, sizeof(redirinfo));
memset(&dialinginfo, 0, sizeof(dialinginfo));
if ((rparam = routeparam(e_action, PARAM_CONTEXT))) {
SCPY(context, rparam->string_value);
}
if ((rparam = routeparam(e_action, PARAM_EXTEN))) {
SCPY(dialinginfo.id, rparam->string_value);
dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
} else {
SCPY(dialinginfo.id, e_extdialing);
}
e_extdialing = e_dialinginfo.id + strlen(e_dialinginfo.id);
/* send setup to remote */
trace_header("ACTION remote (setup)", DIRECTION_NONE);
add_trace("number", NULL, dialinginfo.id);
add_trace("remote", NULL, remote);
if (context[0])
add_trace("context", NULL, context);
end_trace();
message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_SETUP);
memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
memcpy(&message->param.setup.redirinfo, &redirinfo, sizeof(struct redir_info));
memcpy(&message->param.setup.callerinfo, &callerinfo, sizeof(struct caller_info));
memcpy(&message->param.setup.capainfo, &capainfo, sizeof(struct capa_info));
SCPY(message->param.setup.context, context);
message_put(message);
} else {
/* send overlap digits */
trace_header("ACTION remote (dialing)", DIRECTION_NONE);
add_trace("number", NULL, e_extdialing);
end_trace();
if (e_extdialing[0]) {
message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_INFORMATION);
memcpy(&message->param.information, &e_dialinginfo, sizeof(struct dialing_info));
SCPY(message->param.information.id, e_extdialing);
e_extdialing = e_dialinginfo.id + strlen(e_dialinginfo.id);
message_put(message);
}
}
}
/*
* process dialing the "am" and record
*/
@ -2277,12 +2177,6 @@ void EndpointAppPBX::process_dialing(int timeout)
e_action = &action_internal;
goto process_action;
}
/* check for chan call */
if (!strncmp(e_dialinginfo.id, "remote:", 7)) {
e_extdialing = e_dialinginfo.id+7;
e_action = &action_remote;
goto process_action;
}
/* check for vbox call */
if (!strncmp(e_dialinginfo.id, "vbox:", 5)) {
e_extdialing = e_dialinginfo.id+5;

View File

@ -136,6 +136,24 @@ fail:
/* create port for interface */
SPRINT(portname, "%s-%d-out", interface_out->name, 0);
memset(&port_settings, 0, sizeof(port_settings));
#ifdef WITH_MISDN
if (interface_out->remote) {
struct admin_list *admin;
admin = admin_first;
while(admin) {
if (admin->remote_name[0] && !strcmp(admin->remote_name, interface_out->remote_app))
break;
admin = admin->next;
}
if (!admin) {
trace_header("INTERFACE (remote not connected)", DIRECTION_NONE);
add_trace("application", NULL, "%s", interface_out->remote_app);
end_trace();
goto fail;
}
port = new Premote(PORT_TYPE_REMOTE_OUT, portname, &port_settings, interface_out, admin->sock);
} else
#endif
#ifdef WITH_SIP
if (interface_out->sip) {
port = new Psip(PORT_TYPE_SIP_OUT, portname, &port_settings, interface_out);
@ -156,7 +174,6 @@ fail:
#ifdef WITH_MISDN
struct mISDNport *mISDNport;
int channel = 0;
struct admin_list *admin;
int earlyb;
int mode = B_MODE_TRANSPARENT;
@ -176,23 +193,7 @@ fail:
port = ss5_hunt_line(mISDNport);
else
#endif
if (mISDNport->ifport->remote) {
admin = admin_first;
while(admin) {
if (admin->remote_name[0] && !strcmp(admin->remote_name, mISDNport->ifport->remote_app))
break;
admin = admin->next;
}
if (!admin) {
trace_header("INTERFACE (remote not connected)", DIRECTION_NONE);
add_trace("application", NULL, "%s", mISDNport->ifport->remote_app);
end_trace();
cause = 27;
goto fail;
}
port = new Premote(PORT_TYPE_REMOTE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode, admin->sock);
} else
port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
earlyb = mISDNport->earlyb;
#else
trace_header("INTERFACE (has no function)", DIRECTION_NONE);

View File

@ -615,8 +615,8 @@ void EndpointAppPBX::out_setup(int cfnr)
struct port_settings port_settings;
#ifdef WITH_MISDN
int channel = 0;
struct admin_list *admin;
#endif
struct admin_list *admin;
int earlyb;
int mode = B_MODE_TRANSPARENT;
@ -741,6 +741,23 @@ void EndpointAppPBX::out_setup(int cfnr)
}
/* found interface */
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) calling to interface %s\n", ea_endpoint->ep_serial, ifname);
if (interface->remote) {
admin = admin_first;
while(admin) {
if (admin->remote_name[0] && !strcmp(admin->remote_name, interface->remote_app))
break;
admin = admin->next;
}
if (!admin) {
trace_header("INTERFACE (remote not connected)", DIRECTION_NONE);
add_trace("application", NULL, "%s", interface->remote_app);
end_trace();
continue;
}
SPRINT(portname, "%s-%d-out", interface->name, 0);
port = new Premote(PORT_TYPE_REMOTE_OUT, portname, &port_settings, interface, admin->sock);
earlyb = (interface->is_earlyb == IS_YES);
} else
#ifdef WITH_GSM_BS
if (interface->gsm_bs) {
SPRINT(portname, "%s-%d-out", interface->name, 0);
@ -779,22 +796,7 @@ void EndpointAppPBX::out_setup(int cfnr)
port = ss5_hunt_line(mISDNport);
else
#endif
if (mISDNport->ifport->remote) {
admin = admin_first;
while(admin) {
if (admin->remote_name[0] && !strcmp(admin->remote_name, mISDNport->ifport->remote_app))
break;
admin = admin->next;
}
if (!admin) {
trace_header("INTERFACE (remote not connected)", DIRECTION_NONE);
add_trace("application", NULL, "%s", mISDNport->ifport->remote_app);
end_trace();
continue;
}
port = new Premote(PORT_TYPE_REMOTE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode, admin->sock);
} else
port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
earlyb = mISDNport->earlyb;
#else
trace_header("INTERFACE (has no function)", DIRECTION_NONE);
@ -1021,6 +1023,23 @@ void EndpointAppPBX::out_setup(int cfnr)
continue;
}
/* found interface */
if (interface->remote) {
admin = admin_first;
while(admin) {
if (admin->remote_name[0] && !strcmp(admin->remote_name, interface->remote_app))
break;
admin = admin->next;
}
if (!admin) {
trace_header("INTERFACE (remote not connected)", DIRECTION_NONE);
add_trace("application", NULL, "%s", interface->remote_app);
end_trace();
continue;
}
SPRINT(portname, "%s-%d-out", interface->name, 0);
port = new Premote(PORT_TYPE_REMOTE_OUT, portname, &port_settings, interface, admin->sock);
earlyb = (interface->is_earlyb == IS_YES);
} else
#ifdef WITH_GSM_BS
if (interface->gsm_bs) {
SPRINT(portname, "%s-%d-out", interface->name, 0);
@ -1060,22 +1079,7 @@ void EndpointAppPBX::out_setup(int cfnr)
port = ss5_hunt_line(mISDNport);
else
#endif
if (mISDNport->ifport->remote) {
admin = admin_first;
while(admin) {
if (admin->remote_name[0] && !strcmp(admin->remote_name, mISDNport->ifport->remote_app))
break;
admin = admin->next;
}
if (!admin) {
trace_header("INTERFACE (remote not connected)", DIRECTION_NONE);
add_trace("application", NULL, "%s", mISDNport->ifport->remote_app);
end_trace();
continue;
}
port = new Premote(PORT_TYPE_REMOTE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode, admin->sock);
} else
port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
earlyb = mISDNport->earlyb;
#else
trace_header("INTERFACE (has no function)", DIRECTION_NONE);
@ -1568,8 +1572,7 @@ void EndpointAppPBX::port_information(struct port_list *portlist, int message_ty
}
if (e_action)
if (e_action->index==ACTION_OUTDIAL
|| e_action->index==ACTION_EXTERNAL
|| e_action->index==ACTION_REMOTE) {
|| e_action->index==ACTION_EXTERNAL) {
if (!e_extdialing)
set_tone(portlist, "dialing");
else if (!e_extdialing[0])

View File

@ -258,13 +258,10 @@ class EndpointAppPBX : public EndpointApp
struct route_param *routeparam(struct route_action *action, unsigned long long id);
/* init / dialing / hangup */
int _action_init_call(char *remote);
void action_init_call(void);
void action_init_remote(void);
void action_dialing_internal(void);
void action_dialing_external(void);
void action_dialing_h323(void);
void action_dialing_remote(void);
void action_dialing_vbox_record(void);
void action_init_partyline(void);
void action_hangup_call(void);

View File

@ -1,720 +0,0 @@
/*****************************************************************************\
** **
** Linux Call Router **
** **
**---------------------------------------------------------------------------**
** Copyright: Andreas Eversberg **
** **
** mISDN channel handlin for remote application **
** **
\*****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <poll.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <netinet/udp.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/socket.h>
#include <mISDN/mISDNif.h>
#include <mISDN/mISDNcompat.h>
int __af_isdn = MISDN_AF_ISDN;
#include <mISDN/q931.h>
#define HAVE_ATTRIBUTE_always_inline 1
#define HAVE_ARPA_INET_H 1
#define HAVE_TIMERSUB 1
#include <asterisk/autoconfig.h>
#include <asterisk/compiler.h>
#include <asterisk/frame.h>
/* Choose if you want to have chan_lcr for Asterisk 1.4.x or CallWeaver 1.2.x */
/* #define LCR_FOR_CALLWEAVER */
#ifdef LCR_FOR_CALLWEAVER
#include <asterisk/phone_no_utils.h>
#include <asterisk/logger.h>
#include <asterisk/module.h>
#include <asterisk/channel.h>
#endif
#include "extension.h"
#include "message.h"
#include "lcrsocket.h"
#include "cause.h"
#include "select.h"
#include "bchannel.h"
#include "chan_lcr.h"
#include "callerid.h"
#include "options.h"
#ifndef ISDN_PID_L4_B_USER
#define ISDN_PID_L4_B_USER 0x440000ff
#endif
pid_t bchannel_pid;
enum {
BSTATE_IDLE,
BSTATE_ACTIVATING,
BSTATE_ACTIVE,
BSTATE_DEACTIVATING,
};
static void bchannel_send_queue(struct bchannel *bchannel);
int bchannel_initialize(void)
{
return 0;
}
void bchannel_deinitialize(void)
{
}
/*
* send control information to the channel (dsp-module)
*/
static void ph_control(int sock, unsigned int c1, unsigned int c2, char *trace_name, int trace_value, int b_mode)
{
unsigned char buffer[MISDN_HEADER_LEN+sizeof(int)+sizeof(int)];
struct mISDNhead *ctrl = (struct mISDNhead *)buffer;
unsigned int *d = (unsigned int *)(buffer+MISDN_HEADER_LEN);
int ret;
if (b_mode != 0 && b_mode != 2)
return;
CDEBUG(NULL, NULL, "Sending PH_CONTROL %s %x,%x\n", trace_name, c1, c2);
ctrl->prim = PH_CONTROL_REQ;
ctrl->id = 0;
*d++ = c1;
*d++ = c2;
ret = sendto(sock, buffer, MISDN_HEADER_LEN+sizeof(int)*2, 0, NULL, 0);
if (ret < 0)
CERROR(NULL, NULL, "Failed to send to socket %d\n", sock);
}
static void ph_control_block(int sock, unsigned int c1, void *c2, int c2_len, char *trace_name, int trace_value, int b_mode)
{
unsigned char buffer[MISDN_HEADER_LEN+sizeof(int)+c2_len];
struct mISDNhead *ctrl = (struct mISDNhead *)buffer;
unsigned int *d = (unsigned int *)(buffer+MISDN_HEADER_LEN);
int ret;
if (b_mode != 0 && b_mode != 2)
return;
CDEBUG(NULL, NULL, "Sending PH_CONTROL (block) %s %x\n", trace_name, c1);
ctrl->prim = PH_CONTROL_REQ;
ctrl->id = 0;
*d++ = c1;
memcpy(d, c2, c2_len);
ret = sendto(sock, buffer, MISDN_HEADER_LEN+sizeof(int)+c2_len, 0, NULL, 0);
if (ret < 0)
CERROR(NULL, NULL, "Failed to send to socket %d\n", sock);
}
static int bchannel_handle(struct lcr_fd *fd, unsigned int what, void *instance, int index);
/*
* create stack
*/
int bchannel_create(struct bchannel *bchannel, int mode, int queue)
{
int ret;
struct sockaddr_mISDN addr;
if (bchannel->b_sock > -1) {
CERROR(bchannel->call, NULL, "Socket already created for handle 0x%x\n", bchannel->handle);
return 0;
}
/* open socket */
bchannel->b_mode = (mode & 3);
switch(bchannel->b_mode) {
case 0:
CDEBUG(bchannel->call, NULL, "Open DSP audio\n");
bchannel->b_sock = socket(PF_ISDN, SOCK_DGRAM, ISDN_P_B_L2DSP);
break;
case 1:
CDEBUG(bchannel->call, NULL, "Open audio\n");
bchannel->b_sock = socket(PF_ISDN, SOCK_DGRAM, ISDN_P_B_RAW);
break;
case 2:
CDEBUG(bchannel->call, NULL, "Open DSP HDLC\n");
bchannel->b_sock = socket(PF_ISDN, SOCK_DGRAM, ISDN_P_B_L2DSPHDLC);
break;
case 3:
CDEBUG(bchannel->call, NULL, "Open HDLC\n");
bchannel->b_sock = socket(PF_ISDN, SOCK_DGRAM, ISDN_P_B_HDLC);
break;
}
if (bchannel->b_sock < 0) {
CERROR(bchannel->call, NULL, "Failed to open bchannel-socket for handle 0x%x with mISDN-DSP layer. Did you load mISDN_dsp.ko?\n", bchannel->handle);
return 0;
}
/* register fd */
memset(&bchannel->lcr_fd, 0, sizeof(bchannel->lcr_fd));
bchannel->lcr_fd.fd = bchannel->b_sock;
register_fd(&bchannel->lcr_fd, LCR_FD_READ | LCR_FD_EXCEPT, bchannel_handle, bchannel, 0);
/* bind socket to bchannel */
addr.family = AF_ISDN;
addr.dev = (bchannel->handle>>8);
addr.channel = bchannel->handle & 0xff;
ret = bind(bchannel->b_sock, (struct sockaddr *)&addr, sizeof(addr));
if (ret < 0) {
CERROR(bchannel->call, NULL, "Failed to bind bchannel-socket for handle 0x%x with mISDN-DSP layer. (port %d, channel %d) Did you load mISDN_dsp.ko?\n", bchannel->handle, addr.dev, addr.channel);
unregister_fd(&bchannel->lcr_fd);
close(bchannel->b_sock);
bchannel->b_sock = -1;
return 0;
}
/* queue */
if (bchannel->b_mode == 1 && queue) {
bchannel->nodsp_queue_out = 0;
bchannel->nodsp_queue_in = queue * 8;
if (bchannel->nodsp_queue_in > QUEUE_BUFFER_MAX-1)
bchannel->nodsp_queue_in = QUEUE_BUFFER_MAX-1;
bchannel->nodsp_queue = bchannel->nodsp_queue_in; /* store initial load */
memset(&bchannel->nodsp_queue_buffer, (options.law=='a')?0x2a:0xff, QUEUE_BUFFER_SIZE);
bchannel->queue_sent = 0;
} else
bchannel->nodsp_queue = 0;
return 1;
}
/*
* activate / deactivate request
*/
void bchannel_activate(struct bchannel *bchannel, int activate)
{
struct mISDNhead act;
int ret;
/* activate bchannel */
CDEBUG(bchannel->call, NULL, "%sActivating B-channel.\n", activate?"":"De-");
switch(bchannel->b_mode) {
case 0:
case 2:
act.prim = (activate)?DL_ESTABLISH_REQ:DL_RELEASE_REQ;
break;
case 1:
case 3:
act.prim = (activate)?PH_ACTIVATE_REQ:PH_DEACTIVATE_REQ;
break;
}
act.id = 0;
ret = sendto(bchannel->b_sock, &act, MISDN_HEADER_LEN, 0, NULL, 0);
if (ret < 0)
CERROR(bchannel->call, NULL, "Failed to send to socket %d\n", bchannel->b_sock);
bchannel->b_state = (activate)?BSTATE_ACTIVATING:BSTATE_DEACTIVATING;
}
/*
* set features
*/
static void bchannel_activated(struct bchannel *bchannel)
{
int sock;
sock = bchannel->b_sock;
/* set dsp features */
if (bchannel->b_txdata)
ph_control(sock, (bchannel->b_txdata)?DSP_TXDATA_ON:DSP_TXDATA_OFF, 0, "DSP-TXDATA", bchannel->b_txdata, bchannel->b_mode);
if (bchannel->b_delay && bchannel->b_mode == 0)
ph_control(sock, DSP_DELAY, bchannel->b_delay, "DSP-DELAY", bchannel->b_delay, bchannel->b_mode);
if (bchannel->b_tx_dejitter && bchannel->b_mode == 0)
ph_control(sock, (bchannel->b_tx_dejitter)?DSP_TX_DEJITTER:DSP_TX_DEJ_OFF, 0, "DSP-TX_DEJITTER", bchannel->b_tx_dejitter, bchannel->b_mode);
if (bchannel->b_tx_gain && bchannel->b_mode == 0)
ph_control(sock, DSP_VOL_CHANGE_TX, bchannel->b_tx_gain, "DSP-TX_GAIN", bchannel->b_tx_gain, bchannel->b_mode);
if (bchannel->b_rx_gain && bchannel->b_mode == 0)
ph_control(sock, DSP_VOL_CHANGE_RX, bchannel->b_rx_gain, "DSP-RX_GAIN", bchannel->b_rx_gain, bchannel->b_mode);
if (bchannel->b_pipeline[0] && bchannel->b_mode == 0)
ph_control_block(sock, DSP_PIPELINE_CFG, bchannel->b_pipeline, strlen(bchannel->b_pipeline)+1, "DSP-PIPELINE", 0, bchannel->b_mode);
if (bchannel->b_conf)
ph_control(sock, DSP_CONF_JOIN, bchannel->b_conf, "DSP-CONF", bchannel->b_conf, bchannel->b_mode);
if (bchannel->b_echo)
ph_control(sock, DSP_ECHO_ON, 0, "DSP-ECHO", 1, bchannel->b_mode);
if (bchannel->b_tone && bchannel->b_mode == 0)
ph_control(sock, DSP_TONE_PATT_ON, bchannel->b_tone, "DSP-TONE", bchannel->b_tone, bchannel->b_mode);
if (bchannel->b_rxoff)
ph_control(sock, DSP_RECEIVE_OFF, 0, "DSP-RXOFF", 1, bchannel->b_mode);
// if (bchannel->b_txmix && bchannel->b_mode == 0)
// ph_control(sock, DSP_MIX_ON, 0, "DSP-MIX", 1, bchannel->b_mode);
if (bchannel->b_dtmf && bchannel->b_mode == 0)
ph_control(sock, DTMF_TONE_START, 0, "DSP-DTMF", 1, bchannel->b_mode);
if (bchannel->b_bf_len && bchannel->b_mode == 0)
ph_control_block(sock, DSP_BF_ENABLE_KEY, bchannel->b_bf_key, bchannel->b_bf_len, "DSP-CRYPT", bchannel->b_bf_len, bchannel->b_mode);
if (bchannel->b_conf)
ph_control(sock, DSP_CONF_JOIN, bchannel->b_conf, "DSP-CONF", bchannel->b_conf, bchannel->b_mode);
bchannel->b_state = BSTATE_ACTIVE;
}
/*
* destroy stack
*/
void bchannel_destroy(struct bchannel *bchannel)
{
if (bchannel->b_sock > -1) {
unregister_fd(&bchannel->lcr_fd);
close(bchannel->b_sock);
bchannel->b_sock = -1;
}
bchannel->b_state = BSTATE_IDLE;
}
/*
* whenever we get audio data from bchannel, we process it here
*/
static void bchannel_receive(struct bchannel *bchannel, unsigned char *buffer, int len)
{
struct mISDNhead *hh = (struct mISDNhead *)buffer;
unsigned char *data = buffer + MISDN_HEADER_LEN;
unsigned int cont = *((unsigned int *)data);
unsigned char *d;
int i;
struct bchannel *remote_bchannel;
int ret;
if (hh->prim == PH_CONTROL_IND) {
/* non dsp -> ignore ph_control */
if (bchannel->b_mode == 1 || bchannel->b_mode == 3)
return;
if (len < 4) {
CERROR(bchannel->call, NULL, "SHORT READ OF PH_CONTROL INDICATION\n");
return;
}
if ((cont&(~DTMF_TONE_MASK)) == DTMF_TONE_VAL) {
if (bchannel->call)
lcr_in_dtmf(bchannel->call, cont & DTMF_TONE_MASK);
return;
}
switch(cont) {
case DSP_BF_REJECT:
CERROR(bchannel->call, NULL, "Blowfish crypt rejected.\n");
break;
case DSP_BF_ACCEPT:
CDEBUG(bchannel->call, NULL, "Blowfish crypt enabled.\n");
break;
default:
CDEBUG(bchannel->call, NULL, "Unhandled bchannel control 0x%x.\n", cont);
}
return;
}
if (hh->prim == PH_DATA_REQ) {
if (!bchannel->b_txdata) {
/* if tx is off, it may happen that fifos send us pending informations, we just ignore them */
CDEBUG(bchannel->call, NULL, "ignoring tx data, because 'txdata' is turned off\n");
return;
}
return;
}
if (hh->prim != PH_DATA_IND && hh->prim != DL_DATA_IND) {
CERROR(bchannel->call, NULL, "Bchannel received unknown primitve: 0x%lx\n", hh->prim);
return;
}
/* if calls are bridged, but not via dsp (no b_conf), forward here */
if (!bchannel->b_conf
&& bchannel->call
&& bchannel->call->bridge_call
&& bchannel->call->bridge_call->bchannel) {
remote_bchannel = bchannel->call->bridge_call->bchannel;
#if 0
int i = 0;
char string[4096] = "";
while(i < len) {
sprintf(string+strlen(string), " %02x", data[i]);
i++;
}
CDEBUG(remote_bchannel->call, NULL, "Forwarding packet%s\n", string);
#endif
hh->prim = PH_DATA_REQ;
hh->id = 0;
ret = sendto(remote_bchannel->b_sock, buffer, MISDN_HEADER_LEN+len, 0, NULL, 0);
if (ret < 0)
CERROR(remote_bchannel->call, NULL, "Failed to send to socket %d\n", bchannel->b_sock);
return;
}
/* calls will not process any audio data unless
* the call is connected OR interface features audio during call setup.
*/
/* if rx is off, it may happen that fifos send us pending informations, we just ignore them */
if (bchannel->b_rxoff) {
CDEBUG(bchannel->call, NULL, "ignoring data, because rx is turned off\n");
return;
}
if (!bchannel->call) {
CDEBUG(bchannel->call, NULL, "ignoring data, because no call associated with bchannel\n");
return;
}
if (!bchannel->call->audiopath) {
/* return, because we have no audio from port */
return;
}
if (bchannel->call->pipe[1] < 0) {
/* nobody there */
return;
}
/* if no hdlc */
if (bchannel->b_mode == 0 || bchannel->b_mode == 1) {
d = data;
for (i = 0; i < len; i++) {
*d = flip_bits[*d];
d++;
}
}
len = write(bchannel->call->pipe[1], data, len);
if (len < 0)
goto errout;
return;
errout:
close(bchannel->call->pipe[1]);
bchannel->call->pipe[1] = -1;
CDEBUG(bchannel->call, NULL, "broken pipe on bchannel pipe\n");
}
/*
* transmit data to bchannel
*/
void bchannel_transmit(struct bchannel *bchannel, unsigned char *data, int len)
{
unsigned char buff[1024 + MISDN_HEADER_LEN], *p = buff + MISDN_HEADER_LEN;
struct mISDNhead *frm = (struct mISDNhead *)buff;
int ret;
int i;
int space, in;
if (bchannel->b_state != BSTATE_ACTIVE)
return;
if (len > 1024 || len < 1)
return;
if (data) {
switch(bchannel->b_mode) {
case 0:
for (i = 0; i < len; i++)
*p++ = flip_bits[*data++];
frm->prim = DL_DATA_REQ;
break;
case 1:
for (i = 0; i < len; i++)
*p++ = flip_bits[*data++];
frm->prim = PH_DATA_REQ;
break;
case 2:
memcpy(p, data, len);
frm->prim = DL_DATA_REQ;
break;
case 3:
memcpy(p, data, len);
frm->prim = PH_DATA_REQ;
break;
}
} else
memset(p, flip_bits[(options.law=='a')?0x2a:0xff], len);
frm->id = 0;
#ifdef SEAMLESS_TEST
unsigned char test_tone[8] = {0x2a, 0x24, 0xb4, 0x24, 0x2a, 0x25, 0xb5, 0x25};
p = buff + MISDN_HEADER_LEN;
for (i = 0; i < len; i++)
*p++ = test_tone[(bchannel->test + i) & 7];
bchannel->test = (bchannel->test + len) & 7;
#endif
if (bchannel->nodsp_queue) {
space = (bchannel->nodsp_queue_out - bchannel->nodsp_queue_in - 1) & (QUEUE_BUFFER_SIZE - 1);
if (len > space) {
CERROR(bchannel->call, NULL, "Queue buffer overflow, space is %d, len is %d.\n", space, len);
return;
}
p = buff + MISDN_HEADER_LEN;
in = bchannel->nodsp_queue_in;
for (i = 0; i < len; i++) {
bchannel->nodsp_queue_buffer[in] = *p++;
in = (in + 1) & (QUEUE_BUFFER_SIZE - 1);
}
bchannel->nodsp_queue_in = in;
if (bchannel->queue_sent == 0) /* if there is no pending data */
bchannel_send_queue(bchannel);
return;
}
ret = sendto(bchannel->b_sock, buff, MISDN_HEADER_LEN+len, 0, NULL, 0);
if (ret < 0)
CERROR(bchannel->call, NULL, "Failed to send to socket %d\n", bchannel->b_sock);
}
/*
* in case of a send queue, we send from that queue rather directly
*/
static void bchannel_send_queue(struct bchannel *bchannel)
{
unsigned char buff[1024 + MISDN_HEADER_LEN], *p = buff + MISDN_HEADER_LEN;
struct mISDNhead *frm = (struct mISDNhead *)buff;
int ret;
int i;
int len, out;
len = (bchannel->nodsp_queue_in - bchannel->nodsp_queue_out) & (QUEUE_BUFFER_SIZE - 1);
if (len == 0)
return; /* mISDN driver received all load */
#if 0
printf("%4d:(%s|%s)\n", bchannel->nodsp_queue_out,
"----------------------------------------------------------------"+64-len/(8192/64),
" "+len/(8192/64));
#endif
if (len > 1024)
len = 1024;
frm->prim = PH_DATA_REQ;
frm->id = 0;
out = bchannel->nodsp_queue_out;
for (i = 0; i < len; i++) {
*p++ = bchannel->nodsp_queue_buffer[out];
out = (out + 1) & (QUEUE_BUFFER_SIZE - 1);
}
bchannel->nodsp_queue_out = out;
ret = sendto(bchannel->b_sock, buff, MISDN_HEADER_LEN+len, 0, NULL, 0);
if (ret < 0)
CERROR(bchannel->call, NULL, "Failed to send to socket %d\n", bchannel->b_sock);
else
bchannel->queue_sent = 1;
}
/*
* join bchannel
*/
void bchannel_join(struct bchannel *bchannel, unsigned short id)
{
int sock;
sock = bchannel->b_sock;
if (id) {
bchannel->b_conf = (id<<16) + bchannel_pid;
bchannel->b_rxoff = 1;
} else {
bchannel->b_conf = 0;
bchannel->b_rxoff = 0;
}
if (bchannel->b_state == BSTATE_ACTIVE) {
ph_control(sock, DSP_RECEIVE_OFF, bchannel->b_rxoff, "DSP-RX_OFF", bchannel->b_conf, bchannel->b_mode);
ph_control(sock, DSP_CONF_JOIN, bchannel->b_conf, "DSP-CONF", bchannel->b_conf, bchannel->b_mode);
}
}
/*
* dtmf bchannel
*/
void bchannel_dtmf(struct bchannel *bchannel, int on)
{
int sock;
sock = bchannel->b_sock;
bchannel->b_dtmf = on;
if (bchannel->b_state == BSTATE_ACTIVE && bchannel->b_mode == 0)
ph_control(sock, on?DTMF_TONE_START:DTMF_TONE_STOP, 0, "DSP-DTMF", 1, bchannel->b_mode);
}
/*
* blowfish bchannel
*/
void bchannel_blowfish(struct bchannel *bchannel, unsigned char *key, int len)
{
int sock;
sock = bchannel->b_sock;
memcpy(bchannel->b_bf_key, key, len);
bchannel->b_bf_len = len;
if (bchannel->b_state == BSTATE_ACTIVE)
ph_control_block(sock, DSP_BF_ENABLE_KEY, bchannel->b_bf_key, bchannel->b_bf_len, "DSP-CRYPT", bchannel->b_bf_len, bchannel->b_mode);
}
/*
* pipeline bchannel
*/
void bchannel_pipeline(struct bchannel *bchannel, char *pipeline)
{
int sock;
sock = bchannel->b_sock;
strncpy(bchannel->b_pipeline, pipeline, sizeof(bchannel->b_pipeline)-1);
if (bchannel->b_state == BSTATE_ACTIVE)
ph_control_block(sock, DSP_PIPELINE_CFG, bchannel->b_pipeline, strlen(bchannel->b_pipeline)+1, "DSP-PIPELINE", 0, bchannel->b_mode);
}
/*
* gain bchannel
*/
void bchannel_gain(struct bchannel *bchannel, int gain, int tx)
{
int sock;
sock = bchannel->b_sock;
if (tx)
bchannel->b_tx_gain = gain;
else
bchannel->b_rx_gain = gain;
if (bchannel->b_state == BSTATE_ACTIVE && bchannel->b_mode == 0)
ph_control(sock, (tx)?DSP_VOL_CHANGE_TX:DSP_VOL_CHANGE_RX, gain, (tx)?"DSP-TX_GAIN":"DSP-RX_GAIN", gain, bchannel->b_mode);
}
/*
* main loop for processing messages from mISDN
*/
static int bchannel_handle(struct lcr_fd *fd, unsigned int what, void *instance, int index)
{
struct bchannel *bchannel = (struct bchannel *)instance;
int ret;
unsigned char buffer[2048+MISDN_HEADER_LEN];
struct mISDNhead *hh = (struct mISDNhead *)buffer;
ret = recv(bchannel->b_sock, buffer, sizeof(buffer), 0);
if (ret >= (int)MISDN_HEADER_LEN) {
switch(hh->prim) {
/* after a confim, we can send more from queue */
case PH_DATA_CNF:
if (bchannel->nodsp_queue) {
bchannel->queue_sent = 0;
bchannel_send_queue(bchannel);
}
break;
/* we receive audio data, we respond to it AND we send tones */
case PH_DATA_IND:
case PH_DATA_REQ:
case DL_DATA_IND:
case PH_CONTROL_IND:
bchannel_receive(bchannel, buffer, ret-MISDN_HEADER_LEN);
break;
case PH_ACTIVATE_IND:
case DL_ESTABLISH_IND:
case PH_ACTIVATE_CNF:
case DL_ESTABLISH_CNF:
CDEBUG(bchannel->call, NULL, "DL_ESTABLISH confirm: bchannel is now activated (socket %d).\n", bchannel->b_sock);
bchannel_activated(bchannel);
break;
case PH_DEACTIVATE_IND:
case DL_RELEASE_IND:
case PH_DEACTIVATE_CNF:
case DL_RELEASE_CNF:
CDEBUG(bchannel->call, NULL, "DL_RELEASE confirm: bchannel is now de-activated (socket %d).\n", bchannel->b_sock);
// bchannel_deactivated(bchannel);
break;
default:
CERROR(bchannel->call, NULL, "child message not handled: prim(0x%x) socket(%d) data len(%d)\n", hh->prim, bchannel->b_sock, ret - MISDN_HEADER_LEN);
}
} else {
// if (ret < 0 && errno != EWOULDBLOCK)
CERROR(bchannel->call, NULL, "Read from socket %d failed with return code %d\n", bchannel->b_sock, ret);
}
/* if we received at least one b-frame, we will return 1 */
return 0;
}
/*
* bchannel channel handling
*/
struct bchannel *bchannel_first = NULL;
struct bchannel *find_bchannel_handle(unsigned int handle)
{
struct bchannel *bchannel = bchannel_first;
while(bchannel) {
if (bchannel->handle == handle)
break;
bchannel = bchannel->next;
}
return bchannel;
}
#if 0
struct bchannel *find_bchannel_ref(unsigned int ref)
{
struct bchannel *bchannel = bchannel_first;
while(bchannel) {
if (bchannel->ref == ref)
break;
bchannel = bchannel->next;
}
return bchannel;
}
#endif
struct bchannel *alloc_bchannel(unsigned int handle)
{
struct bchannel **bchannelp = &bchannel_first;
while(*bchannelp)
bchannelp = &((*bchannelp)->next);
*bchannelp = (struct bchannel *)calloc(1, sizeof(struct bchannel));
if (!*bchannelp)
return NULL;
(*bchannelp)->handle = handle;
(*bchannelp)->b_state = BSTATE_IDLE;
(*bchannelp)->b_sock = -1;
return *bchannelp;
}
void free_bchannel(struct bchannel *bchannel)
{
struct bchannel **temp = &bchannel_first;
while(*temp) {
if (*temp == bchannel) {
*temp = (*temp)->next;
if (bchannel->b_sock > -1)
bchannel_destroy(bchannel);
if (bchannel->call) {
if (bchannel->call->bchannel)
bchannel->call->bchannel = NULL;
}
free(bchannel);
return;
}
temp = &((*temp)->next);
}
}

View File

@ -1,69 +0,0 @@
/*****************************************************************************\
** **
** Linux Call Router **
** **
**---------------------------------------------------------------------------**
** Copyright: Andreas Eversberg **
** **
** mISDN channel handlin for remote application **
** **
\*****************************************************************************/
/* this test produces a test tone to test gaps in audio stream */
//#define SEAMLESS_TEST
#define QUEUE_BUFFER_SIZE 8192 /* must be the power of two */
#define QUEUE_BUFFER_MAX 4096 /* half of size */
struct bchannel {
struct bchannel *next;
struct chan_call *call; /* link to call process */
unsigned int handle; /* handle for stack id */
int b_sock; /* socket for b-channel */
struct lcr_fd lcr_fd; /* socket register */
int b_mode; /* dsp, raw, dsphdlc */
int b_state;
int b_txdata;
int b_delay;
int b_tx_dejitter;
int b_tx_gain, b_rx_gain;
char b_pipeline[256];
unsigned int b_conf;
int b_echo;
int b_tone;
int b_rxoff;
// int b_txmix;
int b_dtmf;
int b_bf_len;
unsigned char b_bf_key[128];
int nodsp_queue; /* enables nodsp_queue_buffer */
unsigned char nodsp_queue_buffer[QUEUE_BUFFER_SIZE];
/* buffer for seamless transmission */
unsigned int nodsp_queue_in, nodsp_queue_out;
/* in and out pointers */
int queue_sent; /* data for mISDN was not confrmed yet */
#ifdef SEAMLESS_TEST
int test;
#endif
};
extern struct bchannel *bchannel_first;
extern pid_t bchannel_pid;
int bchannel_initialize(void);
void bchannel_deinitialize(void);
void bchannel_destroy(struct bchannel *bchannel);
int bchannel_create(struct bchannel *channel, int mode, int queue);
void bchannel_activate(struct bchannel *channel, int activate);
void bchannel_transmit(struct bchannel *channel, unsigned char *data, int len);
void bchannel_join(struct bchannel *channel, unsigned short id);
void bchannel_dtmf(struct bchannel *channel, int on);
void bchannel_blowfish(struct bchannel *bchannel, unsigned char *key, int len);
void bchannel_pipeline(struct bchannel *bchannel, char *pipeline);
void bchannel_gain(struct bchannel *bchannel, int gain, int tx);
struct bchannel *find_bchannel_handle(unsigned int handle);
//struct bchannel *find_bchannel_ref(unsigned int ref);
struct bchannel *alloc_bchannel(unsigned int handle);
void free_bchannel(struct bchannel *channel);

View File

@ -177,7 +177,6 @@ struct ast_channel;
#include "lcrsocket.h"
#include "cause.h"
#include "select.h"
#include "bchannel.h"
#include "options.h"
#include "chan_lcr.h"
@ -195,7 +194,6 @@ static struct ast_frame nullframe = { AST_FRAME_NULL, };
#endif
int lcr_debug=1;
int mISDN_created=1;
char lcr_type[]="lcr";
@ -297,11 +295,6 @@ void free_call(struct chan_call *call)
close(call->pipe[0]);
if (call->pipe[1] > -1)
close(call->pipe[1]);
if (call->bchannel) {
if (call->bchannel->call != call)
CERROR(call, NULL, "Linked bchannel structure has no link to us.\n");
call->bchannel->call = NULL;
}
if (call->bridge_call) {
if (call->bridge_call->bridge_call != call)
CERROR(call, NULL, "Linked call structure has no link to us.\n");
@ -373,7 +366,8 @@ int send_message(int message_type, unsigned int ref, union parameter *param)
CDEBUG(NULL, NULL, "Ignoring message %d, because socket is closed.\n", message_type);
return -1;
}
CDEBUG(NULL, NULL, "Sending %s to socket. (ref=%d)\n", messages_txt[message_type], ref);
if (message_type != MESSAGE_TRAFFIC)
CDEBUG(NULL, NULL, "Sending %s to socket. (ref=%d)\n", messages_txt[message_type], ref);
adminp = &admin_first;
while(*adminp)
@ -393,7 +387,8 @@ int send_message(int message_type, unsigned int ref, union parameter *param)
if (!wake_global) {
wake_global = 1;
char byte = 0;
write(wake_pipe[1], &byte, 1);
int rc;
rc = write(wake_pipe[1], &byte, 1);
}
return 0;
@ -405,8 +400,8 @@ int send_message(int message_type, unsigned int ref, union parameter *param)
void apply_opt(struct chan_call *call, char *data)
{
union parameter newparam;
char string[1024], *p = string, *opt, *key;
int gain, i;
char string[1024], *p = string, *opt;//, *key;
// int gain, i;
if (!data[0])
return; // no opts
@ -437,12 +432,9 @@ void apply_opt(struct chan_call *call, char *data)
break;
}
CDEBUG(call, call->ast, "Option 'n' (no DTMF).\n");
if (call->dsp_dtmf) {
call->dsp_dtmf = 0;
if (call->bchannel)
bchannel_dtmf(call->bchannel, 0);
}
call->dsp_dtmf = 0;
break;
#if 0
case 'c':
if (opt[1] == '\0') {
CERROR(call, call->ast, "Option 'c' (encrypt) expects key parameter.\n", opt);
@ -490,6 +482,7 @@ void apply_opt(struct chan_call *call, char *data)
if (call->bchannel)
bchannel_blowfish(call->bchannel, call->bf_key, call->bf_len);
break;
#endif
case 'h':
if (opt[1] != '\0') {
CERROR(call, call->ast, "Option 'h' (HDLC) expects no parameter.\n", opt);
@ -516,6 +509,7 @@ void apply_opt(struct chan_call *call, char *data)
CDEBUG(call, call->ast, "Option 'q' (queue).\n");
call->nodsp_queue = atoi(opt+1);
break;
#if 0
case 'e':
if (opt[1] == '\0') {
CERROR(call, call->ast, "Option 'e' (echo cancel) expects parameter.\n", opt);
@ -526,6 +520,7 @@ void apply_opt(struct chan_call *call, char *data)
if (call->bchannel)
bchannel_pipeline(call->bchannel, call->pipeline);
break;
#endif
case 'f':
if (opt[1] == '\0') {
CERROR(call, call->ast, "Option 'f' (faxdetect) expects parameter.\n", opt);
@ -582,6 +577,7 @@ void apply_opt(struct chan_call *call, char *data)
CDEBUG(call, call->ast, "Option 's' (inband DTMF).\n");
call->inband_dtmf = 1;
break;
#if 0
case 'v':
if (opt[1] != 'r' && opt[1] != 't') {
CERROR(call, call->ast, "Option 'v' (volume) expects parameter.\n", opt);
@ -603,6 +599,7 @@ void apply_opt(struct chan_call *call, char *data)
bchannel_gain(call->bchannel, call->tx_gain, 1);
}
break;
#endif
case 'k':
if (opt[1] != '\0') {
CERROR(call, call->ast, "Option 'k' (keypad) expects no parameter.\n", opt);
@ -616,13 +613,6 @@ void apply_opt(struct chan_call *call, char *data)
CERROR(call, call->ast, "Option '%s' unknown.\n", opt);
}
}
/* re-open, if bchannel is created */
if (call->bchannel && call->bchannel->b_sock > -1) {
bchannel_destroy(call->bchannel);
if (bchannel_create(call->bchannel, ((call->nodsp || call->faxdetect > 0)?1:0) + ((call->hdlc)?2:0), call->nodsp_queue))
bchannel_activate(call->bchannel, 1);
}
}
/*
@ -761,19 +751,12 @@ static void bridge_message_if_bridged(struct chan_call *call, int message_type,
}
/*
* send release message to LCR and import bchannel if exported
* send release message to LCR
*/
static void send_release_and_import(struct chan_call *call, int cause, int location)
static void send_release(struct chan_call *call, int cause, int location)
{
union parameter newparam;
/* importing channel */
if (call->bchannel) {
memset(&newparam, 0, sizeof(union parameter));
newparam.bchannel.type = BCHANNEL_RELEASE;
newparam.bchannel.handle = call->bchannel->handle;
send_message(MESSAGE_BCHANNEL, call->ref, &newparam);
}
/* sending release */
memset(&newparam, 0, sizeof(union parameter));
newparam.disconnectinfo.cause = cause;
@ -865,6 +848,15 @@ CDEBUG(call, ast, "Got 'sending complete', but extension '%s' will not match at
goto start;
}
/* send setup acknowledge to lcr */
if (call->state != CHAN_LCR_STATE_IN_DIALING) {
memset(&newparam, 0, sizeof(union parameter));
send_message(MESSAGE_OVERLAP, call->ref, &newparam);
}
/* change state */
call->state = CHAN_LCR_STATE_IN_DIALING;
/* if can match */
CDEBUG(call, ast, "Extensions may match, if more digits are dialed.\n");
return;
@ -875,6 +867,15 @@ CDEBUG(call, ast, "Got 'sending complete', but extension '%s' will not match at
#else
if (!*ast_channel_exten(ast)) {
#endif
/* send setup acknowledge to lcr */
if (call->state != CHAN_LCR_STATE_IN_DIALING) {
memset(&newparam, 0, sizeof(union parameter));
send_message(MESSAGE_OVERLAP, call->ref, &newparam);
}
/* change state */
call->state = CHAN_LCR_STATE_IN_DIALING;
/* if can match */
CDEBUG(call, ast, "There is no 's' extension (and we tried to match it implicitly). Extensions may match, if more digits are dialed.\n");
return;
@ -885,7 +886,7 @@ CDEBUG(call, ast, "Got 'sending complete', but extension '%s' will not match at
release:
/* release lcr */
CDEBUG(call, ast, "Releasing due to extension missmatch.\n");
send_release_and_import(call, cause, LOCATION_PRIVATE_LOCAL);
send_release(call, cause, LOCATION_PRIVATE_LOCAL);
call->ref = 0;
/* release asterisk */
#if ASTERISK_VERSION_NUM < 110000
@ -957,7 +958,7 @@ static void lcr_in_setup(struct chan_call *call, int message_type, union paramet
if (!ast) {
/* release */
CERROR(call, NULL, "Failed to create Asterisk channel - releasing.\n");
send_release_and_import(call, CAUSE_RESSOURCEUNAVAIL, LOCATION_PRIVATE_LOCAL);
send_release(call, CAUSE_RESSOURCEUNAVAIL, LOCATION_PRIVATE_LOCAL);
/* remove call */
free_call(call);
return;
@ -978,8 +979,8 @@ static void lcr_in_setup(struct chan_call *call, int message_type, union paramet
if (param->setup.dialinginfo.id)
#if ASTERISK_VERSION_NUM < 110000
strncpy(ast->exten, param->setup.dialinginfo.id, AST_MAX_EXTENSION-1);
if (param->setup.context[0])
strncpy(ast->context, param->setup.context, AST_MAX_CONTEXT-1);
if (param->setup.dialinginfo.context[0])
strncpy(ast->context, param->setup.dialinginfo.context, AST_MAX_CONTEXT-1);
else
strncpy(ast->context, param->setup.callerinfo.interface, AST_MAX_CONTEXT-1);
#else
@ -1236,7 +1237,8 @@ static void lcr_in_proceeding(struct chan_call *call, int message_type, union pa
if (!wake_global) {
wake_global = 1;
char byte = 0;
write(wake_pipe[1], &byte, 1);
int rc;
rc = write(wake_pipe[1], &byte, 1);
}
strncat(call->queue_string, "P", sizeof(call->queue_string)-1);
}
@ -1257,7 +1259,8 @@ static void lcr_in_alerting(struct chan_call *call, int message_type, union para
if (!wake_global) {
wake_global = 1;
char byte = 0;
write(wake_pipe[1], &byte, 1);
int rc;
rc = write(wake_pipe[1], &byte, 1);
}
strncat(call->queue_string, "R", sizeof(call->queue_string)-1);
}
@ -1268,19 +1271,10 @@ static void lcr_in_alerting(struct chan_call *call, int message_type, union para
*/
static void lcr_in_connect(struct chan_call *call, int message_type, union parameter *param)
{
union parameter newparam;
CDEBUG(call, call->ast, "Incomming connect (answer) from LCR.\n");
/* change state */
call->state = CHAN_LCR_STATE_CONNECT;
/* request bchannel */
if (!call->bchannel) {
CDEBUG(call, call->ast, "Requesting B-channel. (ref=%d)\n", call->ref);
memset(&newparam, 0, sizeof(union parameter));
newparam.bchannel.type = BCHANNEL_REQUEST;
send_message(MESSAGE_BCHANNEL, call->ref, &newparam);
}
/* copy connectinfo */
memcpy(&call->connectinfo, &param->connectinfo, sizeof(struct connect_info));
/* queue event to asterisk */
@ -1288,7 +1282,8 @@ static void lcr_in_connect(struct chan_call *call, int message_type, union param
if (!wake_global) {
wake_global = 1;
char byte = 0;
write(wake_pipe[1], &byte, 1);
int rc;
rc = write(wake_pipe[1], &byte, 1);
}
strncat(call->queue_string, "N", sizeof(call->queue_string)-1);
}
@ -1318,7 +1313,7 @@ static void lcr_in_disconnect(struct chan_call *call, int message_type, union pa
}
#endif
/* release lcr with same cause */
send_release_and_import(call, call->cause, call->location);
send_release(call, call->cause, call->location);
call->ref = 0;
/* change to release state */
call->state = CHAN_LCR_STATE_RELEASE;
@ -1333,7 +1328,8 @@ static void lcr_in_disconnect(struct chan_call *call, int message_type, union pa
if (!wake_global) {
wake_global = 1;
char byte = 0;
write(wake_pipe[1], &byte, 1);
int rc;
rc = write(wake_pipe[1], &byte, 1);
}
strcpy(call->queue_string, "H"); // overwrite other indications
} else {
@ -1371,7 +1367,8 @@ static void lcr_in_release(struct chan_call *call, int message_type, union param
if (!wake_global) {
wake_global = 1;
char byte = 0;
write(wake_pipe[1], &byte, 1);
int rc;
rc = write(wake_pipe[1], &byte, 1);
}
strcpy(call->queue_string, "H");
} else {
@ -1418,7 +1415,8 @@ static void lcr_in_information(struct chan_call *call, int message_type, union p
if (!wake_global) {
wake_global = 1;
char byte = 0;
write(wake_pipe[1], &byte, 1);
int rc;
rc = write(wake_pipe[1], &byte, 1);
}
strncat(call->queue_string, param->information.id, sizeof(call->queue_string)-1);
}
@ -1435,18 +1433,8 @@ static void lcr_in_information(struct chan_call *call, int message_type, union p
*/
static void lcr_in_notify(struct chan_call *call, int message_type, union parameter *param)
{
union parameter newparam;
CDEBUG(call, call->ast, "Incomming notify from LCR. (notify=%d)\n", param->notifyinfo.notify);
/* request bchannel, if call is resumed and we don't have it */
if (param->notifyinfo.notify == INFO_NOTIFY_USER_RESUMED && !call->bchannel && call->ref) {
CDEBUG(call, call->ast, "Reqesting bchannel at resume. (ref=%d)\n", call->ref);
memset(&newparam, 0, sizeof(union parameter));
newparam.bchannel.type = BCHANNEL_REQUEST;
send_message(MESSAGE_BCHANNEL, call->ref, &newparam);
}
if (!call->ast) return;
/* use bridge to forware message not supported by asterisk */
@ -1483,18 +1471,17 @@ static void lcr_in_pattern(struct chan_call *call, int message_type, union param
call->has_pattern = 1;
/* request bchannel */
if (!call->bchannel) {
CDEBUG(call, call->ast, "Requesting B-channel. (ref=%d)\n", call->ref);
memset(&newparam, 0, sizeof(union parameter));
newparam.bchannel.type = BCHANNEL_REQUEST;
send_message(MESSAGE_BCHANNEL, call->ref, &newparam);
}
CDEBUG(call, call->ast, "Requesting audio path (ref=%d)\n", call->ref);
memset(&newparam, 0, sizeof(union parameter));
send_message(MESSAGE_AUDIOPATH, call->ref, &newparam);
/* queue PROGRESS, because tones are available */
if (call->ast && call->pbx_started) {
if (!wake_global) {
wake_global = 1;
char byte = 0;
write(wake_pipe[1], &byte, 1);
int rc;
rc = write(wake_pipe[1], &byte, 1);
}
strncat(call->queue_string, "T", sizeof(call->queue_string)-1);
}
@ -1524,7 +1511,8 @@ void lcr_in_dtmf(struct chan_call *call, int val)
if (!wake_global) {
wake_global = 1;
char byte = 0;
write(wake_pipe[1], &byte, 1);
int rc;
rc = write(wake_pipe[1], &byte, 1);
}
strncat(call->queue_string, digit, sizeof(call->queue_string)-1);
}
@ -1534,103 +1522,12 @@ void lcr_in_dtmf(struct chan_call *call, int val)
*/
int receive_message(int message_type, unsigned int ref, union parameter *param)
{
struct bchannel *bchannel;
struct chan_call *call;
union parameter newparam;
int rc = 0;
memset(&newparam, 0, sizeof(union parameter));
/* handle bchannel message*/
if (message_type == MESSAGE_BCHANNEL) {
switch(param->bchannel.type) {
case BCHANNEL_ASSIGN:
CDEBUG(NULL, NULL, "Received BCHANNEL_ASSIGN message. (handle=%08lx) for ref %d\n", param->bchannel.handle, ref);
if ((bchannel = find_bchannel_handle(param->bchannel.handle))) {
CERROR(NULL, NULL, "bchannel handle %x already assigned.\n", (int)param->bchannel.handle);
return -1;
}
/* create bchannel */
bchannel = alloc_bchannel(param->bchannel.handle);
if (!bchannel) {
CERROR(NULL, NULL, "alloc bchannel handle %x failed.\n", (int)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 && param->bchannel.crypt_len <= sizeof(bchannel->b_bf_key)) {
bchannel->b_bf_len = param->bchannel.crypt_len;
memcpy(bchannel->b_bf_key, param->bchannel.crypt, param->bchannel.crypt_len);
}
bchannel->b_txdata = 0;
bchannel->b_tx_dejitter = 1;
/* in case, ref is not set, this bchannel instance must
* be created until it is removed again by LCR */
/* link to call */
call = find_call_ref(ref);
if (call) {
bchannel->call = call;
call->bchannel = bchannel;
if (call->dsp_dtmf)
bchannel_dtmf(bchannel, 1);
if (call->bf_len)
bchannel_blowfish(bchannel, call->bf_key, call->bf_len);
if (call->pipeline[0])
bchannel_pipeline(bchannel, call->pipeline);
if (call->rx_gain)
bchannel_gain(bchannel, call->rx_gain, 0);
if (call->tx_gain)
bchannel_gain(bchannel, call->tx_gain, 1);
if (call->bridge_id) {
CDEBUG(call, call->ast, "Join bchannel, because call is already bridged.\n");
bchannel_join(bchannel, call->bridge_id);
}
/* ignore all dsp features, if it is a loopback interface */
if (param->bchannel.isloopback)
call->nodsp = 1;
/* create only, if call exists, othewhise it bchannel is freed below... */
if (bchannel_create(bchannel, ((call->nodsp || call->faxdetect > 0)?1:0) + ((call->hdlc)?2:0), call->nodsp_queue))
bchannel_activate(bchannel, 1);
}
/* acknowledge */
newparam.bchannel.type = BCHANNEL_ASSIGN_ACK;
newparam.bchannel.handle = param->bchannel.handle;
send_message(MESSAGE_BCHANNEL, 0, &newparam);
/* if call has released before bchannel is assigned */
if (!call) {
newparam.bchannel.type = BCHANNEL_RELEASE;
newparam.bchannel.handle = param->bchannel.handle;
send_message(MESSAGE_BCHANNEL, 0, &newparam);
}
break;
case BCHANNEL_REMOVE:
CDEBUG(NULL, NULL, "Received BCHANNEL_REMOVE message. (handle=%08lx)\n", param->bchannel.handle);
if (!(bchannel = find_bchannel_handle(param->bchannel.handle))) {
CERROR(NULL, NULL, "Bchannel handle %x not assigned.\n", (int)param->bchannel.handle);
return -1;
}
/* unklink from call and destroy bchannel */
free_bchannel(bchannel);
/* acknowledge */
newparam.bchannel.type = BCHANNEL_REMOVE_ACK;
newparam.bchannel.handle = param->bchannel.handle;
send_message(MESSAGE_BCHANNEL, 0, &newparam);
break;
default:
CDEBUG(NULL, NULL, "Received unknown bchannel message %d.\n", param->bchannel.type);
}
return 0;
}
/* handle new ref */
if (message_type == MESSAGE_NEWREF) {
if (param->newref.direction) {
@ -1671,9 +1568,9 @@ int receive_message(int message_type, unsigned int ref, union parameter *param)
else if (call->state == CHAN_LCR_STATE_RELEASE) {
/* send release */
if (call->cause)
send_release_and_import(call, call->cause, call->location);
send_release(call, call->cause, call->location);
else
send_release_and_import(call, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL);
send_release(call, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL);
/* free call */
free_call(call);
return 0;
@ -1748,11 +1645,21 @@ int receive_message(int message_type, unsigned int ref, union parameter *param)
call->audiopath = param->audiopath;
break;
case MESSAGE_TRAFFIC: // if remote audio connected or hold
{
unsigned char *p = param->traffic.data;
int i, len = param->traffic.len;
for (i = 0; i < len; i++, p++)
*p = flip_bits[*p];
}
rc = write(call->pipe[1], param->traffic.data, param->traffic.len);
break;
default:
CDEBUG(call, call->ast, "Message %d from LCR unhandled.\n", message_type);
break;
}
return 0;
return rc;
}
/*
@ -1788,15 +1695,12 @@ again:
if (!wake_global) {
wake_global = 1;
char byte = 0;
write(wake_pipe[1], &byte, 1);
int rc;
rc = write(wake_pipe[1], &byte, 1);
}
strcpy(call->queue_string, "H");
call = call->next;
}
/* release all bchannels */
while(bchannel_first)
free_bchannel(bchannel_first);
}
void close_socket(void);
@ -1940,8 +1844,9 @@ void close_socket(void)
static int wake_event(struct lcr_fd *fd, unsigned int what, void *instance, int index)
{
char byte;
int rc;
read(wake_pipe[0], &byte, 1);
rc = read(wake_pipe[0], &byte, 1);
wake_global = 0;
@ -2065,8 +1970,6 @@ static void *chan_thread(void *arg)
memset(&socket_retry, 0, sizeof(socket_retry));
add_timer(&socket_retry, handle_retry, NULL, 0);
bchannel_pid = getpid();
/* open socket the first time */
handle_retry(NULL, NULL, 0);
@ -2483,8 +2386,6 @@ static int lcr_call(struct ast_channel *ast, char *dest, int timeout)
/* send MESSAGE_NEWREF */
memset(&newparam, 0, sizeof(union parameter));
newparam.newref.direction = 0; /* request from app */
if (!strcmp(call->interface, "pbx"))
newparam.newref.mode = 1;
send_message(MESSAGE_NEWREF, 0, &newparam);
/* set hdlc if capability requires hdlc */
@ -2697,13 +2598,6 @@ static int lcr_answer(struct ast_channel *ast)
call->state = CHAN_LCR_STATE_CONNECT;
}
/* change state */
/* request bchannel */
if (!call->bchannel) {
CDEBUG(call, ast, "Requesting B-channel.\n");
memset(&newparam, 0, sizeof(union parameter));
newparam.bchannel.type = BCHANNEL_REQUEST;
send_message(MESSAGE_BCHANNEL, call->ref, &newparam);
}
/* enable keypad */
// memset(&newparam, 0, sizeof(union parameter));
// send_message(MESSAGE_ENABLEKEYPAD, call->ref, &newparam);
@ -2751,13 +2645,13 @@ static int lcr_hangup(struct ast_channel *ast)
CDEBUG(call, ast, "Releasing ref and freeing call instance.\n");
#if ASTERISK_VERSION_NUM < 110000
if (ast->hangupcause > 0)
send_release_and_import(call, ast->hangupcause, LOCATION_PRIVATE_LOCAL);
send_release(call, ast->hangupcause, LOCATION_PRIVATE_LOCAL);
#else
if (ast_channel_hangupcause(ast) > 0)
send_release_and_import(call, ast_channel_hangupcause(ast), LOCATION_PRIVATE_LOCAL);
send_release(call, ast_channel_hangupcause(ast), LOCATION_PRIVATE_LOCAL);
#endif
else
send_release_and_import(call, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL);
send_release(call, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL);
/* remove call */
free_call(call);
if (!pthread_equal(tid, chan_tid)) {
@ -2785,8 +2679,11 @@ static int lcr_hangup(struct ast_channel *ast)
static int lcr_write(struct ast_channel *ast, struct ast_frame *fr)
{
union parameter newparam;
struct chan_call *call;
struct ast_frame * f = fr;
unsigned char *p, *q;
int len, l;
#if ASTERISK_VERSION_NUM < 100000
#ifdef AST_1_8_OR_HIGHER
@ -2852,8 +2749,18 @@ static int lcr_write(struct ast_channel *ast, struct ast_frame *fr)
}
return -1;
}
if (call->bchannel && f->samples)
bchannel_transmit(call->bchannel, *((unsigned char **)&(f->data)), f->samples);
len = f->samples;
p = *((unsigned char **)&(f->data));
q = newparam.traffic.data;
memset(&newparam, 0, sizeof(union parameter));
while (len) {
l = (len > sizeof(newparam.traffic.data)) ? sizeof(newparam.traffic.data) : len;
newparam.traffic.len = l;
len -= l;
for (; l; l--)
*q++ = flip_bits[*p++];
send_message(MESSAGE_TRAFFIC, call->ref, &newparam);
}
ast_mutex_unlock(&chan_lock);
if (f != fr) {
ast_frfree(f);
@ -3051,12 +2958,9 @@ static int lcr_indicate(struct ast_channel *ast, int cond, const void *data, siz
case AST_CONTROL_PROGRESS:
CDEBUG(call, ast, "Received indicate AST_CONTROL_PROGRESS from Asterisk.\n");
/* request bchannel */
if (!call->bchannel) {
CDEBUG(call, ast, "Requesting B-channel.\n");
memset(&newparam, 0, sizeof(union parameter));
newparam.bchannel.type = BCHANNEL_REQUEST;
send_message(MESSAGE_BCHANNEL, call->ref, &newparam);
}
CDEBUG(call, ast, "Requesting audio path.\n");
memset(&newparam, 0, sizeof(union parameter));
send_message(MESSAGE_AUDIOPATH, call->ref, &newparam);
break;
case -1:
CDEBUG(call, ast, "Received indicate -1.\n");
@ -3224,6 +3128,7 @@ enum ast_bridge_result lcr_bridge(struct ast_channel *ast1,
/* get bridge id and join */
bridge_id = new_bridge_id();
#if 0
call1->bridge_id = bridge_id;
if (call1->bchannel)
bchannel_join(call1->bchannel, bridge_id);
@ -3231,6 +3136,11 @@ enum ast_bridge_result lcr_bridge(struct ast_channel *ast1,
call2->bridge_id = bridge_id;
if (call2->bchannel)
bchannel_join(call2->bchannel, bridge_id);
#else
printf("FIXME");
exit(0);
#endif
} else
if (call1->nodsp && call2->nodsp)
CDEBUG(NULL, NULL, "Both calls use no DSP, bridging in channel driver.\n");
@ -3331,15 +3241,11 @@ enum ast_bridge_result lcr_bridge(struct ast_channel *ast1,
#endif
if (call1 && call1->bridge_id) {
call1->bridge_id = 0;
if (call1->bchannel)
bchannel_join(call1->bchannel, 0);
if (call1->bridge_call)
call1->bridge_call->bridge_call = NULL;
}
if (call2 && call1->bridge_id) {
call2->bridge_id = 0;
if (call2->bchannel)
bchannel_join(call2->bchannel, 0);
if (call2->bridge_call)
call2->bridge_call->bridge_call = NULL;
}
@ -3546,20 +3452,6 @@ int load_module(void)
ast_mutex_init(&chan_lock);
ast_mutex_init(&log_lock);
if (bchannel_initialize()) {
CERROR(NULL, NULL, "Unable to open mISDN device\n");
close_socket();
#ifdef LCR_FOR_ASTERISK
return AST_MODULE_LOAD_DECLINE;
#endif
#ifdef LCR_FOR_CALLWEAVER
return 0;
#endif
}
mISDN_created = 1;
#if ASTERISK_VERSION_NUM < 100000
lcr_tech.capabilities = (options.law=='a')?AST_FORMAT_ALAW:AST_FORMAT_ULAW;
#else
@ -3572,7 +3464,6 @@ int load_module(void)
#endif
if (ast_channel_register(&lcr_tech)) {
CERROR(NULL, NULL, "Unable to register channel class\n");
bchannel_deinitialize();
close_socket();
#ifdef LCR_FOR_ASTERISK
@ -3605,13 +3496,17 @@ int load_module(void)
" Use queue size in miliseconds for optarg. (try 250)\n"
" f - Adding fax detection. It it timeouts, mISDN_dsp is used.\n"
" Use time to detect for optarg.\n"
#if 0
" c - Make crypted outgoing call, optarg is keyindex.\n"
" e - Perform echo cancelation on this channel.\n"
#endif
" Takes mISDN pipeline option as optarg.\n"
" s - Send Non Inband DTMF as inband.\n"
" r - re-buffer packets (160 bytes). Required for some SIP-phones and fax applications.\n"
#if 0
" vr - rxgain control\n"
" vt - txgain control\n"
#endif
" Volume changes at factor 2 ^ optarg.\n"
" k - use keypad to dial this call.\n"
"\n"
@ -3635,7 +3530,6 @@ int load_module(void)
if ((pthread_create(&chan_tid, NULL, chan_thread, NULL)<0)) {
/* failed to create thread */
bchannel_deinitialize();
close_socket();
ast_channel_unregister(&lcr_tech);
@ -3672,11 +3566,6 @@ int unload_module(void)
ast_unregister_application("lcr_config");
if (mISDN_created) {
bchannel_deinitialize();
mISDN_created = 0;
}
if (lcr_sock >= 0) {
close(lcr_sock);
lcr_sock = -1;

View File

@ -9,8 +9,6 @@
** **
\*****************************************************************************/
/* structure for all calls */
struct bchannel;
struct chan_call {
struct chan_call *next; /* link to next call instance */
int state; /* current call state CHAN_LCR_STATE */
@ -19,8 +17,6 @@ struct chan_call {
void *ast; /* current asterisk channel */
int pbx_started;
/* indicates if pbx que is available */
struct bchannel *bchannel;
/* reference to bchannel, if set */
int audiopath;
/* audio is available */
int cause, location;

View File

@ -184,6 +184,8 @@
# An internal extension does not receive tones ("earlyb"), but sends them.
#[ast]
#remote asterisk
#exten from-lcr
##note: The following keyword means that this interface is an LCR internal extension
#extension
##screen-in % 209
#earlyb no

View File

@ -109,12 +109,3 @@
# This feature is temporarily for test purpose. Don't enable it
#polling
# Two Loopback interfaces for audio transfer between GSM/Asterisk and mISDN.
# The first interface must provide B-channels for each GSM call or channel
# instance, the seond interface links them to LCR.
# Use 30 B-channels unless you need more due to more instances.
# -> Load with: "modprobe mISDN_l1loop pri=1 nchannel=30"
# By default "mISDN_l1loop.1" and "mISDN_l1loop.2" is used.
#loopback-ext mISDN_l1loop.1
#loopback-lcr mISDN_l1loop.2

View File

@ -327,7 +327,6 @@ static int inter_portname(struct interface *interface, char *filename, int line,
return(-1);
#else
struct interface_port *ifport, **ifportp;
struct interface *searchif;
/* goto end of chain */
ifport = interface->ifport;
@ -336,22 +335,6 @@ static int inter_portname(struct interface *interface, char *filename, int line,
ifport = ifport->next;
}
/* check for port already assigned, but not for shared loop interface */
searchif = interface_newlist;
if (!!strcmp(value, options.loopback_lcr))
{
while(searchif) {
ifport = searchif->ifport;
while(ifport) {
if (!strcasecmp(ifport->portname, value)) {
SPRINT(interface_error, "Error in %s (line %d): port '%s' already used above.\n", filename, line, value);
return(-1);
}
ifport = ifport->next;
}
searchif = searchif->next;
}
}
/* alloc port substructure */
ifport = (struct interface_port *)MALLOC(sizeof(struct interface_port));
memuse++;
@ -1096,7 +1079,6 @@ static int inter_ss5(struct interface *interface, char *filename, int line, char
#endif
static int inter_remote(struct interface *interface, char *filename, int line, char *parameter, char *value)
{
struct interface_port *ifport;
struct interface *searchif;
if (!value[0]) {
@ -1105,27 +1087,26 @@ static int inter_remote(struct interface *interface, char *filename, int line, c
}
searchif = interface_newlist;
while(searchif) {
ifport = searchif->ifport;
while(ifport) {
if (ifport->remote && !strcmp(ifport->remote_app, value)) {
SPRINT(interface_error, "Error in %s (line %d): port '%s' already uses remote application '%s'.\n", filename, line, ifport->portname, value);
return(-1);
}
ifport = ifport->next;
if (interface->remote && !strcmp(interface->remote_app, value)) {
SPRINT(interface_error, "Error in %s (line %d): interface '%s' already uses remote application '%s'.\n", filename, line, interface->name, value);
return(-1);
}
searchif = searchif->next;
}
/* set portname */
if (inter_portname(interface, filename, line, (char *)"portname", options.loopback_lcr))
return(-1);
/* goto end of chain again to set application name */
ifport = interface->ifport;
while(ifport->next)
ifport = ifport->next;
ifport->remote = 1;
SCPY(ifport->remote_app, value);
interface->remote = 1;
SCPY(interface->remote_app, value);
return(0);
}
static int inter_context(struct interface *interface, char *filename, int line, char *parameter, char *value)
{
if (!value[0]) {
SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects application context as value.\n", filename, line, parameter);
return(-1);
}
SCPY(interface->remote_context, value);
return(0);
}
@ -1325,6 +1306,8 @@ struct interface_param interface_param[] = {
{"remote", &inter_remote, "<application>",
"Sets up an interface that communicates with the remote application.\n"
"Use \"asterisk\" to use chan_lcr as remote application."},
{"context", &inter_context, "<context>",
"Give context for calls to application."},
{"shutdown", &inter_shutdown, "",
"Interface will not be loaded when processing interface.conf"},

View File

@ -52,8 +52,6 @@ struct interface_port {
int l1hold; /* hold layer 1 (1=on, 0=off) */
int l2hold; /* hold layer 2 (1=force, -1=disable, 0=default) */
unsigned int ss5; /* set, if SS5 signalling enabled, also holds feature bits */
int remote; /* interface is a remote app interface */
char remote_app[32]; /* name of remote application */
int channel_force; /* forces channel by protocol */
int nodtmf; /* disables DTMF */
struct select_channel *out_channel; /* list of channels to select */
@ -106,6 +104,9 @@ struct interface {
char pipeline[256]; /* filter pipeline */
unsigned char bf_key[56]; /* filter blowfish */
int bf_len; /* filter length of blowfish */
int remote; /* interface is a remote app interface */
char remote_app[32]; /* name of remote application */
char remote_context[128]; /* context feld to use for remote application */
#ifdef WITH_GSM_BS
int gsm_bs; /* interface is an GSM BS interface */
#if 0

2
join.h
View File

@ -9,7 +9,7 @@
** **
\*****************************************************************************/
enum { JOIN_TYPE_NONE, JOIN_TYPE_PBX, JOIN_TYPE_REMOTE};
enum { JOIN_TYPE_NONE, JOIN_TYPE_PBX};
/* join
*

View File

@ -499,9 +499,6 @@ int joinpbx_countrelations(unsigned int join_id)
if (!join)
return(0);
if (join->j_type == JOIN_TYPE_REMOTE)
return(2);
if (join->j_type != JOIN_TYPE_PBX)
return(0);
joinpbx = (class JoinPBX *)join;

View File

@ -1,112 +0,0 @@
/*****************************************************************************\
** **
** Linux Call Router **
** **
**---------------------------------------------------------------------------**
** Copyright: Andreas Eversberg **
** **
** join functions for remote application **
** **
\*****************************************************************************/
#include "main.h"
//#define __u8 unsigned char
//#define __u16 unsigned short
//#define __u32 unsigned int
extern unsigned int new_remote;
/*
* constructor for a new join
* the join will have a relation to the calling endpoint
*/
JoinRemote::JoinRemote(unsigned int serial, char *remote_name, int remote_id) : Join()
{
union parameter param;
SCPY(j_remote_name, remote_name);
j_remote_id = remote_id;
j_type = JOIN_TYPE_REMOTE;
j_remote_ref = new_remote++;
PDEBUG(DEBUG_JOIN, "Constructor(new join) ref=%d\n", j_remote_ref);
j_epoint_id = serial; /* this is the endpoint, if created by epoint */
if (j_epoint_id)
PDEBUG(DEBUG_JOIN, "New remote join connected to endpoint id %lu and application %s (ref=%d)\n", j_epoint_id, remote_name, j_remote_ref);
/* send new ref to remote socket */
memset(&param, 0, sizeof(union parameter));
if (serial)
param.newref.direction = 1; /* new ref from lcr */
if (admin_message_from_lcr(j_remote_id, j_remote_ref, MESSAGE_NEWREF, &param)<0)
FATAL("No socket with remote application '%s' found, this shall not happen. because we already created one.\n", j_remote_name);
}
/*
* join descructor
*/
JoinRemote::~JoinRemote()
{
}
void JoinRemote::message_epoint(unsigned int epoint_id, int message_type, union parameter *param)
{
/* if endpoint has just been removed, but still a message in the que */
if (epoint_id != j_epoint_id)
return;
PDEBUG(DEBUG_JOIN, "Message %d of endpoint %d from LCR to remote (ref=%d)\n", message_type, j_epoint_id, j_remote_ref);
/* look for Remote's interface */
if (admin_message_from_lcr(j_remote_id, j_remote_ref, message_type, param)<0) {
PERROR("No socket with remote application '%s' found, this shall not happen. Closing socket shall cause release of all joins.\n", j_remote_name);
return;
}
if (message_type == MESSAGE_RELEASE) {
delete this;
return;
}
}
void JoinRemote::message_remote(int message_type, union parameter *param)
{
struct lcr_msg *message;
PDEBUG(DEBUG_JOIN, "Message %d of endpoint %d from remote to LCR (ref=%d)\n", message_type, j_epoint_id, j_remote_ref);
/* create relation if no relation exists */
if (!j_epoint_id) {
class Endpoint *epoint;
if (!(epoint = new Endpoint(0, j_serial)))
FATAL("No memory for Endpoint instance\n");
j_epoint_id = epoint->ep_serial;
PDEBUG(DEBUG_JOIN, "Created endpoint %d\n", j_epoint_id);
epoint->ep_app = new_endpointapp(epoint, 1, EAPP_TYPE_PBX); // outgoing
}
#ifdef WITH_MISDN
/* set serial on bchannel message
* also ref is given, so we send message with ref */
if (message_type == MESSAGE_BCHANNEL) {
message_bchannel_from_remote(this, param->bchannel.type, param->bchannel.handle);
return;
}
#endif
/* cannot just forward, because param is not of container "struct lcr_msg" */
message = message_create(j_serial, j_epoint_id, JOIN_TO_EPOINT, message_type);
memcpy(&message->param, param, sizeof(message->param));
message_put(message);
if (message_type == MESSAGE_RELEASE) {
delete this;
return;
}
}

View File

@ -1,26 +0,0 @@
/*****************************************************************************\
** **
** Linux Call Router **
** **
**---------------------------------------------------------------------------**
** Copyright: Andreas Eversberg **
** **
** join header file for Asterisk interface **
** **
\*****************************************************************************/
class JoinRemote : public Join
{
public:
JoinRemote(unsigned int serial, char *remote_name, int remote_id);
~JoinRemote();
void message_epoint(unsigned int epoint_id, int message, union parameter *param);
void message_remote(int message_type, union parameter *param);
unsigned int j_remote_ref;
int j_remote_id;
char j_remote_name[32];
unsigned int j_epoint_id;
};

View File

@ -743,18 +743,6 @@ const char *admin_state(int sock, char *argv[])
color(yellow);
addstr("dact'ing");
break;
case B_STATE_EXPORTING:
color(yellow);
addstr("exp'ing ");
break;
case B_STATE_REMOTE:
color(green);
addstr("remote ");
break;
case B_STATE_IMPORTING:
color(yellow);
addstr("imp'ing ");
break;
}
if (m[i].u.i.port[j]) {
/* search for port */

153
loop.c
View File

@ -1,153 +0,0 @@
/*****************************************************************************\
** **
** LCR **
** **
**---------------------------------------------------------------------------**
** Copyright: Andreas Eversberg **
** **
** loopback interface functions **
** **
\*****************************************************************************/
#include "main.h"
struct mISDNloop mISDNloop = { -1, 0 };
void mISDNloop_close(void)
{
if (mISDNloop.sock > -1)
close(mISDNloop.sock);
mISDNloop.sock = -1;
}
int mISDNloop_open()
{
int ret;
int cnt;
unsigned long on = 1;
struct sockaddr_mISDN addr;
struct mISDN_devinfo devinfo;
int pri, bri;
/* already open */
if (mISDNloop.sock > -1)
return 0;
PDEBUG(DEBUG_PORT, "Open external interface of loopback.\n");
/* check port counts */
ret = ioctl(mISDNsocket, IMGETCOUNT, &cnt);
if (ret < 0) {
fprintf(stderr, "Cannot get number of mISDN devices. (ioctl IMGETCOUNT failed ret=%d)\n", ret);
return(ret);
}
if (cnt <= 0) {
PERROR_RUNTIME("Found no card. Please be sure to load card drivers.\n");
return -EIO;
}
mISDNloop.port = mISDN_getportbyname(mISDNsocket, cnt, options.loopback_ext);
if (mISDNloop.port < 0) {
PERROR_RUNTIME("Port name '%s' not found, did you load loopback interface?.\n", options.loopback_ext);
return mISDNloop.port;
}
/* get protocol */
bri = pri = 0;
devinfo.id = mISDNloop.port;
ret = ioctl(mISDNsocket, IMGETDEVINFO, &devinfo);
if (ret < 0) {
PERROR_RUNTIME("Cannot get device information for port %d. (ioctl IMGETDEVINFO failed ret=%d)\n", mISDNloop.port, ret);
return ret;
}
if (devinfo.Dprotocols & (1 << ISDN_P_TE_S0)) {
bri = 1;
}
if (devinfo.Dprotocols & (1 << ISDN_P_TE_E1)) {
pri = 1;
}
if (!bri && !pri) {
PERROR_RUNTIME("loop port %d does not support TE PRI or TE BRI.\n", mISDNloop.port);
}
/* open socket */
if ((mISDNloop.sock = socket(PF_ISDN, SOCK_DGRAM, (pri)?ISDN_P_TE_E1:ISDN_P_TE_S0)) < 0) {
PERROR_RUNTIME("loop port %d failed to open socket.\n", mISDNloop.port);
mISDNloop_close();
return mISDNloop.sock;
}
/* set nonblocking io */
if ((ret = ioctl(mISDNloop.sock, FIONBIO, &on)) < 0) {
PERROR_RUNTIME("loop port %d failed to set socket into nonblocking io.\n", mISDNloop.port);
mISDNloop_close();
return ret;
}
/* bind socket to dchannel */
memset(&addr, 0, sizeof(addr));
addr.family = AF_ISDN;
addr.dev = mISDNloop.port;
addr.channel = 0;
if ((ret = bind(mISDNloop.sock, (struct sockaddr *)&addr, sizeof(addr))) < 0) {
PERROR_RUNTIME("loop port %d failed to bind socket. (name = %s errno=%d)\n", mISDNloop.port, options.loopback_ext, errno);
mISDNloop_close();
return (ret);
}
return 0;
}
int loop_hunt_bchannel(class PmISDN *port, struct mISDNport *mISDNport)
{
int channel;
int i;
char map[mISDNport->b_num];
struct interface *interface;
struct interface_port *ifport;
chan_trace_header(mISDNport, port, "CHANNEL SELECTION (setup)", DIRECTION_NONE);
add_trace("channel", "reserved", "%d", mISDNport->b_reserved);
if (mISDNport->b_reserved >= mISDNport->b_num) { // of out chan..
add_trace("conclusion", NULL, "all channels are reserved");
end_trace();
return(-34); // no channel
}
/* map all used ports of shared loopback interface */
memset(map, 0, sizeof(map));
interface = interface_first;
while(interface) {
ifport = interface->ifport;
while(ifport) {
if (!strcmp(ifport->portname, options.loopback_lcr)) {
i = 0;
while(i < mISDNport->b_num) {
if (mISDNport->b_port[i])
map[i] = 1;
i++;
}
}
ifport = ifport->next;
}
interface = interface->next;
}
/* find channel */
i = 0;
channel = 0;
while(i < mISDNport->b_num) {
if (!map[i]) {
channel = i+1+(i>=15);
break;
}
i++;
}
if (!channel) {
add_trace("conclusion", NULL, "no channel available");
end_trace();
return(-6); // channel unacceptable
}
add_trace("conclusion", NULL, "channel available");
add_trace("connect", "channel", "%d", channel);
end_trace();
return(channel);
}

12
loop.h
View File

@ -1,12 +0,0 @@
struct mISDNloop {
int sock; /* loopback interface external side */
int port; /* port number for external side */
};
extern mISDNloop mISDNloop;
void mISDNloop_close(void);
int mISDNloop_open();
int loop_hunt_bchannel(class PmISDN *port, struct mISDNport *mISDNport);

620
mISDN.cpp
View File

@ -147,8 +147,6 @@ PmISDN::PmISDN(int type, mISDNport *mISDNport, char *portname, struct port_setti
p_m_dtmf = !mISDNport->ifport->nodtmf;
memset(&p_m_timeout, 0, sizeof(p_m_timeout));
add_timer(&p_m_timeout, mISDN_timeout, this, 0);
p_m_remote_ref = 0; /* channel shall be exported to given remote */
p_m_remote_id = 0; /* remote admin socket */
SCPY(p_m_pipeline, mISDNport->ifport->interface->pipeline);
/* audio */
@ -568,22 +566,6 @@ It may be linked to a Port class, that likes to reactivate it.
See above.
After deactivating bchannel, and if not used, the bchannel becomes idle again.
Also the bchannel may be exported, but only if the state is or becomes idle:
- B_STATE_EXPORTING
The bchannel assignment has been sent to the remove application.
- B_STATE_REMOTE
The bchannel assignment is acknowledged by the remote application.
- B_STATE_IMPORTING
The bchannel is re-imported by mISDN port object.
- B_STATE_IDLE
See above.
After re-importing bchannel, and if not used, the bchannel becomes idle again.
A bchannel can have the following events:
- B_EVENT_USE
@ -598,33 +580,8 @@ The bchannel is not required by Port class anymore
- B_EVENT_DEACTIVATED
The bchannel becomes inactive.
- B_EVENT_EXPORTED
The bchannel is now used by remote application.
- B_EVENT_IMPORTED
The bchannel is not used by remote application.
- B_EVENT_EXPORTREQUEST
The bchannel shall be exported to the remote application.
- B_EVENT_IMPORTREQUEST
The bchannel is released from the remote application.
All actions taken on these events depend on the current bchannel's state and if it is linked to a Port class.
if an export request is receive by remote application, p_m_remote_* is set.
the b_remote_*[index] indicates if and where the channel is exported to. (set from the point on, where export is initiated, until imported is acknowledged.)
- set on export request from remote application (if port is assigned)
- set on channel use, if requested by remote application (p_m_remote_*)
- cleared on drop request
the bchannel will be exported with ref and stack given. remote application uses the ref to link bchannel to the call.
the bchannel will be imported with stack given only. remote application must store stack id with the bchannel process.
the bchannel import/export is acknowledged with stack given.
if exporting, b_remote_*[index] is set to the remote socket id.
if importing has been acknowledged. b_remote_*[index] is cleared.
*/
/*
@ -639,19 +596,14 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
class PmISDN *b_port = mISDNport->b_port[i];
int state = mISDNport->b_state[i];
int timer = -1; // no change
unsigned int p_m_remote_ref = 0;
unsigned int p_m_remote_id = 0;
int p_m_tx_gain = 0;
int p_m_rx_gain = 0;
char *p_m_pipeline = NULL;
unsigned char *p_m_crypt_key = NULL;
int p_m_crypt_key_len = 0;
int p_m_crypt_key_type = 0;
unsigned int portid = (mISDNport->portnum<<8) + i+1+(i>=15);
if (b_port) {
p_m_remote_id = b_port->p_m_remote_id;
p_m_remote_ref = b_port->p_m_remote_ref;
p_m_tx_gain = b_port->p_m_tx_gain;
p_m_rx_gain = b_port->p_m_rx_gain;
p_m_pipeline = b_port->p_m_pipeline;
@ -667,140 +619,38 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
FATAL("bchannel must be linked to a Port class\n");
switch(state) {
case B_STATE_IDLE:
if (p_m_remote_ref) {
/* export bchannel */
message_bchannel_to_remote(p_m_remote_id, p_m_remote_ref, BCHANNEL_ASSIGN, portid, p_m_tx_gain, p_m_rx_gain, p_m_pipeline, p_m_crypt_key, p_m_crypt_key_len, p_m_crypt_key_type, 0);
chan_trace_header(mISDNport, b_port, "MESSAGE_BCHANNEL (to remote application)", DIRECTION_NONE);
add_trace("type", NULL, "assign");
add_trace("channel", NULL, "%d.%d", portid>>8, portid&0xff);
end_trace();
state = B_STATE_EXPORTING;
mISDNport->b_remote_id[i] = p_m_remote_id;
mISDNport->b_remote_ref[i] = p_m_remote_ref;
} else {
/* create stack and send activation request */
if (_bchannel_create(mISDNport, i)) {
_bchannel_activate(mISDNport, i, 1, 0);
state = B_STATE_ACTIVATING;
timer = B_TIMER_ACTIVATING;
}
/* create stack and send activation request */
if (_bchannel_create(mISDNport, i)) {
_bchannel_activate(mISDNport, i, 1, 0);
state = B_STATE_ACTIVATING;
timer = B_TIMER_ACTIVATING;
}
break;
case B_STATE_ACTIVATING:
case B_STATE_EXPORTING:
/* do nothing, because it is already activating */
break;
case B_STATE_DEACTIVATING:
case B_STATE_IMPORTING:
/* do nothing, because we must wait until we can reactivate */
break;
default:
/* problems that might ocurr:
* B_EVENT_USE is received when channel already in use.
* bchannel exported, but not freed by other port
*/
PERROR("Illegal event %d at state %d, please correct.\n", event, state);
}
break;
case B_EVENT_EXPORTREQUEST:
/* special case where the bchannel is requested by remote */
if (!p_m_remote_ref) {
PERROR("export request without remote channel set, please correct.\n");
break;
}
switch(state) {
case B_STATE_IDLE:
/* in case, the bchannel is exported right after seize_bchannel */
/* export bchannel */
/* p_m_remote_id is set, when this event happens. */
message_bchannel_to_remote(p_m_remote_id, p_m_remote_ref, BCHANNEL_ASSIGN, portid, p_m_tx_gain, p_m_rx_gain, p_m_pipeline, p_m_crypt_key, p_m_crypt_key_len, p_m_crypt_key_type, 0);
chan_trace_header(mISDNport, b_port, "MESSAGE_BCHANNEL (to remote application)", DIRECTION_NONE);
add_trace("type", NULL, "assign");
add_trace("channel", NULL, "%d.%d", portid>>8, portid&0xff);
end_trace();
state = B_STATE_EXPORTING;
mISDNport->b_remote_id[i] = p_m_remote_id;
mISDNport->b_remote_ref[i] = p_m_remote_ref;
break;
case B_STATE_ACTIVATING:
case B_STATE_EXPORTING:
/* do nothing, because it is already activating */
break;
case B_STATE_DEACTIVATING:
case B_STATE_IMPORTING:
/* do nothing, because we must wait until we can reactivate */
break;
case B_STATE_ACTIVE:
/* bchannel is active, so we deactivate */
_bchannel_activate(mISDNport, i, 0, 0);
state = B_STATE_DEACTIVATING;
timer = B_TIMER_DEACTIVATING;
break;
default:
/* problems that might ocurr:
* ... when channel already in use.
* bchannel exported, but not freed by other port
*/
PERROR("Illegal event %d at state %d, please correct.\n", event, state);
}
break;
case B_EVENT_IMPORTREQUEST:
/* special case where the bchannel is released by remote */
if (p_m_remote_ref) {
PERROR("import request with remote channel set, please correct.\n");
break;
}
switch(state) {
case B_STATE_IDLE:
case B_STATE_ACTIVE:
/* bchannel is not exported */
break;
case B_STATE_ACTIVATING:
case B_STATE_EXPORTING:
/* do nothing because we must wait until bchanenl is active before deactivating */
break;
case B_STATE_REMOTE:
/* bchannel is exported, so we re-import */
message_bchannel_to_remote(mISDNport->b_remote_id[i], 0, BCHANNEL_REMOVE, portid, 0,0,0,0,0,0, 0);
chan_trace_header(mISDNport, b_port, "MESSAGE_BCHANNEL (to remote application)", DIRECTION_NONE);
add_trace("type", NULL, "remove");
add_trace("channel", NULL, "%d.%d", portid>>8, portid&0xff);
end_trace();
state = B_STATE_IMPORTING;
break;
case B_STATE_DEACTIVATING:
case B_STATE_IMPORTING:
/* we may have taken an already deactivating bchannel, but do not require it anymore, so we do nothing */
break;
default:
PERROR("Illegal event %d at state %d, please correct.\n", event, state);
}
break;
case B_EVENT_ACTIVATED:
timer = 0;
switch(state) {
case B_STATE_ACTIVATING:
if (b_port && !p_m_remote_id) {
if (b_port) {
/* bchannel is active and used by Port class, so we configure bchannel */
_bchannel_configure(mISDNport, i);
state = B_STATE_ACTIVE;
b_port->p_m_load = 0;
} else {
/* bchannel is active, but exported OR not used anymore (or has wrong stack config), so we deactivate */
/* bchannel is active, but not used anymore (or has wrong stack config), so we deactivate */
_bchannel_activate(mISDNport, i, 0, 0);
state = B_STATE_DEACTIVATING;
timer = B_TIMER_DEACTIVATING;
@ -812,31 +662,6 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
}
break;
case B_EVENT_EXPORTED:
switch(state) {
case B_STATE_EXPORTING:
if (b_port && p_m_remote_ref && p_m_remote_ref==mISDNport->b_remote_ref[i]) {
/* remote export done */
state = B_STATE_REMOTE;
} else {
/* bchannel is now exported, but we need bchannel back
* OR bchannel is not used anymore
* OR bchannel has been exported to an obsolete ref,
* so reimport, to later export to new remote */
message_bchannel_to_remote(mISDNport->b_remote_id[i], 0, BCHANNEL_REMOVE, portid, 0,0,0,0,0,0, 0);
chan_trace_header(mISDNport, b_port, "MESSAGE_BCHANNEL (to remote application)", DIRECTION_NONE);
add_trace("type", NULL, "remove");
add_trace("channel", NULL, "%d.%d", portid>>8, portid&0xff);
end_trace();
state = B_STATE_IMPORTING;
}
break;
default:
PERROR("Illegal event %d at state %d, please correct.\n", event, state);
}
break;
case B_EVENT_DROP:
if (!b_port)
FATAL("bchannel must be linked to a Port class\n");
@ -846,7 +671,6 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
break;
case B_STATE_ACTIVATING:
case B_STATE_EXPORTING:
/* do nothing because we must wait until bchanenl is active before deactivating */
break;
@ -857,18 +681,7 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
timer = B_TIMER_DEACTIVATING;
break;
case B_STATE_REMOTE:
/* bchannel is exported, so we re-import */
message_bchannel_to_remote(mISDNport->b_remote_id[i], 0, BCHANNEL_REMOVE, portid, 0,0,0,0,0,0, 0);
chan_trace_header(mISDNport, b_port, "MESSAGE_BCHANNEL (to remote application)", DIRECTION_NONE);
add_trace("type", NULL, "remove");
add_trace("channel", NULL, "%d.%d", portid>>8, portid&0xff);
end_trace();
state = B_STATE_IMPORTING;
break;
case B_STATE_DEACTIVATING:
case B_STATE_IMPORTING:
/* we may have taken an already deactivating bchannel, but do not require it anymore, so we do nothing */
break;
@ -888,22 +701,11 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
_bchannel_destroy(mISDNport, i);
state = B_STATE_IDLE;
if (b_port) {
/* bchannel is now deactivate, but is requied by Port class, so we reactivate / export */
if (p_m_remote_ref) {
message_bchannel_to_remote(p_m_remote_id, p_m_remote_ref, BCHANNEL_ASSIGN, portid, p_m_tx_gain, p_m_rx_gain, p_m_pipeline, p_m_crypt_key, p_m_crypt_key_len, p_m_crypt_key_type, 0);
chan_trace_header(mISDNport, b_port, "MESSAGE_BCHANNEL (to remote application)", DIRECTION_NONE);
add_trace("type", NULL, "assign");
add_trace("channel", NULL, "%d.%d", portid>>8, portid&0xff);
end_trace();
state = B_STATE_EXPORTING;
mISDNport->b_remote_id[i] = p_m_remote_id;
mISDNport->b_remote_ref[i] = p_m_remote_ref;
} else {
if (_bchannel_create(mISDNport, i)) {
_bchannel_activate(mISDNport, i, 1, 0);
state = B_STATE_ACTIVATING;
timer = B_TIMER_ACTIVATING;
}
/* bchannel is now deactivate, but is requied by Port class, so we reactivate */
if (_bchannel_create(mISDNport, i)) {
_bchannel_activate(mISDNport, i, 1, 0);
state = B_STATE_ACTIVATING;
timer = B_TIMER_ACTIVATING;
}
}
break;
@ -913,39 +715,6 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
}
break;
case B_EVENT_IMPORTED:
switch(state) {
case B_STATE_IMPORTING:
state = B_STATE_IDLE;
mISDNport->b_remote_id[i] = 0;
mISDNport->b_remote_ref[i] = 0;
if (b_port) {
/* bchannel is now imported, but is requied by Port class, so we reactivate / export */
if (p_m_remote_ref) {
message_bchannel_to_remote(p_m_remote_id, p_m_remote_ref, BCHANNEL_ASSIGN, portid, p_m_tx_gain, p_m_rx_gain, p_m_pipeline, p_m_crypt_key, p_m_crypt_key_len, p_m_crypt_key_type, 0);
chan_trace_header(mISDNport, b_port, "MESSAGE_BCHANNEL (to remote application)", DIRECTION_NONE);
add_trace("type", NULL, "assign");
add_trace("channel", NULL, "%d.%d", portid>>8, portid&0xff);
end_trace();
state = B_STATE_EXPORTING;
mISDNport->b_remote_id[i] = p_m_remote_id;
mISDNport->b_remote_ref[i] = p_m_remote_ref;
} else {
if (_bchannel_create(mISDNport, i)) {
_bchannel_activate(mISDNport, i, 1, 0);
state = B_STATE_ACTIVATING;
timer = B_TIMER_ACTIVATING;
}
}
}
break;
default:
/* ignore, because not assigned */
;
}
break;
case B_EVENT_TIMEOUT:
timer = 0;
switch(state) {
@ -1084,101 +853,6 @@ void PmISDN::drop_bchannel(void)
p_m_b_exclusive = 0;
}
/* process bchannel export/import message from join */
void message_bchannel_from_remote(class JoinRemote *joinremote, int type, unsigned int handle)
{
class Endpoint *epoint;
class Port *port;
class PmISDN *isdnport;
struct mISDNport *mISDNport;
int i, ii;
switch(type) {
case BCHANNEL_REQUEST:
/* find the port object for the join object ref */
if (!(epoint = find_epoint_id(joinremote->j_epoint_id))) {
PDEBUG(DEBUG_BCHANNEL, "join %d has no endpoint (anymore)\n", joinremote->j_serial);
return;
}
if (!epoint->ep_portlist) {
PDEBUG(DEBUG_BCHANNEL, "join %d has no port (anymore in portlist)\n", joinremote->j_serial);
return;
}
if (epoint->ep_portlist->next) {
PERROR("join %d has enpoint %d with more than one port. this shall not happen to remote joins.\n", joinremote->j_serial, epoint->ep_serial);
}
if (!(port = find_port_id(epoint->ep_portlist->port_id))) {
PDEBUG(DEBUG_BCHANNEL, "join %d has no port (anymore as object)\n", joinremote->j_serial);
return;
}
if ((port->p_type&PORT_CLASS_MASK) != PORT_CLASS_mISDN) {
PERROR("join %d has port %d not of mISDN type. This shall not happen.\n", joinremote->j_serial, port->p_serial);
}
isdnport = (class PmISDN *)port;
/* assign */
if (isdnport->p_m_remote_id) {
PERROR("join %d recevied bchannel request from remote, but channel is already assinged.\n", joinremote->j_serial);
break;
}
mISDNport = isdnport->p_m_mISDNport;
i = isdnport->p_m_b_index;
chan_trace_header(mISDNport, isdnport, "MESSAGE_BCHANNEL (from remote application)", DIRECTION_NONE);
add_trace("type", NULL, "export request");
end_trace();
isdnport->p_m_remote_ref = joinremote->j_remote_ref;
isdnport->p_m_remote_id = joinremote->j_remote_id;
if (mISDNport && i>=0) {
bchannel_event(mISDNport, i, B_EVENT_EXPORTREQUEST);
}
break;
case BCHANNEL_RELEASE:
case BCHANNEL_ASSIGN_ACK:
case BCHANNEL_REMOVE_ACK:
/* find mISDNport for stack ID */
mISDNport = mISDNport_first;
while(mISDNport) {
i = 0;
ii = mISDNport->b_num;
while(i < ii) {
if ((unsigned int)(mISDNport->portnum<<8)+i+1+(i>=15) == handle)
break;
i++;
}
if (i != ii)
break;
mISDNport = mISDNport->next;
}
if (!mISDNport) {
PERROR("received assign/remove ack for bchannel's handle=%x, but handle does not exist in any mISDNport structure.\n", handle);
break;
}
if (type!=BCHANNEL_RELEASE) {
/* ack */
chan_trace_header(mISDNport, mISDNport->b_port[i], "MESSAGE_BCHANNEL (from remote application)", DIRECTION_NONE);
add_trace("type", NULL, (type==BCHANNEL_ASSIGN_ACK)?"assign_ack":"remove_ack");
end_trace();
bchannel_event(mISDNport, i, (type==BCHANNEL_ASSIGN_ACK)?B_EVENT_EXPORTED:B_EVENT_IMPORTED);
} else {
/* release */
isdnport = mISDNport->b_port[i];
chan_trace_header(mISDNport, isdnport, "MESSAGE_BCHANNEL (from remote application)", DIRECTION_NONE);
add_trace("type", NULL, "import request");
end_trace();
if (isdnport) {
isdnport->p_m_remote_ref = 0;
isdnport->p_m_remote_id = 0;
}
bchannel_event(mISDNport, i, B_EVENT_IMPORTREQUEST);
}
break;
default:
PERROR("received wrong bchannel message type %d from remote\n", type);
}
}
/*
* handler
@ -1843,98 +1517,96 @@ static int mISDN_upqueue(struct lcr_fd *fd, unsigned int what, void *instance, i
mISDNport = mISDNport_first;
while(mISDNport) {
/* handle queued up-messages (d-channel) */
if (!mISDNport->isloopback) {
while ((mb = mdequeue(&mISDNport->upqueue))) {
l3m = &mb->l3;
switch(l3m->type) {
case MPH_ACTIVATE_IND:
if (mISDNport->l1link != 1) {
l1l2l3_trace_header(mISDNport, NULL, L1_ACTIVATE_IND, DIRECTION_IN);
end_trace();
mISDNport->l1link = 1;
}
break;
case MPH_DEACTIVATE_IND:
if (mISDNport->l1link != 0) {
l1l2l3_trace_header(mISDNport, NULL, L1_DEACTIVATE_IND, DIRECTION_IN);
end_trace();
mISDNport->l1link = 0;
}
break;
while ((mb = mdequeue(&mISDNport->upqueue))) {
l3m = &mb->l3;
switch(l3m->type) {
case MPH_ACTIVATE_IND:
if (mISDNport->l1link != 1) {
l1l2l3_trace_header(mISDNport, NULL, L1_ACTIVATE_IND, DIRECTION_IN);
end_trace();
mISDNport->l1link = 1;
}
break;
case MPH_DEACTIVATE_IND:
if (mISDNport->l1link != 0) {
l1l2l3_trace_header(mISDNport, NULL, L1_DEACTIVATE_IND, DIRECTION_IN);
end_trace();
mISDNport->l1link = 0;
}
break;
case MPH_INFORMATION_IND:
PDEBUG(DEBUG_ISDN, "Received MPH_INFORMATION_IND for port %d (%s).\n", mISDNport->portnum, mISDNport->ifport->interface->name);
switch (l3m->pid) {
case L1_SIGNAL_LOS_ON:
mISDNport->los = 1;
break;
case L1_SIGNAL_LOS_OFF:
mISDNport->los = 0;
break;
case L1_SIGNAL_AIS_ON:
mISDNport->ais = 1;
break;
case L1_SIGNAL_AIS_OFF:
mISDNport->ais = 0;
break;
case L1_SIGNAL_RDI_ON:
mISDNport->rdi = 1;
break;
case L1_SIGNAL_RDI_OFF:
mISDNport->rdi = 0;
break;
case L1_SIGNAL_SLIP_TX:
mISDNport->slip_tx++;
break;
case L1_SIGNAL_SLIP_RX:
mISDNport->slip_rx++;
break;
}
case MPH_INFORMATION_IND:
PDEBUG(DEBUG_ISDN, "Received MPH_INFORMATION_IND for port %d (%s).\n", mISDNport->portnum, mISDNport->ifport->interface->name);
switch (l3m->pid) {
case L1_SIGNAL_LOS_ON:
mISDNport->los = 1;
break;
case L1_SIGNAL_LOS_OFF:
mISDNport->los = 0;
break;
case L1_SIGNAL_AIS_ON:
mISDNport->ais = 1;
break;
case L1_SIGNAL_AIS_OFF:
mISDNport->ais = 0;
break;
case L1_SIGNAL_RDI_ON:
mISDNport->rdi = 1;
break;
case L1_SIGNAL_RDI_OFF:
mISDNport->rdi = 0;
break;
case L1_SIGNAL_SLIP_TX:
mISDNport->slip_tx++;
break;
case L1_SIGNAL_SLIP_RX:
mISDNport->slip_rx++;
break;
}
break;
case MT_L2ESTABLISH:
l1l2l3_trace_header(mISDNport, NULL, L2_ESTABLISH_IND, DIRECTION_IN);
case MT_L2ESTABLISH:
l1l2l3_trace_header(mISDNport, NULL, L2_ESTABLISH_IND, DIRECTION_IN);
add_trace("tei", NULL, "%d", l3m->pid);
end_trace();
mISDNport->l2link = 1;
if (l3m->pid < 128)
mISDNport->l2mask[l3m->pid >> 3] |= (1 << (l3m->pid & 7));
if ((!mISDNport->ntmode || mISDNport->ptp) && l3m->pid < 127) {
if (mISDNport->l2establish.active) {
unsched_timer(&mISDNport->l2establish);
PDEBUG(DEBUG_ISDN, "the link became active before l2establish timer expiry.\n");
}
}
break;
case MT_L2RELEASE:
if (l3m->pid < 128)
mISDNport->l2mask[l3m->pid >> 3] &= ~(1 << (l3m->pid & 7));
if (!mISDNport->l2establish.active) {
l1l2l3_trace_header(mISDNport, NULL, L2_RELEASE_IND, DIRECTION_IN);
add_trace("tei", NULL, "%d", l3m->pid);
end_trace();
mISDNport->l2link = 1;
if (l3m->pid < 128)
mISDNport->l2mask[l3m->pid >> 3] |= (1 << (l3m->pid & 7));
if ((!mISDNport->ntmode || mISDNport->ptp) && l3m->pid < 127) {
if (mISDNport->l2establish.active) {
unsched_timer(&mISDNport->l2establish);
PDEBUG(DEBUG_ISDN, "the link became active before l2establish timer expiry.\n");
}
}
break;
case MT_L2RELEASE:
if (l3m->pid < 128)
mISDNport->l2mask[l3m->pid >> 3] &= ~(1 << (l3m->pid & 7));
if (!mISDNport->l2establish.active) {
l1l2l3_trace_header(mISDNport, NULL, L2_RELEASE_IND, DIRECTION_IN);
add_trace("tei", NULL, "%d", l3m->pid);
end_trace();
/* down if not nt-ptmp */
if (!mISDNport->ntmode || mISDNport->ptp)
mISDNport->l2link = 0;
}
if (!mISDNport->isloopback && (!mISDNport->ntmode || mISDNport->ptp) && l3m->pid < 127) {
if (!mISDNport->l2establish.active && mISDNport->l2hold) {
PDEBUG(DEBUG_ISDN, "set timer and establish.\n");
schedule_timer(&mISDNport->l2establish, 5, 0);
mISDNport->ml3->to_layer3(mISDNport->ml3, MT_L2ESTABLISH, 0, NULL);
}
}
break;
default:
/* l3-data is sent to LCR */
stack2manager(mISDNport, l3m->type, l3m->pid, l3m);
/* down if not nt-ptmp */
if (!mISDNport->ntmode || mISDNport->ptp)
mISDNport->l2link = 0;
}
/* free message */
free_l3_msg(l3m);
if ((!mISDNport->ntmode || mISDNport->ptp) && l3m->pid < 127) {
if (!mISDNport->l2establish.active && mISDNport->l2hold) {
PDEBUG(DEBUG_ISDN, "set timer and establish.\n");
schedule_timer(&mISDNport->l2establish, 5, 0);
mISDNport->ml3->to_layer3(mISDNport->ml3, MT_L2ESTABLISH, 0, NULL);
}
}
break;
default:
/* l3-data is sent to LCR */
stack2manager(mISDNport, l3m->type, l3m->pid, l3m);
}
/* free message */
free_l3_msg(l3m);
}
mISDNport = mISDNport->next;
}
@ -1946,7 +1618,7 @@ static int l2establish_timeout(struct lcr_timer *timer, void *instance, int i)
{
struct mISDNport *mISDNport = (struct mISDNport *)instance;
if (!mISDNport->isloopback && mISDNport->l2hold && (mISDNport->ptp || !mISDNport->ntmode)) {
if (mISDNport->l2hold && (mISDNport->ptp || !mISDNport->ntmode)) {
PDEBUG(DEBUG_ISDN, "the L2 establish timer expired, we try to establish the link portnum=%d.\n", mISDNport->portnum);
mISDNport->ml3->to_layer3(mISDNport->ml3, MT_L2ESTABLISH, 0, NULL);
schedule_timer(&mISDNport->l2establish, 5, 0); /* 5 seconds */
@ -2107,7 +1779,6 @@ struct mISDNport *mISDNport_open(struct interface_port *ifport)
int force_nt = ifport->nt;
int l1hold = ifport->l1hold;
int l2hold = ifport->l2hold;
int loop = 0;
int ss5 = ifport->ss5;
int i, cnt;
int pri, bri, pots;
@ -2116,16 +1787,6 @@ struct mISDNport *mISDNport_open(struct interface_port *ifport)
struct mISDN_devinfo devinfo;
unsigned int protocol, prop;
loop = 0;
//printf("%s == %s\n", ifport->portname, options.loopback_int);
if (!strcmp(ifport->portname, options.loopback_lcr))
loop = 1;
if (loop) {
if (mISDNloop_open())
return NULL;
}
/* check port counts */
ret = ioctl(mISDNsocket, IMGETCOUNT, &cnt);
if (ret < 0) {
@ -2140,10 +1801,7 @@ struct mISDNport *mISDNport_open(struct interface_port *ifport)
if (port < 0) {
port = mISDN_getportbyname(mISDNsocket, cnt, ifport->portname);
if (port < 0) {
if (loop)
PERROR_RUNTIME("Port name '%s' not found, did you load loopback interface?.\n", ifport->portname);
else
PERROR_RUNTIME("Port name '%s' not found, use 'misdn_info' tool to list all existing ports.\n", ifport->portname);
PERROR_RUNTIME("Port name '%s' not found, use 'misdn_info' tool to list all existing ports.\n", ifport->portname);
return(NULL);
}
// note: 'port' has still the port number
@ -2257,15 +1915,14 @@ struct mISDNport *mISDNport_open(struct interface_port *ifport)
mISDNportp = &((*mISDNportp)->next);
mISDNport = (struct mISDNport *)MALLOC(sizeof(struct mISDNport));
add_timer(&mISDNport->l2establish, l2establish_timeout, mISDNport, 0);
if (loop | ss5) {
/* loop/ss5 link is always active */
if (ss5) {
/* ss5 link is always active */
mISDNport->l1link = 1;
mISDNport->l2link = 1;
} else {
mISDNport->l1link = -1;
mISDNport->l2link = -1;
}
mISDNport->isloopback = loop;
pmemuse++;
*mISDNportp = mISDNport;
@ -2307,56 +1964,23 @@ struct mISDNport *mISDNport_open(struct interface_port *ifport)
if (l2hold) // supports layer 2 hold
prop |= (1 << MISDN_FLG_L2_HOLD);
/* open layer 3 and init upqueue */
if (loop) {
unsigned long on = 1;
struct sockaddr_mISDN addr;
if (devinfo.nrbchan < 8) {
printf("loop port %d has a low number of bchannels. (only %d) remember that all interfaces that requires a loopback could run out of channels\n", port, devinfo.nrbchan);
// mISDNport_close(mISDNport);
// return(NULL);
}
if ((mISDNport->lcr_sock = socket(PF_ISDN, SOCK_DGRAM, (bri) ? ISDN_P_TE_S0 : ISDN_P_TE_E1)) < 0) {
PERROR_RUNTIME("loop port %d failed to open socket.\n", port);
mISDNport_close(mISDNport);
return(NULL);
}
/* set nonblocking io */
if (ioctl(mISDNport->lcr_sock, FIONBIO, &on) < 0) {
PERROR_RUNTIME("loop port %d failed to set socket into nonblocking io.\n", port);
mISDNport_close(mISDNport);
return(NULL);
}
/* bind socket to dchannel */
memset(&addr, 0, sizeof(addr));
addr.family = AF_ISDN;
addr.dev = port;
addr.channel = 0;
if (bind(mISDNport->lcr_sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
PERROR_RUNTIME("loop port %d failed to bind socket. (errno %d)\n", port, errno);
mISDNport_close(mISDNport);
return(NULL);
}
} else {
/* queue must be initializes, because l3-thread may send messages during open_layer3() */
mqueue_init(&mISDNport->upqueue);
mISDNport->ml3 = open_layer3(port, protocol, prop , do_layer3, mISDNport);
if (!mISDNport->ml3) {
mqueue_purge(&mISDNport->upqueue);
PERROR_RUNTIME("open_layer3() failed for port %d\n", port);
start_trace(port,
ifport->interface,
NULL,
NULL,
DIRECTION_NONE,
CATEGORY_CH,
0,
"PORT (open failed)");
end_trace();
mISDNport_close(mISDNport);
return(NULL);
}
/* queue must be initializes, because l3-thread may send messages during open_layer3() */
mqueue_init(&mISDNport->upqueue);
mISDNport->ml3 = open_layer3(port, protocol, prop , do_layer3, mISDNport);
if (!mISDNport->ml3) {
mqueue_purge(&mISDNport->upqueue);
PERROR_RUNTIME("open_layer3() failed for port %d\n", port);
start_trace(port,
ifport->interface,
NULL,
NULL,
DIRECTION_NONE,
CATEGORY_CH,
0,
"PORT (open failed)");
end_trace();
mISDNport_close(mISDNport);
return(NULL);
}
SCPY(mISDNport->name, devinfo.name);
@ -2378,7 +2002,7 @@ struct mISDNport *mISDNport_open(struct interface_port *ifport)
}
/* if ptp, pull up the link */
if (!mISDNport->isloopback && mISDNport->l2hold && (mISDNport->ptp || !mISDNport->ntmode)) {
if (mISDNport->l2hold && (mISDNport->ptp || !mISDNport->ntmode)) {
mISDNport->ml3->to_layer3(mISDNport->ml3, MT_L2ESTABLISH, 0, NULL);
l1l2l3_trace_header(mISDNport, NULL, L2_ESTABLISH_REQ, DIRECTION_OUT);
add_trace("tei", NULL, "%d", 0);
@ -2491,18 +2115,12 @@ void mISDNport_close(struct mISDNport *mISDNport)
del_timer(&mISDNport->l2establish);
/* close layer 3, if open */
if (!mISDNport->isloopback && mISDNport->ml3) {
if (mISDNport->ml3) {
close_layer3(mISDNport->ml3);
}
/* close gsm socket, if open */
if (mISDNport->isloopback && mISDNport->lcr_sock > -1) {
close(mISDNport->lcr_sock);
}
/* purge upqueue */
if (!mISDNport->isloopback)
mqueue_purge(&mISDNport->upqueue);
mqueue_purge(&mISDNport->upqueue);
/* remove from list */
mISDNportp = &mISDNport_first;

18
mISDN.h
View File

@ -18,15 +18,11 @@ extern int mISDNdevice;
extern int mISDNsocket;
enum {
B_EVENT_USE, /* activate/export bchannel */
B_EVENT_EXPORTREQUEST, /* remote app requests bchannel */
B_EVENT_IMPORTREQUEST, /* remote app releases bchannel */
B_EVENT_USE, /* activate bchannel */
B_EVENT_ACTIVATED, /* DL_ESTABLISH received */
B_EVENT_DROP, /* deactivate/re-import bchannel */
B_EVENT_DROP, /* deactivate bchannel */
B_EVENT_DEACTIVATED, /* DL_RELEASE received */
B_EVENT_EXPORTED, /* BCHANNEL_ASSIGN received */
B_EVENT_IMPORTED, /* BCHANNEL_REMOVE received */
B_EVENT_TIMEOUT, /* timeout for bchannel state */
B_EVENT_TIMEOUT, /* timeout happed during (de)activation */
};
/* mISDN port structure list */
@ -59,14 +55,9 @@ struct mISDNport {
int b_mode[128]; /* B_MODE_* */
int b_state[128]; /* statemachine, 0 = IDLE */
struct lcr_timer b_timer[128]; /* timer for bchannel state machine */
int b_remote_id[128]; /* the socket currently exported (0=none) */
unsigned int b_remote_ref[128]; /* the ref currently exported */
int locally; /* local causes are sent as local causes not remote */
int los, ais, rdi, slip_rx, slip_tx;
int lcr_sock; /* socket of loopback on LCR side */
int isloopback; /* will be set on open, in case it is a loopback if */
/* ss5 */
unsigned int ss5; /* set, if SS5 signalling enabled, also holds feature bits */
};
@ -103,7 +94,6 @@ void ph_control_block(struct mISDNport *mISDNport, unsigned int handle, unsigned
void chan_trace_header(struct mISDNport *mISDNport, class PmISDN *port, const char *msgtext, int direction);
void l1l2l3_trace_header(struct mISDNport *mISDNport, class PmISDN *port, unsigned int prim, int direction);
void bchannel_event(struct mISDNport *mISDNport, int i, int event);
void message_bchannel_from_remote(class JoinRemote *joinremote, int type, unsigned int handle);
/* mISDN port classes */
@ -164,8 +154,6 @@ class PmISDN : public Port
int p_m_b_mode; /* bchannel mode */
int p_m_hold; /* if port is on hold */
struct lcr_timer p_m_timeout; /* timeout of timers */
unsigned int p_m_remote_ref; /* join to export bchannel to */
int p_m_remote_id; /* sock to export bchannel to */
int p_m_inband_send_on; /* triggers optional send function */
int p_m_inband_receive_on; /* triggers optional receive function */

6
main.c
View File

@ -627,12 +627,6 @@ exit is done when interface is down
sip_exit();
#endif
#ifdef WITH_MISDN
/* close loopback, if used by GSM or remote */
if (mISDNloop.sock > -1)
mISDNloop_close();
#endif
/* display memory leak */
#define MEMCHECK(a, b) \
if (b) { \

4
main.h
View File

@ -149,11 +149,10 @@ void debug(const char *file, const char *function, int line, const char *prefix,
#include "callerid.h"
#include "route.h"
#include "port.h"
#include "remote.h"
#ifdef WITH_MISDN
#include "mISDN.h"
#include "dss1.h"
#include "loop.h"
#include "remote.h"
#endif
#if defined WITH_GSM_BS || defined WITH_GSM_MS
#include "gsm.h"
@ -175,7 +174,6 @@ void debug(const char *file, const char *function, int line, const char *prefix,
#include "vbox.h"
#include "join.h"
#include "joinpbx.h"
#include "joinremote.h"
#include "cause.h"
#include "alawulaw.h"
#include "tones.h"

View File

@ -126,23 +126,13 @@ enum { /* isdnsignal */
mISDNSIGNAL_DELAY, /* use delay or adaptive jitter */
};
enum { /* bchannel assignment */
BCHANNEL_REQUEST, /* application requests bchannel */
BCHANNEL_RELEASE, /* application releases bchannel */
BCHANNEL_ASSIGN, /* bchannel assigned by LCR */
BCHANNEL_ASSIGN_ACK, /* application acknowledges */
BCHANNEL_REMOVE, /* bchannel removed by LCR */
BCHANNEL_REMOVE_ACK, /* application acknowledges */
};
enum {
B_STATE_IDLE, /* not open */
B_STATE_ACTIVATING, /* DL_ESTABLISH sent */
B_STATE_ACTIVE, /* channel active */
B_STATE_DEACTIVATING, /* DL_RELEASE sent */
B_STATE_EXPORTING, /* BCHANNEL_ASSIGN sent */
B_STATE_REMOTE, /* bchannel assigned to remote application */
B_STATE_IMPORTING, /* BCHANNEL_REMOVE sent */
};
enum {
B_MODE_TRANSPARENT, /* normal transparent audio */
B_MODE_HDLC, /* hdlc data mode */
@ -194,6 +184,7 @@ struct dialing_info {
int sending_complete; /* end of dialing */
char display[84]; /* display information */
char keypad[33]; /* send keypad facility */
char context[32]; /* asterisk context */
};
/* call-info structure CONNECT */
@ -288,7 +279,6 @@ struct message_setup {
struct useruser_info useruser; /* user-user */
struct progress_info progress; /* info on call progress */
struct rtp_info rtpinfo; /* info about RTP peer */
char context[128]; /* asterisk context */
};
/* call-info structure PARK */
@ -346,7 +336,11 @@ struct param_bchannel {
struct param_newref {
int direction; /* who requests a refe? */
int mode; /* 0 = direct-mode, 1 = PBX mode */
};
struct param_traffic {
int len; /* how much data */
unsigned char data[160]; /* 20ms */
};
/* structure of message parameter */
@ -374,6 +368,7 @@ union parameter {
struct param_bchannel bchannel; /* MESSAGE_BCHANNEL */
struct param_newref newref; /* MESSAGE_NEWREF */
unsigned int bridge_id; /* MESSAGE_BRIDGE */
struct param_traffic traffic; /* MESSAGE_TRAFFIC */
};
enum { /* message flow */
@ -427,6 +422,7 @@ enum { /* messages between entities */
MESSAGE_HELLO, /* hello message for remote application */
MESSAGE_NEWREF, /* special message to create and inform ref */
MESSAGE_BRIDGE, /* control port bridge */
MESSAGE_TRAFFIC, /* exchange bchannel traffic */
};
#define MESSAGES static const char *messages_txt[] = { \
@ -462,6 +458,7 @@ enum { /* messages between entities */
"MESSAGE_HELLO", \
"MESSAGE_NEWREF", \
"MESSAGE_BRIDGE", \
"MESSAGE_TRAFFIC", \
};

View File

@ -36,8 +36,6 @@ struct options options = {
-1, /* socket user (-1= no change) */
-1, /* socket group (-1= no change) */
1, /* use polling of main loop */
"mISDN_l1loop.1", /* GSM/Asterisk side */
"mISDN_l1loop.2", /* LCR side */
};
char options_error[256];
@ -237,22 +235,6 @@ int read_options(char *options_error)
} else
if (!strcmp(option,"polling")) {
options.polling = 1;
} else
if (!strcmp(option,"loopback-ext")) {
if (param[0]==0) {
UPRINT(options_error, "Error in %s (line %d): parameter for option %s missing.\n",filename,line, option);
goto error;
}
SCPY(options.loopback_ext, param);
} else
if (!strcmp(option,"loopback-lcr")) {
if (param[0]==0) {
UPRINT(options_error, "Error in %s (line %d): parameter for option %s missing.\n",filename,line, option);
goto error;
}
SCPY(options.loopback_lcr, param);
} else {
UPRINT(options_error, "Error in %s (line %d): wrong option keyword %s.\n", filename,line,option);
goto error;

View File

@ -30,8 +30,6 @@ struct options {
int socketuser; /* socket chown to this user */
int socketgroup; /* socket chgrp to this group */
int polling;
char loopback_ext[64]; /* loopback interface GSM side */
char loopback_lcr[64]; /* loopback interface LCR side */
};
extern struct options options;

6
port.h
View File

@ -19,11 +19,11 @@
#define PORT_CLASS_DSS1_NT 0x1110
#define PORT_CLASS_DSS1_TE 0x1120
#define PORT_CLASS_SS5 0x1300
#define PORT_CLASS_REMOTE 0x1400
#define PORT_CLASS_SIP 0x2000
#define PORT_CLASS_GSM 0x3000
#define PORT_CLASS_GSM_BS 0x3100
#define PORT_CLASS_GSM_MS 0x3200
#define PORT_CLASS_REMOTE 0x4000
#define PORT_CLASS_MASK 0xf000
#define PORT_CLASS_mISDN_MASK 0xff00
#define PORT_CLASS_DSS1_MASK 0xfff0
@ -47,8 +47,8 @@
#define PORT_TYPE_SS5_OUT 0x1312
#define PORT_TYPE_SS5_IDLE 0x1313
/* remote */
#define PORT_TYPE_REMOTE_IN 0x1411
#define PORT_TYPE_REMOTE_OUT 0x1412
#define PORT_TYPE_REMOTE_IN 0x4001
#define PORT_TYPE_REMOTE_OUT 0x4002
/* SIP */
#define PORT_TYPE_SIP_IN 0x2001
#define PORT_TYPE_SIP_OUT 0x2002

View File

@ -16,24 +16,25 @@ unsigned int new_remote = 1000;
/*
* constructor
*/
Premote::Premote(int type, struct mISDNport *mISDNport, char *portname, struct port_settings *settings, int channel, int exclusive, int mode, int remote_id) : PmISDN(type, mISDNport, portname, settings, channel, exclusive, mode)
Premote::Premote(int type, char *portname, struct port_settings *settings, struct interface *interface, int remote_id) : Port(type, portname, settings)
{
union parameter param;
p_callerinfo.itype = (mISDNport->ifport->interface->extension)?INFO_ITYPE_ISDN_EXTENSION:INFO_ITYPE_ISDN;
p_m_r_ref = new_remote++;
SCPY(p_m_r_remote_app, mISDNport->ifport->remote_app);
p_m_r_handle = 0;
p_callerinfo.itype = (interface->extension)?INFO_ITYPE_ISDN_EXTENSION:INFO_ITYPE_ISDN;
p_r_ref = new_remote++;
SCPY(p_r_remote_app, interface->remote_app);
SCPY(p_r_interface_name, interface->name);
p_r_tones = (interface->is_tones == IS_YES);
/* send new ref to remote socket */
memset(&param, 0, sizeof(union parameter));
if (type == PORT_TYPE_REMOTE_OUT)
param.newref.direction = 1; /* new ref from lcr */
p_m_r_remote_id = remote_id;
if (admin_message_from_lcr(p_m_r_remote_id, p_m_r_ref, MESSAGE_NEWREF, &param) < 0)
FATAL("No socket with remote application '%s' found, this shall not happen. because we already created one.\n", mISDNport->ifport->remote_app);
p_r_remote_id = remote_id;
if (admin_message_from_lcr(p_r_remote_id, p_r_ref, MESSAGE_NEWREF, &param) < 0)
FATAL("No socket with remote application '%s' found, this shall not happen. because we already created one.\n", p_r_remote_app);
PDEBUG(DEBUG_GSM, "Created new RemotePort(%s).\n", portname);
PDEBUG(DEBUG_PORT, "Created new RemotePort(%s).\n", portname);
}
@ -42,17 +43,7 @@ Premote::Premote(int type, struct mISDNport *mISDNport, char *portname, struct p
*/
Premote::~Premote()
{
/* need to remote (import) external channel from remote application */
if (p_m_r_handle) {
message_bchannel_to_remote(p_m_r_remote_id, p_m_r_ref, BCHANNEL_REMOVE, p_m_r_handle, 0, 0, 0, 0, 0, 0, 1);
chan_trace_header(p_m_mISDNport, this, "MESSAGE_BCHANNEL (to remote application)", DIRECTION_NONE);
add_trace("type", NULL, "remove");
add_trace("channel", NULL, "%d.%d", p_m_r_handle>>8, p_m_r_handle&0xff);
end_trace();
}
PDEBUG(DEBUG_GSM, "Destroyed Remote process(%s).\n", p_name);
PDEBUG(DEBUG_PORT, "Destroyed Remote process(%s).\n", p_name);
}
/*
@ -60,32 +51,18 @@ Premote::~Premote()
*/
int Premote::message_epoint(unsigned int epoint_id, int message_type, union parameter *param)
{
struct lcr_msg *message;
int channel;
int ret;
struct epoint_list *epointlist;
if (PmISDN::message_epoint(epoint_id, message_type, param))
if (Port::message_epoint(epoint_id, message_type, param))
return 1;
if (message_type == MESSAGE_SETUP) {
ret = channel = hunt_bchannel();
if (ret < 0)
goto no_channel;
/* open channel */
ret = seize_bchannel(channel, 1);
if (ret < 0) {
no_channel:
message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
message->param.disconnectinfo.cause = 34;
message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
message_put(message);
new_state(PORT_STATE_RELEASE);
delete this;
struct interface *interface;
interface = getinterfacebyname(p_r_interface_name);
if (!interface) {
PERROR("Cannot find interface %s.\n", p_r_interface_name);
return 0;
}
bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_USE);
/* attach only if not already */
epointlist = p_epointlist;
while(epointlist) {
@ -97,23 +74,34 @@ int Premote::message_epoint(unsigned int epoint_id, int message_type, union para
epointlist_new(epoint_id);
/* set context to pbx */
SCPY(param->setup.context, "pbx");
if (!param->setup.dialinginfo.context[0]) {
if (interface->remote_context[0])
SCPY(param->setup.dialinginfo.context, interface->remote_context);
else
SCPY(param->setup.dialinginfo.context, "lcr");
}
}
/* look for Remote's interface */
if (admin_message_from_lcr(p_m_r_remote_id, p_m_r_ref, message_type, param)<0) {
PERROR("No socket with remote application '%s' found, this shall not happen. Closing socket shall cause release of all remote ports.\n", p_m_mISDNport->ifport->remote_app);
if (admin_message_from_lcr(p_r_remote_id, p_r_ref, message_type, param)<0) {
PERROR("No socket with remote application '%s' found, this shall not happen. Closing socket shall cause release of all remote ports.\n", p_r_remote_app);
return 0;
}
#if 0
/* enable audio path */
if (message_type == MESSAGE_SETUP) {
union parameter newparam;
memset(&newparam, 0, sizeof(union parameter));
admin_message_from_lcr(p_m_r_remote_id, p_m_r_ref, MESSAGE_PATTERN, &newparam);
admin_message_from_lcr(p_r_remote_id, p_r_ref, MESSAGE_PATTERN, &newparam);
newparam.audiopath = 1;
admin_message_from_lcr(p_m_r_remote_id, p_m_r_ref, MESSAGE_AUDIOPATH, &newparam);
admin_message_from_lcr(p_r_remote_id, p_r_ref, MESSAGE_AUDIOPATH, &newparam);
}
#endif
if (message_type == MESSAGE_CONNECT)
new_state(PORT_STATE_CONNECT);
if (message_type == MESSAGE_RELEASE) {
new_state(PORT_STATE_RELEASE);
@ -128,93 +116,81 @@ void Premote::message_remote(int message_type, union parameter *param)
{
class Endpoint *epoint;
struct lcr_msg *message;
int channel;
int ret;
struct interface *interface;
switch (message_type) {
case MESSAGE_TRAFFIC:
bridge_tx(param->traffic.data, param->traffic.len);
break;
case MESSAGE_SETUP:
interface = getinterfacebyname(p_r_interface_name);
if (!interface) {
PERROR("Cannot find interface %s.\n", p_r_interface_name);
return;
}
if (message_type == MESSAGE_SETUP) {
/* enable audio path */
union parameter newparam;
memset(&newparam, 0, sizeof(union parameter));
admin_message_from_lcr(p_m_r_remote_id, p_m_r_ref, MESSAGE_PATTERN, &newparam);
newparam.audiopath = 1;
admin_message_from_lcr(p_m_r_remote_id, p_m_r_ref, MESSAGE_AUDIOPATH, &newparam);
if (interface->is_tones == IS_YES) {
union parameter newparam;
memset(&newparam, 0, sizeof(union parameter));
admin_message_from_lcr(p_r_remote_id, p_r_ref, MESSAGE_PATTERN, &newparam);
newparam.audiopath = 1;
admin_message_from_lcr(p_r_remote_id, p_r_ref, MESSAGE_AUDIOPATH, &newparam);
}
/* set source interface */
param->setup.callerinfo.itype = p_callerinfo.itype;
param->setup.callerinfo.isdn_port = p_m_portnum;
SCPY(param->setup.callerinfo.interface, p_m_mISDNport->ifport->interface->name);
SCPY(param->setup.callerinfo.interface, interface->name);
ret = channel = hunt_bchannel();
if (ret < 0)
goto no_channel;
/* open channel */
ret = seize_bchannel(channel, 1);
if (ret < 0) {
no_channel:
message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_RELEASE);
message->param.disconnectinfo.cause = 34;
message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
message_put(message);
new_state(PORT_STATE_RELEASE);
delete this;
return;
}
bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_USE);
/* create endpoint */
if (p_epointlist)
FATAL("Incoming call but already got an endpoint.\n");
if (!(epoint = new Endpoint(p_serial, 0)))
FATAL("No memory for Endpoint instance\n");
epoint->ep_app = new_endpointapp(epoint, 0, p_m_mISDNport->ifport->interface->app); //incoming
epoint->ep_app = new_endpointapp(epoint, 0, interface->app); //incoming
epointlist_new(epoint->ep_serial);
}
/* FALL THROUGH: */
default:
if (message_type == MESSAGE_CONNECT)
new_state(PORT_STATE_CONNECT);
/* cannot just forward, because param is not of container "struct lcr_msg" */
message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, message_type);
memcpy(&message->param, param, sizeof(message->param));
message_put(message);
/* set serial on bchannel message
* also ref is given, so we send message with ref */
if (message_type == MESSAGE_BCHANNEL) {
int i = p_m_b_index;
unsigned int portid = (mISDNloop.port<<8) + i+1+(i>=15);
switch (param->bchannel.type) {
case BCHANNEL_REQUEST:
p_m_r_handle = portid;
message_bchannel_to_remote(p_m_r_remote_id, p_m_r_ref, BCHANNEL_ASSIGN, portid, 0, 0, 0, 0, 0, 0, 1);
chan_trace_header(p_m_mISDNport, this, "MESSAGE_BCHANNEL (to remote application)", DIRECTION_NONE);
add_trace("type", NULL, "assign");
add_trace("channel", NULL, "%d.%d", portid>>8, portid&0xff);
end_trace();
break;
case BCHANNEL_RELEASE:
p_m_r_handle = 0;
message_bchannel_to_remote(p_m_r_remote_id, p_m_r_ref, BCHANNEL_REMOVE, portid, 0, 0, 0, 0, 0, 0, 1);
chan_trace_header(p_m_mISDNport, this, "MESSAGE_BCHANNEL (to remote application)", DIRECTION_NONE);
add_trace("type", NULL, "remove");
add_trace("channel", NULL, "%d.%d", portid>>8, portid&0xff);
end_trace();
break;
if (message_type == MESSAGE_RELEASE) {
new_state(PORT_STATE_RELEASE);
delete this;
return;
}
return;
}
/* cannot just forward, because param is not of container "struct lcr_msg" */
message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, message_type);
memcpy(&message->param, param, sizeof(message->param));
message_put(message);
if (message_type == MESSAGE_RELEASE) {
new_state(PORT_STATE_RELEASE);
delete this;
return;
}
}
/* select free bchannel from loopback interface */
int Premote::hunt_bchannel(void)
/* receive from remote Port instance */
int Premote::bridge_rx(unsigned char *data, int len)
{
return loop_hunt_bchannel(this, p_m_mISDNport);
union parameter newparam;
int l;
/* don't send tones, if not enabled or not connected */
if (!p_r_tones
&& p_state != PORT_STATE_CONNECT)
return 0;
memset(&newparam, 0, sizeof(union parameter));
/* split, if exeeds data size */
while(len) {
l = (len > (int)sizeof(newparam.traffic.data)) ? sizeof(newparam.traffic.data) : len;
newparam.traffic.len = l;
len -= l;
memcpy(newparam.traffic.data, data, l);
data += l;
admin_message_from_lcr(p_r_remote_id, p_r_ref, MESSAGE_TRAFFIC, &newparam);
}
return 0;
}

View File

@ -1,20 +1,21 @@
/* GSM port class */
class Premote : public PmISDN
class Premote : public Port
{
public:
Premote(int type, struct mISDNport *mISDNport, char *portname, struct port_settings *settings, int channel, int exclusive, int mode, int remote_id);
Premote(int type, char *portname, struct port_settings *settings, struct interface *interface, int remote_id);
~Premote();
unsigned int p_m_r_ref;
int p_m_r_remote_id; /* remote instance (socket) */
char p_m_r_remote_app[32];
unsigned int p_m_r_handle; /* 0, if no bchannel is exported */
unsigned int p_r_ref;
int p_r_remote_id; /* remote instance (socket) */
char p_r_remote_app[32];
char p_r_interface_name[64];
int p_r_tones;
int message_epoint(unsigned int epoint_id, int message_id, union parameter *param);
void message_remote(int message_type, union parameter *param);
int hunt_bchannel(void);
int bridge_rx(unsigned char *data, int len);
};

14
route.c
View File

@ -251,7 +251,7 @@ struct param_defs param_defs[] = {
struct action_defs action_defs[] = {
{ ACTION_EXTERNAL,
"extern", &EndpointAppPBX::action_init_call, &EndpointAppPBX::action_dialing_external, &EndpointAppPBX::action_hangup_call,
PARAM_CONNECT | PARAM_PREFIX | PARAM_COMPLETE | PARAM_TYPE | PARAM_CAPA | PARAM_BMODE | PARAM_INFO1 | PARAM_HLC | PARAM_EXTHLC | PARAM_PRESENT | PARAM_INTERFACES | PARAM_CALLERID | PARAM_CALLERIDTYPE | PARAM_KEYPAD | PARAM_TIMEOUT,
PARAM_CONNECT | PARAM_PREFIX | PARAM_COMPLETE | PARAM_TYPE | PARAM_CAPA | PARAM_BMODE | PARAM_INFO1 | PARAM_HLC | PARAM_EXTHLC | PARAM_PRESENT | PARAM_INTERFACES | PARAM_CALLERID | PARAM_CALLERIDTYPE | PARAM_KEYPAD | PARAM_CONTEXT | PARAM_TIMEOUT,
"Call is routed to extern number as dialed."},
{ ACTION_INTERNAL,
"intern", &EndpointAppPBX::action_init_call, &EndpointAppPBX::action_dialing_internal, &EndpointAppPBX::action_hangup_call,
@ -261,10 +261,6 @@ struct action_defs action_defs[] = {
"outdial", &EndpointAppPBX::action_init_call, &EndpointAppPBX::action_dialing_external, &EndpointAppPBX::action_hangup_call,
PARAM_CONNECT | PARAM_PREFIX | PARAM_COMPLETE | PARAM_TYPE | PARAM_CAPA | PARAM_BMODE | PARAM_INFO1 | PARAM_HLC | PARAM_EXTHLC | PARAM_PRESENT | PARAM_INTERFACES | PARAM_CALLERID | PARAM_CALLERIDTYPE | PARAM_KEYPAD | PARAM_TIMEOUT,
"Same as 'extern'"},
{ ACTION_REMOTE,
"remote", &EndpointAppPBX::action_init_remote, &EndpointAppPBX::action_dialing_remote, &EndpointAppPBX::action_hangup_call,
PARAM_CONNECT | PARAM_APPLICATION | PARAM_CONTEXT | PARAM_EXTEN | PARAM_TIMEOUT,
"Call is routed to Remote application, like Asterisk."},
{ ACTION_VBOX_RECORD,
"vbox-record",&EndpointAppPBX::action_init_call, &EndpointAppPBX::action_dialing_vbox_record, &EndpointAppPBX::action_hangup_call,
PARAM_CONNECT | PARAM_EXTENSION | PARAM_ANNOUNCEMENT | PARAM_TIMEOUT,
@ -2409,14 +2405,6 @@ struct route_action action_internal = {
0,
};
struct route_action action_remote = {
NULL,
NULL,
ACTION_REMOTE,
0,
0,
};
struct route_action action_vbox = {
NULL,
NULL,

59
route.h
View File

@ -156,36 +156,35 @@ enum { /* defines when a statement should be executed */
#define ACTION_EXTERNAL 0
#define ACTION_INTERNAL 1
#define ACTION_OUTDIAL 2
#define ACTION_REMOTE 3
#define ACTION_VBOX_RECORD 4
#define ACTION_PARTYLINE 5
#define ACTION_LOGIN 6
#define ACTION_CALLERID 7
#define ACTION_CALLERIDNEXT 8
#define ACTION_FORWARD 9
#define ACTION_REDIAL 10
#define ACTION_REPLY 11
#define ACTION_POWERDIAL 12
#define ACTION_CALLBACK 13
#define ACTION_ABBREV 14
#define ACTION_TEST 15
#define ACTION_PLAY 16
#define ACTION_VBOX_PLAY 17
#define ACTION_CALCULATOR 18
#define ACTION_TIMER 19
#define ACTION_GOTO 20
#define ACTION_MENU 21
#define ACTION_DISCONNECT 22
#define ACTION_RELEASE 23
#define ACTION_DEFLECT 24
#define ACTION_SETFORWARD 25
#define ACTION_EXECUTE 26
#define ACTION_FILE 27
#define ACTION_PICK 28
#define ACTION_PASSWORD 29
#define ACTION_PASSWORD_WRITE 30
#define ACTION_NOTHING 31
#define ACTION_EFI 32
#define ACTION_VBOX_RECORD 3
#define ACTION_PARTYLINE 4
#define ACTION_LOGIN 5
#define ACTION_CALLERID 6
#define ACTION_CALLERIDNEXT 7
#define ACTION_FORWARD 8
#define ACTION_REDIAL 9
#define ACTION_REPLY 10
#define ACTION_POWERDIAL 11
#define ACTION_CALLBACK 12
#define ACTION_ABBREV 13
#define ACTION_TEST 14
#define ACTION_PLAY 15
#define ACTION_VBOX_PLAY 16
#define ACTION_CALCULATOR 17
#define ACTION_TIMER 18
#define ACTION_GOTO 19
#define ACTION_MENU 20
#define ACTION_DISCONNECT 21
#define ACTION_RELEASE 22
#define ACTION_DEFLECT 23
#define ACTION_SETFORWARD 24
#define ACTION_EXECUTE 25
#define ACTION_FILE 26
#define ACTION_PICK 27
#define ACTION_PASSWORD 28
#define ACTION_PASSWORD_WRITE 29
#define ACTION_NOTHING 30
#define ACTION_EFI 31
struct route_cond { /* an item */
struct route_cond *next; /* next entry */

View File

@ -76,23 +76,17 @@ int admin_init(void)
/*
* free connection
* also releases all remote joins
*/
void free_connection(struct admin_list *admin)
{
struct admin_queue *response;
void *temp;
#ifdef WITH_MISDN
union parameter param;
class Join *join, *joinnext;
struct mISDNport *mISDNport;
int i, ii;
class Port *port, *portnext;
class Premote *remote;
#endif
struct admin_list **adminp;
/* free remote joins */
/* free remote ports */
if (admin->remote_name[0]) {
start_trace(-1,
NULL,
@ -104,45 +98,13 @@ void free_connection(struct admin_list *admin)
"REMOTE APP release");
add_trace("app", "name", "%s", admin->remote_name);
end_trace();
#ifdef WITH_MISDN
/* release all exported channels */
mISDNport = mISDNport_first;
while(mISDNport) {
i = 0;
ii = mISDNport->b_num;
while(i < ii) {
if (mISDNport->b_remote_id[i] == admin->sock) {
mISDNport->b_state[i] = B_STATE_IDLE;
unsched_timer(&mISDNport->b_timer[i]);
mISDNport->b_remote_id[i] = 0;
mISDNport->b_remote_ref[i] = 0;
}
i++;
}
mISDNport = mISDNport->next;
}
#endif
#ifdef WITH_MISDN
/* release join */
join = join_first;
while(join) {
joinnext = join->next;
if (join->j_type==JOIN_TYPE_REMOTE) if (((class JoinRemote *)join)->j_remote_id == admin->sock) {
memset(&param, 0, sizeof(param));
param.disconnectinfo.cause = CAUSE_OUTOFORDER;
param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
((class JoinRemote *)join)->message_remote(MESSAGE_RELEASE, &param);
/* join is now destroyed, so we go to next join */
}
join = joinnext;
}
/* release remote port */
port = port_first;
while(port) {
portnext = port->next;
if ((port->p_type & PORT_CLASS_MASK) == PORT_CLASS_REMOTE) {
remote = (class Premote *) port;
if (remote->p_m_r_remote_id == admin->sock) {
if (remote->p_r_remote_id == admin->sock) {
memset(&param, 0, sizeof(param));
param.disconnectinfo.cause = CAUSE_OUTOFORDER;
param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
@ -152,7 +114,6 @@ void free_connection(struct admin_list *admin)
}
port = portnext;
}
#endif
}
if (admin->sock >= 0) {
@ -290,9 +251,6 @@ int admin_route(struct admin_queue **responsep)
case ACTION_EXTERNAL:
apppbx->e_action = &action_external;
break;
case ACTION_REMOTE:
apppbx->e_action = &action_remote;
break;
case ACTION_VBOX_RECORD:
apppbx->e_action = &action_vbox;
break;
@ -617,13 +575,9 @@ void admin_call_response(int adminid, int message, const char *connected, int ca
*/
int admin_message_to_lcr(struct admin_msg *msg, struct admin_list *admin)
{
#ifdef WITH_MISDN
struct mISDNport *mISDNport;
class Port *port;
class Premote *remote = NULL; /* make GCC happy */
class Join *join;
class JoinRemote *joinremote = NULL; /* make GCC happy */
#endif
struct interface *interface;
struct admin_list *temp;
/* hello message */
@ -664,104 +618,52 @@ int admin_message_to_lcr(struct admin_msg *msg, struct admin_list *admin)
return(-1);
}
#ifdef WITH_MISDN
/* new join. the reply (NEWREF assignment) is sent from constructor */
if (msg->type == MESSAGE_NEWREF) {
if (msg->param.newref.mode) {
char name[32];
/* find remote port */
mISDNport = mISDNport_first;
while(mISDNport) {
if (mISDNport->ifport->remote && !strcmp(mISDNport->ifport->remote_app, admin->remote_name))
break;
mISDNport = mISDNport->next;
}
if (!mISDNport) {
union parameter param;
/* create new join instance */
join = joinremote = new JoinRemote(0, admin->remote_name, admin->sock); // must have no serial, because no endpoint is connected
if (!join) {
FATAL("No memory for remote join instance\n");
return(-1);
}
memset(&param, 0, sizeof(union parameter));
param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
param.disconnectinfo.cause = CAUSE_RESSOURCEUNAVAIL;
admin_message_from_lcr(joinremote->j_remote_id, joinremote->j_remote_ref, MESSAGE_RELEASE, &param);
return 0;
}
/* creating port object, transparent until setup with hdlc */
SPRINT(name, "%s-%s-in", mISDNport->ifport->interface->name, mISDNport->ifport->remote_app);
if (!(remote = new Premote(PORT_TYPE_REMOTE_IN, mISDNport, name, NULL, 0, 0, B_MODE_TRANSPARENT, admin->sock)))
FATAL("Cannot create Port instance.\n");
} else {
/* create new join instance */
join = new JoinRemote(0, admin->remote_name, admin->sock); // must have no serial, because no endpoint is connected
if (!join) {
FATAL("No memory for remote join instance\n");
return(-1);
}
char name[32];
/* find remote port */
interface = interface_first;
while(interface) {
if (interface->remote && !strcmp(interface->remote_app, admin->remote_name))
break;
interface = interface->next;
}
return(0);
}
#endif
if (!interface) {
union parameter param;
#ifdef WITH_MISDN
/* bchannel message
* no ref given for *_ack */
if (msg->type == MESSAGE_BCHANNEL)
if (msg->param.bchannel.type == BCHANNEL_ASSIGN_ACK
|| msg->param.bchannel.type == BCHANNEL_REMOVE_ACK
|| msg->param.bchannel.type == BCHANNEL_RELEASE) {
/* no ref, but address */
message_bchannel_from_remote(NULL, msg->param.bchannel.type, msg->param.bchannel.handle);
memset(&param, 0, sizeof(union parameter));
param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
param.disconnectinfo.cause = CAUSE_RESSOURCEUNAVAIL;
admin_message_from_lcr(admin->sock, 0, MESSAGE_RELEASE, &param);
return 0;
}
/* creating port object, transparent until setup with hdlc */
SPRINT(name, "%s-%s-in", interface->name, interface->remote_app);
if (!(remote = new Premote(PORT_TYPE_REMOTE_IN, name, NULL, interface, admin->sock)))
FATAL("Cannot create Port instance.\n");
return(0);
}
#endif
/* check for ref */
if (!msg->ref) {
PERROR("Remote application did not send us a valid ref with a message.\n");
return(-1);
}
#ifdef WITH_MISDN
/* find join instance */
join = join_first;
while(join) {
if (join->j_type == JOIN_TYPE_REMOTE) {
joinremote = (class JoinRemote *)join;
if (joinremote->j_remote_ref == msg->ref)
break;
}
join = join->next;
}
if (join) {
if (admin->sock != joinremote->j_remote_id) {
PERROR("Ref %d belongs to remote application %s, but not to sending application %s.\n", msg->ref, joinremote->j_remote_name, admin->remote_name);
return(-1);
}
/* send message */
joinremote->message_remote(msg->type, &msg->param);
return(0);
}
/* find port instance */
port = port_first;
while(port) {
if ((port->p_type & PORT_CLASS_mISDN_MASK) == PORT_CLASS_REMOTE) {
remote = (class Premote *) port;
if (remote->p_m_r_ref == msg->ref)
if (remote->p_r_ref == msg->ref)
break;
}
port = port->next;
}
if (port) {
if (admin->sock != remote->p_m_r_remote_id) {
PERROR("Ref %d belongs to remote application %s, but not to sending application %s.\n", msg->ref, remote->p_m_r_remote_app, admin->remote_name);
if (admin->sock != remote->p_r_remote_id) {
PERROR("Ref %d belongs to remote application %s, but not to sending application %s.\n", msg->ref, remote->p_r_remote_app, admin->remote_name);
return(-1);
}
@ -770,7 +672,6 @@ int admin_message_to_lcr(struct admin_msg *msg, struct admin_list *admin)
return(0);
}
#endif
PDEBUG(DEBUG_LOG, "No remote instance found with ref %d. (May have been already released.)\n", msg->ref);
return(0);
@ -1058,9 +959,6 @@ int admin_state(struct admin_queue **responsep)
/* partyline */
if (join->j_type == JOIN_TYPE_PBX)
response->am[num].u.j.partyline = ((class JoinPBX *)join)->j_partyline;
/* remote application */
if (join->j_type == JOIN_TYPE_REMOTE)
SCPY(response->am[num].u.j.remote, ((class JoinRemote *)join)->j_remote_name);
/* */
join = join->next;
num++;
@ -1388,24 +1286,3 @@ int admin_handle_con(struct lcr_fd *fd, unsigned int what, void *instance, int i
return 0;
}
void message_bchannel_to_remote(unsigned int remote_id, unsigned int ref, int type, unsigned int handle, int tx_gain, int rx_gain, char *pipeline, unsigned char *crypt, int crypt_len, int crypt_type, int isloopback)
{
union parameter param;
memset(&param, 0, sizeof(union parameter));
param.bchannel.isloopback = isloopback;
param.bchannel.type = type;
param.bchannel.handle = handle;
param.bchannel.tx_gain = tx_gain;
param.bchannel.rx_gain = rx_gain;
if (pipeline)
SCPY(param.bchannel.pipeline, pipeline);
if (crypt_len)
memcpy(param.bchannel.crypt, crypt, crypt_len);
param.bchannel.crypt_type = crypt_type;
if (admin_message_from_lcr(remote_id, ref, MESSAGE_BCHANNEL, &param)<0) {
PERROR("No socket with remote id %d found, this happens, if the socket is closed before all bchannels are imported.\n", remote_id);
return;
}
}

View File

@ -35,7 +35,6 @@ void admin_cleanup(void);
void admin_call_response(int adminid, int message, const char *connected, int cause, int location, int notify);
int admin_message_to_lcr(struct admin_message *msg, int remote_id);
int admin_message_from_lcr(int remote_id, unsigned int ref, int message_type, union parameter *param);
void message_bchannel_to_remote(unsigned int remote_id, unsigned int ref, int type, unsigned int handle, int tx_gain, int rx_gain, char *pipeline, unsigned char *crypt, int crypt_len, int crypt_type, int isloopback);