From: Super User Date: Sat, 11 Aug 2007 13:57:58 +0000 (+0200) Subject: added exporting/importing bchannel stacks to the remote application X-Git-Url: http://git.eversberg.eu/gitweb.cgi?p=lcr.git;a=commitdiff_plain;h=cbe9d412a37e75b61cc74e8a65b0293923eb5160 added exporting/importing bchannel stacks to the remote application --- diff --git a/admin_client.c b/admin_client.c index 6bf964c..dac2b78 100644 --- a/admin_client.c +++ b/admin_client.c @@ -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]) { diff --git a/admin_server.c b/admin_server.c index f1275a6..6b0647b 100644 --- a/admin_server.c +++ b/admin_server.c @@ -107,7 +107,7 @@ void free_connection(struct admin_list *admin) memset(¶m, 0, sizeof(param)); param.disconnectinfo.cause = CAUSE_OUTOFORDER; param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL; - ((class JoinRemote *)join)->message_remote(0, MESSAGE_RELEASE, ¶m); + ((class JoinRemote *)join)->message_remote(MESSAGE_RELEASE, ¶m); /* 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); } diff --git a/apppbx.cpp b/apppbx.cpp index 1cef961..375980a 100644 --- a/apppbx.cpp +++ b/apppbx.cpp @@ -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); diff --git a/dss1.cpp b/dss1.cpp index a52f66e..9a6a922 100644 --- a/dss1.cpp +++ b/dss1.cpp @@ -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) diff --git a/endpoint.cpp b/endpoint.cpp index b5d6f64..e0f6365 100644 --- a/endpoint.cpp +++ b/endpoint.cpp @@ -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) diff --git a/endpoint.h b/endpoint.h index 460c0d7..a336beb 100644 --- a/endpoint.h +++ b/endpoint.h @@ -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 */ diff --git a/joinpbx.cpp b/joinpbx.cpp index ff8fcd1..6d8b1b9 100644 --- a/joinpbx.cpp +++ b/joinpbx.cpp @@ -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))) diff --git a/joinremote.cpp b/joinremote.cpp index 3b7291c..f2c08b7 100644 --- a/joinremote.cpp +++ b/joinremote.cpp @@ -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(¶m, 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(¶m, 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, ¶m)<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; + } +} + diff --git a/joinremote.h b/joinremote.h index ac86467..f80d0d9 100644 --- a/joinremote.h +++ b/joinremote.h @@ -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); diff --git a/mISDN.cpp b/mISDN.cpp index 66c17ee..6196ee2 100644 --- a/mISDN.cpp +++ b/mISDN.cpp @@ -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: diff --git a/mISDN.h b/mISDN.h index db1a8cb..90ec032 100644 --- a/mISDN.h +++ b/mISDN.h @@ -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); diff --git a/message.h b/message.h index d60c1b3..422ada1 100644 --- a/message.h +++ b/message.h @@ -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 */ }; diff --git a/message.txt b/message.txt index a78bba4..0c770a3 100644 --- a/message.txt +++ b/message.txt @@ -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. + + +