Added support of mISDN to direct bridge feature
authorAndreas Eversberg <jolly@eversberg.eu>
Tue, 21 Feb 2012 10:32:31 +0000 (11:32 +0100)
committerAndreas Eversberg <jolly@eversberg.eu>
Tue, 21 Feb 2012 10:32:31 +0000 (11:32 +0100)
Now it is possible to directly bridge:

- GSM with SIP
- GSM with ISDN
- SIP with ISDN

appbridge.cpp
appbridge.h
apppbx.cpp
apppbx.h
endpointapp.cpp
endpointapp.h

index 50808ca..b52e125 100644 (file)
@@ -78,55 +78,6 @@ void EndpointAppBridge::trace_header(const char *name, int direction)
                    msgtext);
 }
 
                    msgtext);
 }
 
-/* hunts for the given interface
- * it does not need to have an mISDNport instance */
-struct interface *EndpointAppBridge::hunt_interface(char *ifname)
-{
-       struct interface *interface;
-       int there_is_an_external = 0;
-
-       interface = interface_first;
-
-       /* first find the given interface or, if not given, one with no extension */
-       checknext:
-       if (!interface) {
-               if (!there_is_an_external && !(ifname && ifname[0])) {
-                       trace_header("CHANNEL SELECTION (no external interface specified)", DIRECTION_NONE);
-                       add_trace("info", NULL, "Add 'extern' parameter to interface.conf.");
-                       end_trace();
-               }
-               return(NULL);
-       }
-
-       /* check for given interface */
-       if (ifname && ifname[0]) {
-               if (!strcasecmp(interface->name, ifname)) {
-                       /* found explicit interface */
-                       trace_header("CHANNEL SELECTION (found given interface)", DIRECTION_NONE);
-                       add_trace("interface", NULL, "%s", ifname);
-                       end_trace();
-                       goto foundif;
-               }
-
-       } else {
-               if (interface->external) {
-                       there_is_an_external = 1;
-                       /* found non extension */
-                       trace_header("CHANNEL SELECTION (found external interface)", DIRECTION_NONE);
-                       add_trace("interface", NULL, "%s", interface->name);
-                       end_trace();
-                       goto foundif;
-               }
-       }
-
-       interface = interface->next;
-       goto checknext;
-foundif:
-
-       return interface;
-}
-
-
 /* port MESSAGE_SETUP */
 void EndpointAppBridge::port_setup(struct port_list *portlist, int message_type, union parameter *param)
 {
 /* port MESSAGE_SETUP */
 void EndpointAppBridge::port_setup(struct port_list *portlist, int message_type, union parameter *param)
 {
@@ -138,6 +89,7 @@ void EndpointAppBridge::port_setup(struct port_list *portlist, int message_type,
        unsigned int bridge_id;
        unsigned int source_port_id = portlist->port_id;
        char portname[64];
        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);
 
 
        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);
 
@@ -156,10 +108,10 @@ void EndpointAppBridge::port_setup(struct port_list *portlist, int message_type,
                interface_in = interface_in->next;
        }
        if (!interface_in) {
                interface_in = interface_in->next;
        }
        if (!interface_in) {
-fail:
                PERROR("Cannot find source interface %s.\n", param->setup.callerinfo.interface);
                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 = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
-               message->param.disconnectinfo.cause = 47;
+               message->param.disconnectinfo.cause = cause;
                message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
                message_put(message);
 
                message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
                message_put(message);
 
@@ -186,18 +138,69 @@ fail:
 #ifdef WITH_SIP
        if (interface_out->sip) {
                port = new Psip(PORT_TYPE_SIP_OUT, portname, &port_settings, interface_out);
 #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);
 #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_bs(PORT_TYPE_GSM_MS_OUT, portname, &port_settings, interface_out);
 #endif
 #ifdef WITH_GSM_MS
        if (interface_out->gsm_ms) {
                port = new Pgsm_bs(PORT_TYPE_GSM_MS_OUT, portname, &port_settings, interface_out);
-       }
+       } else
 #endif
 #endif
+       {
+#ifdef WITH_MISDN
+               struct mISDNport *mISDNport;
+               char *ifname = interface_out->name;
+               int channel = 0;
+               struct admin_list *admin;
+               int earlyb;
+               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
+               if (mISDNport->ifport->remote) {
+                       admin = admin_first;
+                       while(admin) {
+                               if (admin->remote_name[0] && !strcmp(admin->remote_name, mISDNport->ifport->remote_app))
+                                       break;
+                               admin = admin->next;
+                       }
+                       if (!admin) {
+                               trace_header("INTERFACE (remote not connected)", DIRECTION_NONE);
+                               add_trace("application", NULL, "%s", mISDNport->ifport->remote_app);
+                               end_trace();
+                               cause = 27;
+                               goto fail;
+                       }
+                       port = new Premote(PORT_TYPE_REMOTE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode, admin->sock);
+               } else
+                       port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
+               earlyb = mISDNport->earlyb;
+#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 (!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);
index 2e4ea06..bfad94d 100644 (file)
@@ -26,7 +26,6 @@ class EndpointAppBridge : public EndpointApp
        void port_release(struct port_list *portlist, int message_type, union parameter *param);
        void port_other(struct port_list *portlist, int message_type, union parameter *param);
        void ea_message_port(unsigned int port_id, int message, union parameter *param);
        void port_release(struct port_list *portlist, int message_type, union parameter *param);
        void port_other(struct port_list *portlist, int message_type, union parameter *param);
        void ea_message_port(unsigned int port_id, int message, union parameter *param);
-       struct interface *hunt_interface(char *ifname);
 
        void trace_header(const char *name, int direction);
 };
 
        void trace_header(const char *name, int direction);
 };
index a61d108..bacdba9 100644 (file)
@@ -584,306 +584,6 @@ void EndpointAppPBX::set_tone(struct port_list *portlist, const char *tone)
        }
 }
 
        }
 }
 
