backup
[lcr.git] / h323.cpp
1 /*****************************************************************************\
2 **                                                                           **
3 ** PBX4Linux                                                                 **
4 **                                                                           **
5 **---------------------------------------------------------------------------**
6 ** Copyright: Andreas Eversberg                                              **
7 **                                                                           **
8 ** h323 port                                                                 **
9 **                                                                           **
10 \*****************************************************************************/ 
11
12 #include <stdio.h>
13 #include <string.h>
14 #include <stdlib.h>
15 #include <unistd.h>
16 #include <poll.h>
17 #include <errno.h>
18 #include <sys/ioctl.h>
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <fcntl.h>
22 #include "main.h"
23
24
25 /*
26  * initialize h323 port
27  */
28 H323Port::H323Port(int type, char *portname, struct port_settings *settings) : Port(type, portname, settings)
29 {
30         p_h323_channel_in = p_h323_channel_out = NULL;
31         p_h323_connect = NULL;
32
33         /* configure device */
34         switch (type)
35         {
36                 case PORT_TYPE_H323_IN:
37                 break;
38                 case PORT_TYPE_H323_OUT:
39                 SPRINT(p_name, "H323_outgoing_port_#%lu", p_serial);
40                 break;
41         }
42         if (options.law == 'u')
43         {
44         }
45 }
46
47
48 /*
49  * destructor
50  */
51 H323Port::~H323Port()
52 {
53 }
54
55
56 /*
57  * endpoint sends messages to the interface
58  */
59 int H323Port::message_epoint(unsigned long epoint_id, int message_id, union parameter *param)
60 {
61         H323Connection *connection;
62         H323Connection::CallEndReason h323_cause;
63         char name[sizeof(p_name)];
64
65         if (Port::message_epoint(epoint_id, message_id, param))
66                 return(1);
67
68         switch(message_id)
69         {
70                 case MESSAGE_mISDNSIGNAL: /* isdn command */
71                 PDEBUG(DEBUG_H323, "H323Port(%s) mISDN signal not supported.\n", p_name);
72                 break;
73
74                 case MESSAGE_INFORMATION: /* additional digits from endpoint */
75                 PDEBUG(DEBUG_H323, "H323Port(%s) h323 port with (caller id %s) received more digit information: '%s'\n", p_name, p_callerinfo.id, param->information.number);
76 /* queue to be done */
77                 if (p_state != PORT_STATE_OUT_OVERLAP)
78                 {
79                         PERROR("H323Port(%s) additinal digits are only possible in outgoing overlap state.\n", p_name);
80                         break;
81                 }
82                 if (strlen(param->information.number)>30)
83                 {
84                         PERROR("H323Port(%s) information string too long.\n", p_name);
85                         break;
86                 }
87                 SCAT((char *)p_dialinginfo.number, param->information.number);
88                 break;
89
90                 case MESSAGE_PROCEEDING: /* call of endpoint is proceeding */
91                 PDEBUG(DEBUG_H323, "H323Port(%s) h323 port with (caller id %s) received proceeding\n", p_name, p_callerinfo.id);
92                 if (p_state != PORT_STATE_IN_OVERLAP)
93                 {
94                         PERROR("H323Port(%s) proceeding command only possible in setup state.\n", p_name);
95                         break;
96                 }
97                 p_state = PORT_STATE_IN_PROCEEDING;
98                 break;
99
100                 case MESSAGE_ALERTING: /* call of endpoint is ringing */
101                 PDEBUG(DEBUG_H323, "H323Port(%s) h323 port with (caller id %s) received alerting\n", p_name, p_callerinfo.id);
102                 if (p_state != PORT_STATE_IN_OVERLAP
103                  && p_state != PORT_STATE_IN_PROCEEDING)
104                 {
105                         PERROR("H323Port(%s) alerting command only possible in setup or proceeding state.\n", p_name);
106                         break;
107                 }
108                 p_state = PORT_STATE_IN_ALERTING;
109                 UCPY(name, p_name);
110                 mutex_h323.Signal();
111                 connection = h323_ep->FindConnectionWithLock(name);
112                 if (connection)
113                 {
114                         if (options.h323_ringconnect && !p_callerinfo.intern[0])
115                         {
116                                 connection->AnsweringCall(H323Connection::AnswerCallNow);
117                                 p_state = PORT_STATE_CONNECT;
118                         } else
119                                 connection->AnsweringCall(H323Connection::AnswerCallPending);
120                         connection->Unlock();
121                 }
122                 mutex_h323.Wait();
123                 break;
124
125                 case MESSAGE_CONNECT: /* call of endpoint is connected */
126                 PDEBUG(DEBUG_H323, "H323Port(%s) h323 port with (caller id %s) received connect\n", p_name, p_callerinfo.id);
127                 if (p_state != PORT_STATE_IN_OVERLAP
128                  && p_state != PORT_STATE_IN_PROCEEDING
129                  && p_state != PORT_STATE_IN_ALERTING)
130                 {
131                         PDEBUG(DEBUG_H323, "H323Port(%s) connect command only possible in setup, proceeding or alerting state.\n", p_name);
132                         break;
133                 }
134                 new_state(PORT_STATE_CONNECT);
135                 /* copy connected information */
136                 memcpy(&p_connectinfo, &param->connectinfo, sizeof(p_connectinfo));
137                 p_connectinfo.itype = INFO_ITYPE_H323;
138                 UCPY(name, p_name);
139                 mutex_h323.Signal();
140                 connection = h323_ep->FindConnectionWithLock(name);
141                 if (connection)
142                 {
143                         int type, present, screen;
144                         PString connect_number;
145                         /* modify connectinfo (COLP) */
146                         if (p_connectinfo.present!=INFO_PRESENT_NULL)
147                         {
148                                 connect_number = p_connectinfo.id;
149                                 switch(p_connectinfo.ntype)
150                                 {
151                                         case INFO_NTYPE_SUBSCRIBER:
152                                         type = Q931::SubscriberType;
153                                         break;
154                                         case INFO_NTYPE_NATIONAL:
155                                         type = Q931::NationalType;
156                                         break;
157                                         case INFO_NTYPE_INTERNATIONAL:
158                                         type = Q931::InternationalType;
159                                         break;
160                                         default: /* INFO_TYPE_UNKNOWN */
161                                         type = Q931::UnknownType;
162                                 }
163                                 switch(p_connectinfo.present)
164                                 {
165                                         case INFO_PRESENT_RESTRICTED:
166                                         present = 1;
167                                         break;
168                                         case INFO_PRESENT_NOTAVAIL:
169                                         present = 2;
170                                         break;
171                                         default: /* INFO_PRESENT_ALLOWED */
172                                         present = 0;
173                                 }
174                                 switch(p_connectinfo.screen)
175                                 {
176                                         case INFO_SCREEN_USER:
177                                         screen = 0;
178                                         break;
179                                         default: /* INFO_SCREEN_NETWORK */
180                                         screen = 3;
181                                 }
182 #if 0
183                                 if (p_h323_connect)
184                                 {
185 //PDEBUG(DEBUG_H323, "DDDEBUG: number %s, type=%d, present %d, screen %d\n", p_connectinfo.id, type, present, screen);
186                                         ((Q931 *)p_h323_connect)->SetConnectedNumber(connect_number, Q931::ISDNPlan, type, present, screen);
187                                 }
188                                 else
189                                         PERROR("missing p_h323_connect\n");
190 #endif
191                         }
192
193                         connection->AnsweringCall(H323Connection::AnswerCallNow);
194                         connection->Unlock();
195                 }
196                 mutex_h323.Wait();
197                 break;
198
199                 case MESSAGE_DISCONNECT: /* call has been disconnected */
200 #if 0
201                 PDEBUG(DEBUG_H323, "H323Port(%s) h323 port with (caller id %s) received disconnect cause=%d\n", p_name, p_callerinfo.id, param->disconnectinfo.cause);
202                 /* we just play what we hear from the remote site */
203                 if (p_state == PORT_STATE_IN_OVERLAP
204                  || p_state == PORT_STATE_IN_PROCEEDING)
205                 {
206                         /* copy connected information */
207                         memcpy(&p_connectinfo, &param->connectinfo, sizeof(p_connectinfo));
208                         UCPY(name, p_name);
209                         mutex_h323.Signal();
210                         connection = h323_ep->FindConnectionWithLock(name);
211                         if (connection)
212                         {
213                                 connection->AnsweringCall(H323Connection::AnswerCallNow);
214                                 connection->Unlock();
215                         }
216                         mutex_h323.Wait();
217                 }
218                 new_state(PORT_STATE_DISCONNECT);
219                 break;
220 #endif
221
222                 case MESSAGE_RELEASE: /* release h323 port */
223                 PDEBUG(DEBUG_H323, "H323Port(%s) h323 port with (caller id %s) received disconnect cause=%d\n", p_name, p_callerinfo.id, param->disconnectinfo.cause);
224                 if (p_state != PORT_STATE_IN_OVERLAP
225                  && p_state != PORT_STATE_IN_PROCEEDING
226                  && p_state != PORT_STATE_IN_ALERTING
227                  && p_state != PORT_STATE_OUT_SETUP
228                  && p_state != PORT_STATE_OUT_OVERLAP
229                  && p_state != PORT_STATE_OUT_PROCEEDING
230                  && p_state != PORT_STATE_OUT_ALERTING
231                  && p_state != PORT_STATE_CONNECT)
232                 {
233                         PERROR("H323Port(%s) disconnect command only possible in setup, proceeding, alerting or connect state.\n", p_name);
234                         break;
235                 }
236
237                 switch(param->disconnectinfo.cause)
238                 {
239                         case 1:
240                         h323_cause = H323Connection::EndedByNoUser;
241                         break;
242
243                         case 2:
244                         case 3:
245                         case 5:
246                         h323_cause = H323Connection::EndedByUnreachable;
247                         break;
248
249                         case 17:
250                         h323_cause = H323Connection::EndedByRemoteBusy;
251                         break;
252         
253                         case 18:
254                         h323_cause = H323Connection::EndedByNoEndPoint;
255                         break;
256         
257                         case 19:
258                         h323_cause = H323Connection::EndedByNoAnswer;
259                         break;
260         
261                         case 21:
262                         h323_cause = H323Connection::EndedByRefusal;
263                         break;
264         
265                         case 27:
266                         h323_cause = H323Connection::EndedByHostOffline;
267                         break;
268         
269                         case 47:
270                         h323_cause = H323Connection::EndedByConnectFail;
271                         break;
272         
273                         case 65:
274                         h323_cause = H323Connection::EndedByCapabilityExchange;
275                         break;
276         
277                         case 42:
278                         h323_cause = H323Connection::EndedByRemoteCongestion;
279                         break;
280         
281                         case 41:
282                         h323_cause = H323Connection::EndedByTemporaryFailure;
283                         break;
284         
285                         default:
286                         h323_cause = H323Connection::EndedByRemoteUser;
287                         break;
288                 }
289                 UCPY(name, p_name);
290                 mutex_h323.Signal();
291                 h323_ep->ClearCall(name, h323_cause);
292                 mutex_h323.Wait();
293
294                 delete this;
295                 break;
296
297                 case MESSAGE_SETUP: /* dial-out command received from epoint */
298                 PDEBUG(DEBUG_H323, "H323Port(%s) h323 port received setup from '%s' to '%s'\n", p_name, param->setup.callerinfo.id, param->setup.dialinginfo.number);
299                 if (p_type!=PORT_TYPE_H323_OUT)
300                 {
301                         PERROR("H323Port(%s) cannot dial because h323 port not of outgoing type.\n", p_name);
302                         break;
303                 }
304                 if (p_state != PORT_STATE_IDLE)
305                 {
306                         PERROR("H323Port(%s) error: dialing command only possible in idle state.\n", p_name);
307                         break;
308                 }
309
310                 /* link relation */
311                 if (p_epointlist)
312                 {
313                         PERROR("H323Port(%s) software error: epoint pointer is set in idle state, how bad!! exitting.\n", p_name);
314                         exit(-1);
315                 }
316                 if (!(epointlist_new(epoint_id)))
317                 {
318                         PERROR("no memory for epointlist\n");
319                         exit(-1);
320                 }
321
322                 /* copy setup infos to port */
323                 memcpy(&p_callerinfo, &param->setup.callerinfo, sizeof(p_callerinfo));
324                 memcpy(&p_dialinginfo, &param->setup.dialinginfo, sizeof(p_dialinginfo));
325                 memcpy(&p_capainfo, &param->setup.capainfo, sizeof(p_capainfo));
326                 memcpy(&p_redirinfo, &param->setup.redirinfo, sizeof(p_redirinfo));
327
328                 p_state = PORT_STATE_OUT_SETUP;
329
330                 UCPY(name, p_name);
331                 mutex_h323.Signal();
332                 h323_ep->Call(name, param->setup.callerinfo.id, param->setup.dialinginfo.number);
333                 mutex_h323.Wait();
334                 break;
335
336                 default:
337                 PDEBUG(DEBUG_H323, "H323Port(%s) h323 port with (caller id %s) received an unsupported message: %d\n", p_name, p_callerinfo.id, message_id);
338         }
339
340         return(1);
341 }
342
343