Fix: Disable DTMF dialing after first received KP (pulse) digit
[lcr.git] / appbridge.cpp
1 /*****************************************************************************\
2 **                                                                           **
3 ** Linux Call Router                                                         **
4 **                                                                           **
5 **---------------------------------------------------------------------------**
6 ** Copyright: Andreas Eversberg                                              **
7 **                                                                           **
8 ** The EndpointAppBridge implements direct bridge between interfaces         **
9 **                                                                           **
10 \*****************************************************************************/ 
11
12
13 #include "main.h"
14
15 class EndpointAppBridge *appbridge_first = NULL;
16
17 /*
18  * EndpointAppBridge constructor
19  */
20 EndpointAppBridge::EndpointAppBridge(class Endpoint *epoint, int origin) : EndpointApp(epoint, origin, EAPP_TYPE_BRIDGE)
21 {
22         class EndpointAppBridge **apppointer;
23
24         /* add application to chain */
25         next = NULL;
26         apppointer = &appbridge_first;
27         while(*apppointer)
28                 apppointer = &((*apppointer)->next);
29         *apppointer = this;
30
31         PDEBUG(DEBUG_EPOINT, "Bridge endpoint created\n");
32 }
33
34 /*
35  * EpointAppBridge destructor
36  */
37 EndpointAppBridge::~EndpointAppBridge(void)
38 {
39         class EndpointAppBridge *temp, **tempp;
40
41         /* detach */
42         temp =appbridge_first;
43         tempp = &appbridge_first;
44         while(temp) {
45                 if (temp == this)
46                         break;
47
48                 tempp = &temp->next;
49                 temp = temp->next;
50         }
51         if (temp == 0)
52                 FATAL("Endpoint not in endpoint's list.\n");
53         *tempp = next;
54
55         PDEBUG(DEBUG_EPOINT, "Bridge endpoint destroyed\n");
56 }
57
58
59 /*
60  * trace header for application
61  */
62 void EndpointAppBridge::trace_header(const char *name, int direction)
63 {
64         struct trace _trace;
65
66         char msgtext[sizeof(_trace.name)];
67
68         SCPY(msgtext, name);
69
70         /* init trace with given values */
71         start_trace(-1,
72                     NULL,
73                     "", //numberrize_callerinfo(e_callerinfo.id, e_callerinfo.ntype, options.national, options.international),
74                     "", // e_dialinginfo.id,
75                     direction,
76                     CATEGORY_EP,
77                     ea_endpoint->ep_serial,
78                     msgtext);
79 }
80
81 /* port MESSAGE_SETUP */
82 void EndpointAppBridge::port_setup(struct port_list *portlist, int message_type, union parameter *param)
83 {
84         struct interface *interface_in = interface_first;
85         struct interface *interface_out = interface_first;
86         struct port_settings    port_settings;
87         class Port              *port = NULL;
88         struct lcr_msg *message;
89         unsigned int bridge_id;
90         unsigned int source_port_id = portlist->port_id;
91         char portname[64];
92         int cause = 47;
93
94         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);
95
96         if (!ea_endpoint->ep_portlist) {
97                 PERROR("Endpoint has no port in portlist\n");
98                 return;
99         }
100         if (ea_endpoint->ep_portlist->next) {
101                 PDEBUG(DEBUG_EPOINT, "Endpoint already received setup, ignoring.\n");
102                 return;
103         }
104
105         while (interface_in) {
106                 if (!strcmp(interface_in->name, param->setup.callerinfo.interface))
107                         break;
108                 interface_in = interface_in->next;
109         }
110         if (!interface_in) {
111                 PERROR("Cannot find source interface %s.\n", param->setup.callerinfo.interface);
112 fail:
113                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
114                 message->param.disconnectinfo.cause = cause;
115                 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
116                 message_put(message);
117                 ea_endpoint->free_portlist(portlist);
118
119                 /* destroy endpoint */
120                 ea_endpoint->ep_use = 0;
121                 trigger_work(&ea_endpoint->ep_delete);
122                 return;
123         }
124
125         while (interface_out) {
126                 if (!strcmp(interface_out->name, interface_in->bridge_if))
127                         break;
128                 interface_out = interface_out->next;
129         }
130         if (!interface_out) {
131                 PERROR("Cannot find destination interface %s.\n", interface_in->bridge_if);
132                 goto fail;
133                 return;
134         }
135
136         /* create port for interface */
137         SPRINT(portname, "%s-%d-out", interface_out->name, 0);
138         memset(&port_settings, 0, sizeof(port_settings));
139 #ifdef WITH_MISDN
140         if (interface_out->remote) {
141                 struct admin_list       *admin;
142                 admin = admin_first;
143                 while(admin) {
144                         if (admin->remote_name[0] && !strcmp(admin->remote_name, interface_out->remote_app))
145                                 break;
146                         admin = admin->next;
147                 }
148                 if (!admin) {
149                         trace_header("INTERFACE (remote not connected)", DIRECTION_NONE);
150                         add_trace("application", NULL, "%s", interface_out->remote_app);
151                         end_trace();
152                         goto fail;
153                 }
154                 port = new Premote(PORT_TYPE_REMOTE_OUT, portname, &port_settings, interface_out, admin->sock);
155         } else
156 #endif
157 #ifdef WITH_SIP
158         if (interface_out->sip) {
159                 port = new Psip(PORT_TYPE_SIP_OUT, portname, &port_settings, interface_out);
160         } else
161 #endif
162 #ifdef WITH_GSM_BS
163         if (interface_out->gsm_bs) {
164                 port = new Pgsm_bs(PORT_TYPE_GSM_BS_OUT, portname, &port_settings, interface_out);
165         } else
166 #endif
167 #ifdef WITH_GSM_MS
168         if (interface_out->gsm_ms) {
169                 port = new Pgsm_ms(PORT_TYPE_GSM_MS_OUT, portname, &port_settings, interface_out);
170         } else
171 #endif
172         {
173                 char *ifname = interface_out->name;
174 #ifdef WITH_MISDN
175                 struct mISDNport *mISDNport;
176                 int channel = 0;
177                 int earlyb;
178                 int mode = B_MODE_TRANSPARENT;
179
180                 /* hunt for mISDNport and create Port */
181                 mISDNport = hunt_port(ifname, &channel);
182                 if (!mISDNport) {
183                         trace_header("INTERFACE (busy)", DIRECTION_NONE);
184                         add_trace("interface", NULL, "%s", ifname);
185                         end_trace();
186                         cause = 33;
187                         goto fail;
188                 }
189
190                 SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
191 #ifdef WITH_SS5
192                 if (mISDNport->ss5)
193                         port = ss5_hunt_line(mISDNport);
194                 else
195 #endif
196                 earlyb = mISDNport->earlyb;
197 #ifdef ISDN_P_FXS_POTS
198                 if (mISDNport->pots)
199                         port = new Pfxs(PORT_TYPE_POTS_FXS_OUT, mISDNport, portname, &port_settings, mISDNport->ifport->interface, mode);
200                 else
201 #endif
202                         port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, mISDNport->ifport->interface, channel, mISDNport->ifport->channel_force, mode);
203 #else
204                 trace_header("INTERFACE (has no function)", DIRECTION_NONE);
205                 add_trace("interface", NULL, "%s", ifname);
206                 end_trace();
207                 cause = 31;
208                 goto fail;
209 #endif
210         }
211         if (!port)
212                 FATAL("Remote interface, but not supported???\n");
213         portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, interface_out->is_earlyb == IS_YES);
214         if (!portlist)
215                 FATAL("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
216         /* forward setup */
217         message_forward(ea_endpoint->ep_serial, port->p_serial, EPOINT_TO_PORT, param);  
218
219         /* apply bridge to interfaces */
220         /* FIXME: use mISDN bridge for mISDN ports */
221         bridge_id = join_serial++;
222         message = message_create(ea_endpoint->ep_serial, source_port_id, EPOINT_TO_PORT, MESSAGE_BRIDGE);
223         message->param.bridge_id = bridge_id;
224         message_put(message);
225         message = message_create(ea_endpoint->ep_serial, port->p_serial, EPOINT_TO_PORT, MESSAGE_BRIDGE);
226         message->param.bridge_id = bridge_id;
227         message_put(message);
228 }
229
230 /* port MESSAGE_RELEASE */
231 void EndpointAppBridge::port_release(struct port_list *portlist, int message_type, union parameter *param)
232 {
233         struct port_list *remote;
234
235         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint received release from port\n");
236
237         if (!ea_endpoint->ep_portlist || !ea_endpoint->ep_portlist->next)
238                 goto out;
239         if (ea_endpoint->ep_portlist->port_id == portlist->port_id)
240                 remote = ea_endpoint->ep_portlist->next;
241         else
242                 remote = ea_endpoint->ep_portlist;
243         /* forward release */
244         message_forward(ea_endpoint->ep_serial, remote->port_id, EPOINT_TO_PORT, param);  
245
246         /* remove relations to in and out port */
247         ea_endpoint->free_portlist(portlist);
248         ea_endpoint->free_portlist(remote);
249
250 out:
251         /* destroy endpoint */
252         ea_endpoint->ep_use = 0;
253         trigger_work(&ea_endpoint->ep_delete);
254 }
255
256 /* port other messages */
257 void EndpointAppBridge::port_other(struct port_list *portlist, int message_type, union parameter *param)
258 {
259         unsigned int remote;
260
261         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint received message %d from port\n", message_type);
262
263         if (!ea_endpoint->ep_portlist || !ea_endpoint->ep_portlist->next)
264                 return;
265         if (ea_endpoint->ep_portlist->port_id == portlist->port_id)
266                 remote = ea_endpoint->ep_portlist->next->port_id;
267         else
268                 remote = ea_endpoint->ep_portlist->port_id;
269         /* forward release */
270         message_forward(ea_endpoint->ep_serial, remote, EPOINT_TO_PORT, param);  
271 }
272
273 /* port sends message to the endpoint
274  */
275 void EndpointAppBridge::ea_message_port(unsigned int port_id, int message_type, union parameter *param)
276 {
277         struct port_list *portlist;
278
279         portlist = ea_endpoint->ep_portlist;
280         while(portlist) {
281                 if (port_id == portlist->port_id)
282                         break;
283                 portlist = portlist->next;
284         }
285         if (!portlist) {
286                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) warning: port is not related to this endpoint. This may happen, if port has been released after the message was created.\n", ea_endpoint->ep_serial);
287                 return;
288         }
289
290 //      PDEBUG(DEBUG_EPOINT, "received message %d (terminal %s, caller id %s)\n", message, e_ext.number, e_callerinfo.id);
291         switch(message_type) {
292                 /* PORT sends SETUP message */
293                 case MESSAGE_SETUP:
294                 port_setup(portlist, message_type, param);
295                 break;
296
297                 /* PORT sends RELEASE message */
298                 case MESSAGE_RELEASE:
299                 port_release(portlist, message_type, param);
300                 break;
301
302                 default:
303                 port_other(portlist, message_type, param);
304         }
305
306         /* Note: this endpoint may be destroyed, so we MUST return */
307 }
308