Fixed chan_lcr unload bug, found by Patrick
[lcr.git] / remote.cpp
1 /*****************************************************************************\
2 **                                                                           **
3 ** LCR                                                                       **
4 **                                                                           **
5 **---------------------------------------------------------------------------**
6 ** Copyright: Andreas Eversberg                                              **
7 **                                                                           **
8 ** mISDN remote                                                              **
9 **                                                                           **
10 \*****************************************************************************/ 
11
12 #include "main.h"
13
14 unsigned int new_remote = 1000;
15
16 /*
17  * constructor
18  */
19 Premote::Premote(int type, struct mISDNport *mISDNport, char *portname, struct port_settings *settings, int channel, int exclusive, int mode, int remote_id) : PmISDN(type, mISDNport, portname, settings, channel, exclusive, mode)
20 {
21         union parameter param;
22
23         p_callerinfo.itype = (mISDNport->ifport->interface->extension)?INFO_ITYPE_ISDN_EXTENSION:INFO_ITYPE_ISDN;
24         p_m_r_ref = new_remote++;
25         SCPY(p_m_r_remote_app, mISDNport->ifport->remote_app);
26         p_m_r_handle = 0;
27
28         /* send new ref to remote socket */
29         memset(&param, 0, sizeof(union parameter));
30         if (type == PORT_TYPE_REMOTE_OUT)
31                 param.newref.direction = 1; /* new ref from lcr */
32         p_m_r_remote_id = remote_id;
33         if (admin_message_from_lcr(p_m_r_remote_id, p_m_r_ref, MESSAGE_NEWREF, &param) < 0)
34                 FATAL("No socket with remote application '%s' found, this shall not happen. because we already created one.\n", mISDNport->ifport->remote_app);
35
36         PDEBUG(DEBUG_GSM, "Created new RemotePort(%s).\n", portname);
37
38 }
39
40 /*
41  * destructor
42  */
43 Premote::~Premote()
44 {
45         /* need to remote (import) external channel from remote application */
46         if (p_m_r_handle) {
47                 message_bchannel_to_remote(p_m_r_remote_id, p_m_r_ref, BCHANNEL_REMOVE, p_m_r_handle, 0, 0, 0, 0, 0, 0, 1);
48                 chan_trace_header(p_m_mISDNport, this, "MESSAGE_BCHANNEL (to remote application)", DIRECTION_NONE);
49                 add_trace("type", NULL, "remove");
50                 add_trace("channel", NULL, "%d.%d", p_m_r_handle>>8, p_m_r_handle&0xff);
51                 end_trace();
52         }
53
54         PDEBUG(DEBUG_GSM, "Destroyed Remote process(%s).\n", p_name);
55
56 }
57
58 /*
59  * endpoint sends messages to the port
60  */
61 int Premote::message_epoint(unsigned int epoint_id, int message_type, union parameter *param)
62 {
63         struct lcr_msg *message;
64         int channel;
65         int ret;
66         struct epoint_list *epointlist;
67
68         if (PmISDN::message_epoint(epoint_id, message_type, param))
69                 return 1;
70
71         if (message_type == MESSAGE_SETUP) {
72                 ret = channel = hunt_bchannel();
73                 if (ret < 0)
74                         goto no_channel;
75                 /* open channel */
76                 ret = seize_bchannel(channel, 1);
77                 if (ret < 0) {
78                         no_channel:
79                         message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
80                         message->param.disconnectinfo.cause = 34;
81                         message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
82                         message_put(message);
83                         new_state(PORT_STATE_RELEASE);
84                         delete this;
85                         return 0;
86                 }
87                 bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_USE);
88
89                 /* attach only if not already */
90                 epointlist = p_epointlist;
91                 while(epointlist) {
92                         if (epointlist->epoint_id == epoint_id)
93                                 break;
94                         epointlist = epointlist->next;
95                 }
96                 if (!epointlist)
97                         epointlist_new(epoint_id);
98
99                 /* set context to pbx */
100                 SCPY(param->setup.context, "pbx");
101         }
102
103         /* look for Remote's interface */
104         if (admin_message_from_lcr(p_m_r_remote_id, p_m_r_ref, message_type, param)<0) {
105                 PERROR("No socket with remote application '%s' found, this shall not happen. Closing socket shall cause release of all remote ports.\n", p_m_mISDNport->ifport->remote_app);
106                 return 0;               
107         }
108
109         /* enable audio path */
110         if (message_type == MESSAGE_SETUP) {
111                 union parameter newparam;
112                 memset(&newparam, 0, sizeof(union parameter));
113                 admin_message_from_lcr(p_m_r_remote_id, p_m_r_ref, MESSAGE_PATTERN, &newparam);
114                 newparam.audiopath = 1;
115                 admin_message_from_lcr(p_m_r_remote_id, p_m_r_ref, MESSAGE_AUDIOPATH, &newparam);
116         }
117
118         if (message_type == MESSAGE_RELEASE) {
119                 new_state(PORT_STATE_RELEASE);
120                 delete this;
121                 return 0;
122         }
123
124         return 0;
125 }
126
127 void Premote::message_remote(int message_type, union parameter *param)
128 {
129         class Endpoint *epoint;
130         struct lcr_msg *message;
131         int channel;
132         int ret;
133
134         if (message_type == MESSAGE_SETUP) {
135                 /* enable audio path */
136                 union parameter newparam;
137                 memset(&newparam, 0, sizeof(union parameter));
138                 admin_message_from_lcr(p_m_r_remote_id, p_m_r_ref, MESSAGE_PATTERN, &newparam);
139                 newparam.audiopath = 1;
140                 admin_message_from_lcr(p_m_r_remote_id, p_m_r_ref, MESSAGE_AUDIOPATH, &newparam);
141
142                 /* set source interface */
143                 param->setup.callerinfo.itype = p_callerinfo.itype;
144                 param->setup.callerinfo.isdn_port = p_m_portnum;
145                 SCPY(param->setup.callerinfo.interface, p_m_mISDNport->ifport->interface->name);
146                 
147                 ret = channel = hunt_bchannel();
148                 if (ret < 0)
149                         goto no_channel;
150
151                 /* open channel */
152                 ret = seize_bchannel(channel, 1);
153                 if (ret < 0) {
154                         no_channel:
155                         message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_RELEASE);
156                         message->param.disconnectinfo.cause = 34;
157                         message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
158                         message_put(message);
159                         new_state(PORT_STATE_RELEASE);
160                         delete this;
161                         return;
162                 }
163                 bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_USE);
164
165                 /* create endpoint */
166                 if (p_epointlist)
167                         FATAL("Incoming call but already got an endpoint.\n");
168                 if (!(epoint = new Endpoint(p_serial, 0)))
169                         FATAL("No memory for Endpoint instance\n");
170                 epoint->ep_app = new_endpointapp(epoint, 0, p_m_mISDNport->ifport->interface->app); //incoming
171
172                 epointlist_new(epoint->ep_serial);
173         }
174
175         /* set serial on bchannel message
176          * also ref is given, so we send message with ref */
177         if (message_type == MESSAGE_BCHANNEL) {
178                 int i = p_m_b_index;
179                 unsigned int portid = (mISDNloop.port<<8) + i+1+(i>=15);
180                 switch (param->bchannel.type) {
181                 case BCHANNEL_REQUEST:
182                         p_m_r_handle = portid;
183                         message_bchannel_to_remote(p_m_r_remote_id, p_m_r_ref, BCHANNEL_ASSIGN, portid, 0, 0, 0, 0, 0, 0, 1);
184                         chan_trace_header(p_m_mISDNport, this, "MESSAGE_BCHANNEL (to remote application)", DIRECTION_NONE);
185                         add_trace("type", NULL, "assign");
186                         add_trace("channel", NULL, "%d.%d", portid>>8, portid&0xff);
187                         end_trace();
188                         break;
189                 case BCHANNEL_RELEASE:
190                         p_m_r_handle = 0;
191                         message_bchannel_to_remote(p_m_r_remote_id, p_m_r_ref, BCHANNEL_REMOVE, portid, 0, 0, 0, 0, 0, 0, 1);
192                         chan_trace_header(p_m_mISDNport, this, "MESSAGE_BCHANNEL (to remote application)", DIRECTION_NONE);
193                         add_trace("type", NULL, "remove");
194                         add_trace("channel", NULL, "%d.%d", portid>>8, portid&0xff);
195                         end_trace();
196                         break;
197                 }
198                 return;
199         }
200         
201         /* cannot just forward, because param is not of container "struct lcr_msg" */
202         message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, message_type);
203         memcpy(&message->param, param, sizeof(message->param));
204         message_put(message);
205
206         if (message_type == MESSAGE_RELEASE) {
207                 new_state(PORT_STATE_RELEASE);
208                 delete this;
209                 return;
210         }
211 }
212
213 /* select free bchannel from loopback interface */
214 int Premote::hunt_bchannel(void)
215 {
216         return loop_hunt_bchannel(this, p_m_mISDNport);
217 }
218
219
220