added exporting/importing bchannel stacks to the remote application

This commit is contained in:
Super User 2007-08-11 15:57:58 +02:00
parent 0a0643e3a5
commit cbe9d412a3
13 changed files with 504 additions and 97 deletions

View File

@ -717,12 +717,41 @@ char *admin_state(int sock, char *argv[])
if (m[i].u.i.l2link && m[i].u.i.block==0)
{
ptmp:
color((m[i].u.i.busy[j])?yellow:blue);
addstr((m[i].u.i.busy[j])?"busy":"idle");
switch(m[i].u.i.busy[j])
{
case B_STATE_IDLE:
color(blue);
addstr("idle ");
break;
case B_STATE_ACTIVATING:
color(yellow);
addstr("act'ing ");
break;
case B_STATE_ACTIVE:
color(green);
addstr("busy ");
break;
case B_STATE_DEACTIVATING:
color(yellow);
addstr("dact'ing");
break;
case B_STATE_EXPORTING:
color(yellow);
addstr("exp'ing ");
break;
case B_STATE_REMOTE:
color(green);
addstr("remote ");
break;
case B_STATE_IMPORTING:
color(yellow);
addstr("imp'ing ");
break;
}
} else
{
color(red);
addstr("blk ");
addstr("blocked ");
}
if (m[i].u.i.port[j])
{

View File

@ -107,7 +107,7 @@ void free_connection(struct admin_list *admin)
memset(&param, 0, sizeof(param));
param.disconnectinfo.cause = CAUSE_OUTOFORDER;
param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
((class JoinRemote *)join)->message_remote(0, MESSAGE_RELEASE, &param);
((class JoinRemote *)join)->message_remote(MESSAGE_RELEASE, &param);
/* join is now destroyed, so we go to next join */
}
join = joinnext;
@ -511,7 +511,7 @@ int admin_call(struct admin_list *admin, struct admin_message *msg)
class Endpoint *epoint;
class EndpointAppPBX *apppbx;
if (!(epoint = new Endpoint(0, 0, 0)))
if (!(epoint = new Endpoint(0, 0)))
FATAL("No memory for Endpoint instance\n");
if (!(epoint->ep_app = apppbx = new DEFAULT_ENDPOINT_APP(epoint)))
FATAL("No memory for Endpoint Application instance\n");
@ -641,6 +641,17 @@ int admin_message_to_join(struct admin_msg *msg, char *remote_name, int sock_id)
return(0);
}
/* bchannel message
* no ref given for *_ack */
if (msg->type == MESSAGE_BCHANNEL)
if (msg->param.bchannel.type == BCHANNEL_ASSIGN_ACK
|| msg->param.bchannel.type == BCHANNEL_REMOVE_ACK)
{
/* no ref, but address */
message_bchannel_from_join(NULL, msg->param.bchannel.type, msg->param.bchannel.addr);
return(0);
}
/* check for ref */
if (!msg->ref)
{
@ -675,7 +686,7 @@ int admin_message_to_join(struct admin_msg *msg, char *remote_name, int sock_id)
}
/* send message */
((class JoinRemote *)join)->message_remote(msg->ref, msg->type, &msg->param);
((class JoinRemote *)join)->message_remote(msg->type, &msg->param);
return(0);
}

View File