-/* hunts for the given interface
- * it does not need to have an mISDNport instance */
-struct interface *EndpointAppPBX::hunt_interface(char *ifname)
-{
-       struct interface *interface;
-       int there_is_an_external = 0;
-
-       interface = interface_first;
-
-       /* first find the given interface or, if not given, one with no extension */
-       checknext:
-       if (!interface) {
-               if (!there_is_an_external && !(ifname && ifname[0])) {
-                       trace_header("CHANNEL SELECTION (no external interface specified)", DIRECTION_NONE);
-                       add_trace("info", NULL, "Add 'extern' parameter to interface.conf.");
-                       end_trace();
-               }
-               return(NULL);
-       }
-
-       /* check for given interface */
-       if (ifname && ifname[0]) {
-               if (!strcasecmp(interface->name, ifname)) {
-                       /* found explicit interface */
-                       trace_header("CHANNEL SELECTION (found given interface)", DIRECTION_NONE);
-                       add_trace("interface", NULL, "%s", ifname);
-                       end_trace();
-                       goto foundif;
-               }
-       } else {
-               if (interface->external) {
-                       there_is_an_external = 1;
-                       /* found non extension */
-                       trace_header("CHANNEL SELECTION (found external interface)", DIRECTION_NONE);
-                       add_trace("interface", NULL, "%s", interface->name);
-                       end_trace();
-                       goto foundif;
-               }
-       }
-
-       interface = interface->next;
-       goto checknext;
-foundif:
-
-       return interface;
-}
-
-
-#ifdef WITH_MISDN
-/*
- * hunts an mISDNport that is available for an outgoing call
- * if no ifname was given, any interface that is not an extension
- * will be searched.
- */
-struct mISDNport *EndpointAppPBX::hunt_port(char *ifname, int *channel)
-{
-       struct interface *interface;
-       struct interface_port *ifport, *ifport_start;
-       struct select_channel *selchannel; 
-       struct mISDNport *mISDNport;
-       int index, i;
-       int there_is_an_external = 0;
-
-       interface = interface_first;
-
-       /* first find the given interface or, if not given, one with no extension */
-       checknext:
-       if (!interface) {
-               if (!there_is_an_external && !(ifname && ifname[0])) {
-                       trace_header("CHANNEL SELECTION (no external interface specified)", DIRECTION_NONE);
-                       add_trace("info", NULL, "Add 'extern' parameter to interface.conf.");
-                       end_trace();
-               }
-               return(NULL);
-       }
-
-       /* check for given interface */
-       if (ifname && ifname[0]) {
-               if (!strcasecmp(interface->name, ifname)) {
-                       /* found explicit interface */
-                       trace_header("CHANNEL SELECTION (found given interface)", DIRECTION_NONE);
-                       add_trace("interface", NULL, "%s", ifname);
-                       end_trace();
-                       goto foundif;
-               }
-
-       } else {
-               if (interface->external) {
-                       there_is_an_external = 1;
-                       /* found non extension */
-                       trace_header("CHANNEL SELECTION (found external interface)", DIRECTION_NONE);
-                       add_trace("interface", NULL, "%s", interface->name);
-                       end_trace();
-                       goto foundif;
-               }
-       }
-
-       interface = interface->next;
-       goto checknext;
-foundif:
-
-       /* see if interface has ports */
-       if (!interface->ifport) {
-               /* no ports */
-               trace_header("CHANNEL SELECTION (active ports, skipping)", DIRECTION_NONE);
-               add_trace("interface", NULL, "%s", interface->name);
-               end_trace();
-               interface = interface->next;
-               goto checknext;
-       }
-
-       /* select port by algorithm */
-       ifport_start = interface->ifport;
-       index = 0;
-       if (interface->hunt == HUNT_ROUNDROBIN) {
-               while(ifport_start->next && index<interface->hunt_next) {
-                       ifport_start = ifport_start->next;
-                       index++;
-               }
-               trace_header("CHANNEL SELECTION (starting round-robin)", DIRECTION_NONE);
-               add_trace("port", NULL, "%d", ifport_start->portnum);
-               add_trace("position", NULL, "%d", index);
-               end_trace();
-       }
-
-       /* loop ports */
-       ifport = ifport_start;
-       nextport:
-
-       /* see if port is available */
-       if (!ifport->mISDNport) {
-               trace_header("CHANNEL SELECTION (port not available, skipping)", DIRECTION_NONE);
-               add_trace("port", NULL, "%d", ifport->portnum);
-               add_trace("position", NULL, "%d", index);
-               end_trace();
-               goto portbusy;
-       }
-       mISDNport = ifport->mISDNport;
-
-       /* see if port is administratively blocked */
-       if (ifport->block) {
-               trace_header("CHANNEL SELECTION (port blocked by admin, skipping)", DIRECTION_NONE);
-               add_trace("port", NULL, "%d", ifport->portnum);
-               add_trace("position", NULL, "%d", index);
-               end_trace();
-               goto portbusy;
-       }
-
-       /* see if link is up on PTP*/
-       if (mISDNport->l2hold && mISDNport->l2link<1) {
-               trace_header("CHANNEL SELECTION (port's layer 2 is down, skipping)", DIRECTION_NONE);
-               add_trace("port", NULL, "%d", ifport->portnum);
-               add_trace("position", NULL, "%d", index);
-               end_trace();
-               goto portbusy;
-       }
-
-       /* check for channel form selection list */
-       *channel = 0;
-#ifdef WITH_SS5
-       if (mISDNport->ss5) {
-               class Pss5 *port;
-               port = ss5_hunt_line(mISDNport);
-               if (port) {
-                       *channel = port->p_m_b_channel;
-                       trace_header("CHANNEL SELECTION (selecting SS5 channel)", DIRECTION_NONE);
-                       add_trace("port", NULL, "%d", ifport->portnum);
-                       add_trace("position", NULL, "%d", index);
-                       add_trace("channel", NULL, "%d", *channel);
-                       end_trace();
-               }
-       } else
-#endif
-       {
-               selchannel = ifport->out_channel;
-               while(selchannel) {
-                       switch(selchannel->channel) {
-                               case CHANNEL_FREE: /* free channel */
-                               if (mISDNport->b_reserved >= mISDNport->b_num)
-                                       break; /* all channel in use or reserverd */
-                               /* find channel */
-                               i = 0;
-                               while(i < mISDNport->b_num) {
-                                       if (mISDNport->b_port[i] == NULL) {
-                                               *channel = i+1+(i>=15);
-                                               trace_header("CHANNEL SELECTION (selecting free channel)", DIRECTION_NONE);
-                                               add_trace("port", NULL, "%d", ifport->portnum);
-                                               add_trace("position", NULL, "%d", index);
-                                               add_trace("channel", NULL, "%d", *channel);
-                                               end_trace();
-                                               break;
-                                       }
-                                       i++;
-                               }
-                               if (*channel)
-                                       break;
-                               trace_header("CHANNEL SELECTION (no channel is 'free')", DIRECTION_NONE);
-                               add_trace("port", NULL, "%d", ifport->portnum);
-                               add_trace("position", NULL, "%d", index);
-                               end_trace();
-                               break;
-
-                               case CHANNEL_ANY: /* don't ask for channel */
-                               if (mISDNport->b_reserved >= mISDNport->b_num) {
-                                       trace_header("CHANNEL SELECTION (cannot ask for 'any' channel, all reserved)", DIRECTION_NONE);
-                                       add_trace("port", NULL, "%d", ifport->portnum);
-                                       add_trace("position", NULL, "%d", index);
-                                       add_trace("total", NULL, "%d", mISDNport->b_num);
-                                       add_trace("reserved", NULL, "%d", mISDNport->b_reserved);
-                                       end_trace();
-                                       break; /* all channel in use or reserverd */
-                               }
-                               trace_header("CHANNEL SELECTION (using 'any' channel)", DIRECTION_NONE);
-                               add_trace("port", NULL, "%d", ifport->portnum);
-                               add_trace("position", NULL, "%d", index);
-                               end_trace();
-                               *channel = CHANNEL_ANY;
-                               break;
-
-                               case CHANNEL_NO: /* call waiting */
-                               trace_header("CHANNEL SELECTION (using 'no' channel, call-waiting)", DIRECTION_NONE);
-                               add_trace("port", NULL, "%d", ifport->portnum);
-                               add_trace("position", NULL, "%d", index);
-                               end_trace();
-                               *channel = CHANNEL_NO;
-                               break;
-
-                               default:
-                               if (selchannel->channel<1 || selchannel->channel==16) {
-                                       trace_header("CHANNEL SELECTION (channel out of range)", DIRECTION_NONE);
-                                       add_trace("port", NULL, "%d", ifport->portnum);
-                                       add_trace("position", NULL, "%d", index);
-                                       add_trace("channel", NULL, "%d", selchannel->channel);
-                                       end_trace();
-                                       break; /* invalid channels */
-                               }
-                               i = selchannel->channel-1-(selchannel->channel>=17);
-                               if (i >= mISDNport->b_num) {
-                                       trace_header("CHANNEL SELECTION (channel out of range)", DIRECTION_NONE);
-                                       add_trace("port", NULL, "%d", ifport->portnum);
-                                       add_trace("position", NULL, "%d", index);
-                                       add_trace("channel", NULL, "%d", selchannel->channel);
-                                       add_trace("channels", NULL, "%d", mISDNport->b_num);
-                                       end_trace();
-                                       break; /* channel not in port */
-                               }
-                               if (mISDNport->b_port[i] == NULL) {
-                                       *channel = selchannel->channel;
-                                       trace_header("CHANNEL SELECTION (selecting given channel)", DIRECTION_NONE);
-                                       add_trace("port", NULL, "%d", ifport->portnum);
-                                       add_trace("position", NULL, "%d", index);
-                                       add_trace("channel", NULL, "%d", *channel);
-                                       end_trace();
-                                       break;
-                               }
-                               break;
-                       }
-                       if (*channel)
-                               break; /* found channel */
-                       selchannel = selchannel->next;
-               }
-       }
-
-       /* if channel was found, return mISDNport and channel */
-       if (*channel) {
-               /* setting next port to start next time */
-               if (interface->hunt == HUNT_ROUNDROBIN) {
-                       index++;
-                       if (!ifport->next)
-                               index = 0;
-                       interface->hunt_next = index;
-               }
-               
-               return(mISDNport);
-       }
-
-       trace_header("CHANNEL SELECTION (skipping, no channel found)", DIRECTION_NONE);
-       add_trace("port", NULL, "%d", ifport->portnum);
-       add_trace("position", NULL, "%d", index);
-       end_trace();
-
-       portbusy:
-       /* go next port, until all ports are checked */
-       index++;
-       ifport = ifport->next;
-       if (!ifport) {
-               index = 0;
-               ifport = interface->ifport;
-       }
-       if (ifport != ifport_start)
-               goto nextport;
-
-       if (!ifname) {
-               interface = interface->next;
-               goto checknext;
-       }
-
-       return(NULL); /* no port found */
-}
-#endif
 
 /* outgoing setup to port(s)
  * ports will be created and a setup is sent if everything is ok. otherwhise
 
 /* outgoing setup to port(s)
  * ports will be created and a setup is sent if everything is ok. otherwhise
index 8b49506..c3d2d68 100644 (file)
--- a/apppbx.h
+++ b/apppbx.h
@@ -236,8 +236,6 @@ class EndpointAppPBX : public EndpointApp
        void keypad_function(char digit);
        void set_tone(struct port_list *portlist, const char *tone);
        void out_setup(int cfnr);
        void keypad_function(char digit);
        void set_tone(struct port_list *portlist, const char *tone);
        void out_setup(int cfnr);
-       struct mISDNport *hunt_port(char *ifname, int *channel);
-       struct interface *hunt_interface(char *ifname);
        char *apply_callerid_display(const char *id, int itype, int ntype, int present, int screen, const char *extension, const char *name);
        void auth(int job, int bit_num);
 
        char *apply_callerid_display(const char *id, int itype, int ntype, int present, int screen, const char *extension, const char *name);
        void auth(int job, int bit_num);
 
index da797de..a3ad7dd 100644 (file)
@@ -64,3 +64,308 @@ class EndpointApp *new_endpointapp(class Endpoint *epoint, int origin, int type)
 
        return app;
 }
 
        return app;
 }
+
+#ifdef WITH_MISDN
+/*
+ * hunts an mISDNport that is available for an outgoing call
+ * if no ifname was given, any interface that is not an extension
+ * will be searched.
+ */
+struct mISDNport *EndpointApp::hunt_port(char *ifname, int *channel)
+{
+       struct interface *interface;
+       struct interface_port *ifport, *ifport_start;
+       struct select_channel *selchannel; 
+       struct mISDNport *mISDNport;
+       int index, i;
+       int there_is_an_external = 0;
+
+       interface = interface_first;
+
+       /* first find the given interface or, if not given, one with no extension */
+       checknext:
+       if (!interface) {
+               if (!there_is_an_external && !(ifname && ifname[0])) {
+                       trace_header("CHANNEL SELECTION (no external interface specified)", DIRECTION_NONE);
+                       add_trace("info", NULL, "Add 'extern' parameter to interface.conf.");
+                       end_trace();
+               }
+               return(NULL);
+       }
+
+       /* check for given interface */
+       if (ifname && ifname[0]) {
+               if (!strcasecmp(interface->name, ifname)) {
+                       /* found explicit interface */
+                       trace_header("CHANNEL SELECTION (found given interface)", DIRECTION_NONE);
+                       add_trace("interface", NULL, "%s", ifname);
+                       end_trace();
+                       goto foundif;
+               }
+
+       } else {
+               if (interface->external) {
+                       there_is_an_external = 1;
+                       /* found non extension */
+                       trace_header("CHANNEL SELECTION (found external interface)", DIRECTION_NONE);
+                       add_trace("interface", NULL, "%s", interface->name);
+                       end_trace();
+                       goto foundif;
+               }
+       }
+
+       interface = interface->next;
+       goto checknext;
+foundif:
+
+       /* see if interface has ports */
+       if (!interface->ifport) {
+               /* no ports */
+               trace_header("CHANNEL SELECTION (active ports, skipping)", DIRECTION_NONE);
+               add_trace("interface", NULL, "%s", interface->name);
+               end_trace();
+               interface = interface->next;
+               goto checknext;
+       }
+
+       /* select port by algorithm */
+       ifport_start = interface->ifport;
+       index = 0;
+       if (interface->hunt == HUNT_ROUNDROBIN) {
+               while(ifport_start->next && index<interface->hunt_next) {
+                       ifport_start = ifport_start->next;
+                       index++;
+               }
+               trace_header("CHANNEL SELECTION (starting round-robin)", DIRECTION_NONE);
+               add_trace("port", NULL, "%d", ifport_start->portnum);
+               add_trace("position", NULL, "%d", index);
+               end_trace();
+       }
+
+       /* loop ports */
+       ifport = ifport_start;
+       nextport:
+
+       /* see if port is available */
+       if (!ifport->mISDNport) {
+               trace_header("CHANNEL SELECTION (port not available, skipping)", DIRECTION_NONE);
+               add_trace("port", NULL, "%d", ifport->portnum);
+               add_trace("position", NULL, "%d", index);
+               end_trace();
+               goto portbusy;
+       }
+       mISDNport = ifport->mISDNport;
+
+       /* see if port is administratively blocked */
+       if (ifport->block) {
+               trace_header("CHANNEL SELECTION (port blocked by admin, skipping)", DIRECTION_NONE);
+               add_trace("port", NULL, "%d", ifport->portnum);
+               add_trace("position", NULL, "%d", index);
+               end_trace();
+               goto portbusy;
+       }
+
+       /* see if link is up on PTP*/
+       if (mISDNport->l2hold && mISDNport->l2link<1) {
+               trace_header("CHANNEL SELECTION (port's layer 2 is down, skipping)", DIRECTION_NONE);
+               add_trace("port", NULL, "%d", ifport->portnum);
+               add_trace("position", NULL, "%d", index);
+               end_trace();
+               goto portbusy;
+       }
+
+       /* check for channel form selection list */
+       *channel = 0;
+#ifdef WITH_SS5
+       if (mISDNport->ss5) {
+               class Pss5 *port;
+               port = ss5_hunt_line(mISDNport);
+               if (port) {
+                       *channel = port->p_m_b_channel;
+                       trace_header("CHANNEL SELECTION (selecting SS5 channel)", DIRECTION_NONE);
+                       add_trace("port", NULL, "%d", ifport->portnum);
+                       add_trace("position", NULL, "%d", index);
+                       add_trace("channel", NULL, "%d", *channel);
+                       end_trace();
+               }
+       } else
+#endif
+       {
+               selchannel = ifport->out_channel;
+               while(selchannel) {
+                       switch(selchannel->channel) {
+                               case CHANNEL_FREE: /* free channel */
+                               if (mISDNport->b_reserved >= mISDNport->b_num)
+                                       break; /* all channel in use or reserverd */
+                               /* find channel */
+                               i = 0;
+                               while(i < mISDNport->b_num) {
+                                       if (mISDNport->b_port[i] == NULL) {
+                                               *channel = i+1+(i>=15);
+                                               trace_header("CHANNEL SELECTION (selecting free channel)", DIRECTION_NONE);
+                                               add_trace("port", NULL, "%d", ifport->portnum);
+                                               add_trace("position", NULL, "%d", index);
+                                               add_trace("channel", NULL, "%d", *channel);
+                                               end_trace();
+                                               break;
+                                       }
+                                       i++;
+                               }
+                               if (*channel)
+                                       break;
+                               trace_header("CHANNEL SELECTION (no channel is 'free')", DIRECTION_NONE);
+                               add_trace("port", NULL, "%d", ifport->portnum);
+                               add_trace("position", NULL, "%d", index);
+                               end_trace();
+                               break;
+
+                               case CHANNEL_ANY: /* don't ask for channel */
+                               if (mISDNport->b_reserved >= mISDNport->b_num) {
+                                       trace_header("CHANNEL SELECTION (cannot ask for 'any' channel, all reserved)", DIRECTION_NONE);
+                                       add_trace("port", NULL, "%d", ifport->portnum);
+                                       add_trace("position", NULL, "%d", index);
+                                       add_trace("total", NULL, "%d", mISDNport->b_num);
+                                       add_trace("reserved", NULL, "%d", mISDNport->b_reserved);
+                                       end_trace();
+                                       break; /* all channel in use or reserverd */
+                               }
+                               trace_header("CHANNEL SELECTION (using 'any' channel)", DIRECTION_NONE);
+                               add_trace("port", NULL, "%d", ifport->portnum);
+                               add_trace("position", NULL, "%d", index);
+                               end_trace();
+                               *channel = CHANNEL_ANY;
+                               break;
+
+                               case CHANNEL_NO: /* call waiting */
+                               trace_header("CHANNEL SELECTION (using 'no' channel, call-waiting)", DIRECTION_NONE);
+                               add_trace("port", NULL, "%d", ifport->portnum);
+                               add_trace("position", NULL, "%d", index);
+                               end_trace();
+                               *channel = CHANNEL_NO;
+                               break;
+
+                               default:
+                               if (selchannel->channel<1 || selchannel->channel==16) {
+                                       trace_header("CHANNEL SELECTION (channel out of range)", DIRECTION_NONE);
+                                       add_trace("port", NULL, "%d", ifport->portnum);
+                                       add_trace("position", NULL, "%d", index);
+                                       add_trace("channel", NULL, "%d", selchannel->channel);
+                                       end_trace();
+                                       break; /* invalid channels */
+                               }
+                               i = selchannel->channel-1-(selchannel->channel>=17);
+                               if (i >= mISDNport->b_num) {
+                                       trace_header("CHANNEL SELECTION (channel out of range)", DIRECTION_NONE);
+                                       add_trace("port", NULL, "%d", ifport->portnum);
+                                       add_trace("position", NULL, "%d", index);
+                                       add_trace("channel", NULL, "%d", selchannel->channel);
+                                       add_trace("channels", NULL, "%d", mISDNport->b_num);
+                                       end_trace();
+                                       break; /* channel not in port */
+                               }
+                               if (mISDNport->b_port[i] == NULL) {
+                                       *channel = selchannel->channel;
+                                       trace_header("CHANNEL SELECTION (selecting given channel)", DIRECTION_NONE);
+                                       add_trace("port", NULL, "%d", ifport->portnum);
+                                       add_trace("position", NULL, "%d", index);
+                                       add_trace("channel", NULL, "%d", *channel);
+                                       end_trace();
+                                       break;
+                               }
+                               break;
+                       }
+                       if (*channel)
+                               break; /* found channel */
+                       selchannel = selchannel->next;
+               }
+       }
+
+       /* if channel was found, return mISDNport and channel */
+       if (*channel) {
+               /* setting next port to start next time */
+               if (interface->hunt == HUNT_ROUNDROBIN) {
+                       index++;
+                       if (!ifport->next)
+                               index = 0;
+                       interface->hunt_next = index;
+               }
+               
+               return(mISDNport);
+       }
+
+       trace_header("CHANNEL SELECTION (skipping, no channel found)", DIRECTION_NONE);
+       add_trace("port", NULL, "%d", ifport->portnum);
+       add_trace("position", NULL, "%d", index);
+       end_trace();
+
+       portbusy:
+       /* go next port, until all ports are checked */
+       index++;
+       ifport = ifport->next;
+       if (!ifport) {
+               index = 0;
+               ifport = interface->ifport;
+       }
+       if (ifport != ifport_start)
+               goto nextport;
+
+       if (!ifname) {
+               interface = interface->next;
+               goto checknext;
+       }
+
+       return(NULL); /* no port found */
+}
+#endif
+
+/* hunts for the given interface
+ * it does not need to have an mISDNport instance */
+struct interface *EndpointApp::hunt_interface(char *ifname)
+{
+       struct interface *interface;
+       int there_is_an_external = 0;
+
+       interface = interface_first;
+
+       /* first find the given interface or, if not given, one with no extension */
+       checknext:
+       if (!interface) {
+               if (!there_is_an_external && !(ifname && ifname[0])) {
+                       trace_header("CHANNEL SELECTION (no external interface specified)", DIRECTION_NONE);
+                       add_trace("info", NULL, "Add 'extern' parameter to interface.conf.");
+                       end_trace();
+               }
+               return(NULL);
+       }
+
+       /* check for given interface */
+       if (ifname && ifname[0]) {
+               if (!strcasecmp(interface->name, ifname)) {
+                       /* found explicit interface */
+                       trace_header("CHANNEL SELECTION (found given interface)", DIRECTION_NONE);
+                       add_trace("interface", NULL, "%s", ifname);
+                       end_trace();
+                       goto foundif;
+               }
+       } else {
+               if (interface->external) {
+                       there_is_an_external = 1;
+                       /* found non extension */
+                       trace_header("CHANNEL SELECTION (found external interface)", DIRECTION_NONE);
+                       add_trace("interface", NULL, "%s", interface->name);
+                       end_trace();
+                       goto foundif;
+               }
+       }
+
+       interface = interface->next;
+       goto checknext;
+foundif:
+
+       return interface;
+}
+
+/* must be overloaded by specific app */
+void EndpointApp::trace_header(const char *name, int direction)
+{
+}
index 4147c51..5d6f253 100644 (file)
@@ -23,6 +23,12 @@ class EndpointApp
        class Endpoint          *ea_endpoint;
        virtual void ea_message_port(unsigned int port_id, int message, union parameter *param);
        virtual void ea_message_join(unsigned int join_id, int message, union parameter *param);
        class Endpoint          *ea_endpoint;
        virtual void ea_message_port(unsigned int port_id, int message, union parameter *param);
        virtual void ea_message_join(unsigned int join_id, int message, union parameter *param);
+       virtual void trace_header(const char *name, int direction);
+
+#ifdef WITH_MISDN
+       struct mISDNport *hunt_port(char *ifname, int *channel);
+#endif
+       struct interface *hunt_interface(char *ifname);
 };
 
 class EndpointApp *new_endpointapp(class Endpoint *epoint, int origin, int type);
 };
 
 class EndpointApp *new_endpointapp(class Endpoint *epoint, int origin, int type);