307 lines
9.2 KiB
C++
307 lines
9.2 KiB
C++
/*****************************************************************************\
|
|
** **
|
|
** Linux Call Router **
|
|
** **
|
|
**---------------------------------------------------------------------------**
|
|
** Copyright: Andreas Eversberg **
|
|
** **
|
|
** The EndpointAppBridge implements direct bridge between interfaces **
|
|
** **
|
|
\*****************************************************************************/
|
|
|
|
|
|
#include "main.h"
|
|
|
|
class EndpointAppBridge *appbridge_first = NULL;
|
|
|
|
/*
|
|
* EndpointAppBridge constructor
|
|
*/
|
|
EndpointAppBridge::EndpointAppBridge(class Endpoint *epoint, int origin) : EndpointApp(epoint, origin, EAPP_TYPE_BRIDGE)
|
|
{
|
|
class EndpointAppBridge **apppointer;
|
|
|
|
/* add application to chain */
|
|
next = NULL;
|
|
apppointer = &appbridge_first;
|
|
while(*apppointer)
|
|
apppointer = &((*apppointer)->next);
|
|
*apppointer = this;
|
|
|
|
PDEBUG(DEBUG_EPOINT, "Bridge endpoint created\n");
|
|
}
|
|
|
|
/*
|
|
* EpointAppBridge destructor
|
|
*/
|
|
EndpointAppBridge::~EndpointAppBridge(void)
|
|
{
|
|
class EndpointAppBridge *temp, **tempp;
|
|
|
|
/* detach */
|
|
temp =appbridge_first;
|
|
tempp = &appbridge_first;
|
|
while(temp) {
|
|
if (temp == this)
|
|
break;
|
|
|
|
tempp = &temp->next;
|
|
temp = temp->next;
|
|
}
|
|
if (temp == 0)
|
|
FATAL("Endpoint not in endpoint's list.\n");
|
|
*tempp = next;
|
|
|
|
PDEBUG(DEBUG_EPOINT, "Bridge endpoint destroyed\n");
|
|
}
|
|
|
|
|
|
/*
|
|
* trace header for application
|
|
*/
|
|
void EndpointAppBridge::trace_header(const char *name, int direction)
|
|
{
|
|
struct trace _trace;
|
|
|
|
char msgtext[sizeof(_trace.name)];
|
|
|
|
SCPY(msgtext, name);
|
|
|
|
/* init trace with given values */
|
|
start_trace(-1,
|
|
NULL,
|
|
"", //numberrize_callerinfo(e_callerinfo.id, e_callerinfo.ntype, options.national, options.international),
|
|
"", // e_dialinginfo.id,
|
|
direction,
|
|
CATEGORY_EP,
|
|
ea_endpoint->ep_serial,
|
|
msgtext);
|
|
}
|
|
|
|
/* port MESSAGE_SETUP */
|
|
void EndpointAppBridge::port_setup(struct port_list *portlist, int message_type, union parameter *param)
|
|
{
|
|
struct interface *interface_in = interface_first;
|
|
struct interface *interface_out = interface_first;
|
|
struct port_settings port_settings;
|
|
class Port *port = NULL;
|
|
struct lcr_msg *message;
|
|
unsigned int bridge_id;
|
|
unsigned int source_port_id = portlist->port_id;
|
|
char portname[64];
|
|
int cause = 47;
|
|
|
|
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint received setup from='%s' to='%s'\n", ea_endpoint->ep_serial, param->setup.callerinfo.id, param->setup.dialinginfo.id);
|
|
|
|
if (!ea_endpoint->ep_portlist) {
|
|
PERROR("Endpoint has no port in portlist\n");
|
|
return;
|
|
}
|
|
if (ea_endpoint->ep_portlist->next) {
|
|
PDEBUG(DEBUG_EPOINT, "Endpoint already received setup, ignoring.\n");
|
|
return;
|
|
}
|
|
|
|
while (interface_in) {
|
|
if (!strcmp(interface_in->name, param->setup.callerinfo.interface))
|
|
break;
|
|
interface_in = interface_in->next;
|
|
}
|
|
if (!interface_in) {
|
|
PERROR("Cannot find source interface %s.\n", param->setup.callerinfo.interface);
|
|
fail:
|
|
message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
|
|
message->param.disconnectinfo.cause = cause;
|
|
message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
|
|
message_put(message);
|
|
ea_endpoint->free_portlist(portlist);
|
|
|
|
/* destroy endpoint */
|
|
ea_endpoint->ep_use = 0;
|
|
trigger_work(&ea_endpoint->ep_delete);
|
|
return;
|
|
}
|
|
|
|
while (interface_out) {
|
|
if (!strcmp(interface_out->name, interface_in->bridge_if))
|
|
break;
|
|
interface_out = interface_out->next;
|
|
}
|
|
if (!interface_out) {
|
|
PERROR("Cannot find destination interface %s.\n", interface_in->bridge_if);
|
|
goto fail;
|
|
return;
|
|
}
|
|
|
|
/* 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);
|
|
} else
|
|
#endif
|
|
#ifdef WITH_GSM_BS
|
|
if (interface_out->gsm_bs) {
|
|
port = new Pgsm_bs(PORT_TYPE_GSM_BS_OUT, portname, &port_settings, interface_out);
|
|
} else
|
|
#endif
|
|
#ifdef WITH_GSM_MS
|
|
if (interface_out->gsm_ms) {
|
|
port = new Pgsm_ms(PORT_TYPE_GSM_MS_OUT, portname, &port_settings, interface_out);
|
|
} else
|
|
#endif
|
|
{
|
|
char *ifname = interface_out->name;
|
|
#ifdef WITH_MISDN
|
|
struct mISDNport *mISDNport;
|
|
int channel = 0;
|
|
int mode = B_MODE_TRANSPARENT;
|
|
|
|
/* hunt for mISDNport and create Port */
|
|
mISDNport = hunt_port(ifname, &channel);
|
|
if (!mISDNport) {
|
|
trace_header("INTERFACE (busy)", DIRECTION_NONE);
|
|
add_trace("interface", NULL, "%s", ifname);
|
|
end_trace();
|
|
cause = 33;
|
|
goto fail;
|
|
}
|
|
|
|
SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
|
|
#ifdef WITH_SS5
|
|
if (mISDNport->ss5)
|
|
port = ss5_hunt_line(mISDNport);
|
|
else
|
|
#endif
|
|
#ifdef ISDN_P_FXS_POTS
|
|
if (mISDNport->pots)
|
|
port = new Pfxs(PORT_TYPE_POTS_FXS_OUT, mISDNport, portname, &port_settings, mISDNport->ifport->interface, mode);
|
|
else
|
|
#endif
|
|
port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, mISDNport->ifport->interface, channel, mISDNport->ifport->channel_force, mode);
|
|
#else
|
|
trace_header("INTERFACE (has no function)", DIRECTION_NONE);
|
|
add_trace("interface", NULL, "%s", ifname);
|
|
end_trace();
|
|
cause = 31;
|
|
goto fail;
|
|
#endif
|
|
}
|
|
if (!port)
|
|
FATAL("Remote interface, but not supported???\n");
|
|
portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, interface_out->is_earlyb == IS_YES);
|
|
if (!portlist)
|
|
FATAL("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
|
|
/* forward setup */
|
|
message_forward(ea_endpoint->ep_serial, port->p_serial, EPOINT_TO_PORT, param);
|
|
|
|
/* apply bridge to interfaces */
|
|
/* FIXME: use mISDN bridge for mISDN ports */
|
|
bridge_id = join_serial++;
|
|
message = message_create(ea_endpoint->ep_serial, source_port_id, EPOINT_TO_PORT, MESSAGE_BRIDGE);
|
|
message->param.bridge_id = bridge_id;
|
|
message_put(message);
|
|
message = message_create(ea_endpoint->ep_serial, port->p_serial, EPOINT_TO_PORT, MESSAGE_BRIDGE);
|
|
message->param.bridge_id = bridge_id;
|
|
message_put(message);
|
|
}
|
|
|
|
/* port MESSAGE_RELEASE */
|
|
void EndpointAppBridge::port_release(struct port_list *portlist, int message_type, union parameter *param)
|
|
{
|
|
struct port_list *remote;
|
|
|
|
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint received release from port\n");
|
|
|
|
if (!ea_endpoint->ep_portlist || !ea_endpoint->ep_portlist->next)
|
|
goto out;
|
|
if (ea_endpoint->ep_portlist->port_id == portlist->port_id)
|
|
remote = ea_endpoint->ep_portlist->next;
|
|
else
|
|
remote = ea_endpoint->ep_portlist;
|
|
/* forward release */
|
|
message_forward(ea_endpoint->ep_serial, remote->port_id, EPOINT_TO_PORT, param);
|
|
|
|
/* remove relations to in and out port */
|
|
ea_endpoint->free_portlist(portlist);
|
|
ea_endpoint->free_portlist(remote);
|
|
|
|
out:
|
|
/* destroy endpoint */
|
|
ea_endpoint->ep_use = 0;
|
|
trigger_work(&ea_endpoint->ep_delete);
|
|
}
|
|
|
|
/* port other messages */
|
|
void EndpointAppBridge::port_other(struct port_list *portlist, int message_type, union parameter *param)
|
|
{
|
|
unsigned int remote;
|
|
|
|
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint received message %d from port\n", message_type);
|
|
|
|
if (!ea_endpoint->ep_portlist || !ea_endpoint->ep_portlist->next)
|
|
return;
|
|
if (ea_endpoint->ep_portlist->port_id == portlist->port_id)
|
|
remote = ea_endpoint->ep_portlist->next->port_id;
|
|
else
|
|
remote = ea_endpoint->ep_portlist->port_id;
|
|
/* forward release */
|
|
message_forward(ea_endpoint->ep_serial, remote, EPOINT_TO_PORT, param);
|
|
}
|
|
|
|
/* port sends message to the endpoint
|
|
*/
|
|
void EndpointAppBridge::ea_message_port(unsigned int port_id, int message_type, union parameter *param)
|
|
{
|
|
struct port_list *portlist;
|
|
|
|
portlist = ea_endpoint->ep_portlist;
|
|
while(portlist) {
|
|
if (port_id == portlist->port_id)
|
|
break;
|
|
portlist = portlist->next;
|
|
}
|
|
if (!portlist) {
|
|
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) warning: port is not related to this endpoint. This may happen, if port has been released after the message was created.\n", ea_endpoint->ep_serial);
|
|
return;
|
|
}
|
|
|
|
// PDEBUG(DEBUG_EPOINT, "received message %d (terminal %s, caller id %s)\n", message, e_ext.number, e_callerinfo.id);
|
|
switch(message_type) {
|
|
/* PORT sends SETUP message */
|
|
case MESSAGE_SETUP:
|
|
port_setup(portlist, message_type, param);
|
|
break;
|
|
|
|
/* PORT sends RELEASE message */
|
|
case MESSAGE_RELEASE:
|
|
port_release(portlist, message_type, param);
|
|
break;
|
|
|
|
default:
|
|
port_other(portlist, message_type, param);
|
|
}
|
|
|
|
/* Note: this endpoint may be destroyed, so we MUST return */
|
|
}
|
|
|