@ -2901,14 +2901,15 @@ void EndpointAppPBX::ea_message_port(unsigned long port_id, int message_type, un
port_resume(portlist, message_type, param);
break;
#if 0
/* port assigns bchannel */
case MESSAGE_BCHANNEL: /* indicates the assigned bchannel */
case MESSAGE_BCHANNEL_FREE: /* requests bchannel back (e.g. when call is holded) */
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received bchannel assignment.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
case MESSAGE_BCHANNEL: /* bchannel assignment messafe */
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received bchannel message %d from port.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id, param->bchannel.type);
/* only one port is expected to be connected to bchannel */
message = message_forward(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, param);
logmessage(message->type, &message->param, portlist->port_id, DIRECTION_IN);
break;
#endif
default:
@ -3459,7 +3460,7 @@ void EndpointAppPBX::join_notify(struct port_list *portlist, int message_type, u
}
}
/* call sends messages to the endpoint
/* JOIN sends messages to the endpoint
*/
void EndpointAppPBX::ea_message_join(unsigned long join_id, int message_type, union parameter *param)
{
@ -3468,7 +3469,7 @@ void EndpointAppPBX::ea_message_join(unsigned long join_id, int message_type, un
if (!join_id)
{
PERROR("EPOINT(%d) error: call == NULL.\n", ea_endpoint->ep_serial);
PERROR("EPOINT(%d) error: JOIN == NULL.\n", ea_endpoint->ep_serial);
return;
}
@ -3477,7 +3478,7 @@ void EndpointAppPBX::ea_message_join(unsigned long join_id, int message_type, un
/* send MESSAGE_DATA to port */
if (message_type == MESSAGE_DATA)
{
if (join_id == ea_endpoint->ep_join_id) // still linked with call
if (join_id == ea_endpoint->ep_join_id) // still linked with JOIN
{
/* skip if no port relation */
if (!portlist)
@ -3491,28 +3492,28 @@ void EndpointAppPBX::ea_message_join(unsigned long join_id, int message_type, un
}
}
// PDEBUG(DEBUG_EPOINT, "EPOINT(%d) received message %d for active call (terminal %s, caller id %s state=%d)\n", ea_endpoint->ep_serial, message, e_ext.number, e_callerinfo.id, e_state);
// PDEBUG(DEBUG_EPOINT, "EPOINT(%d) received message %d for active JOIN (terminal %s, caller id %s state=%d)\n", ea_endpoint->ep_serial, message, e_ext.number, e_callerinfo.id, e_state);
switch(message_type)
{
/* CALL SENDS CRYPT message */
/* JOIN SENDS CRYPT message */
case MESSAGE_CRYPT:
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received crypt message: '%d'\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id, param->crypt.type);
join_crypt(portlist, message_type, param);
break;
/* CALL sends INFORMATION message */
/* JOIN sends INFORMATION message */
case MESSAGE_INFORMATION:
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received more digits: '%s'\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id, param->information.id);
join_information(portlist, message_type, param);
break;
/* CALL sends FACILITY message */
/* JOIN sends FACILITY message */
case MESSAGE_FACILITY:
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received facility\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
join_facility(portlist, message_type, param);
break;
/* CALL sends OVERLAP message */
/* JOIN sends OVERLAP message */
case MESSAGE_OVERLAP:
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received 'more info available'\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
if (e_state!=EPOINT_STATE_IN_SETUP
@ -3524,7 +3525,7 @@ void EndpointAppPBX::ea_message_join(unsigned long join_id, int message_type, un
join_overlap(portlist, message_type, param);
break;
/* CALL sends PROCEEDING message */
/* JOIN sends PROCEEDING message */
case MESSAGE_PROCEEDING:
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s (caller id '%s') received proceeding\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
if(e_state!=EPOINT_STATE_IN_OVERLAP)
@ -3535,7 +3536,7 @@ void EndpointAppPBX::ea_message_join(unsigned long join_id, int message_type, un
join_proceeding(portlist, message_type, param);
break;
/* CALL sends ALERTING message */
/* JOIN sends ALERTING message */
case MESSAGE_ALERTING:
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received alerting\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
if (e_state!=EPOINT_STATE_IN_OVERLAP
@ -3547,7 +3548,7 @@ void EndpointAppPBX::ea_message_join(unsigned long join_id, int message_type, un
join_alerting(portlist, message_type, param);
break;
/* CALL sends CONNECT message */
/* JOIN sends CONNECT message */
case MESSAGE_CONNECT:
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received connect\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
if (e_state!=EPOINT_STATE_IN_OVERLAP
@ -3560,29 +3561,29 @@ void EndpointAppPBX::ea_message_join(unsigned long join_id, int message_type, un
join_connect(portlist, message_type, param);
break;
/* CALL sends DISCONNECT/RELEASE message */
case MESSAGE_DISCONNECT: /* call disconnect */
case MESSAGE_RELEASE: /* call releases */
/* JOIN sends DISCONNECT/RELEASE message */
case MESSAGE_DISCONNECT: /* JOIN disconnect */
case MESSAGE_RELEASE: /* JOIN releases */
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received %s with cause %d location %d\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id, (message_type==MESSAGE_DISCONNECT)?"disconnect":"release", param->disconnectinfo.cause, param->disconnectinfo.location);
join_disconnect_release(message_type, param);
break;
/* CALL sends SETUP message */
/* JOIN sends SETUP message */
case MESSAGE_SETUP:
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint received setup from terminal='%s',id='%s' to id='%s' (dialing itype=%d)\n", ea_endpoint->ep_serial, param->setup.callerinfo.extension, param->setup.callerinfo.id, param->setup.dialinginfo.id, param->setup.dialinginfo.itype);
join_setup(portlist, message_type, param);
break;
/* CALL sends special mISDNSIGNAL message */
/* JOIN sends special mISDNSIGNAL message */
case MESSAGE_mISDNSIGNAL: /* isdn message to port */
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received mISDNsignal message.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
join_mISDNsignal(portlist, message_type, param);
break;
/* call requests bchannel */
#if 0
/* JOIN requests bchannel */
case MESSAGE_BCHANNEL: /* indicates the need of own bchannel access */
case MESSAGE_BCHANNEL_FREE: /* indicates that the bchannel is free */
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received bchannel request.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received bchannel assignment %d from join.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id, param->bchannel.type);
/* only one port is expected to be connected to bchannel */
if (!portlist)
break;
@ -3594,8 +3595,9 @@ void EndpointAppPBX::ea_message_join(unsigned long join_id, int message_type, un
message = message_forward(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, param);
logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
break;
#endif
/* CALL has pattern available */
/* JOIN has pattern available */
case MESSAGE_PATTERN: /* indicating pattern available */
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received pattern availability.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
if (!e_join_pattern)
@ -3620,7 +3622,7 @@ void EndpointAppPBX::ea_message_join(unsigned long join_id, int message_type, un
}
break;
/* CALL has no pattern available */
/* JOIN has no pattern available */
case MESSAGE_NOPATTERN: /* indicating no pattern available */
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received pattern NOT available.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
if (e_join_pattern)
@ -3635,7 +3637,7 @@ void EndpointAppPBX::ea_message_join(unsigned long join_id, int message_type, un
break;
#if 0
/* CALL (dunno at the moment) */
/* JOIN (dunno at the moment) */
case MESSAGE_REMOTE_AUDIO:
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received audio remote request.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
@ -3644,7 +3646,7 @@ void EndpointAppPBX::ea_message_join(unsigned long join_id, int message_type, un
break;
#endif
/* CALL sends a notify message */
/* JOIN sends a notify message */
case MESSAGE_NOTIFY:
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received notify.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
join_notify(portlist, message_type, param);
@ -4478,13 +4480,32 @@ void EndpointAppPBX::logmessage(int message_type, union parameter *param, unsign
end_trace();
break;
#if 0
case MESSAGE_BCHANNEL:
case MESSAGE_BCHANNEL_FREE:
trace_header("BCHANNEL", dir);
switch(param->bchannel.type)
{
case BCHANNEL_REQUEST:
add_trace("type", NULL, "request");
break;
case BCHANNEL_ASSIGN:
add_trace("type", NULL, "assign");
break;
case BCHANNEL_ASSIGN_ACK:
add_trace("type", NULL, "assign_ack");
break;
case BCHANNEL_REMOVE:
add_trace("type", NULL, "remove");
break;
case BCHANNEL_REMOVE_ACK:
add_trace("type", NULL, "remove_ack");
break;
}
if (param->bchannel.addr)
add_trace("address", NULL, "%x", param->bchannel.addr);
end_trace();
break;
#endif
default:
PERROR("EPOINT(%d) message not of correct type (%d)\n", ea_endpoint->ep_serial, message_type);

View File

@ -164,7 +164,7 @@ int Pdss1::received_first_reply_to_setup(unsigned long prim, int channel, int ex
end_trace();
/* activate our exclusive channel */
bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_ACTIVATE);
bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_USE, p_m_exportremote);
} else
if (p_m_b_channel)
{
@ -185,7 +185,7 @@ int Pdss1::received_first_reply_to_setup(unsigned long prim, int channel, int ex
add_trace("connect", "channel", "%d", p_m_b_channel);
end_trace();
p_m_b_exclusive = 1; // we are done
bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_ACTIVATE);
bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_USE, p_m_exportremote);
return(0);
}
@ -212,7 +212,7 @@ int Pdss1::received_first_reply_to_setup(unsigned long prim, int channel, int ex
end_trace();
/* activate channel given by remote */
bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_ACTIVATE);
bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_USE, p_m_exportremote);
} else
if (p_m_b_reserve)
{
@ -248,7 +248,7 @@ int Pdss1::received_first_reply_to_setup(unsigned long prim, int channel, int ex
end_trace();
/* activate channel given by remote */
bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_ACTIVATE);
bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_USE, p_m_exportremote);
} else
{
/*** we sent 'no channel available' ***/
@ -277,7 +277,7 @@ int Pdss1::received_first_reply_to_setup(unsigned long prim, int channel, int ex
p_m_b_exclusive = 1; // we are done
/* activate channel given by remote */
bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_ACTIVATE);
bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_USE, p_m_exportremote);
return(0);
}
@ -312,7 +312,7 @@ int Pdss1::received_first_reply_to_setup(unsigned long prim, int channel, int ex
p_m_b_exclusive = 1; // we are done
/* activate channel given by remote */
bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_ACTIVATE);
bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_USE, p_m_exportremote);
}
return(0);
@ -731,12 +731,12 @@ void Pdss1::setup_ind(unsigned long prim, unsigned long dinfo, void *data)
p_m_delete = 1;
return;
}
bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_ACTIVATE);
bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_USE, p_m_exportremote);
/* create endpoint */
if (p_epointlist)
FATAL("Incoming call but already got an endpoint.\n");
if (!(epoint = new Endpoint(p_serial, 0, 0)))
if (!(epoint = new Endpoint(p_serial, 0)))
FATAL("No memory for Endpoint instance\n");
if (!(epoint->ep_app = new DEFAULT_ENDPOINT_APP(epoint)))
FATAL("No memory for Endpoint Application instance\n");
@ -1473,7 +1473,7 @@ void Pdss1::retrieve_ind(unsigned long prim, unsigned long dinfo, void *data)
cause = -ret;
goto reject;
}
bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_ACTIVATE);
bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_USE, p_m_exportremote);
/* set hold state */
p_m_hold = 0;
@ -1645,7 +1645,7 @@ void Pdss1::resume_ind(unsigned long prim, unsigned long dinfo, void *data)
p_m_delete = 1;
return;
}
bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_ACTIVATE);
bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_USE, p_m_exportremote);
/* create endpoint */
if (p_epointlist)

