Fixed 'earlyb' handling
[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 /* hunts for the given interface
82  * it does not need to have an mISDNport instance */
83 struct interface *EndpointAppBridge::hunt_interface(char *ifname)
84 {
85         struct interface *interface;
86         int there_is_an_external = 0;
87
88         interface = interface_first;
89
90         /* first find the given interface or, if not given, one with no extension */
91         checknext:
92         if (!interface) {
93                 if (!there_is_an_external && !(ifname && ifname[0])) {
94                         trace_header("CHANNEL SELECTION (no external interface specified)", DIRECTION_NONE);
95                         add_trace("info", NULL, "Add 'extern' parameter to interface.conf.");
96                         end_trace();
97                 }
98                 return(NULL);
99         }
100
101         /* check for given interface */
102         if (ifname && ifname[0]) {
103                 if (!strcasecmp(interface->name, ifname)) {
104                         /* found explicit interface */
105                         trace_header("CHANNEL SELECTION (found given interface)", DIRECTION_NONE);
106                         add_trace("interface", NULL, "%s", ifname);
107                         end_trace();
108                         goto foundif;
109                 }
110
111         } else {
112                 if (interface->external) {
113                         there_is_an_external = 1;
114                         /* found non extension */
115                         trace_header("CHANNEL SELECTION (found external interface)", DIRECTION_NONE);
116                         add_trace("interface", NULL, "%s", interface->name);
117                         end_trace();
118                         goto foundif;
119                 }
120         }
121
122         interface = interface->next;
123         goto checknext;
124 foundif:
125
126         return interface;
127 }
128
129
130 /* port MESSAGE_SETUP */
131 void EndpointAppBridge::port_setup(struct port_list *portlist, int message_type, union parameter *param)
132 {
133         struct interface *interface_in = interface_first;
134         struct interface *interface_out = interface_first;
135         struct port_settings    port_settings;
136         class Port              *port = NULL;
137         struct lcr_msg *message;
138         unsigned int bridge_id;
139         unsigned int source_port_id = portlist->port_id;
140         char portname[64];
141
142         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);
143
144         if (!ea_endpoint->ep_portlist) {
145                 PERROR("Endpoint has no port in portlist\n");
146                 return;
147         }
148         if (ea_endpoint->ep_portlist->next) {
149                 PDEBUG(DEBUG_EPOINT, "Endpoint already received setup, ignoring.\n");
150                 return;
151         }
152
153         while (interface_in) {
154                 if (!strcmp(interface_in->name, param->setup.callerinfo.interface))
155                         break;
156                 interface_in = interface_in->next;
157         }
158         if (!interface_in) {
159 fail:
160                 PERROR("Cannot find source interface %s.\n", param->setup.callerinfo.interface);
161                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
162                 message->param.disconnectinfo.cause = 47;
163                 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
164                 message_put(message);
165
166                 /* destroy endpoint */
167                 ea_endpoint->ep_use = 0;
168                 trigger_work(&ea_endpoint->ep_delete);
169                 return;
170         }
171
172         while (interface_out) {
173                 if (!strcmp(interface_out->name, interface_in->bridge_if))
174                         break;
175                 interface_out = interface_out->next;
176         }
177         if (!interface_out) {
178                 PERROR("Cannot find destination interface %s.\n", interface_in->bridge_if);
179                 goto fail;
180                 return;
181         }
182
183         /* create port for interface */
184         SPRINT(portname, "%s-%d-out", interface_out->name, 0);
185         memset(&port_settings, 0, sizeof(port_settings));
186 #ifdef WITH_SIP
187         if (interface_out->sip) {
188                 port = new Psip(PORT_TYPE_SIP_OUT, portname, &port_settings, interface_out);
189         }
190 #endif
191 #ifdef WITH_GSM_BS
192         if (interface_out->gsm_bs) {
193                 port = new Pgsm_bs(PORT_TYPE_GSM_BS_OUT, portname, &port_settings, interface_out);
194         }
195 #endif
196 #ifdef WITH_GSM_MS
197         if (interface_out->gsm_ms) {
198                 port = new Pgsm_bs(PORT_TYPE_GSM_MS_OUT, portname, &port_settings, interface_out);
199         }
200 #endif
201         if (!port)
202                 FATAL("Remote interface, but not supported???\n");
203         portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, interface_out->is_earlyb == IS_YES);
204         if (!portlist)
205                 FATAL("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
206         /* forward setup */
207         message_forward(ea_endpoint->ep_serial, port->p_serial, EPOINT_TO_PORT, param);  
208
209         /* apply bridge to interfaces */
210         /* FIXME: use mISDN bridge for mISDN ports */
211         bridge_id = join_serial++;
212         message = message_create(ea_endpoint->ep_serial, source_port_id, EPOINT_TO_PORT, MESSAGE_BRIDGE);
213         message->param.bridge_id = bridge_id;
214         message_put(message);
215         message = message_create(ea_endpoint->ep_serial, port->p_serial, EPOINT_TO_PORT, MESSAGE_BRIDGE);
216         message->param.bridge_id = bridge_id;
217         message_put(message);
218 }
219
220 /* port MESSAGE_RELEASE */
221 void EndpointAppBridge::port_release(struct port_list *portlist, int message_type, union parameter *param)
222 {
223         unsigned int remote;
224
225         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint received release from port\n");
226
227         if (!ea_endpoint->ep_portlist || !ea_endpoint->ep_portlist->next)
228                 goto out;
229         if (ea_endpoint->ep_portlist->port_id == portlist->port_id)
230                 remote = ea_endpoint->ep_portlist->next->port_id;
231         else
232                 remote = ea_endpoint->ep_portlist->port_id;
233         /* forward release */
234         message_forward(ea_endpoint->ep_serial, remote, EPOINT_TO_PORT, param);  
235
236 out:
237         /* destroy endpoint */
238         ea_endpoint->ep_use = 0;
239         trigger_work(&ea_endpoint->ep_delete);
240 }
241
242 /* port other messages */
243 void EndpointAppBridge::port_other(struct port_list *portlist, int message_type, union parameter *param)
244 {
245         unsigned int remote;
246
247         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint received message %d from port\n", message_type);
248
249         if (!ea_endpoint->ep_portlist || !ea_endpoint->ep_portlist->next)
250                 return;
251         if (ea_endpoint->ep_portlist->port_id == portlist->port_id)
252                 remote = ea_endpoint->ep_portlist->next->port_id;
253         else
254                 remote = ea_endpoint->ep_portlist->port_id;
255         /* forward release */
256         message_forward(ea_endpoint->ep_serial, remote, EPOINT_TO_PORT, param);  
257 }
258
259 /* port sends message to the endpoint
260  */
261 void EndpointAppBridge::ea_message_port(unsigned int port_id, int message_type, union parameter *param)
262 {
263         struct port_list *portlist;
264
265         portlist = ea_endpoint->ep_portlist;
266         while(portlist) {
267                 if (port_id == portlist->port_id)
268                         break;
269                 portlist = portlist->next;
270         }
271         if (!portlist) {
272                 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);
273                 return;
274         }
275
276 //      PDEBUG(DEBUG_EPOINT, "received message %d (terminal %s, caller id %s)\n", message, e_ext.number, e_callerinfo.id);
277         switch(message_type) {
278                 /* PORT sends SETUP message */
279                 case MESSAGE_SETUP:
280                 port_setup(portlist, message_type, param);
281                 break;
282
283                 /* PORT sends RELEASE message */
284                 case MESSAGE_RELEASE:
285                 port_release(portlist, message_type, param);
286                 break;
287
288                 default:
289                 port_other(portlist, message_type, param);
290         }
291
292         /* Note: this endpoint may be destroyed, so we MUST return */
293 }
294