summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Eversberg2010-12-13 09:22:49 +0100
committerAndreas Eversberg2010-12-13 09:22:49 +0100
commit3a8f58ec8946b7f1683208d1cc3b054486f12e6c (patch)
treeb7cf56794d5bc684a658b6c1e970d0bc4efb1ab5
parentAdding various arguments to 'execute' condition and 'execute' action. (diff)
downloadlcr-3a8f58ec8946b7f1683208d1cc3b054486f12e6c.tar.gz
lcr-3a8f58ec8946b7f1683208d1cc3b054486f12e6c.tar.xz
lcr-3a8f58ec8946b7f1683208d1cc3b054486f12e6c.zip
Adding interface support for remote app (chan_lcr).
chan_lcr can be handled as an interface. This way it is possible to (e.g.): - make a SIP phone become an LCR extension with all LCR features. - make conference calls. (untested) - perform parallel ringing. (ISDN phone and SIP phones can ring in parallel.) - do voice recoding. It is still also possible to link chan_lcr directly without interface (as before). Documentation/howto for that will follow.
-rw-r--r--Makefile.am4
-rw-r--r--Makefile.in43
-rw-r--r--apppbx.cpp42
-rw-r--r--chan_lcr.c349
-rw-r--r--default/gsm.conf10
-rw-r--r--default/interface.conf14
-rw-r--r--default/options.conf10
-rw-r--r--gsm.cpp145
-rw-r--r--gsm.h4
-rw-r--r--gsm_conf.c18
-rw-r--r--interface.c48
-rw-r--r--interface.h2
-rw-r--r--joinremote.cpp29
-rw-r--r--joinremote.h2
-rw-r--r--loop.c153
-rw-r--r--loop.h12
-rw-r--r--mISDN.cpp88
-rw-r--r--mISDN.h3
-rw-r--r--main.c4
-rw-r--r--main.h2
-rw-r--r--message.h9
-rw-r--r--options.c20
-rw-r--r--options.h2
-rw-r--r--port.h7
-rw-r--r--remote.cpp221
-rw-r--r--remote.h20
-rw-r--r--socket_server.c139
-rw-r--r--socket_server.h5
28 files changed, 924 insertions, 481 deletions
diff --git a/Makefile.am b/Makefile.am
index f71d715..ea96ae7 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -125,8 +125,8 @@ endif
INCLUDES = $(all_includes) $(GSM_INCLUDE) $(SS5_INCLUDE) -Wall $(INSTALLATION_DEFINES)
-lcr_SOURCES = $(GSM_SOURCE) $(SS5_SOURCE) select.c action.cpp mISDN.cpp tones.c \
- action_efi.cpp crypt.cpp mail.c trace.c \
+lcr_SOURCES = $(GSM_SOURCE) $(SS5_SOURCE) select.c action.cpp mISDN.cpp \
+ tones.c loop.c remote.c action_efi.cpp crypt.cpp mail.c trace.c \
action_vbox.cpp dss1.cpp main.c \
vbox.cpp alawulaw.c endpoint.cpp interface.c message.c \
apppbx.cpp endpointapp.cpp join.cpp options.c \
diff --git a/Makefile.in b/Makefile.in
index 067dfe1..3568597 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -97,12 +97,12 @@ am__lcr_SOURCES_DIST = gsm_audio.c gsm.cpp gsm_conf.c gsm_bs.cpp \
openbsc/src/vty_interface_layer3.c openbsc/src/bsc_api.c \
openbsc/src/bsc_version.c gsm_ms.cpp \
layer23/src/mobile/app_mobile.c ss5.cpp ss5_encode.c \
- ss5_decode.c select.c action.cpp mISDN.cpp tones.c \
- action_efi.cpp crypt.cpp mail.c trace.c action_vbox.cpp \
- dss1.cpp main.c vbox.cpp alawulaw.c endpoint.cpp interface.c \
- message.c apppbx.cpp endpointapp.cpp join.cpp options.c \
- extension.c joinpbx.cpp port.cpp callerid.c joinremote.cpp \
- route.c cause.c socket_server.c
+ ss5_decode.c select.c action.cpp mISDN.cpp tones.c loop.c \
+ remote.c action_efi.cpp crypt.cpp mail.c trace.c \
+ action_vbox.cpp dss1.cpp main.c vbox.cpp alawulaw.c \
+ endpoint.cpp interface.c message.c apppbx.cpp endpointapp.cpp \
+ join.cpp options.c extension.c joinpbx.cpp port.cpp callerid.c \
+ joinremote.cpp route.c cause.c socket_server.c
@ENABLE_GSM_TRUE@am__objects_1 = gsm_audio.$(OBJEXT) gsm.$(OBJEXT) \
@ENABLE_GSM_TRUE@ gsm_conf.$(OBJEXT)
@ENABLE_GSM_BS_TRUE@am__objects_2 = gsm_bs.$(OBJEXT) \
@@ -116,14 +116,15 @@ am__objects_4 = $(am__objects_1) $(am__objects_2) $(am__objects_3)
@ENABLE_SS5_TRUE@ ss5_decode.$(OBJEXT)
am_lcr_OBJECTS = $(am__objects_4) $(am__objects_5) select.$(OBJEXT) \
action.$(OBJEXT) mISDN.$(OBJEXT) tones.$(OBJEXT) \
- action_efi.$(OBJEXT) crypt.$(OBJEXT) mail.$(OBJEXT) \
- trace.$(OBJEXT) action_vbox.$(OBJEXT) dss1.$(OBJEXT) \
- main.$(OBJEXT) vbox.$(OBJEXT) alawulaw.$(OBJEXT) \
- endpoint.$(OBJEXT) interface.$(OBJEXT) message.$(OBJEXT) \
- apppbx.$(OBJEXT) endpointapp.$(OBJEXT) join.$(OBJEXT) \
- options.$(OBJEXT) extension.$(OBJEXT) joinpbx.$(OBJEXT) \
- port.$(OBJEXT) callerid.$(OBJEXT) joinremote.$(OBJEXT) \
- route.$(OBJEXT) cause.$(OBJEXT) socket_server.$(OBJEXT)
+ loop.$(OBJEXT) remote.$(OBJEXT) action_efi.$(OBJEXT) \
+ crypt.$(OBJEXT) mail.$(OBJEXT) trace.$(OBJEXT) \
+ action_vbox.$(OBJEXT) dss1.$(OBJEXT) main.$(OBJEXT) \
+ vbox.$(OBJEXT) alawulaw.$(OBJEXT) endpoint.$(OBJEXT) \
+ interface.$(OBJEXT) message.$(OBJEXT) apppbx.$(OBJEXT) \
+ endpointapp.$(OBJEXT) join.$(OBJEXT) options.$(OBJEXT) \
+ extension.$(OBJEXT) joinpbx.$(OBJEXT) port.$(OBJEXT) \
+ callerid.$(OBJEXT) joinremote.$(OBJEXT) route.$(OBJEXT) \
+ cause.$(OBJEXT) socket_server.$(OBJEXT)
lcr_OBJECTS = $(am_lcr_OBJECTS)
am__DEPENDENCIES_1 =
@ENABLE_GSM_BS_TRUE@am__DEPENDENCIES_2 = ./openbsc/src/libbsc.a \
@@ -285,8 +286,8 @@ GSM_LIB = $(am__append_3) $(am__append_6) $(am__append_9)
@ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@chan_lcr_so_LDFLAGS = -shared
@ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@chan_lcr_so_LDADD = chan_lcr.po bchannel.po options.po callerid.po select.po
INCLUDES = $(all_includes) $(GSM_INCLUDE) $(SS5_INCLUDE) -Wall $(INSTALLATION_DEFINES)
-lcr_SOURCES = $(GSM_SOURCE) $(SS5_SOURCE) select.c action.cpp mISDN.cpp tones.c \
- action_efi.cpp crypt.cpp mail.c trace.c \
+lcr_SOURCES = $(GSM_SOURCE) $(SS5_SOURCE) select.c action.cpp mISDN.cpp \
+ tones.c loop.c remote.c action_efi.cpp crypt.cpp mail.c trace.c \
action_vbox.cpp dss1.cpp main.c \
vbox.cpp alawulaw.c endpoint.cpp interface.c message.c \
apppbx.cpp endpointapp.cpp join.cpp options.c \
@@ -318,15 +319,15 @@ $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
- echo ' cd $(srcdir) && $(AUTOMAKE) --gnu'; \
- $(am__cd) $(srcdir) && $(AUTOMAKE) --gnu \
+ echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \
+ $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \
&& exit 0; \
exit 1;; \
esac; \
done; \
- echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \
$(am__cd) $(top_srcdir) && \
- $(AUTOMAKE) --gnu Makefile
+ $(AUTOMAKE) --foreign Makefile
.PRECIOUS: Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
@@ -499,12 +500,14 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/joinpbx.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/joinremote.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lcradmin.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/loop.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mISDN.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mail.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/message.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/options.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/port.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/remote.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/route.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/select.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/socket_server.Po@am__quote@
diff --git a/apppbx.cpp b/apppbx.cpp
index 87e4f41..aaa02cb 100644
--- a/apppbx.cpp
+++ b/apppbx.cpp
@@ -851,6 +851,7 @@ void EndpointAppPBX::out_setup(int cfnr)
int channel = 0;
int earlyb;
int mode = B_MODE_TRANSPARENT;
+ struct admin_list *admin;
/* set bchannel mode */
mode = e_capainfo.source_mode;
@@ -989,6 +990,21 @@ void EndpointAppPBX::out_setup(int cfnr)
port = new Pgsm_ms(PORT_TYPE_GSM_MS_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
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);
if (!port)
FATAL("Failed to create Port instance\n");
@@ -1208,6 +1224,21 @@ void EndpointAppPBX::out_setup(int cfnr)
port = new Pgsm_ms(PORT_TYPE_GSM_MS_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
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);
if (!port)
FATAL("No memory for Port instance\n");
@@ -2048,10 +2079,8 @@ void EndpointAppPBX::port_connect(struct port_list *portlist, int message_type,
/* other calls with no caller id (or not available for the extension) and force colp */
if ((e_connectinfo.id[0]=='\0' || (e_connectinfo.present==INFO_PRESENT_RESTRICTED && !e_ext.anon_ignore))&& e_ext.colp==COLP_FORCE) {
e_connectinfo.ntype = INFO_NTYPE_NOTPRESENT;
- if (portlist->port_type==PORT_TYPE_DSS1_TE_OUT
- || portlist->port_type==PORT_TYPE_DSS1_NT_OUT
- || portlist->port_type==PORT_TYPE_GSM_BS_OUT
- || portlist->port_type==PORT_TYPE_GSM_MS_OUT) { /* external extension answered */
+ if ((portlist->port_type & PORT_CLASS_DIR_MASK) == PORT_CLASS_DIR_OUT) {
+ /* external extension answered */
port = find_port_id(portlist->port_id);
if (port) {
SCPY(e_connectinfo.id, nationalize_callerinfo(port->p_dialinginfo.id, &e_connectinfo.ntype, options.national, options.international));
@@ -3530,10 +3559,7 @@ void EndpointAppPBX::pick_join(char *extensions)
break;
}
}
- if ((port->p_type==PORT_TYPE_DSS1_NT_OUT
- || port->p_type==PORT_TYPE_DSS1_TE_OUT
- || port->p_type==PORT_TYPE_GSM_BS_OUT
- || port->p_type==PORT_TYPE_GSM_MS_OUT)
+ if ((portlist->port_type & PORT_CLASS_DIR_MASK) == PORT_CLASS_DIR_OUT
&& port->p_state==PORT_STATE_OUT_ALERTING)
if (match_list(extensions, eapp->e_ext.number)) {
found = eapp;
diff --git a/chan_lcr.c b/chan_lcr.c
index f4d8378..e9e26fa 100644
--- a/chan_lcr.c
+++ b/chan_lcr.c
@@ -40,7 +40,7 @@ a new call reference (ref).
The ref_was_assigned ist set to 1.
Further dialing information is queued.
After the new callref is received by special MESSAGE_NEWREF reply, new ref
-is stored in the chan_call structure.
+is stored in the chan_call structure.
The setup information is sent to LCR using MESSAGE_SETUP.
The state changes to CHAN_LCR_STATE_OUT_SETUP.
@@ -207,7 +207,7 @@ int global_change = 0;
int wake_global = 0;
int wake_pipe[2];
struct lcr_fd wake_fd;
-
+
int quit;
int glob_channel = 0;
@@ -266,7 +266,7 @@ struct chan_call *find_call_ref(unsigned int ref)
{
struct chan_call *call = call_first;
int assigned = (ref > 0);
-
+
while(call) {
if (call->ref == ref && call->ref_was_assigned == assigned)
break;
@@ -595,8 +595,8 @@ void apply_opt(struct chan_call *call, char *data)
default:
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);
@@ -622,15 +622,16 @@ static void send_setup_to_lcr(struct chan_call *call)
/* send setup message to LCR */
memset(&newparam, 0, sizeof(union parameter));
- newparam.setup.dialinginfo.itype = INFO_ITYPE_ISDN;
- newparam.setup.dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
+ newparam.setup.dialinginfo.itype = INFO_ITYPE_ISDN;
+ newparam.setup.dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
if (call->keypad)
strncpy(newparam.setup.dialinginfo.keypad, call->dialstring, sizeof(newparam.setup.dialinginfo.keypad)-1);
else
strncpy(newparam.setup.dialinginfo.id, call->dialstring, sizeof(newparam.setup.dialinginfo.id)-1);
- strncpy(newparam.setup.dialinginfo.interfaces, call->interface, sizeof(newparam.setup.dialinginfo.interfaces)-1);
- newparam.setup.callerinfo.itype = INFO_ITYPE_CHAN;
- newparam.setup.callerinfo.ntype = INFO_NTYPE_UNKNOWN;
+ if (!!strcmp(call->interface, "pbx"))
+ strncpy(newparam.setup.dialinginfo.interfaces, call->interface, sizeof(newparam.setup.dialinginfo.interfaces)-1);
+ newparam.setup.callerinfo.itype = INFO_ITYPE_CHAN;
+ newparam.setup.callerinfo.ntype = INFO_NTYPE_UNKNOWN;
strncpy(newparam.setup.callerinfo.display, call->display, sizeof(newparam.setup.callerinfo.display)-1);
call->display[0] = '\0';
if (call->cid_num[0])
@@ -639,8 +640,8 @@ static void send_setup_to_lcr(struct chan_call *call)
strncpy(newparam.setup.callerinfo.name, call->cid_name, sizeof(newparam.setup.callerinfo.name)-1);
if (call->cid_rdnis[0]) {
strncpy(newparam.setup.redirinfo.id, call->cid_rdnis, sizeof(newparam.setup.redirinfo.id)-1);
- newparam.setup.redirinfo.itype = INFO_ITYPE_CHAN;
- newparam.setup.redirinfo.ntype = INFO_NTYPE_UNKNOWN;
+ newparam.setup.redirinfo.itype = INFO_ITYPE_CHAN;
+ newparam.setup.redirinfo.ntype = INFO_NTYPE_UNKNOWN;
}
switch(ast->cid.cid_pres & AST_PRES_RESTRICTION) {
case AST_PRES_RESTRICTED:
@@ -697,7 +698,7 @@ static void send_dialque_to_lcr(struct chan_call *call)
if (!call->ast || !call->ref || !call->dialque[0])
return;
-
+
CDEBUG(call, call->ast, "Sending dial queue to LCR. (dialing=%s)\n", call->dialque);
/* send setup message to LCR */
@@ -758,7 +759,7 @@ static void lcr_start_pbx(struct chan_call *call, struct ast_channel *ast, int c
exten = "s";
CDEBUG(call, ast, "Try to start pbx. (exten=%s context=%s complete=%s)\n", exten, ast->context, complete?"yes":"no");
-
+
if (complete) {
/* if not match */
if (!ast_canmatch_extension(ast, ast->context, exten, 1, call->oad)) {
@@ -822,16 +823,16 @@ static void lcr_start_pbx(struct chan_call *call, struct ast_channel *ast, int c
call->state = CHAN_LCR_STATE_RELEASE;
ast_hangup(ast); // call will be destroyed here
return;
-
+
start:
/* send setup to asterisk */
CDEBUG(call, ast, "Starting call to Asterisk due to matching extension.\n");
- #ifdef LCR_FOR_CALLWEAVER
+ #ifdef LCR_FOR_CALLWEAVER
ast->type = "LCR";
snprintf(ast->name, sizeof(ast->name), "LCR/%s-%04x",ast->cid.cid_num, ast_random() & 0xffff);
#endif
-
+
ret = ast_pbx_start(ast);
if (ret < 0) {
cause = (ret==-2)?34:27;
@@ -859,7 +860,7 @@ static void lcr_in_setup(struct chan_call *call, int message_type, union paramet
#ifdef LCR_FOR_ASTERISK
ast = ast_channel_alloc(1, AST_STATE_RESERVED, NULL, NULL, "", NULL, "", 0, "%s/%d", lcr_type, ++glob_channel);
#endif
-
+
if (!ast) {
/* release */
CERROR(call, NULL, "Failed to create Asterisk channel - releasing.\n");
@@ -873,7 +874,7 @@ static void lcr_in_setup(struct chan_call *call, int message_type, union paramet
ast->tech_pvt = call;
ast->tech = &lcr_tech;
ast->fds[0] = call->pipe[0];
-
+
/* fill setup information */
if (param->setup.dialinginfo.id)
strncpy(ast->exten, param->setup.dialinginfo.id, AST_MAX_EXTENSION-1);
@@ -1080,8 +1081,8 @@ static void lcr_in_release(struct chan_call *call, int message_type, union param
call->state = CHAN_LCR_STATE_RELEASE;
/* copy release info */
if (!call->cause) {
- call->cause = param->disconnectinfo.cause;
- call->location = param->disconnectinfo.location;
+ call->cause = param->disconnectinfo.cause;
+ call->location = param->disconnectinfo.location;
}
/* if we have an asterisk instance, queue hangup, else we are done */
if (ast) {
@@ -1099,7 +1100,7 @@ static void lcr_in_release(struct chan_call *call, int message_type, union param
} else {
free_call(call);
}
-
+
}
/*
@@ -1110,7 +1111,7 @@ static void lcr_in_information(struct chan_call *call, int message_type, union p
struct ast_channel *ast = call->ast;
CDEBUG(call, call->ast, "Incoming information from LCR. (dialing=%s)\n", param->information.id);
-
+
if (!ast) return;
/* pbx not started */
@@ -1120,14 +1121,14 @@ static void lcr_in_information(struct chan_call *call, int message_type, union p
lcr_start_pbx(call, ast, param->information.sending_complete);
return;
}
-
+
/* change dailing state after setup */
if (call->state == CHAN_LCR_STATE_IN_SETUP) {
CDEBUG(call, call->ast, "Changing from SETUP to DIALING state.\n");
call->state = CHAN_LCR_STATE_IN_DIALING;
// ast_setstate(ast, AST_STATE_DIALING);
}
-
+
/* queue digits */
if (call->state == CHAN_LCR_STATE_IN_DIALING && param->information.id[0]) {
if (!wake_global) {
@@ -1303,6 +1304,10 @@ int receive_message(int message_type, unsigned int ref, union parameter *param)
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);
@@ -1333,7 +1338,7 @@ int receive_message(int message_type, unsigned int ref, union parameter *param)
newparam.bchannel.type = BCHANNEL_REMOVE_ACK;
newparam.bchannel.handle = param->bchannel.handle;
send_message(MESSAGE_BCHANNEL, 0, &newparam);
-
+
break;
default:
@@ -1344,7 +1349,7 @@ int receive_message(int message_type, unsigned int ref, union parameter *param)
/* handle new ref */
if (message_type == MESSAGE_NEWREF) {
- if (param->direction) {
+ if (param->newref.direction) {
/* new ref from lcr */
CDEBUG(NULL, NULL, "Received new ref by LCR, due to incomming call. (ref=%ld)\n", ref);
if (!ref || find_call_ref(ref)) {
@@ -1527,7 +1532,7 @@ static int handle_socket(struct lcr_fd *fd, unsigned int what, void *instance, i
/* read from socket */
len = read(lcr_sock, &msg, sizeof(msg));
if (len == 0) {
- CERROR(NULL, NULL, "Socket closed.\n");
+ CERROR(NULL, NULL, "Socket closed.(read)\n");
error:
CERROR(NULL, NULL, "Handling of socket failed - closing for some seconds.\n");
close_socket();
@@ -1560,7 +1565,7 @@ static int handle_socket(struct lcr_fd *fd, unsigned int what, void *instance, i
admin = admin_first;
len = write(lcr_sock, &admin->msg, sizeof(msg));
if (len == 0) {
- CERROR(NULL, NULL, "Socket closed.\n");
+ CERROR(NULL, NULL, "Socket closed.(write)\n");
goto error;
}
if (len > 0) {
@@ -1638,7 +1643,7 @@ void close_socket(void)
admin_first = NULL;
/* close socket */
- if (lcr_sock >= 0)
+ if (lcr_sock >= 0)
close(lcr_sock);
lcr_sock = -1;
global_change = 1;
@@ -1706,7 +1711,7 @@ again:
CDEBUG(call, ast, "Sending queued digit '%c' to Asterisk.\n", *p);
/* send digit to asterisk */
memset(&fr, 0, sizeof(fr));
-
+
#ifdef LCR_FOR_ASTERISK
fr.frametype = AST_FRAME_DTMF_BEGIN;
#endif
@@ -1714,16 +1719,16 @@ again:
#ifdef LCR_FOR_CALLWEAVER
fr.frametype = AST_FRAME_DTMF;
#endif
-
+
fr.subclass = *p;
fr.delivery = ast_tv(0, 0);
ast_queue_frame(ast, &fr);
-
+
#ifdef LCR_FOR_ASTERISK
fr.frametype = AST_FRAME_DTMF_END;
ast_queue_frame(ast, &fr);
#endif
-
+
break;
default:
CDEBUG(call, ast, "Ignoring queued digit 0x%02x.\n", *p);
@@ -1805,7 +1810,7 @@ struct ast_channel *lcr_request(const char *type, int format, void *data, int *c
{
char exten[256], *dial, *interface, *opt;
struct ast_channel *ast;
- struct chan_call *call;
+ struct chan_call *call;
ast_mutex_lock(&chan_lock);
CDEBUG(NULL, NULL, "Received request from Asterisk. (data=%s)\n", (char *)data);
@@ -1830,11 +1835,11 @@ struct ast_channel *lcr_request(const char *type, int format, void *data, int *c
#ifdef LCR_FOR_ASTERISK
ast = ast_channel_alloc(1, AST_STATE_RESERVED, NULL, NULL, "", NULL, "", 0, "%s/%d", lcr_type, ++glob_channel);
#endif
-
+
#ifdef LCR_FOR_CALLWEAVER
ast = ast_channel_alloc(1);
#endif
-
+
if (!ast) {
CERROR(NULL, NULL, "Failed to create Asterisk channel.\n");
free_call(call);
@@ -1894,16 +1899,16 @@ struct ast_channel *lcr_request(const char *type, int format, void *data, int *c
static int lcr_call(struct ast_channel *ast, char *dest, int timeout)
{
union parameter newparam;
- struct chan_call *call;
+ struct chan_call *call;
ast_mutex_lock(&chan_lock);
- call = ast->tech_pvt;
-
- #ifdef LCR_FOR_CALLWEAVER
- ast->type = "LCR";
- snprintf(ast->name, sizeof(ast->name), "LCR/%s-%04x",call->dialstring, ast_random() & 0xffff);
- #endif
-
+ call = ast->tech_pvt;
+
+ #ifdef LCR_FOR_CALLWEAVER
+ ast->type = "LCR";
+ snprintf(ast->name, sizeof(ast->name), "LCR/%s-%04x",call->dialstring, ast_random() & 0xffff);
+ #endif
+
if (!call) {
CERROR(NULL, ast, "Received call from Asterisk, but call instance does not exist.\n");
ast_mutex_unlock(&chan_lock);
@@ -1916,7 +1921,9 @@ static int lcr_call(struct ast_channel *ast, char *dest, int timeout)
call->pbx_started = 1;
/* send MESSAGE_NEWREF */
memset(&newparam, 0, sizeof(union parameter));
- newparam.direction = 0; /* request from app */
+ 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 */
@@ -1940,49 +1947,49 @@ static int lcr_call(struct ast_channel *ast, char *dest, int timeout)
sizeof(call->cid_num)-1);
if (ast->cid.cid_name) if (ast->cid.cid_name[0])
- strncpy(call->cid_name, ast->cid.cid_name,
+ strncpy(call->cid_name, ast->cid.cid_name,
sizeof(call->cid_name)-1);
if (ast->cid.cid_rdnis) if (ast->cid.cid_rdnis[0])
- strncpy(call->cid_rdnis, ast->cid.cid_rdnis,
+ strncpy(call->cid_rdnis, ast->cid.cid_rdnis,
sizeof(call->cid_rdnis)-1);
ast_mutex_unlock(&chan_lock);
- return 0;
+ return 0;
}
static void send_digit_to_chan(struct ast_channel * ast, char digit )
{
- static const char* dtmf_tones[] = {
- "!941+1336/100,!0/100", /* 0 */
- "!697+1209/100,!0/100", /* 1 */
- "!697+1336/100,!0/100", /* 2 */
- "!697+1477/100,!0/100", /* 3 */
- "!770+1209/100,!0/100", /* 4 */
- "!770+1336/100,!0/100", /* 5 */
- "!770+1477/100,!0/100", /* 6 */
- "!852+1209/100,!0/100", /* 7 */
- "!852+1336/100,!0/100", /* 8 */
- "!852+1477/100,!0/100", /* 9 */
- "!697+1633/100,!0/100", /* A */
- "!770+1633/100,!0/100", /* B */
- "!852+1633/100,!0/100", /* C */
- "!941+1633/100,!0/100", /* D */
- "!941+1209/100,!0/100", /* * */
- "!941+1477/100,!0/100" }; /* # */
-
- if (digit >= '0' && digit <='9')
- ast_playtones_start(ast,0,dtmf_tones[digit-'0'], 0);
- else if (digit >= 'A' && digit <= 'D')
- ast_playtones_start(ast,0,dtmf_tones[digit-'A'+10], 0);
- else if (digit == '*')
- ast_playtones_start(ast,0,dtmf_tones[14], 0);
- else if (digit == '#')
- ast_playtones_start(ast,0,dtmf_tones[15], 0);
- else {
- /* not handled */
+ static const char* dtmf_tones[] = {
+ "!941+1336/100,!0/100", /* 0 */
+ "!697+1209/100,!0/100", /* 1 */
+ "!697+1336/100,!0/100", /* 2 */
+ "!697+1477/100,!0/100", /* 3 */
+ "!770+1209/100,!0/100", /* 4 */
+ "!770+1336/100,!0/100", /* 5 */
+ "!770+1477/100,!0/100", /* 6 */
+ "!852+1209/100,!0/100", /* 7 */
+ "!852+1336/100,!0/100", /* 8 */
+ "!852+1477/100,!0/100", /* 9 */
+ "!697+1633/100,!0/100", /* A */
+ "!770+1633/100,!0/100", /* B */
+ "!852+1633/100,!0/100", /* C */
+ "!941+1633/100,!0/100", /* D */
+ "!941+1209/100,!0/100", /* * */
+ "!941+1477/100,!0/100" }; /* # */
+
+ if (digit >= '0' && digit <='9')
+ ast_playtones_start(ast,0,dtmf_tones[digit-'0'], 0);
+ else if (digit >= 'A' && digit <= 'D')
+ ast_playtones_start(ast,0,dtmf_tones[digit-'A'+10], 0);
+ else if (digit == '*')
+ ast_playtones_start(ast,0,dtmf_tones[14], 0);
+ else if (digit == '#')
+ ast_playtones_start(ast,0,dtmf_tones[15], 0);
+ else {
+ /* not handled */
CDEBUG(NULL, ast, "Unable to handle DTMF tone "
"'%c' for '%s'\n", digit, ast->name);
- }
+ }
}
#ifdef LCR_FOR_ASTERISK
@@ -1992,7 +1999,7 @@ static int lcr_digit_begin(struct ast_channel *ast, char digit)
static int lcr_digit(struct ast_channel *ast, char digit)
#endif
{
- struct chan_call *call;
+ struct chan_call *call;
union parameter newparam;
char buf[]="x";
@@ -2005,7 +2012,7 @@ static int lcr_digit(struct ast_channel *ast, char digit)
return 0;
ast_mutex_lock(&chan_lock);
- call = ast->tech_pvt;
+ call = ast->tech_pvt;
if (!call) {
CERROR(NULL, ast, "Received digit from Asterisk, but no call instance exists.\n");
ast_mutex_unlock(&chan_lock);
@@ -2043,17 +2050,17 @@ static int lcr_digit(struct ast_channel *ast, char digit)
static int lcr_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
{
int inband_dtmf = 0;
- struct chan_call *call;
+ struct chan_call *call;
#endif
ast_mutex_lock(&chan_lock);
- call = ast->tech_pvt;
+ call = ast->tech_pvt;
if (!call) {
- CERROR(NULL, ast,
- "Received digit from Asterisk, "
- "but no call instance exists.\n");
+ CERROR(NULL, ast,
+ "Received digit from Asterisk, "
+ "but no call instance exists.\n");
ast_mutex_unlock(&chan_lock);
return -1;
}
@@ -2077,18 +2084,18 @@ static int lcr_digit_end(struct ast_channel *ast, char digit, unsigned int durat
static int lcr_answer(struct ast_channel *ast)
{
union parameter newparam;
- struct chan_call *call;
+ struct chan_call *call;
ast_mutex_lock(&chan_lock);
- call = ast->tech_pvt;
+ call = ast->tech_pvt;
if (!call) {
CERROR(NULL, ast, "Received answer from Asterisk, but no call instance exists.\n");
ast_mutex_unlock(&chan_lock);
return -1;
}
-
+
CDEBUG(call, ast, "Received answer from Asterisk (maybe during lcr_bridge).\n");
-
+
/* copy connectinfo, if bridged */
if (call->bridge_call)
memcpy(&call->connectinfo, &call->bridge_call->connectinfo, sizeof(struct connect_info));
@@ -2110,20 +2117,20 @@ static int lcr_answer(struct ast_channel *ast)
/* enable keypad */
// memset(&newparam, 0, sizeof(union parameter));
// send_message(MESSAGE_ENABLEKEYPAD, call->ref, &newparam);
-
- ast_mutex_unlock(&chan_lock);
- return 0;
+
+ ast_mutex_unlock(&chan_lock);
+ return 0;
}
static int lcr_hangup(struct ast_channel *ast)
{
- struct chan_call *call;
+ struct chan_call *call;
pthread_t tid = pthread_self();
if (!pthread_equal(tid, chan_tid)) {
ast_mutex_lock(&chan_lock);
}
- call = ast->tech_pvt;
+ call = ast->tech_pvt;
if (!call) {
CERROR(NULL, ast, "Received hangup from Asterisk, but no call instance exists.\n");
if (!pthread_equal(tid, chan_tid)) {
@@ -2165,7 +2172,7 @@ static int lcr_hangup(struct ast_channel *ast)
call->state = CHAN_LCR_STATE_RELEASE;
call->ast = NULL;
}
- }
+ }
if (!pthread_equal(tid, chan_tid)) {
ast_mutex_unlock(&chan_lock);
}
@@ -2174,14 +2181,14 @@ static int lcr_hangup(struct ast_channel *ast)
static int lcr_write(struct ast_channel *ast, struct ast_frame *fr)
{
- struct chan_call *call;
+ struct chan_call *call;
struct ast_frame * f = fr;
if (!f->subclass)
CDEBUG(NULL, ast, "No subclass\n");
if (!(f->subclass & ast->nativeformats)) {
CDEBUG(NULL, ast,
- "Unexpected format. "
+ "Unexpected format. "
"Activating emergency conversion...\n");
ast_set_write_format(ast, f->subclass);
@@ -2190,7 +2197,7 @@ static int lcr_write(struct ast_channel *ast, struct ast_frame *fr)
}
ast_mutex_lock(&chan_lock);
- call = ast->tech_pvt;
+ call = ast->tech_pvt;
if (!call) {
ast_mutex_unlock(&chan_lock);
if (f != fr) {
@@ -2210,11 +2217,11 @@ static int lcr_write(struct ast_channel *ast, struct ast_frame *fr)
static struct ast_frame *lcr_read(struct ast_channel *ast)
{
- struct chan_call *call;
+ struct chan_call *call;
int len = 0;
ast_mutex_lock(&chan_lock);
- call = ast->tech_pvt;
+ call = ast->tech_pvt;
if (!call) {
ast_mutex_unlock(&chan_lock);
return NULL;
@@ -2235,11 +2242,11 @@ static struct ast_frame *lcr_read(struct ast_channel *ast)
#ifdef LCR_FOR_ASTERISK
return &ast_null_frame;
#endif
-
+
#ifdef LCR_FOR_CALLWEAVER
return &nullframe;
#endif
-
+
}
if (len <= 0) {
close(call->pipe[0]);
@@ -2274,20 +2281,20 @@ static struct ast_frame *lcr_read(struct ast_channel *ast)
static int lcr_indicate(struct ast_channel *ast, int cond, const void *data, size_t datalen)
{
union parameter newparam;
- int res = 0;
- struct chan_call *call;
+ int res = 0;
+ struct chan_call *call;
const struct tone_zone_sound *ts = NULL;
ast_mutex_lock(&chan_lock);
- call = ast->tech_pvt;
+ call = ast->tech_pvt;
if (!call) {
CERROR(NULL, ast, "Received indicate from Asterisk, but no call instance exists.\n");
ast_mutex_unlock(&chan_lock);
return -1;
}
- switch (cond) {
- case AST_CONTROL_BUSY:
+ switch (cond) {
+ case AST_CONTROL_BUSY:
CDEBUG(call, ast, "Received indicate AST_CONTROL_BUSY from Asterisk.\n");
ast_setstate(ast, AST_STATE_BUSY);
if (call->state != CHAN_LCR_STATE_OUT_DISCONNECT) {
@@ -2303,7 +2310,7 @@ static int lcr_indicate(struct ast_channel *ast, int cond, const void *data, siz
ts = ast_get_indication_tone(ast->zone, "busy");
}
break;
- case AST_CONTROL_CONGESTION:
+ case AST_CONTROL_CONGESTION:
CDEBUG(call, ast, "Received indicate AST_CONTROL_CONGESTION from Asterisk. (cause %d)\n", ast->hangupcause);
if (call->state != CHAN_LCR_STATE_OUT_DISCONNECT) {
/* send message to lcr */
@@ -2318,7 +2325,7 @@ static int lcr_indicate(struct ast_channel *ast, int cond, const void *data, siz
ts = ast_get_indication_tone(ast->zone, "congestion");
}
break;
- case AST_CONTROL_PROCEEDING:
+ case AST_CONTROL_PROCEEDING:
CDEBUG(call, ast, "Received indicate AST_CONTROL_PROCEEDING from Asterisk.\n");
if (call->state == CHAN_LCR_STATE_IN_SETUP
|| call->state == CHAN_LCR_STATE_IN_DIALING) {
@@ -2329,7 +2336,7 @@ static int lcr_indicate(struct ast_channel *ast, int cond, const void *data, siz
call->state = CHAN_LCR_STATE_IN_PROCEEDING;
}
break;
- case AST_CONTROL_RINGING:
+ case AST_CONTROL_RINGING:
CDEBUG(call, ast, "Received indicate AST_CONTROL_RINGING from Asterisk.\n");
ast_setstate(ast, AST_STATE_RING);
if (call->state == CHAN_LCR_STATE_IN_SETUP
@@ -2355,35 +2362,35 @@ static int lcr_indicate(struct ast_channel *ast, int cond, const void *data, siz
send_message(MESSAGE_BCHANNEL, call->ref, &newparam);
}
break;
- case -1:
+ case -1:
CDEBUG(call, ast, "Received indicate -1.\n");
ast_playtones_stop(ast);
- res = -1;
+ res = -1;
break;
- case AST_CONTROL_VIDUPDATE:
+ case AST_CONTROL_VIDUPDATE:
CDEBUG(call, ast, "Received indicate AST_CONTROL_VIDUPDATE.\n");
- res = -1;
- break;
- case AST_CONTROL_HOLD:
+ res = -1;
+ break;
+ case AST_CONTROL_HOLD:
CDEBUG(call, ast, "Received indicate AST_CONTROL_HOLD from Asterisk.\n");
/* send message to lcr */
memset(&newparam, 0, sizeof(union parameter));
newparam.notifyinfo.notify = INFO_NOTIFY_REMOTE_HOLD;
send_message(MESSAGE_NOTIFY, call->ref, &newparam);
-
+
/*start music onhold*/
#ifdef LCR_FOR_ASTERISK
ast_moh_start(ast,data,ast->musicclass);
#endif
-
+
#ifdef LCR_FOR_CALLWEAVER
ast_moh_start(ast, NULL);
#endif
-
+
call->on_hold = 1;
- break;
- case AST_CONTROL_UNHOLD:
+ break;
+ case AST_CONTROL_UNHOLD:
CDEBUG(call, ast, "Received indicate AST_CONTROL_UNHOLD from Asterisk.\n");
/* send message to lcr */
memset(&newparam, 0, sizeof(union parameter));
@@ -2391,21 +2398,21 @@ static int lcr_indicate(struct ast_channel *ast, int cond, const void *data, siz
send_message(MESSAGE_NOTIFY, call->ref, &newparam);
/*stop moh*/
- ast_moh_stop(ast);
+ ast_moh_stop(ast);
call->on_hold = 0;
- break;
+ break;
#ifdef AST_CONTROL_SRCUPDATE
- case AST_CONTROL_SRCUPDATE:
+ case AST_CONTROL_SRCUPDATE:
#else
- case 20:
+ case 20:
#endif
CDEBUG(call, ast, "Received AST_CONTROL_SRCUPDATE from Asterisk.\n");
- break;
- default:
+ break;
+ default:
CERROR(call, ast, "Received indicate from Asterisk with unknown condition %d.\n", cond);
- res = -1;
+ res = -1;
break;
- }
+ }
if (ts && ts->data[0]) {
ast_playtones_start(ast, 0, ts->data, 1);
@@ -2413,7 +2420,7 @@ static int lcr_indicate(struct ast_channel *ast, int cond, const void *data, siz
/* return */
ast_mutex_unlock(&chan_lock);
- return res;
+ return res;
}
/*
@@ -2421,7 +2428,7 @@ static int lcr_indicate(struct ast_channel *ast, int cond, const void *data, siz
*/
static int lcr_fixup(struct ast_channel *oldast, struct ast_channel *ast)
{
- struct chan_call *call;
+ struct chan_call *call;
if (!ast) {
return -1;
@@ -2446,7 +2453,7 @@ static int lcr_fixup(struct ast_channel *oldast, struct ast_channel *ast)
*/
static int lcr_send_text(struct ast_channel *ast, const char *text)
{
- struct chan_call *call;
+ struct chan_call *call;
union parameter newparam;
ast_mutex_lock(&chan_lock);
@@ -2495,15 +2502,15 @@ enum ast_bridge_result lcr_bridge(struct ast_channel *ast1,
return AST_BRIDGE_COMPLETE;
}
- /* join, if both call instances uses dsp
+ /* join, if both call instances uses dsp
ignore the case of fax detection here it may be benificial for ISDN fax machines or pass through.
- */
+ */
if (!call1->nodsp && !call2->nodsp) {
CDEBUG(NULL, NULL, "Both calls use DSP, bridging via DSP.\n");
/* get bridge id and join */
bridge_id = new_bridge_id();
-
+
call1->bridge_id = bridge_id;
if (call1->bchannel)
bchannel_join(call1->bchannel, bridge_id);
@@ -2557,9 +2564,9 @@ enum ast_bridge_result lcr_bridge(struct ast_channel *ast1,
call2->on_hold = 0;
}
-
+
ast_mutex_unlock(&chan_lock);
-
+
while(1) {
to = -1;
who = ast_waitfor_n(carr, 2, &to);
@@ -2569,7 +2576,7 @@ enum ast_bridge_result lcr_bridge(struct ast_channel *ast1,
break;
}
f = ast_read(who);
-
+
if (!f || f->frametype == AST_FRAME_CONTROL) {
if (!f)
CDEBUG(NULL, NULL, "Got hangup.\n");
@@ -2580,14 +2587,14 @@ enum ast_bridge_result lcr_bridge(struct ast_channel *ast1,
*rc=who;
break;
}
-
+
if ( f->frametype == AST_FRAME_DTMF ) {
CDEBUG(NULL, NULL, "Got DTMF.\n");
*fo=f;
*rc=who;
break;
}
-
+
if (who == ast1) {
ast_write(ast2,f);
@@ -2595,9 +2602,9 @@ enum ast_bridge_result lcr_bridge(struct ast_channel *ast1,
else {
ast_write(ast1,f);
}
-
+
}
-
+
CDEBUG(NULL, NULL, "Releasing bridge.\n");
/* split channels */
@@ -2640,7 +2647,7 @@ static struct ast_channel_tech lcr_tech = {
#endif
.call = lcr_call,
- .bridge = lcr_bridge,
+ .bridge = lcr_bridge,
.hangup = lcr_hangup,
.answer = lcr_answer,
.read = lcr_read,
@@ -2757,11 +2764,11 @@ static int lcr_config_exec(struct ast_channel *ast, void *data, char **argv)
#ifdef LCR_FOR_ASTERISK
CDEBUG(NULL, ast, "Received lcr_config (data=%s)\n", (char *)data);
#endif
-
+
#ifdef LCR_FOR_CALLWEAVER
CDEBUG(NULL, ast, "Received lcr_config (data=%s)\n", argv[0]);
#endif
-
+
/* find channel */
call = call_first;
while(call) {
@@ -2770,12 +2777,12 @@ static int lcr_config_exec(struct ast_channel *ast, void *data, char **argv)
call = call->next;
}
if (call)
-
+
#ifdef LCR_FOR_ASTERISK
apply_opt(call, (char *)data);
- #endif
-
- #ifdef LCR_FOR_CALLWEAVER
+ #endif
+
+ #ifdef LCR_FOR_CALLWEAVER
apply_opt(call, (char *)argv[0]);
#endif
@@ -2804,12 +2811,12 @@ int load_module(void)
#ifdef LCR_FOR_ASTERISK
return AST_MODULE_LOAD_DECLINE;
- #endif
-
+ #endif
+
#ifdef LCR_FOR_CALLWEAVER
return 0;
#endif
-
+
}
ast_mutex_init(&chan_lock);
@@ -2818,11 +2825,11 @@ int load_module(void)
if (bchannel_initialize()) {
CERROR(NULL, NULL, "Unable to open mISDN device\n");
close_socket();
-
+
#ifdef LCR_FOR_ASTERISK
return AST_MODULE_LOAD_DECLINE;
- #endif
-
+ #endif
+
#ifdef LCR_FOR_CALLWEAVER
return 0;
#endif
@@ -2837,29 +2844,29 @@ int load_module(void)
#ifdef LCR_FOR_ASTERISK
return AST_MODULE_LOAD_DECLINE;
- #endif
-
+ #endif
+
#ifdef LCR_FOR_CALLWEAVER
return 0;
#endif
}
ast_register_application("lcr_config", lcr_config_exec, "lcr_config",
-
+
#ifdef LCR_FOR_ASTERISK
"lcr_config(<opt><optarg>:<opt>:...)\n"
#endif
-
+
#ifdef LCR_FOR_CALLWEAVER
- "lcr_config(<opt><optarg>:<opt>:...)\n",
+ "lcr_config(<opt><optarg>:<opt>:...)\n",
#endif
-
+
"Sets LCR opts. and optargs\n"
"\n"
"The available options are:\n"
" d - Send display text on called phone, text is the optarg.\n"
" n - Don't detect dtmf tones on called channel.\n"
- " h - Force data call (HDLC).\n"
+ " h - Force data call (HDLC).\n"
" t - Disable mISDN_dsp features (required for fax application).\n"
" q - Add queue to make fax stream seamless (required for fax app).\n"
" Use queue size in miliseconds for optarg. (try 250)\n"
@@ -2882,8 +2889,8 @@ int load_module(void)
"options: \"n:t:q250\" for seamless audio transmission.\n"
);
-
-#if 0
+
+#if 0
ast_cli_register(&cli_show_lcr);
ast_cli_register(&cli_show_calls);
ast_cli_register(&cli_reload_routing);
@@ -2893,7 +2900,7 @@ int load_module(void)
ast_cli_register(&cli_port_unload);
#endif
- quit = 0;
+ quit = 0;
if ((pthread_create(&chan_tid, NULL, chan_thread, NULL)<0)) {
/* failed to create thread */
bchannel_deinitialize();
@@ -2902,12 +2909,12 @@ int load_module(void)
#ifdef LCR_FOR_ASTERISK
return AST_MODULE_LOAD_DECLINE;
- #endif
-
+ #endif
+
#ifdef LCR_FOR_CALLWEAVER
return 0;
#endif
-
+
}
return 0;
}
@@ -2918,11 +2925,11 @@ int unload_module(void)
CDEBUG(NULL, NULL, "-- Unregistering mISDN Channel Driver --\n");
quit = 1;
- pthread_join(chan_tid, NULL);
-
+ pthread_join(chan_tid, NULL);
+
ast_channel_unregister(&lcr_tech);
- ast_unregister_application("lcr_config");
+ ast_unregister_application("lcr_config");
if (mISDN_created) {
diff --git a/default/gsm.conf b/default/gsm.conf
index 148513b..713a620 100644
--- a/default/gsm.conf
+++ b/default/gsm.conf
@@ -1,15 +1,7 @@
# LCR GSM options
#################
-# Two Loopback interfaces for audio transfer between OpenBSC and mISDN.
-# They are also used for any Osmocom-BB interface, if exists.
-# The first interface must provide B-channelis for each call mobile call.
-# The seond interface links them to LCR.
-# Use 30 B-channels unless you need more due to many TRXs or mobile stations.
-# -> Load with: "modprobe mISDN_l1loop pri=1 nchannel=30"
-# By default "mISDN_l1loop.1" and "mISDN_l1loop.2" is used.
-#interface-bsc mISDN_l1loop.1
-#interface-lcr mISDN_l1loop.2
+# interfaces-bsc and interface-lcr has been moved to options.conf!
# Enable debugging of OpenBSC library.
# Refer to OpenBSC project for debugging options.
diff --git a/default/interface.conf b/default/interface.conf
index 6e19538..4c80fed 100644
--- a/default/interface.conf
+++ b/default/interface.conf
@@ -191,6 +191,20 @@
##external
+# Use chan_lcr (Asterisk PBX interface) as internal interface.
+# The interface requires mISDN_l1loop.ko to be loaded:
+# modprobe mISDN_l1loop nchannel=8 # use up to 8 b-channels
+# The caller ID is used as extension, if "extension" parameter is given.
+# Use "screen-in % xxx" to modify any caller id to xxx.
+# An internal extension does not receive tones ("earlyb"), but sends them.
+#[ast]
+#remote asterisk
+#extension
+##screen-in % 209
+#earlyb no
+#tones yes
+
+
# Hint: Enter "lcr interface" for quick help on interface options.
diff --git a/default/options.conf b/default/options.conf
index e0e93a0..cb48ea7 100644
--- a/default/options.conf
+++ b/default/options.conf
@@ -120,3 +120,13 @@
# Enable polling in main loop.
# 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
+
diff --git a/gsm.cpp b/gsm.cpp
index 7245632..e7216dd 100644
--- a/gsm.cpp
+++ b/gsm.cpp
@@ -119,7 +119,7 @@ void Pgsm::bchannel_close(void)
static int b_handler(struct lcr_fd *fd, unsigned int what, void *instance, int index);
-/* open bsc side bchannel */
+/* open external side bchannel */
int Pgsm::bchannel_open(int index)
{
int ret;
@@ -295,70 +295,10 @@ void gsm_trace_header(struct mISDNport *mISDNport, class PmISDN *port, unsigned
msgtext);
}
-/* select bchannel */
+/* select free bchannel from loopback interface */
int Pgsm::hunt_bchannel(void)
{
- int channel;
- int i;
- char map[p_m_mISDNport->b_num];
- struct interface *interface;
- struct interface_port *ifport;
-
- chan_trace_header(p_m_mISDNport, this, "CHANNEL SELECTION (setup)", DIRECTION_NONE);
- add_trace("channel", "reserved", "%d", p_m_mISDNport->b_reserved);
- if (p_m_mISDNport->b_reserved >= p_m_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 defined WITH_GSM_BS && defined WITH_GSM_MS
- if ((ifport->gsm_bs || ifport->gsm_ms) && ifport->mISDNport) {
-#else
-#ifdef WITH_GSM_BS
- if (ifport->gsm_bs && ifport->mISDNport) {
-#endif
-#ifdef WITH_GSM_MS
- if (ifport->gsm_ms && ifport->mISDNport) {
-#endif
-#endif
- i = 0;
- while(i < p_m_mISDNport->b_num) {
- if (p_m_mISDNport->b_port[i])
- map[i] = 1;
- i++;
- }
- }
- ifport = ifport->next;
- }
- interface = interface->next;
- }
-
- /* find channel */
- i = 0;
- channel = 0;
- while(i < p_m_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);
+ return loop_hunt_bchannel(this, p_m_mISDNport);
}
/* PROCEEDING INDICATION */
@@ -884,87 +824,10 @@ static int b_handler(struct lcr_fd *fd, unsigned int what, void *instance, int i
return 0;
}
-static void gsm_sock_close(void)
-{
- if (gsm->gsm_sock > -1)
- close(gsm->gsm_sock);
- gsm->gsm_sock = -1;
-}
-
-static int gsm_sock_open(char *portname)
-{
- int ret;
- int cnt;
- unsigned long on = 1;
- struct sockaddr_mISDN addr;
- struct mISDN_devinfo devinfo;
- int pri, bri;
-
- /* 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;
- }
- gsm->gsm_port = mISDN_getportbyname(mISDNsocket, cnt, portname);
- if (gsm->gsm_port < 0) {
- PERROR_RUNTIME("Port name '%s' not found, did you load loopback interface for GSM?.\n", portname);
- return gsm->gsm_port;
- }
- /* get protocol */
- bri = pri = 0;
- devinfo.id = gsm->gsm_port;
- ret = ioctl(mISDNsocket, IMGETDEVINFO, &devinfo);
- if (ret < 0) {
- PERROR_RUNTIME("Cannot get device information for port %d. (ioctl IMGETDEVINFO failed ret=%d)\n", gsm->gsm_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 (!pri && !pri) {
- PERROR_RUNTIME("GSM port %d does not support TE PRI or TE BRI.\n", gsm->gsm_port);
- }
- /* open socket */
- if ((gsm->gsm_sock = socket(PF_ISDN, SOCK_DGRAM, (pri)?ISDN_P_TE_E1:ISDN_P_TE_S0)) < 0) {
- PERROR_RUNTIME("GSM port %d failed to open socket.\n", gsm->gsm_port);
- gsm_sock_close();
- return gsm->gsm_sock;
- }
- /* set nonblocking io */
- if ((ret = ioctl(gsm->gsm_sock, FIONBIO, &on)) < 0) {
- PERROR_RUNTIME("GSM port %d failed to set socket into nonblocking io.\n", gsm->gsm_port);
- gsm_sock_close();
- return ret;
- }
- /* bind socket to dchannel */
- memset(&addr, 0, sizeof(addr));
- addr.family = AF_ISDN;
- addr.dev = gsm->gsm_port;
- addr.channel = 0;
- if ((ret = bind(gsm->gsm_sock, (struct sockaddr *)&addr, sizeof(addr))) < 0) {
- PERROR_RUNTIME("GSM port %d failed to bind socket. (name = %s errno=%d)\n", gsm->gsm_port, portname, errno);
- gsm_sock_close();
- return (ret);
- }
-
- return 0;
-}
-
int gsm_exit(int rc)
{
/* free gsm instance */
if (gsm) {
- if (gsm->gsm_sock > -1)
- gsm_sock_close();
free(gsm);
gsm = NULL;
}
@@ -996,7 +859,7 @@ int gsm_init(void)
}
/* open gsm loop interface */
- if (gsm_sock_open(gsm->conf.interface_bsc)) {
+ if (loopback_open()) {
return gsm_exit(-1);
}
diff --git a/gsm.h b/gsm.h
index 71ed759..de4c02b 100644
--- a/gsm.h
+++ b/gsm.h
@@ -2,8 +2,6 @@ extern int new_callref;
struct gsm_conf {
char debug[128]; /* debug info */
- char interface_bsc[64]; /* loopback interface BSC side */
- char interface_lcr[64]; /* loopback interface LCR side */
char openbsc_cfg[128]; /* openbsc config file */
char short_name[64]; /* short network name */
char long_name[64]; /* long network name */
@@ -17,8 +15,6 @@ struct gsm_conf {
struct lcr_gsm {
void *network; /* OpenBSC network handle */
struct gsm_conf conf; /* gsm.conf options */
- int gsm_sock; /* loopback interface GSM side */
- int gsm_port; /* loopback interface port number */
};
extern struct lcr_gsm *gsm;
diff --git a/gsm_conf.c b/gsm_conf.c
index a64f2ff..f25cf85 100644
--- a/gsm_conf.c
+++ b/gsm_conf.c
@@ -29,8 +29,6 @@ int gsm_conf(struct gsm_conf *gsm_conf, char *conf_error)
/* set defaults */
SCPY(gsm_conf->debug, "");
- SCPY(gsm_conf->interface_bsc, "mISDN_l1loop.1");
- SCPY(gsm_conf->interface_lcr, "mISDN_l1loop.2");
SCPY(gsm_conf->hlr, "hlr.sqlite3");
SCPY(gsm_conf->openbsc_cfg, "openbsc.cfg");
gsm_conf->reject_cause = 0;
@@ -105,22 +103,6 @@ int gsm_conf(struct gsm_conf *gsm_conf, char *conf_error)
SCPY(gsm_conf->debug, params[0]);
} else
- if (!strcmp(option,"interface-bsc")) {
- if (params[0][0]==0) {
- UPRINT(conf_error, "Error in %s (line %d): parameter for option %s missing.\n",filename,line, option);
- goto error;
- }
- SCPY(gsm_conf->interface_bsc, params[0]);
-
- } else
- if (!strcmp(option,"interface-lcr")) {
- if (params[0][0]==0) {
- UPRINT(conf_error, "Error in %s (line %d): parameter for option %s missing.\n",filename,line, option);
- goto error;
- }
- SCPY(gsm_conf->interface_lcr, params[0]);
-
- } else
if (!strcmp(option,"config")) {
if (params[0][0]==0) {
UPRINT(conf_error, "Error in %s (line %d): parameter for option %s missing.\n",filename,line, option);
diff --git a/interface.c b/interface.c
index a312e4e..448affc 100644
--- a/interface.c
+++ b/interface.c
@@ -327,9 +327,7 @@ static int inter_portname(struct interface *interface, char *filename, int line,
/* check for port already assigned, but not for shared gsm interface */
searchif = interface_newlist;
-#if defined WITH_GSM_BS || defined WITH_GSM_MS
- if (!strcmp(value, gsm->conf.interface_lcr))
-#endif
+ if (!strcmp(value, options.loopback_lcr))
{
while(searchif) {
ifport = searchif->ifport;
@@ -918,7 +916,7 @@ static int inter_gsm_bs(struct interface *interface, char *filename, int line, c
}
/* set portname */
- if (inter_portname(interface, filename, line, (char *)"portname", gsm->conf.interface_lcr))
+ if (inter_portname(interface, filename, line, (char *)"portname", options.loopback_lcr))
return(-1);
/* goto end of chain again to set gsmflag */
@@ -947,7 +945,7 @@ static int inter_gsm_ms(struct interface *interface, char *filename, int line, c
}
/* set portname */
- if (inter_portname(interface, filename, line, (char *)"portname", gsm->conf.interface_lcr))
+ if (inter_portname(interface, filename, line, (char *)"portname", options.loopback_lcr))
return(-1);
/* goto end of chain again to set gsmflag and socket */
@@ -1054,6 +1052,42 @@ static int inter_ss5(struct interface *interface, char *filename, int line, char
return(0);
}
#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]) {
+ SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects application name as value.\n", filename, line, parameter);
+ return(-1);
+ }
+ 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;
+ }
+ 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);
+
+
+ return(0);
+}
/*
@@ -1215,6 +1249,10 @@ struct interface_param interface_param[] = {
" suppress - Suppress received tones, as they will be recognized."},
#endif
+ {"remote", &inter_remote, "<application>",
+ "Sets up an interface that communicates with the remote application.\n"
+ "Use \"asterisk\" to use chan_lcr as remote application."},
+
{NULL, NULL, NULL, NULL}
};
diff --git a/interface.h b/interface.h
index d1bea04..eea6915 100644
--- a/interface.h
+++ b/interface.h
@@ -61,6 +61,8 @@ struct interface_port {
char gsm_ms_service; /* see GSM_SERVICE_* */
#endif
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 */
diff --git a/joinremote.cpp b/joinremote.cpp
index 167bbce..c02de8e 100644
--- a/joinremote.cpp
+++ b/joinremote.cpp
@@ -14,6 +14,7 @@
//#define __u16 unsigned short
//#define __u32 unsigned int
+extern unsigned int new_remote;
/*
* constructor for a new join
@@ -27,6 +28,7 @@ JoinRemote::JoinRemote(unsigned int serial, char *remote_name, int remote_id) :
SCPY(j_remote_name, remote_name);
j_remote_id = remote_id;
j_type = JOIN_TYPE_REMOTE;
+ j_remote_ref = new_remote++;
j_epoint_id = serial; /* this is the endpoint, if created by epoint */
if (j_epoint_id)
@@ -35,9 +37,8 @@ JoinRemote::JoinRemote(unsigned int serial, char *remote_name, int remote_id) :
/* send new ref to remote socket */
memset(&param, 0, sizeof(union parameter));
if (serial)
- param.direction = 1; /* new ref from lcr */
- /* the j_serial is assigned by Join() parent. this is sent as new ref */
- if (admin_message_from_join(j_remote_id, j_serial, MESSAGE_NEWREF, &param)<0)
+ 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);
}
@@ -56,7 +57,7 @@ void JoinRemote::message_epoint(unsigned int epoint_id, int message_type, union
return;
/* look for Remote's interface */
- if (admin_message_from_join(j_remote_id, j_serial, message_type, param)<0) {
+ 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;
}
@@ -100,25 +101,5 @@ void JoinRemote::message_remote(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)
-{
- union parameter param;
-
- memset(&param, 0, sizeof(union parameter));
- 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_join(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;
- }
-}
-
diff --git a/joinremote.h b/joinremote.h
index 1582133..a933466 100644
--- a/joinremote.h
+++ b/joinremote.h
@@ -17,10 +17,10 @@ class JoinRemote : public Join
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;
};
-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);
diff --git a/loop.c b/loop.c
new file mode 100644
index 0000000..cbd82e5
--- /dev/null
+++ b/loop.c
@@ -0,0 +1,153 @@
+/*****************************************************************************\
+** **
+** 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);
+}
+
+
diff --git a/loop.h b/loop.h
new file mode 100644
index 0000000..cb2ad05
--- /dev/null
+++ b/loop.h
@@ -0,0 +1,12 @@
+
+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);
+
diff --git a/mISDN.cpp b/mISDN.cpp
index ee50bf1..087963c 100644
--- a/mISDN.cpp
+++ b/mISDN.cpp
@@ -33,21 +33,6 @@ int __af_isdn = MISDN_AF_ISDN;
#define B_TIMER_ACTIVATING 1 // seconds
#define B_TIMER_DEACTIVATING 1 // seconds
-/* GSM condition */
-#if defined WITH_GSM_BS && defined WITH_GSM_MS
- #define MISDNPORT_GSM (mISDNport->gsm_bs || mISDNport->gsm_ms)
-#else
- #ifdef WITH_GSM_BS
- #define MISDNPORT_GSM (mISDNport->gsm_bs)
- #endif
- #ifdef WITH_GSM_MS
- #define MISDNPORT_GSM (mISDNport->gsm_ms)
- #endif
-#endif
-#ifndef MISDNPORT_GSM
- #define MISDNPORT_GSM (0)
-#endif
-
/* list of mISDN ports */
struct mISDNport *mISDNport_first;
@@ -671,7 +656,7 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
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);
+ 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);
@@ -719,7 +704,7 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
/* 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);
+ 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);
@@ -774,7 +759,7 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
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);
+ 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);
@@ -825,7 +810,7 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
* 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);
+ 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);
@@ -861,7 +846,7 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
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);
+ 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);
@@ -892,7 +877,7 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
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);
+ 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);
@@ -924,7 +909,7 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
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);
+ 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);
@@ -1856,7 +1841,7 @@ 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_GSM) {
+ if (!mISDNport->isloopback) {
while ((mb = mdequeue(&mISDNport->upqueue))) {
l3m = &mb->l3;
switch(l3m->type) {
@@ -1932,7 +1917,7 @@ static int mISDN_upqueue(struct lcr_fd *fd, unsigned int what, void *instance, i
if (!mISDNport->ntmode || mISDNport->ptp)
mISDNport->l2link = 0;
}
- if (!MISDNPORT_GSM && (!mISDNport->ntmode || mISDNport->ptp) && l3m->pid < 127) {
+ 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);
@@ -1959,7 +1944,7 @@ static int l2establish_timeout(struct lcr_timer *timer, void *instance, int i)
{
struct mISDNport *mISDNport = (struct mISDNport *)instance;
- if (!MISDNPORT_GSM && mISDNport->l2hold && (mISDNport->ptp || !mISDNport->ntmode)) {
+ if (!mISDNport->isloopback && 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 */
@@ -2119,7 +2104,7 @@ struct mISDNport *mISDNport_open(struct interface_port *ifport)
int force_nt = ifport->nt;
int l1hold = ifport->l1hold;
int l2hold = ifport->l2hold;
- int gsm = 0;
+ int loop = 0;
int ss5 = ifport->ss5;
int i, cnt;
int pri, bri, pots;
@@ -2129,15 +2114,23 @@ struct mISDNport *mISDNport_open(struct interface_port *ifport)
unsigned int protocol, prop;
#if defined WITH_GSM_BS && defined WITH_GSM_MS
- gsm = ifport->gsm_ms | ifport->gsm_bs;
+ loop = ifport->gsm_ms | ifport->gsm_bs;
#else
#ifdef WITH_GSM_BS
- gsm = ifport->gsm_bs;
+ loop = ifport->gsm_bs;
#endif
#ifdef WITH_GSM_MS
- gsm = ifport->gsm_ms;
+ loop = ifport->gsm_ms;
#endif
#endif
+//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);
@@ -2153,8 +2146,8 @@ struct mISDNport *mISDNport_open(struct interface_port *ifport)
if (port < 0) {
port = mISDN_getportbyname(mISDNsocket, cnt, ifport->portname);
if (port < 0) {
- if (gsm)
- PERROR_RUNTIME("Port name '%s' not found, did you load loopback interface for GSM?.\n", ifport->portname);
+ 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);
return(NULL);
@@ -2270,8 +2263,8 @@ 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 (gsm | ss5) {
- /* gsm/ss5 link is always active */
+ if (loop | ss5) {
+ /* loop/ss5 link is always active */
mISDNport->l1link = 1;
mISDNport->l2link = 1;
} else {
@@ -2284,6 +2277,7 @@ struct mISDNport *mISDNport_open(struct interface_port *ifport)
#ifdef WITH_GSM_MS
mISDNport->gsm_ms = ifport->gsm_ms;
#endif
+ mISDNport->isloopback = loop;
pmemuse++;
*mISDNportp = mISDNport;
@@ -2325,25 +2319,24 @@ 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 (gsm) {
-#if defined WITH_GSM_BS || defined WITH_GSM_MS
+ if (loop) {
unsigned long on = 1;
struct sockaddr_mISDN addr;
if (devinfo.nrbchan < 8) {
- PERROR_RUNTIME("GSM port %d must have at least 8 b-channels.\n", port);
- mISDNport_close(mISDNport);
- return(NULL);
+ 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, ISDN_P_NT_S0)) < 0) {
- PERROR_RUNTIME("GSM port %d failed to open socket.\n", port);
+ 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("GSM port %d failed to set socket into nonblocking io.\n", port);
+ PERROR_RUNTIME("loop port %d failed to set socket into nonblocking io.\n", port);
mISDNport_close(mISDNport);
return(NULL);
}
@@ -2353,11 +2346,10 @@ struct mISDNport *mISDNport_open(struct interface_port *ifport)
addr.dev = port;
addr.channel = 0;
if (bind(mISDNport->lcr_sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
- PERROR_RUNTIME("GSM port %d failed to bind socket. (errno %d)\n", port, errno);
+ PERROR_RUNTIME("loop port %d failed to bind socket. (errno %d)\n", port, errno);
mISDNport_close(mISDNport);
return(NULL);
}
-#endif
} else {
/* queue must be initializes, because l3-thread may send messages during open_layer3() */
mqueue_init(&mISDNport->upqueue);
@@ -2398,7 +2390,7 @@ struct mISDNport *mISDNport_open(struct interface_port *ifport)
}
/* if ptp, pull up the link */
- if (!MISDNPORT_GSM && mISDNport->l2hold && (mISDNport->ptp || !mISDNport->ntmode)) {
+ if (!mISDNport->isloopback && 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);
@@ -2511,19 +2503,17 @@ void mISDNport_close(struct mISDNport *mISDNport)
del_timer(&mISDNport->l2establish);
/* close layer 3, if open */
- if (!MISDNPORT_GSM && mISDNport->ml3) {
+ if (!mISDNport->isloopback && mISDNport->ml3) {
close_layer3(mISDNport->ml3);
}
-#if defined WITH_GSM_BS || defined WITH_GSM_MS
/* close gsm socket, if open */
- if (MISDNPORT_GSM && mISDNport->lcr_sock > -1) {
+ if (mISDNport->isloopback && mISDNport->lcr_sock > -1) {
close(mISDNport->lcr_sock);
}
-#endif
/* purge upqueue */
- if (!MISDNPORT_GSM)
+ if (!mISDNport->isloopback)
mqueue_purge(&mISDNport->upqueue);
/* remove from list */
diff --git a/mISDN.h b/mISDN.h
index 644658b..de223c8 100644
--- a/mISDN.h
+++ b/mISDN.h
@@ -71,9 +71,8 @@ struct mISDNport {
#ifdef WITH_GSM_MS
int gsm_ms; /* this is the an GSM MS interface */
#endif
-#if defined WITH_GSM_BS || defined WITH_GSM_MS
int lcr_sock; /* socket of loopback on LCR side */
-#endif
+ 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 */
diff --git a/main.c b/main.c
index 98be1c0..0cc68a4 100644
--- a/main.c
+++ b/main.c
@@ -602,6 +602,10 @@ free:
#endif
}
+ /* close loopback, if used by GSM or remote */
+ if (mISDNloop.sock > -1)
+ mISDNloop_close();
+
/* display memory leak */
#define MEMCHECK(a, b) \
if (b) { \
diff --git a/main.h b/main.h
index 8e45581..7aad3c2 100644
--- a/main.h
+++ b/main.h
@@ -148,6 +148,8 @@ extern "C" {
#include "port.h"
#include "mISDN.h"
#include "dss1.h"
+#include "loop.h"
+#include "remote.h"
#if defined WITH_GSM_BS || defined WITH_GSM_MS
#include "gsm.h"
#endif
diff --git a/message.h b/message.h
index 471e2c8..c2076af 100644
--- a/message.h
+++ b/message.h
@@ -324,6 +324,7 @@ struct param_hello {
struct param_bchannel {
int type; /* BCHANNEL_* */
unsigned int handle; /* bchannel stack/portid */
+ int isloopback; /* in this case the application behaves like an interface, dsp should not be used */
int tx_gain, rx_gain;
char pipeline[256];
unsigned char crypt[128];
@@ -331,6 +332,11 @@ struct param_bchannel {
int crypt_type; /* 1 = blowfish */
};
+struct param_newref {
+ int direction; /* who requests a refe? */
+ int mode; /* 0 = direct-mode, 1 = PBX mode */
+};
+
/* structure of message parameter */
union parameter {
struct param_tone tone; /* MESSAGE_TONE */
@@ -355,7 +361,7 @@ union parameter {
struct param_crypt crypt; /* MESSAGE_CRYPT */
struct param_hello hello; /* MESSAGE_HELLO */
struct param_bchannel bchannel; /* MESSAGE_BCHANNEL */
- int direction; /* MESSAGE_NEWREF */
+ struct param_newref newref; /* MESSAGE_NEWREF */
};
enum { /* message flow */
@@ -428,6 +434,7 @@ enum { /* messages between entities */
"MESSAGE_RELEASE", \
"MESSAGE_TIMEOUT", \
"MESSAGE_NOTIFY", \
+ "MESSAGE_PROGRESS", \
"MESSAGE_FACILITY", \
"MESSAGE_SUSPEND", \
"MESSAGE_RESUME", \
diff --git a/options.c b/options.c
index 88f6424..7fb9bcb 100644
--- a/options.c
+++ b/options.c
@@ -36,7 +36,9 @@ struct options options = {
-1, /* socket user (-1= no change) */
-1, /* socket group (-1= no change) */
0, /* enable gsm */
- 1 /* use polling of main loop */
+ 1, /* use polling of main loop */
+ "mISDN_l1loop.1", /* GSM/Asterisk side */
+ "mISDN_l1loop.2", /* LCR side */
};
char options_error[256];
@@ -239,6 +241,22 @@ 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;
diff --git a/options.h b/options.h
index c13ee2c..c7f9f8f 100644
--- a/options.h
+++ b/options.h
@@ -31,6 +31,8 @@ struct options {
int socketgroup; /* socket chgrp to this group */
int gsm; /* enable gsm support */
int polling;
+ char loopback_ext[64]; /* loopback interface GSM side */
+ char loopback_lcr[64]; /* loopback interface LCR side */
};
extern struct options options;
diff --git a/port.h b/port.h
index d7c0580..a4da7de 100644
--- a/port.h
+++ b/port.h
@@ -22,10 +22,14 @@
#define PORT_CLASS_GSM_BS 0x1210
#define PORT_CLASS_GSM_MS 0x1220
#define PORT_CLASS_SS5 0x1300
+#define PORT_CLASS_REMOTE 0x1400
#define PORT_CLASS_MASK 0xf000
#define PORT_CLASS_mISDN_MASK 0xff00
#define PORT_CLASS_DSS1_MASK 0xfff0
#define PORT_CLASS_GSM_MASK 0xfff0
+#define PORT_CLASS_DIR_MASK 0x000f
+#define PORT_CLASS_DIR_IN 0x0001
+#define PORT_CLASS_DIR_OUT 0x0002
/* nt-mode */
#define PORT_TYPE_DSS1_NT_IN 0x1111
#define PORT_TYPE_DSS1_NT_OUT 0x1112
@@ -41,6 +45,9 @@
#define PORT_TYPE_SS5_IN 0x1311
#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
/* answering machine */
#define PORT_TYPE_VBOX_OUT 0x3111
diff --git a/remote.cpp b/remote.cpp
new file mode 100644
index 0000000..e14c8e3
--- /dev/null
+++ b/remote.cpp
@@ -0,0 +1,221 @@
+/*****************************************************************************\
+** **
+** LCR **
+** **
+**---------------------------------------------------------------------------**
+** Copyright: Andreas Eversberg **
+** **
+** mISDN remote **
+** **
+\*****************************************************************************/
+
+#include "main.h"
+
+unsigned int new_remote = 0x00000001;
+
+/*
+ * 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)
+{
+ 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;
+
+ /* 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);
+
+ PDEBUG(DEBUG_GSM, "Created new RemotePort(%s).\n", portname);
+
+}
+
+/*
+ * destructor
+ */
+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);
+
+}
+
+/*
+ * endpoint sends messages to the port
+ */
+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))
+ 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;
+ return 0;
+ }
+ bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_USE);
+
+ /* attach only if not already */
+ epointlist = p_epointlist;
+ while(epointlist) {
+ if (epointlist->epoint_id == epoint_id)
+ break;
+ epointlist = epointlist->next;
+ }
+ if (!epointlist)
+ epointlist_new(epoint_id);
+
+ /* set context to pbx */
+ SCPY(param->setup.context, "pbx");
+ }
+
+ /* 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);
+ return 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);
+ newparam.audiopath = 1;
+ admin_message_from_lcr(p_m_r_remote_id, p_m_r_ref, MESSAGE_AUDIOPATH, &newparam);
+ }
+
+ if (message_type == MESSAGE_RELEASE) {
+ new_state(PORT_STATE_RELEASE);
+ delete this;
+ return 0;
+ }
+
+ return 0;
+}
+
+void Premote::message_remote(int message_type, union parameter *param)
+{
+ class Endpoint *epoint;
+ struct lcr_msg *message;
+ int channel;
+ int ret;
+
+ 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);
+
+ /* 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);
+
+ 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");
+ if (!(epoint->ep_app = new DEFAULT_ENDPOINT_APP(epoint, 0))) //incoming
+ FATAL("No memory for Endpoint Application instance\n");
+
+ epointlist_new(epoint->ep_serial);
+ }
+
+ /* 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;
+ }
+ 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)
+{
+ return loop_hunt_bchannel(this, p_m_mISDNport);
+}
+
+
+
diff --git a/remote.h b/remote.h
new file mode 100644
index 0000000..f39245b
--- /dev/null
+++ b/remote.h
@@ -0,0 +1,20 @@
+
+/* GSM port class */
+class Premote : public PmISDN
+{
+ public:
+ Premote(int type, struct mISDNport *mISDNport, char *portname, struct port_settings *settings, int channel, int exclusive, int mode, 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 */
+
+ 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);
+};
+
+
diff --git a/socket_server.c b/socket_server.c
index e84fa5e..9922dc6 100644
--- a/socket_server.c
+++ b/socket_server.c
@@ -19,6 +19,7 @@
char socket_name[128];
int sock = -1;
struct sockaddr_un sock_address;
+extern unsigned int new_remote;
struct admin_list *admin_first = NULL;
static struct lcr_fd admin_fd;
@@ -84,6 +85,8 @@ void free_connection(struct admin_list *admin)
struct mISDNport *mISDNport;
int i, ii;
struct admin_list **adminp;
+ class Port *port, *portnext;
+ class Premote *remote;
/* free remote joins */
if (admin->remote_name[0]) {
@@ -126,6 +129,22 @@ void free_connection(struct admin_list *admin)
}
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) {
+ memset(&param, 0, sizeof(param));
+ param.disconnectinfo.cause = CAUSE_OUTOFORDER;
+ param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
+ remote->message_remote(MESSAGE_RELEASE, &param);
+ /* port is now destroyed, so we go to next join */
+ }
+ }
+ port = portnext;
+ }
}
if (admin->sock >= 0) {
@@ -586,9 +605,13 @@ void admin_call_response(int adminid, int message, const char *connected, int ca
/*
* send data to the remote socket join instance
*/
-int admin_message_to_join(struct admin_msg *msg, struct admin_list *admin)
+int admin_message_to_lcr(struct admin_msg *msg, struct admin_list *admin)
{
+ struct mISDNport *mISDNport;
class Join *join;
+ class JoinRemote *joinremote = NULL; /* make GCC happy */
+ class Port *port;
+ class Premote *remote = NULL; /* make GCC happy */
struct admin_list *temp;
/* hello message */
@@ -629,13 +652,41 @@ int admin_message_to_join(struct admin_msg *msg, struct admin_list *admin)
return(-1);
}
- /* new join */
+ /* new join. the reply (NEWREF assignment) is sent from constructor */
if (msg->type == MESSAGE_NEWREF) {
- /* 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);
+ 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) {
+ unsigned int remote_ref = new_remote++;
+ union parameter param;
+
+ memset(&param, 0, sizeof(union parameter));
+ admin_message_from_lcr(mISDNport->ifport->remote, remote_ref, MESSAGE_NEWREF, &param);
+ memset(&param, 0, sizeof(union parameter));
+ param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
+ param.disconnectinfo.cause = CAUSE_RESSOURCEUNAVAIL;
+ admin_message_from_lcr(mISDNport->ifport->remote, 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);
+ }
}
return(0);
}
@@ -646,6 +697,7 @@ int admin_message_to_join(struct admin_msg *msg, struct admin_list *admin)
if (msg->param.bchannel.type == BCHANNEL_ASSIGN_ACK
|| msg->param.bchannel.type == BCHANNEL_REMOVE_ACK
|| msg->param.bchannel.type == BCHANNEL_RELEASE) {
+#warning TODO: depending on the mode (join / remoteport) forward message
/* no ref, but address */
message_bchannel_from_remote(NULL, msg->param.bchannel.type, msg->param.bchannel.handle);
return(0);
@@ -660,36 +712,56 @@ int admin_message_to_join(struct admin_msg *msg, struct admin_list *admin)
/* find join instance */
join = join_first;
while(join) {
- if (join->j_serial == msg->ref)
- break;
+ if (join->j_type != JOIN_TYPE_REMOTE) {
+ joinremote = (class JoinRemote *)join;
+ if (joinremote->j_remote_ref == msg->ref)
+ break;
+ }
join = join->next;
}
- if (!join) {
- PDEBUG(DEBUG_LOG, "No join found with serial %d. (May have been already released.)\n", msg->ref);
+ 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);
}
- /* check application */
- if (join->j_type != JOIN_TYPE_REMOTE) {
- PERROR("Ref %d does not belong to a remote join instance.\n", msg->ref);
- return(-1);
- }
- if (admin->sock != ((class JoinRemote *)join)->j_remote_id) {
- PERROR("Ref %d belongs to remote application %s, but not to sending application %s.\n", msg->ref, ((class JoinRemote *)join)->j_remote_name, admin->remote_name);
- return(-1);
+ /* 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)
+ 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);
+ return(-1);
+ }
+
+ /* send message */
+ remote->message_remote(msg->type, &msg->param);
- /* send message */
- ((class JoinRemote *)join)->message_remote(msg->type, &msg->param);
+ return(0);
+ }
+ PDEBUG(DEBUG_LOG, "No remote instance found with ref %d. (May have been already released.)\n", msg->ref);
return(0);
+
}
/*
* this function is called for every message to remote socket
*/
-int admin_message_from_join(int remote_id, unsigned int ref, int message_type, union parameter *param)
+int admin_message_from_lcr(int remote_id, unsigned int ref, int message_type, union parameter *param)
{
struct admin_list *admin;
struct admin_queue **responsep; /* response pointer */
@@ -1234,7 +1306,7 @@ int admin_handle_con(struct lcr_fd *fd, unsigned int what, void *instance, int i
break;
case ADMIN_MESSAGE:
- if (admin_message_to_join(&msg.u.msg, admin) < 0) {
+ if (admin_message_to_lcr(&msg.u.msg, admin) < 0) {
PERROR("Failed to deliver message for socket %d.\n", admin->sock);
goto response_error;
}
@@ -1281,3 +1353,24 @@ 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;
+ }
+}
+
diff --git a/socket_server.h b/socket_server.h
index b3ea89a..9a31b10 100644
--- a/socket_server.h
+++ b/socket_server.h
@@ -33,8 +33,9 @@ extern struct admin_list *admin_first;
int admin_init(void);
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_join(struct admin_message *msg, int remote_id);
-int admin_message_from_join(int remote_id, unsigned int ref, int message_type, union parameter *param);
+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);