Added support of mISDN to direct bridge feature
[lcr.git] / endpointapp.cpp
1 /*****************************************************************************\
2 **                                                                           **
3 ** Linux Call Router                                                         **
4 **                                                                           **
5 **---------------------------------------------------------------------------**
6 ** Copyright: Andreas Eversberg                                              **
7 **                                                                           **
8 ** The EndpointApp represents the application for the Endpoint.              **
9 **                                                                           **
10 \*****************************************************************************/ 
11
12 #include "main.h"
13
14 /*
15  * EndpointApp constructor
16  */
17 EndpointApp::EndpointApp(class Endpoint *epoint, int origin, int type)
18 {
19         ea_endpoint = epoint;
20         ea_type = type;
21         classuse++;
22 }
23
24 /*
25  * endpoint destructor
26  */
27 EndpointApp::~EndpointApp(void)
28 {
29         classuse--;
30 }
31
32 /* mini application for test purpose only */
33
34 void EndpointApp::ea_message_port(unsigned int port_id, int message_type, union parameter *param)
35 {
36         PDEBUG(DEBUG_EPOINT, "%s: Spare function.\n", __FUNCTION__);
37 }
38
39 void EndpointApp::ea_message_join(unsigned int join_id, int message_type, union parameter *param)
40 {
41         PDEBUG(DEBUG_EPOINT, "%s: Spare function.\n", __FUNCTION__);
42 }
43
44
45 /* create endpoint app */
46 class EndpointApp *new_endpointapp(class Endpoint *epoint, int origin, int type)
47 {
48         class EndpointApp *app = NULL;
49
50         switch (type) {
51         case EAPP_TYPE_PBX:
52                 app = new EndpointAppPBX(epoint, origin);
53                 break;
54         case EAPP_TYPE_BRIDGE:
55                 app = new EndpointAppBridge(epoint, origin);
56                 break;
57         }
58
59         if (!app)
60                 FATAL("Failed to create endpoint APP (type %d)\n", type);
61
62         epoint->ep_app_type = type;
63         epoint->ep_app = app;
64
65         return app;
66 }
67
68 #ifdef WITH_MISDN
69 /*
70  * hunts an mISDNport that is available for an outgoing call
71  * if no ifname was given, any interface that is not an extension
72  * will be searched.
73  */
74 struct mISDNport *EndpointApp::hunt_port(char *ifname, int *channel)
75 {
76         struct interface *interface;
77         struct interface_port *ifport, *ifport_start;
78         struct select_channel *selchannel; 
79         struct mISDNport *mISDNport;
80         int index, i;
81         int there_is_an_external = 0;
82
83         interface = interface_first;
84
85         /* first find the given interface or, if not given, one with no extension */
86         checknext:
87         if (!interface) {
88                 if (!there_is_an_external && !(ifname && ifname[0])) {
89                         trace_header("CHANNEL SELECTION (no external interface specified)", DIRECTION_NONE);
90                         add_trace("info", NULL, "Add 'extern' parameter to interface.conf.");
91                         end_trace();
92                 }
93                 return(NULL);
94         }
95
96         /* check for given interface */
97         if (ifname && ifname[0]) {
98                 if (!strcasecmp(interface->name, ifname)) {
99                         /* found explicit interface */
100                         trace_header("CHANNEL SELECTION (found given interface)", DIRECTION_NONE);
101                         add_trace("interface", NULL, "%s", ifname);
102                         end_trace();
103                         goto foundif;
104                 }
105
106         } else {
107                 if (interface->external) {
108                         there_is_an_external = 1;
109                         /* found non extension */
110                         trace_header("CHANNEL SELECTION (found external interface)", DIRECTION_NONE);
111                         add_trace("interface", NULL, "%s", interface->name);
112                         end_trace();
113                         goto foundif;
114                 }
115         }
116
117         interface = interface->next;
118         goto checknext;
119 foundif:
120
121         /* see if interface has ports */
122         if (!interface->ifport) {
123                 /* no ports */
124                 trace_header("CHANNEL SELECTION (active ports, skipping)", DIRECTION_NONE);
125                 add_trace("interface", NULL, "%s", interface->name);
126                 end_trace();
127                 interface = interface->next;
128                 goto checknext;
129         }
130
131         /* select port by algorithm */
132         ifport_start = interface->ifport;
133         index = 0;
134         if (interface->hunt == HUNT_ROUNDROBIN) {
135                 while(ifport_start->next && index<interface->hunt_next) {
136                         ifport_start = ifport_start->next;
137                         index++;
138                 }
139                 trace_header("CHANNEL SELECTION (starting round-robin)", DIRECTION_NONE);
140                 add_trace("port", NULL, "%d", ifport_start->portnum);
141                 add_trace("position", NULL, "%d", index);
142                 end_trace();
143         }
144
145         /* loop ports */
146         ifport = ifport_start;
147         nextport:
148
149         /* see if port is available */
150         if (!ifport->mISDNport) {
151                 trace_header("CHANNEL SELECTION (port not available, skipping)", DIRECTION_NONE);
152                 add_trace("port", NULL, "%d", ifport->portnum);
153                 add_trace("position", NULL, "%d", index);
154                 end_trace();
155                 goto portbusy;
156         }
157         mISDNport = ifport->mISDNport;
158
159         /* see if port is administratively blocked */
160         if (ifport->block) {
161                 trace_header("CHANNEL SELECTION (port blocked by admin, skipping)", DIRECTION_NONE);
162                 add_trace("port", NULL, "%d", ifport->portnum);
163                 add_trace("position", NULL, "%d", index);
164                 end_trace();
165                 goto portbusy;
166         }
167
168         /* see if link is up on PTP*/
169         if (mISDNport->l2hold && mISDNport->l2link<1) {
170                 trace_header("CHANNEL SELECTION (port's layer 2 is down, skipping)", DIRECTION_NONE);
171                 add_trace("port", NULL, "%d", ifport->portnum);
172                 add_trace("position", NULL, "%d", index);
173                 end_trace();
174                 goto portbusy;
175         }
176
177         /* check for channel form selection list */
178         *channel = 0;
179 #ifdef WITH_SS5
180         if (mISDNport->ss5) {
181                 class Pss5 *port;
182                 port = ss5_hunt_line(mISDNport);
183                 if (port) {
184                         *channel = port->p_m_b_channel;
185                         trace_header("CHANNEL SELECTION (selecting SS5 channel)", DIRECTION_NONE);
186                         add_trace("port", NULL, "%d", ifport->portnum);
187                         add_trace("position", NULL, "%d", index);
188                         add_trace("channel", NULL, "%d", *channel);
189                         end_trace();
190                 }
191         } else
192 #endif
193         {
194                 selchannel = ifport->out_channel;
195                 while(selchannel) {
196                         switch(selchannel->channel) {
197                                 case CHANNEL_FREE: /* free channel */
198                                 if (mISDNport->b_reserved >= mISDNport->b_num)
199                                         break; /* all channel in use or reserverd */
200                                 /* find channel */
201                                 i = 0;
202                                 while(i < mISDNport->b_num) {
203                                         if (mISDNport->b_port[i] == NULL) {
204                                                 *channel = i+1+(i>=15);
205                                                 trace_header("CHANNEL SELECTION (selecting free channel)", DIRECTION_NONE);
206                                                 add_trace("port", NULL, "%d", ifport->portnum);
207                                                 add_trace("position", NULL, "%d", index);
208                                                 add_trace("channel", NULL, "%d", *channel);
209                                                 end_trace();
210                                                 break;
211                                         }
212                                         i++;
213                                 }
214                                 if (*channel)
215                                         break;
216                                 trace_header("CHANNEL SELECTION (no channel is 'free')", DIRECTION_NONE);
217                                 add_trace("port", NULL, "%d", ifport->portnum);
218                                 add_trace("position", NULL, "%d", index);
219                                 end_trace();
220                                 break;
221
222                                 case CHANNEL_ANY: /* don't ask for channel */
223                                 if (mISDNport->b_reserved >= mISDNport->b_num) {
224                                         trace_header("CHANNEL SELECTION (cannot ask for 'any' channel, all reserved)", DIRECTION_NONE);
225                                         add_trace("port", NULL, "%d", ifport->portnum);
226                                         add_trace("position", NULL, "%d", index);
227                                         add_trace("total", NULL, "%d", mISDNport->b_num);
228                                         add_trace("reserved", NULL, "%d", mISDNport->b_reserved);
229                                         end_trace();
230                                         break; /* all channel in use or reserverd */
231                                 }
232                                 trace_header("CHANNEL SELECTION (using 'any' channel)", DIRECTION_NONE);
233                                 add_trace("port", NULL, "%d", ifport->portnum);
234                                 add_trace("position", NULL, "%d", index);
235                                 end_trace();
236                                 *channel = CHANNEL_ANY;
237                                 break;
238
239                                 case CHANNEL_NO: /* call waiting */
240                                 trace_header("CHANNEL SELECTION (using 'no' channel, call-waiting)", DIRECTION_NONE);
241                                 add_trace("port", NULL, "%d", ifport->portnum);
242                                 add_trace("position", NULL, "%d", index);
243                                 end_trace();
244                                 *channel = CHANNEL_NO;
245                                 break;
246
247                                 default:
248                                 if (selchannel->channel<1 || selchannel->channel==16) {
249                                         trace_header("CHANNEL SELECTION (channel out of range)", DIRECTION_NONE);
250                                         add_trace("port", NULL, "%d", ifport->portnum);
251                                         add_trace("position", NULL, "%d", index);
252                                         add_trace("channel", NULL, "%d", selchannel->channel);
253                                         end_trace();
254                                         break; /* invalid channels */
255                                 }
256                                 i = selchannel->channel-1-(selchannel->channel>=17);
257                                 if (i >= mISDNport->b_num) {
258                                         trace_header("CHANNEL SELECTION (channel out of range)", DIRECTION_NONE);
259                                         add_trace("port", NULL, "%d", ifport->portnum);
260                                         add_trace("position", NULL, "%d", index);
261                                         add_trace("channel", NULL, "%d", selchannel->channel);
262                                         add_trace("channels", NULL, "%d", mISDNport->b_num);
263                                         end_trace();
264                                         break; /* channel not in port */
265                                 }
266                                 if (mISDNport->b_port[i] == NULL) {
267                                         *channel = selchannel->channel;
268                                         trace_header("CHANNEL SELECTION (selecting given channel)", DIRECTION_NONE);
269                                         add_trace("port", NULL, "%d", ifport->portnum);
270                                         add_trace("position", NULL, "%d", index);
271                                         add_trace("channel", NULL, "%d", *channel);
272                                         end_trace();
273                                         break;
274                                 }
275                                 break;
276                         }
277                         if (*channel)
278                                 break; /* found channel */
279                         selchannel = selchannel->next;
280                 }
281         }
282
283         /* if channel was found, return mISDNport and channel */
284         if (*channel) {
285                 /* setting next port to start next time */
286                 if (interface->hunt == HUNT_ROUNDROBIN) {
287                         index++;
288                         if (!ifport->next)
289                                 index = 0;
290                         interface->hunt_next = index;
291                 }
292                 
293                 return(mISDNport);
294         }
295
296         trace_header("CHANNEL SELECTION (skipping, no channel found)", DIRECTION_NONE);
297         add_trace("port", NULL, "%d", ifport->portnum);
298         add_trace("position", NULL, "%d", index);
299         end_trace();
300
301         portbusy:
302         /* go next port, until all ports are checked */
303         index++;
304         ifport = ifport->next;
305         if (!ifport) {
306                 index = 0;
307                 ifport = interface->ifport;
308         }
309         if (ifport != ifport_start)
310                 goto nextport;
311
312         if (!ifname) {
313                 interface = interface->next;
314                 goto checknext;
315         }
316
317         return(NULL); /* no port found */
318 }
319 #endif
320
321 /* hunts for the given interface
322  * it does not need to have an mISDNport instance */
323 struct interface *EndpointApp::hunt_interface(char *ifname)
324 {
325         struct interface *interface;
326         int there_is_an_external = 0;
327
328         interface = interface_first;
329
330         /* first find the given interface or, if not given, one with no extension */
331         checknext:
332         if (!interface) {
333                 if (!there_is_an_external && !(ifname && ifname[0])) {
334                         trace_header("CHANNEL SELECTION (no external interface specified)", DIRECTION_NONE);
335                         add_trace("info", NULL, "Add 'extern' parameter to interface.conf.");
336                         end_trace();
337                 }
338                 return(NULL);
339         }
340
341         /* check for given interface */
342         if (ifname && ifname[0]) {
343                 if (!strcasecmp(interface->name, ifname)) {
344                         /* found explicit interface */
345                         trace_header("CHANNEL SELECTION (found given interface)", DIRECTION_NONE);
346                         add_trace("interface", NULL, "%s", ifname);
347                         end_trace();
348                         goto foundif;
349                 }
350         } else {
351                 if (interface->external) {
352                         there_is_an_external = 1;
353                         /* found non extension */
354                         trace_header("CHANNEL SELECTION (found external interface)", DIRECTION_NONE);
355                         add_trace("interface", NULL, "%s", interface->name);
356                         end_trace();
357                         goto foundif;
358                 }
359         }
360
361         interface = interface->next;
362         goto checknext;
363 foundif:
364
365         return interface;
366 }
367
368 /* must be overloaded by specific app */
369 void EndpointApp::trace_header(const char *name, int direction)
370 {
371 }