backup
[lcr.git] / h323_ep.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 //                                                                           //
3 // PBX4Linux                                                                 //
4 //                                                                           //
5 //---------------------------------------------------------------------------//
6 // Copyright: Andreas Eversberg                                              //
7 //                                                                           //
8 // h323_ep class                                                             //
9 //                                                                           //
10 ///////////////////////////////////////////////////////////////////////////////
11
12 /*
13  NOTE:
14
15  The code was inspired by the isdn2h323 gateway my marco bode.
16  Thanx to marco budde for lerarning to program h323 and c++ from your code.
17  His homepage is www.telos.de, there you'll find the isdn2h323 gateway.
18
19  Also thanx to others who write documents and applications for OpenH323.
20
21  Andreas Eversberg
22 */
23
24 #include <stdio.h>
25 #include <sys/types.h>
26 #include <unistd.h>
27 #include "main.h"
28
29 //#include <gsmcodec.h>
30 //#include <g7231codec.h>
31 //#include <g729codec.h>
32 //#include "g726codec.h"
33 //#include <speexcodec.h>
34
35 #include <cstdio>
36 #include <cstdlib>
37 #include <cstring>
38
39 //
40 // constructor
41 //
42 H323_ep::H323_ep(void)
43 {
44         terminalType = e_GatewayOnly;
45
46         PDEBUG(DEBUG_H323, "H323 endpoint  constuctor\n");
47 }
48
49 //
50 // destructor
51 //
52 H323_ep::~H323_ep()
53 {
54         // clear all calls to remote endpoints  
55         ClearAllCalls();
56
57         PDEBUG(DEBUG_H323, "H323 endpoint  destuctor\n");
58 }
59
60
61 //
62 // create connection
63 //
64 H323Connection *H323_ep::CreateConnection(unsigned callReference)
65 {
66         PDEBUG(DEBUG_H323, "H323 endpoint  create connection\n");
67
68         return new H323_con(*this, callReference);
69 }    
70
71
72 //
73 // on establishment of conneciton
74 //
75 void H323_ep::OnConnectionEstablished(H323Connection &connection, const PString &token)
76 {
77         const unsigned char *token_string = token;
78
79         PDEBUG(DEBUG_H323, "H323 endpoint  connection established to: %s\n", token_string);
80
81         H323EndPoint::OnConnectionEstablished(connection, token);
82 }
83
84 //
85 // on remote alerting
86 //
87 BOOL H323_ep::OnAlerting(H323Connection &connection, const H323SignalPDU &alertingPDU, const PString &user)
88 {
89         class H323Port *port;
90         const unsigned char *token_string = connection.GetCallToken();
91         const unsigned char *user_string = user;
92         struct message *message;
93
94         PDEBUG(DEBUG_H323, "H323 endpoint  alerting at: %s\n", user_string);
95
96         mutex_h323.Wait();
97
98         if (!(port=(class H323Port *)find_port_with_token((char *)token_string)))
99         {
100                 PERROR("cannot find port with token '%s'\n", token_string);
101                 mutex_h323.Signal();
102                 return FALSE;
103         }
104         if (port->p_state==PORT_STATE_OUT_SETUP
105          || port->p_state==PORT_STATE_OUT_OVERLAP
106          || port->p_state==PORT_STATE_OUT_PROCEEDING)
107         {
108                 port->new_state(PORT_STATE_OUT_ALERTING);
109                 message = message_create(port->p_serial, ACTIVE_EPOINT(port->p_epointlist), PORT_TO_EPOINT, MESSAGE_ALERTING);
110                 message_put(message);
111         }
112
113         mutex_h323.Signal();
114
115         return TRUE;
116 }
117
118
119 //
120 // on clearing of connection
121 //
122 void H323_ep::OnConnectionCleared(H323Connection &connection, const PString &token)
123 {
124         int cause;
125         class H323Port *port;
126         const unsigned char *token_string = token;
127         struct message *message;
128
129         PDEBUG(DEBUG_H323, "H323 endpoint  connection cleared.\n");
130
131         mutex_h323.Wait();
132
133         if (!(port=(class H323Port *)find_port_with_token((char *)token_string)))
134         {
135                 PERROR("cannot find port with token '%s'\n", token_string);
136                 mutex_h323.Signal();
137                 return;
138         }
139
140         switch(connection.GetCallEndReason())
141         {
142                 case H323Connection::EndedByRemoteUser:
143                 case H323Connection::EndedByCallerAbort:
144                 case H323Connection::EndedByGatekeeper:
145                 case H323Connection::EndedByCallForwarded:
146                 cause = 16; // normal call clearing
147                 break;
148                 
149                 case H323Connection::EndedByRefusal:
150                 case H323Connection::EndedBySecurityDenial:
151                 cause = 21; // call rejected
152                 break;
153                 
154                 case H323Connection::EndedByNoAnswer:
155                 cause = 19; // no answer from user
156                 break;
157                 
158                 case H323Connection::EndedByTransportFail:
159                 cause = 47; // resource unavaiable, unspecified
160                 break;
161                 
162                 case H323Connection::EndedByNoBandwidth:
163                 cause = 49; // quality of service not available
164                 break;
165                 
166                 case H323Connection::EndedByNoUser:
167                 cause = 1; // unallocated number
168                 break;
169                 
170                 case H323Connection::EndedByCapabilityExchange:
171                 cause = 65; // bearer capability not implemented
172                 break;
173                 
174                 case H323Connection::EndedByRemoteBusy:
175                 cause = 17; // user busy
176                 break;
177                 
178                 case H323Connection::EndedByRemoteCongestion:
179                 cause = 42; // switching equipment congestion
180                 break;
181                 
182                 case H323Connection::EndedByUnreachable:
183                 cause = 2; // no route ...
184                 break;
185
186                 case H323Connection::EndedByNoEndPoint:
187                 case H323Connection::EndedByConnectFail:
188                 cause = 18; // no user responding
189                 break;
190                 
191                 case H323Connection::EndedByHostOffline:
192                 cause = 27; // destination out of order
193                 break;
194                 
195                 case H323Connection::EndedByTemporaryFailure:
196                 cause = 41; // temporary failure
197                 break;
198                 
199                 default:
200                 cause = 31; // normal, unspecified
201                 break;
202                 
203         }
204
205         // delete channels
206         if (port->p_h323_channel_in)
207                 delete port->p_h323_channel_in;
208         port->p_h323_channel_in = NULL;
209         if (port->p_h323_channel_out)
210                 delete port->p_h323_channel_out;
211         port->p_h323_channel_out = NULL;
212
213         /* release endpoint */
214         message = message_create(port->p_serial, ACTIVE_EPOINT(port->p_epointlist), PORT_TO_EPOINT, MESSAGE_RELEASE);
215         message->param.disconnectinfo.cause = cause;
216         message->param.disconnectinfo.location = LOCATION_BEYOND;
217         message_put(message);
218
219         /* delete port */
220         delete port;
221
222         mutex_h323.Signal();
223 }
224
225
226 //
227 // open audio channel
228 //
229 BOOL H323_ep::OpenAudioChannel(H323Connection &connection, BOOL isEncoding, unsigned bufferSize, H323AudioCodec &codec)
230 {
231         H323_chan *channel;
232         class H323Port *port;
233         const unsigned char *token_string = connection.GetCallToken();
234
235         PDEBUG(DEBUG_H323, "H323 endpoint  audio channel open (isEndcoding=%d).\n", isEncoding);
236
237         // disable the silence detection
238         codec.SetSilenceDetectionMode (H323AudioCodec::NoSilenceDetection); 
239
240         // create channels
241         if (isEncoding)
242         {
243                 channel = new H323_chan(connection.GetCallToken(), TRUE);
244         } else
245         {
246                 channel = new H323_chan(connection.GetCallToken(), FALSE);
247         }
248         if (!channel)
249         {
250                 PERROR("channel for token '%s' not set", token_string);
251                 return FALSE;
252         }
253
254         // return the channel object
255         mutex_h323.Wait();
256         if (!(port=(class H323Port *)find_port_with_token((char *)token_string)))
257         {
258                 PERROR("cannot find port with token '%s'\n", token_string);
259                 mutex_h323.Signal();
260                 return FALSE;
261         }
262
263         // set channels
264         if (isEncoding)
265         {
266                 port->p_h323_channel_out = channel;
267         } else
268         {
269                 port->p_h323_channel_in = channel;
270         }
271
272         mutex_h323.Signal();
273         return codec.AttachChannel(channel, FALSE);
274 }
275
276
277 //
278 // open video channel
279 //
280 BOOL H323_ep::OpenVideoChannel(H323Connection &connection, BOOL isEncoding, H323VideoCodec &codec)
281 {
282         PDEBUG(DEBUG_H323, "H323 endpoint  video channel open (isEndcoding=%d).\n", isEncoding);
283
284
285         return FALSE;
286 }
287
288
289 //
290 // initialize H323 endpoint
291 //
292 BOOL H323_ep::Init(void)
293 {
294         H323ListenerTCP  *listener;
295         int pri;
296
297         PDEBUG(DEBUG_H323, "H323 endpoint  initialize\n");
298
299         // add keypad capability
300         H323_UserInputCapability::AddAllCapabilities(capabilities, 0, P_MAX_INDEX);
301
302         /* will add codec in order of priority 1 = highest, 0 = don't use */ 
303         pri = 1;
304         while (pri < 256)
305         {
306 #warning codecs are temporarily disabled due to api change
307 #if 0
308                 if (options.h323_gsm_pri == pri)
309                 { 
310                         H323_GSM0610Capability * gsm_cap;
311                         MicrosoftGSMAudioCapability * msgsm_cap;
312
313                         SetCapability(0, 0, gsm_cap = new H323_GSM0610Capability);
314                         gsm_cap->SetTxFramesInPacket(options.h323_gsm_opt);
315                         SetCapability(0, 0, msgsm_cap = new MicrosoftGSMAudioCapability);
316                         msgsm_cap->SetTxFramesInPacket(options.h323_gsm_opt);
317                 }
318                 if (options.h323_g726_pri == pri)
319                 {
320                         if (options.h323_g726_opt > 4) 
321                                 SetCapability(0, 0, new H323_G726_Capability(*this, H323_G726_Capability::e_40k));
322                         if (options.h323_g726_opt > 3) 
323                                 SetCapability(0, 0, new H323_G726_Capability(*this, H323_G726_Capability::e_32k));
324                         if (options.h323_g726_opt > 2) 
325                                 SetCapability(0, 0, new H323_G726_Capability(*this, H323_G726_Capability::e_24k));
326                         SetCapability(0, 0, new H323_G726_Capability(*this, H323_G726_Capability::e_16k));
327                 }
328                 if (options.h323_g7231_pri == pri)
329                 {
330 #if 0  
331                         SetCapability(0, 0, new H323_G7231Capability(FALSE));
332 #endif
333                 }
334                 if (options.h323_g729a_pri == pri)
335                 {
336 #if 0  
337                         SetCapability(0, 0, new H323_G729Capability());
338 #endif
339                 }
340                 if (options.h323_lpc10_pri == pri)
341                 {  
342                         SetCapability(0, 0, new H323_LPC10Capability(*this));
343                 }
344                 if (options.h323_speex_pri == pri)
345                 {
346                         if (options.h323_speex_opt > 5) 
347                                 SetCapability(0, 0, new SpeexNarrow6AudioCapability());
348                         if (options.h323_speex_opt > 4) 
349                                 SetCapability(0, 0, new SpeexNarrow5AudioCapability());
350                         if (options.h323_speex_opt > 3) 
351                                 SetCapability(0, 0, new SpeexNarrow4AudioCapability());
352                         if (options.h323_speex_opt > 2) 
353                                 SetCapability(0, 0, new SpeexNarrow3AudioCapability());
354                         SetCapability(0, 0, new SpeexNarrow2AudioCapability());
355                 }
356                 if (options.h323_xspeex_pri == pri)
357                 {
358                         if (options.h323_xspeex_opt > 5) 
359                                 SetCapability(0, 0, new XiphSpeexNarrow6AudioCapability());
360                         if (options.h323_xspeex_opt > 4) 
361                                 SetCapability(0, 0, new XiphSpeexNarrow5AudioCapability());
362                         if (options.h323_xspeex_opt > 3) 
363                                 SetCapability(0, 0, new XiphSpeexNarrow4AudioCapability());
364                         if (options.h323_xspeex_opt > 2) 
365                                 SetCapability(0, 0, new XiphSpeexNarrow3AudioCapability());
366                         SetCapability(0, 0, new XiphSpeexNarrow2AudioCapability());
367                 }
368 #endif
369                 if (options.h323_law_pri == pri)
370                 {
371                         H323_G711Capability * g711uCap;
372                         H323_G711Capability * g711aCap;
373                         SetCapability(0, 0, g711uCap = new H323_G711Capability (H323_G711Capability::ALaw/*, H323_G711Capability::At64k*/));
374 #warning H323_law frame size is disabled due to bug in OpenH323
375 //                      g711uCap->SetTxFramesInPacket(options.h323_law_opt);
376                         SetCapability(0, 0, g711aCap = new H323_G711Capability (H323_G711Capability::muLaw/*, H323_G711Capability::At64k*/));
377 //                      g711aCap->SetTxFramesInPacket(options.h323_law_opt);
378                 }
379                 pri++;
380         }
381
382         // h323 user is the hostname or given by h323_name
383         if (options.h323_name[0] == '\0')
384         {
385                 if (getenv("HOSTNAME") == NULL)
386                 {
387                         cout << "OpenH323: Environment variable HOSTNAME not set. Please specify 'h323_name' in options.conf" << endl;
388                         return FALSE;
389                 }
390         }
391         SetLocalUserName((options.h323_name[0])?options.h323_name:getenv("HOSTNAME"));
392
393         // create listener
394         if (options.h323_icall)
395         {
396                 PIPSocket::Address interfaceAddress(INADDR_ANY);
397                 listener = new H323ListenerTCP(*this, interfaceAddress, options.h323_port);
398                 if (!StartListener(listener))
399                 {
400                         cout << "OpenH323: Could not open H323 port " << listener->GetListenerPort() << endl;
401                         return FALSE;
402                 }
403                 cout << "OpenH323: Waiting for incoming H323 connections on port " << listener->GetListenerPort() << endl;
404         }
405
406         // register with gatekeeper
407         if (options.h323_gatekeeper)
408         {
409                 if (options.h323_gatekeeper_host[0] == '\0')
410                 {
411                         if (DiscoverGatekeeper(new H323TransportUDP(*this)))
412                         {
413                                 cout << "OpenH323: Registering with gatekeeper " << gatekeeper->GetIdentifier() << " (automatically)" << endl;
414                         } else
415                         {
416                                 cout << "OpenH323: Gatekeeper not found." << endl;
417                                 sleep(2);
418                         }
419                 } else
420                 {
421                         if (SetGatekeeper(options.h323_gatekeeper_host) == TRUE)
422                         {
423                                 cout << "OpenH323: Registering with gatekeeper " << gatekeeper->GetIdentifier() << " (automatically)" << endl;
424                         } else
425                         {
426                                 cout << "OpenH323: Gatekeeper at " << gatekeeper->GetIdentifier() << " not found." << endl;
427                                 sleep(2);
428                         }
429                 }
430         }
431
432         return TRUE;
433 }
434
435
436 //
437 // make an outgoing h323 call
438 //
439
440 BOOL H323_ep::Call(char *token_string, char *caller, char *host)
441 {
442         PString address;
443         PString token = "";
444         BOOL failed = FALSE;
445         class H323Port *port;
446         struct message *message;
447         char *newtoken_string;
448
449         PDEBUG(DEBUG_H323, "H323 endpoint  call to host '%s'\n", host);
450
451         address = host;
452
453         if (!MakeCall(address, token))
454         {
455                 PDEBUG(DEBUG_H323, "H323 endpoint  call to host '%s'\n", host);
456                 failed = TRUE;
457         }
458
459         // set new token
460         mutex_h323.Wait();
461         if (!(port=(class H323Port *)find_port_with_token((char *)token_string)))
462         {
463                 PERROR("cannot find port with token '%s'\n", token_string);
464                 mutex_h323.Signal();
465                 return FALSE;
466         }
467         if (failed == TRUE)
468         {
469                 PDEBUG(DEBUG_H323, "call of port '%s' failed.\n", token_string);
470                 message = message_create(port->p_serial, ACTIVE_EPOINT(port->p_epointlist), PORT_TO_EPOINT, MESSAGE_RELEASE);
471                 message->param.disconnectinfo.cause = 31;
472                 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
473                 message_put(message);
474         } else
475         {
476                 PDEBUG(DEBUG_H323, "changing port name from '%s' to token '%s'\n", token_string, token.GetPointer());
477                 newtoken_string = token.GetPointer();
478                 SCPY(port->p_name, newtoken_string);
479         }
480         mutex_h323.Signal();
481         PDEBUG(DEBUG_H323, "H323 endpoint call to host '%s'\n", host);
482
483         if (failed == TRUE)
484                 return FALSE;
485         return TRUE;
486 }
487
488 void H323_ep::SetEndpointTypeInfo(H225_EndpointType &info) const
489 {
490 //      H225_VoiceCaps voicecaps;
491         PDEBUG(DEBUG_H323, "H323 endpoint  set endpoint type info *TBD*\n");
492
493         H323EndPoint::SetEndpointTypeInfo(info);
494
495 //      protocols.SetTag(H225_SupportedProtocols::e_voice);
496 //      (H225_VoiceCaps&)protocols = voicecaps;
497 //      a_protocols.SetSize(1);
498 //      a_protocols[0] = protocols;
499
500 //      gateway.IncludeOptionalField(H225_GatewayInfo::e_protocol);
501 //      gateway.m_protocol = a_protocols;
502 //      info.m_gateway = gateway;
503 }