View File

@ -39,7 +39,7 @@ class Endpoint *find_epoint_id(unsigned long epoint_id)
/*
* endpoint constructor (link with either port or join id)
*/
Endpoint::Endpoint(unsigned long port_id, unsigned long join_id, unsigned long use_epoint_id)
Endpoint::Endpoint(unsigned long port_id, unsigned long join_id)
{
class Port *port;
class Endpoint **epointpointer;
@ -60,10 +60,7 @@ Endpoint::Endpoint(unsigned long port_id, unsigned long join_id, unsigned long u
*epointpointer = this;
/* serial */
if (use_epoint_id)
ep_serial = use_epoint_id;
else
ep_serial = epoint_serial++;
ep_serial = epoint_serial++;
/* link to join or port */
if (port_id)

View File

@ -22,7 +22,7 @@ struct port_list {
class Endpoint
{
public:
Endpoint(unsigned long port_id, unsigned long join_id, unsigned long use_epoint_id);
Endpoint(unsigned long port_id, unsigned long join_id);
~Endpoint();
class Endpoint *next; /* next in list */
unsigned long ep_serial; /* a unique serial to identify */

View File

@ -983,7 +983,7 @@ int JoinPBX::out_setup(unsigned long epoint_id, int message_type, union paramete
relation->tx_state = NOTIFY_STATE_ACTIVE; /* new joins always assumed to be active */
relation->rx_state = NOTIFY_STATE_ACTIVE; /* new joins always assumed to be active */
/* create a new endpoint */
epoint = new Endpoint(0, j_serial, 0);
epoint = new Endpoint(0, j_serial);
if (!epoint)
FATAL("No memory for Endpoint instance\n");
if (!(epoint->ep_app = new DEFAULT_ENDPOINT_APP(epoint)))

View File

@ -37,12 +37,13 @@ JoinRemote::JoinRemote(unsigned long serial, char *remote_name, int remote_id) :
j_remote_id = remote_id;
j_type = JOIN_TYPE_REMOTE;
j_epoint_id = serial;
j_epoint_id = serial; /* this is the endpoint, if created by epoint */
if (j_epoint_id)
PDEBUG(DEBUG_JOIN, "New remote join connected to endpoint id %lu and application %s\n", j_epoint_id, remote_name);
/* send new ref to remote socket */
memset(&param, 0, sizeof(param));
/* 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)
FATAL("No socket with remote application '%s' found, this shall not happen. because we already created one.\n", j_remote_name);
}
@ -53,7 +54,6 @@ JoinRemote::JoinRemote(unsigned long serial, char *remote_name, int remote_id) :
*/
JoinRemote::~JoinRemote()
{
}
@ -87,7 +87,7 @@ void JoinRemote::message_epoint(unsigned long epoint_id, int message_type, union
}
}
void JoinRemote::message_remote(unsigned long ref, int message_type, union parameter *param)
void JoinRemote::message_remote(int message_type, union parameter *param)
{
struct message *message;
@ -96,12 +96,22 @@ void JoinRemote::message_remote(unsigned long ref, int message_type, union param
{
class Endpoint *epoint;
if (!(epoint = new Endpoint(0, j_serial, ref)))
if (!(epoint = new Endpoint(0, j_serial)))
FATAL("No memory for Endpoint instance\n");
j_epoint_id = epoint->ep_serial;
if (!(epoint->ep_app = new DEFAULT_ENDPOINT_APP(epoint)))
FATAL("No memory for Endpoint Application instance\n");
}
/* set serial on bchannel message
* also ref is given, so we send message with ref */
if (message_type == MESSAGE_BCHANNEL)
{
message_bchannel_from_join(this, param->bchannel.type, param->bchannel.addr);
return;
}
/* cannot just forward, because param is not of container "struct message" */
message = message_create(j_serial, j_epoint_id, JOIN_TO_EPOINT, message_type);
memcpy(&message->param, param, sizeof(message->param));
message_put(message);
@ -113,5 +123,35 @@ void JoinRemote::message_remote(unsigned long ref, int message_type, union param
}
}
void message_bchannel_to_join(int serial, int type, unsigned long addr)
{
union parameter param;
class Join *join;
class JoinRemote *joinremote;
/* find join serial */
join = find_join_id(serial);
if (!join)
{
PDEBUG(DEBUG_JOIN | DEBUG_BCHANNEL, "Join %d not found\n", serial);
return;
}
if (!join->j_type != JOIN_TYPE_REMOTE)
{
PERROR("Join %d not of remote type. This shall not happen.\n", serial);
return;
}
joinremote = (class JoinRemote *)join;
memset(&param, 0, sizeof(union parameter));
param.bchannel.type = type;
param.bchannel.addr = addr;
if (admin_message_from_join(joinremote->j_remote_id, joinremote->j_serial, MESSAGE_BCHANNEL, &param)<0)
{
PERROR("No socket with remote application '%s' found, this shall not happen. Closing socket shall cause release of all joins.\n", joinremote->j_remote_name);
return;
}
}

View File

@ -15,7 +15,7 @@ class JoinRemote : public Join
JoinRemote(unsigned long serial, char *remote_name, int remote_id);
~JoinRemote();
void message_epoint(unsigned long epoint_id, int message, union parameter *param);
void message_remote(unsigned long ref, int message_type, union parameter *param);
void message_remote(int message_type, union parameter *param);
int handler(void);
int j_remote_id;
@ -24,3 +24,4 @@ class JoinRemote : public Join
};
void message_bchannel_to_join(int serial, int type, unsigned long addr);

305
mISDN.cpp
View File

@ -159,6 +159,7 @@ PmISDN::PmISDN(int type, mISDNport *mISDNport, char *portname, struct port_setti
p_m_dtmf = !mISDNport->ifport->nodtmf;
p_m_timeout = 0;
p_m_timer = 0;
p_m_exportremote = 0; /* channel shall be exported to given remote */
/* audio */
p_m_load = 0;
@ -472,7 +473,7 @@ failed:
/*
* subfunction for bchannel_event
* activate request
* activate / deactivate request
*/
static void _bchannel_activate(struct mISDNport *mISDNport, int i, int activate)
{
@ -582,21 +583,43 @@ It may be linked to a Port class, that likes to reactivate it.
See above.
After deactivating bchannel, and if not used, the bchannel becomes idle again.
Also the bchannel may be exported, but only if the state is or becomes idle:
- B_STATE_EXPORTING
The bchannel assignment has been sent to the remove application.
- B_STATE_REMOTE
The bchannel assignment is acknowledged by the remote application.
- B_STATE_IMPORTING
The bchannel is re-imported by mISDN port object.
- B_STATE_IDLE
See above.
After re-importing bchannel, and if not used, the bchannel becomes idle again.
A bchannel can have the following events:
- B_EVENT_ACTIVATE
- B_EVENT_USE
A bchannel is required by a Port class.
The bchannel shall be exported to the remote application.
- B_EVENT_ACTIVATED
The bchannel beomes active.
- B_EVENT_DEACTIVATE
- B_EVENT_DROP
The bchannel is not required by Port class anymore
- B_EVENT_DEACTIVATED
The bchannel becomes inactive.
- B_EVENT_EXPORTED
The bchannel is now used by remote application.
- B_EVENT_IMPORTED
The bchannel is not used by remote application.
All actions taken on these events depend on the current bchannel's state and if it is linked to a Port class.
*/
@ -608,36 +631,106 @@ All actions taken on these events depend on the current bchannel's state and if
* - event is the B_EVENT_* value
* - port is the PmISDN class pointer
*/
void bchannel_event(struct mISDNport *mISDNport, int i, int event)
void bchannel_event(struct mISDNport *mISDNport, int i, int event, unsigned long to_remote)
{
class PmISDN *b_port = mISDNport->b_port[i];
int state = mISDNport->b_state[i];
unsigned long remote = mISDNport->b_remote[i];
unsigned long addr = mISDNport->b_addr[i];
switch(event)
{
case B_EVENT_ACTIVATE:
case B_EVENT_USE:
/* port must be linked in order to allow activation */
if (!mISDNport->b_port[i])
if (!b_port)
FATAL("bchannel must be linked to a Port class\n");
switch(state)
{
case B_STATE_IDLE:
/* create stack and send activation request */
if (_bchannel_create(mISDNport, i))
if (remote)
PDEBUG(DEBUG_BCHANNEL, "idle channels don't have remote link.\n");
if (to_remote)
{
_bchannel_activate(mISDNport, i, 1);
state = B_STATE_ACTIVATING;
/* export bchannel */
mISDNport->b_remote[i] = remote = to_remote;
message_bchannel_to_join(remote, BCHANNEL_ASSIGN, addr);
chan_trace_header(mISDNport, b_port, "MESSAGE_BCHANNEL (to remote application)", DIRECTION_NONE);
add_trace("type", NULL, "assign");
add_trace("stack", "address", "%x", addr);
end_trace();
state = B_STATE_EXPORTING;
} else
{
/* create stack and send activation request */
if (_bchannel_create(mISDNport, i))
{
_bchannel_activate(mISDNport, i, 1);
state = B_STATE_ACTIVATING;
}
}
break;
case B_STATE_ACTIVATING:
case B_STATE_EXPORTING:
/* do nothing, because it is already activating */
break;
case B_STATE_DEACTIVATING:
case B_STATE_IMPORTING:
/* do nothing, because we must wait until we can reactivate */
break;
default:
/* problems that might ocurr:
* B_EVENT_USE is received when channel already in use.
* bchannel exported, but not freed by other port
*/
PERROR("Illegal event %d at state %d, please correct.\n", event, state);
}
break;
case B_EVENT_EXPORTREQUEST:
/* special case where the bchannel is requested by remote */
if (remote)
{
PERROR("channel for join %d already exported to join %d, please correct.\n", to_remote, remote);
}
mISDNport->b_remote[i] = remote = to_remote;
switch(state)
{
case B_STATE_IDLE:
/* export bchannel */
message_bchannel_to_join(remote, BCHANNEL_ASSIGN, addr);
chan_trace_header(mISDNport, b_port, "MESSAGE_BCHANNEL (to remote application)", DIRECTION_NONE);
add_trace("type", NULL, "assign");
add_trace("stack", "address", "%x", addr);
end_trace();
state = B_STATE_EXPORTING;
break;
case B_STATE_ACTIVATING:
case B_STATE_EXPORTING:
/* do nothing, because it is already activating */
break;
case B_STATE_DEACTIVATING:
case B_STATE_IMPORTING:
/* do nothing, because we must wait until we can reactivate */
break;
case B_STATE_ACTIVE:
/* bchannel is active, so we deactivate */
_bchannel_activate(mISDNport, i, 0);
state = B_STATE_DEACTIVATING;
break;
default:
/* problems that might ocurr:
* ... when channel already in use.
* bchannel exported, but not freed by other port
*/
PERROR("Illegal event %d at state %d, please correct.\n", event, state);
}
break;
@ -646,14 +739,14 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
switch(state)
{
case B_STATE_ACTIVATING:
if (mISDNport->b_port[i])
if (b_port && !remote)
{
/* bchannel is active and used by Port class, so we configure bchannel */
_bchannel_configure(mISDNport, i);
state = B_STATE_ACTIVE;
} else
{
/* bchannel is active, but not used anymore (or has wrong stack config), so we deactivate */
/* bchannel is active, but exported OR not used anymore (or has wrong stack config), so we deactivate */
_bchannel_activate(mISDNport, i, 0);
state = B_STATE_DEACTIVATING;
}
@ -664,9 +757,35 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
}
break;
case B_EVENT_DEACTIVATE:
if (!mISDNport->b_port[i])
case B_EVENT_EXPORTED:
switch(state)
{
case B_STATE_EXPORTING:
if (b_port && remote && to_remote==remote)
{
/* remote export done */
state = B_STATE_REMOTE;
} else
{
/* bchannel is now exported, but we need bchannel back OR bchannel is not used anymore OR remote has changed, so reimport, to later export to new remote */
message_bchannel_to_join(remote, BCHANNEL_REMOVE, addr);
chan_trace_header(mISDNport, b_port, "MESSAGE_BCHANNEL (to remote application)", DIRECTION_NONE);
add_trace("type", NULL, "remove");
add_trace("stack", "address", "%x", addr);
end_trace();
state = B_STATE_IMPORTING;
}
break;
default:
PERROR("Illegal event %d at state %d, please correct.\n", event, state);
}
break;
case B_EVENT_DROP:
if (!b_port)
FATAL("bchannel must be linked to a Port class\n");
mISDNport->b_remote[i] = 0;
switch(state)
{
case B_STATE_IDLE:
@ -674,6 +793,7 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
break;
case B_STATE_ACTIVATING:
case B_STATE_EXPORTING:
/* do nothing because we must wait until bchanenl is active before deactivating */
break;
@ -683,7 +803,18 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
state = B_STATE_DEACTIVATING;
break;
case B_STATE_REMOTE:
/* bchannel is exported, so we re-import */
message_bchannel_to_join(remote, BCHANNEL_REMOVE, addr);
chan_trace_header(mISDNport, b_port, "MESSAGE_BCHANNEL (to remote application)", DIRECTION_NONE);
add_trace("type", NULL, "remove");
add_trace("stack", "address", "%x", addr);
end_trace();
state = B_STATE_IMPORTING;
break;
case B_STATE_DEACTIVATING:
case B_STATE_IMPORTING:
/* we may have taken an already deactivating bchannel, but do not require it anymore, so we do nothing */
break;
@ -702,13 +833,24 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
case B_STATE_DEACTIVATING:
_bchannel_destroy(mISDNport, i);
state = B_STATE_IDLE;
if (mISDNport->b_port[i])
if (b_port)
{
/* bchannel is now deactivate, but is requied by Port class, so we reactivate */
if (_bchannel_create(mISDNport, i))
/* bchannel is now deactivate, but is requied by Port class, so we reactivate / export */
if (remote)
{
_bchannel_activate(mISDNport, i, 1);
state = B_STATE_ACTIVATING;
message_bchannel_to_join(remote, BCHANNEL_ASSIGN, addr);
chan_trace_header(mISDNport, b_port, "MESSAGE_BCHANNEL (to remote application)", DIRECTION_NONE);
add_trace("type", NULL, "assign");
add_trace("stack", "address", "%x", addr);
end_trace();
state = B_STATE_EXPORTING;
} else
{
if (_bchannel_create(mISDNport, i))
{
_bchannel_activate(mISDNport, i, 1);
state = B_STATE_ACTIVATING;
}
}
}
break;
@ -718,6 +860,39 @@ void bchannel_event(struct mISDNport *mISDNport, int i, int event)
}
break;
case B_EVENT_IMPORTED:
switch(state)
{
case B_STATE_IMPORTING:
state = B_STATE_IDLE;
if (b_port)
{
/* bchannel is now imported, but is requied by Port class, so we reactivate / export */
if (remote)
{
message_bchannel_to_join(remote, BCHANNEL_ASSIGN, addr);
chan_trace_header(mISDNport, b_port, "MESSAGE_BCHANNEL (to remote application)", DIRECTION_NONE);
add_trace("type", NULL, "assign");
add_trace("stack", "address", "%x", addr);
end_trace();
state = B_STATE_EXPORTING;
} else
{
if (_bchannel_create(mISDNport, i))
{
_bchannel_activate(mISDNport, i, 1);
state = B_STATE_ACTIVATING;
}
}
}
break;
default:
/* ignore, because not assigned */
;
}
break;
default:
PERROR("Illegal event %d, please correct.\n", event);
}
@ -792,6 +967,7 @@ seize:
/* link Port */
p_m_mISDNport->b_port[i] = this;
p_m_mISDNport->b_remote[i] = p_m_exportremote;
p_m_b_index = i;
p_m_b_channel = channel;
p_m_b_exclusive = exclusive;
@ -827,13 +1003,98 @@ void PmISDN::drop_bchannel(void)
PDEBUG(DEBUG_BCHANNEL, "PmISDN(%s) dropping bchannel\n", p_name);
if (p_m_mISDNport->b_state[p_m_b_index] != B_STATE_IDLE)
bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_DEACTIVATE);
bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_DROP, 0);
p_m_mISDNport->b_port[p_m_b_index] = NULL;
p_m_mISDNport->b_remote[p_m_b_index] = 0;
p_m_b_index = -1;
p_m_b_channel = 0;
p_m_b_exclusive = 0;
}
/* process bchannel export/import message from join */
void message_bchannel_from_join(class JoinRemote *joinremote, int type, unsigned long addr)
{
class Endpoint *epoint;
class Port *port;
class PmISDN *isdnport;
struct mISDNport *mISDNport;
int i, ii;
switch(type)
{
case BCHANNEL_REQUEST:
/* find the port object for the join object ref */
if (!(epoint = find_epoint_id(joinremote->j_epoint_id)))
{
PDEBUG(DEBUG_BCHANNEL, "join %d has no endpoint (anymore)\n", joinremote->j_serial);
return;
}
if (!epoint->ep_portlist)
{
PDEBUG(DEBUG_BCHANNEL, "join %d has no port (anymore in portlist)\n", joinremote->j_serial);
return;
}
if (epoint->ep_portlist->next)
{
PERROR("join %d has enpoint %d with more than one port. this shall not happen to remote joins.\n", joinremote->j_serial, epoint->ep_serial);
}
if (!(port = find_port_id(epoint->ep_portlist->port_id)))
{
PDEBUG(DEBUG_BCHANNEL, "join %d has no port (anymore as object)\n", joinremote->j_serial);
return;
}
if (!((port->p_type&PORT_CLASS_MASK) != PORT_CLASS_mISDN))
{
PERROR("join %d has port %d not of mISDN type. This shall not happen.\n", joinremote->j_serial, port->p_serial);
}
isdnport = (class PmISDN *)port;
/* assign */
if (isdnport->p_m_exportremote)
{
PERROR("join %d recevied bchannel request from remote, but channel is already assinged.\n", joinremote->j_serial);
break;
}
chan_trace_header(isdnport->p_m_mISDNport, isdnport, "MESSAGE_BCHANNEL (from remote application)", DIRECTION_NONE);
add_trace("type", NULL, "export request");
isdnport->p_m_exportremote = joinremote->j_serial;
if (isdnport->p_m_mISDNport && isdnport->p_m_b_index>=0)
bchannel_event(isdnport->p_m_mISDNport, isdnport->p_m_b_index, B_EVENT_EXPORTREQUEST, joinremote->j_serial);
end_trace();
break;
case BCHANNEL_ASSIGN_ACK:
case BCHANNEL_REMOVE_ACK:
/* find mISDNport for stack ID */
mISDNport = mISDNport_first;
while(mISDNport)
{
i = 0;
ii = mISDNport->b_num;
while(i < ii)
{
if (mISDNport->b_addr[i] == addr)
break;
i++;
}
if (i != ii)
break;
mISDNport = mISDNport->next;
}
/* mISDNport may now be set or NULL */
/* set */
chan_trace_header(mISDNport, mISDNport->b_port[i], "MESSAGE_BCHANNEL (from remote application)", DIRECTION_NONE);
add_trace("type", NULL, (type==BCHANNEL_ASSIGN_ACK)?"assign_ack":"remove_ack");
if (mISDNport && i>=0)
bchannel_event(mISDNport, i, (type==BCHANNEL_ASSIGN_ACK)?B_EVENT_EXPORTED:B_EVENT_IMPORTED, 0);
end_trace();
break;
default:
PERROR("received wrong bchannel message type %d from remote\n", type);
}
}
/*
* handler
@ -1815,7 +2076,7 @@ int mISDN_handler(void)
PERROR("unhandled b-establish (prim 0x%x address 0x%x).\n", frm->prim, frm->addr);
break;
}
bchannel_event(mISDNport, i, B_EVENT_ACTIVATED);
bchannel_event(mISDNport, i, B_EVENT_ACTIVATED, 0);
break;
case PH_DEACTIVATE | INDICATION:
@ -1835,7 +2096,7 @@ int mISDN_handler(void)
PERROR("unhandled b-release (prim 0x%x address 0x%x).\n", frm->prim, frm->addr);
break;
}
bchannel_event(mISDNport, i, B_EVENT_DEACTIVATED);
bchannel_event(mISDNport, i, B_EVENT_DEACTIVATED, 0);
break;
default:

25
mISDN.h
View File

@ -9,20 +9,6 @@
** **
\*****************************************************************************/
enum {
B_STATE_IDLE,
B_STATE_ACTIVATING,
B_STATE_ACTIVE,
B_STATE_DEACTIVATING,
};
enum {
B_EVENT_ACTIVATE,
B_EVENT_ACTIVATED,
B_EVENT_DEACTIVATE,
B_EVENT_DEACTIVATED,
};
#define FROMUP_BUFFER_SIZE 1024
#define FROMUP_BUFFER_MASK 1023
@ -53,10 +39,11 @@ struct mISDNport {
int d_stid;
int b_num; /* number of bchannels */
int b_reserved; /* number of bchannels reserved or in use */
class PmISDN *b_port[128]; /* maximum number of ports shall be 128 due to S0 / E1 / special E1 */
class PmISDN *b_port[128]; /* bchannel assigned to port object */
int b_stid[128];
int b_addr[128];
int b_state[128]; /* state 0 = IDLE */
unsigned long b_addr[128];
int b_state[128]; /* statemachine, 0 = IDLE */
unsigned long b_remote[128]; /* if remote application requires bchannel */
int procids[128]; /* keep track of free ids */
int locally; /* local causes are sent as local causes not remote */
msg_queue_t downqueue; /* l4->l3 */
@ -96,7 +83,8 @@ int stack2manager_nt(void *dat, void *arg);
int stack2manager_te(struct mISDNport *mISDNport, msg_t *msg);
void chan_trace_header(struct mISDNport *mISDNport, class PmISDN *port, char *msgtext, int direction);
void l1l2l3_trace_header(struct mISDNport *mISDNport, class PmISDN *port, unsigned long prim, int direction);
void bchannel_event(struct mISDNport *mISDNport, int i, int event);
void bchannel_event(struct mISDNport *mISDNport, int i, int event, unsigned long to_remote);
void message_bchannel_from_join(class JoinRemote *joinremote, int type, unsigned long addr);
/* mISDN port classes */
@ -158,6 +146,7 @@ class PmISDN : public Port
int p_m_hold; /* if port is on hold */
unsigned long p_m_timeout; /* timeout of timers */
time_t p_m_timer; /* start of timer */
unsigned char p_m_exportremote; /* join to export bchannel to */
int seize_bchannel(int channel, int exclusive); /* requests / reserves / links bchannels, but does not open it! */
void drop_bchannel(void);

View File

@ -125,6 +125,33 @@ enum { /* isdnsignal */
mISDNSIGNAL_DELAY, /* use delay or adaptive jitter */
};
enum { /* bchannel assignment */
BCHANNEL_REQUEST, /* application requests bchannel */
BCHANNEL_ASSIGN, /* bchannel assigned by LCR */
BCHANNEL_ASSIGN_ACK, /* application acknowledges */
BCHANNEL_REMOVE, /* bchannel removed by LCR */
BCHANNEL_REMOVE_ACK, /* application acknowledges */
};
enum {
B_STATE_IDLE, /* not open */
B_STATE_ACTIVATING, /* DL_ESTABLISH sent */
B_STATE_ACTIVE, /* channel active */
B_STATE_DEACTIVATING, /* DL_RELEASE sent */
B_STATE_EXPORTING, /* BCHANNEL_ASSIGN sent */
B_STATE_REMOTE, /* bchannel assigned to remote application */
B_STATE_IMPORTING, /* BCHANNEL_REMOVE sent */
};
enum {
B_EVENT_USE, /* activate/export bchannel */
B_EVENT_EXPORTREQUEST, /* remote app requests bchannel */
B_EVENT_ACTIVATED, /* DL_ESTABLISH received */
B_EVENT_DROP, /* deactivate/re-import bchannel */
B_EVENT_DEACTIVATED, /* DL_RELEASE received */
B_EVENT_EXPORTED, /* BCHANNEL_ASSIGN received */
B_EVENT_IMPORTED, /* BCHANNEL_REMOVE received */
};
/* call-info structure CALLER */
struct caller_info {
char id[32]; /* id of caller (user number) */
@ -279,6 +306,7 @@ struct param_hello {
};
struct param_bchannel {
int type; /* BCHANNEL_* */
unsigned long addr; /* bchannel stack address */
};
@ -359,8 +387,7 @@ enum { /* messages between entities */
MESSAGE_VBOX_TONE, /* set answering VBOX tone */
MESSAGE_TONE_COUNTER, /* tone counter (for VBOX tone use) */
MESSAGE_TONE_EOF, /* tone is end of file */
MESSAGE_BCHANNEL, /* request/assign bchannel */
MESSAGE_BCHANNEL_FREE, /* requests/assigns bchannel to be free */
MESSAGE_BCHANNEL, /* request/assign/remove bchannel */
MESSAGE_HELLO, /* hello message for remote application */
MESSAGE_NEWREF, /* special message to create and inform ref */
};

View File

@ -159,3 +159,34 @@ the endpoint may receive MESSAGE_RELEASE from a call but may NOT send it
to the port. the port MUST get a MESSAGE_DISCONNECT instead.
REMOTE APPLICATION PROCEDURE
----------------------------
MESSAGE_NEWREF
- is sent before outgoing setup may be sent
- is received before outgoing setup may be sent
- is received before incoming call
MESSAGE_BCHANNEL
- type BCHANNEL_REQUEST is sent to get the bchannel stack
the ref is required to find the corresponding port class
- type BCHANNEL_ASSIGN is received, if channel is available, ACK must be sent
the ref is given with the bchannel stack.
- type BCHANNEL_ASSIGN_ACK must be sent to acknowledge channel
the ref is 0, the stack address must be set to find corresponding channel
- type BCHANNEL_REMOVE is received, if channel is not available anymore
the stack must then be release, the ACK must be sent.
the ref is given with the bchannel stack.
- type BCHANNEL_REMOVE_ACK must be sent after releasing stack.
the ref is 0, the stack address must be set to find corresponding channel
MESSAGE_RELEASE
- will be received or sent to release call and ref.
- also bchannel socket must be closed AND BCHANNEL_REMOVE_ACK must be sent!
the bchannel is in exported state until acked by the remote application.
what happenes to channels that are not acked?
-> one solution may be: they are blocked until the port is unloaded/unblocked.