backup
[lcr.git] / h323_con.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 //                                                                           //
3 // PBX4Linux                                                                 //
4 //                                                                           //
5 //---------------------------------------------------------------------------//
6 // Copyright: Andreas Eversberg                                              //
7 //                                                                           //
8 // h323_con connection class                                                 //
9 //                                                                           //
10 ///////////////////////////////////////////////////////////////////////////////
11
12 #include <stdio.h>
13 #include <sys/types.h>
14 #include <unistd.h>
15 #include "main.h"
16
17 #include <cstdio>
18 #include <cstdlib>
19 #include <cstring>
20
21 //
22 // constructor
23 //
24 H323_con::H323_con(H323_ep &endpoint, unsigned callReference) : H323Connection(endpoint, callReference)
25 {
26         PDEBUG(DEBUG_H323, "H323 connection  constuctor\n");
27
28         SetAudioJitterDelay(0, 0);
29 }
30
31
32 //
33 // destructor
34 //
35 H323_con::~H323_con()
36 {
37         class H323Port *port;
38         const unsigned char *token_string = callToken;
39         struct message *message;
40
41         mutex_h323.Wait();
42
43         // get ioport
44         port = (class H323Port *)find_port_with_token((char *)token_string);
45         if (!port)
46         {
47                 PERROR("no port with token '%s'\n", token_string);
48         } else
49         {
50                 /* sending release (if not already) */
51                 message = message_create(port->p_serial, ACTIVE_EPOINT(port->p_epointlist), PORT_TO_EPOINT, MESSAGE_RELEASE);
52                 message->param.disconnectinfo.cause = 16;
53                 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
54                 message_put(message);
55         }
56
57         mutex_h323.Signal();
58
59         PDEBUG(DEBUG_H323, "H323 connection  destuctor\n");
60 }
61
62
63 //
64 // AnswerCallResponse (incoming call)
65 //
66 H323Connection::AnswerCallResponse H323_con::OnAnswerCall(const PString &, const H323SignalPDU &setupPDU, H323SignalPDU &connectPDU)
67 {  
68         class H323Port *port;
69         const char *calleraddress;
70         char callerip[32], *extension;
71         const char *dialing = NULL;
72         const H225_Setup_UUIE &setup = setupPDU.m_h323_uu_pdu.m_h323_message_body;
73         const H225_ArrayOf_AliasAddress &adr = setup.m_destinationAddress;
74         PINDEX i;
75         const unsigned char *token_string = callToken;
76         struct message *message;
77         class Endpoint *epoint;
78
79         const Q931 setup_q931 = setupPDU.GetQ931();
80         PString calling_number;
81         PString redir_number;
82         unsigned type, plan, present, screen, reason;
83
84         struct caller_info *callerinfo;
85         struct dialing_info *dialinginfo;
86         struct capa_info *capainfo;
87         struct redir_info *redirinfo;
88         char option[64] = "";
89
90         PDEBUG(DEBUG_H323, "H323 connection  incoming call\n");
91
92         mutex_h323.Wait();
93
94         // alloc new h323 port structure
95         if (!(port = new H323Port(PORT_TYPE_H323_IN, (char *)token_string, NULL)))
96         {
97                 mutex_h323.Signal();
98                 return AnswerCallDenied;
99         }
100         callerinfo = &port->p_callerinfo;
101         redirinfo = &port->p_redirinfo;
102         capainfo = &port->p_capainfo;
103         dialinginfo = &port->p_dialinginfo;
104
105         memset(callerinfo, 0, sizeof(struct caller_info));
106         memset(redirinfo, 0, sizeof(struct redir_info));
107         memset(capainfo, 0, sizeof(struct capa_info));
108         memset(dialinginfo, 0, sizeof(struct dialing_info));
109
110         callerinfo->itype = INFO_ITYPE_H323;
111
112         // get calling party information
113         if (setup_q931.GetCallingPartyNumber(calling_number, &plan, &type, &present, &screen))
114         {
115                 SCPY(callerinfo->id, calling_number.GetPointer());
116                 switch (present)
117                 {
118                         case 1:
119                         callerinfo->present = INFO_PRESENT_RESTRICTED;
120                         break;
121                         case 2:
122                         callerinfo->present = INFO_PRESENT_NOTAVAIL;
123                         break;
124                         default:
125                         callerinfo->present = INFO_PRESENT_ALLOWED;
126                         break;
127                 }
128                 switch (type)
129                 {
130                         case Q931::InternationalType:
131                         callerinfo->ntype = INFO_NTYPE_INTERNATIONAL;
132                         break;
133                         case Q931::NationalType:
134                         callerinfo->ntype = INFO_NTYPE_NATIONAL;
135                         break;
136                         case Q931::SubscriberType:
137                         callerinfo->ntype = INFO_NTYPE_SUBSCRIBER;
138                         break;
139                         default:
140                         callerinfo->ntype = INFO_NTYPE_UNKNOWN;
141                         break;
142                 }
143                 switch (screen)
144                 {
145                         case 0:
146                         callerinfo->screen = INFO_SCREEN_USER;
147                         break;
148                         default:
149                         callerinfo->screen = INFO_SCREEN_NETWORK;
150                         break;
151                 }
152         }
153         redirinfo->itype = INFO_ITYPE_H323;
154         // get redirecting number information
155         if (setup_q931.GetRedirectingNumber(redir_number, &plan, &type, &present, &screen, &reason))
156         {
157                 SCPY(redirinfo->id, redir_number.GetPointer());
158                 switch (present)
159                 {
160                         case 1:
161                         redirinfo->present = INFO_PRESENT_RESTRICTED;
162                         break;
163                         case 2:
164                         redirinfo->present = INFO_PRESENT_NOTAVAIL;
165                         break;
166                         default:
167                         redirinfo->present = INFO_PRESENT_ALLOWED;
168                         break;
169                 }
170                 switch (type)
171                 {
172                         case Q931::InternationalType:
173                         redirinfo->ntype = INFO_NTYPE_INTERNATIONAL;
174                         break;
175                         case Q931::NationalType:
176                         redirinfo->ntype = INFO_NTYPE_NATIONAL;
177                         break;
178                         case Q931::SubscriberType:
179                         redirinfo->ntype = INFO_NTYPE_SUBSCRIBER;
180                         break;
181                         default:
182                         redirinfo->ntype = INFO_NTYPE_UNKNOWN;
183                         break;
184                 }
185                 switch (screen)
186                 {
187                         case 0:
188                         redirinfo->screen = INFO_SCREEN_USER;
189                         break;
190                         default:
191                         redirinfo->screen = INFO_SCREEN_NETWORK;
192                         break;
193                 }
194                 switch (reason)
195                 {
196                         case 1:
197                         redirinfo->reason = INFO_REDIR_BUSY;
198                         break;
199                         case 2:
200                         redirinfo->reason = INFO_REDIR_NORESPONSE;
201                         break;
202                         case 15:
203                         redirinfo->reason = INFO_REDIR_UNCONDITIONAL;
204                         break;
205                         case 10:
206                         redirinfo->reason = INFO_REDIR_CALLDEFLECT;
207                         break;
208                         case 9:
209                         redirinfo->reason = INFO_REDIR_OUTOFORDER;
210                         break;
211                         default:
212                         redirinfo->reason = INFO_REDIR_UNKNOWN;
213                         break;
214                 }
215         }
216
217         // get remote party h323-address information
218         calleraddress = GetRemotePartyAddress();
219         callerip[0] = '\0';
220         if (calleraddress)
221         {
222                 if (strstr(calleraddress, "ip$"))
223                 {
224                         SCPY(callerip, strstr(calleraddress, "ip$")+3);
225                         if (strchr(callerip, ':'))
226                                 *strchr(callerip, ':') = '\0';
227                         memmove(strstr(calleraddress, "ip$"), strstr(calleraddress, "ip$")+3, strlen(strstr(calleraddress, "ip$")+3)+1);
228                 }
229                 if (strchr(calleraddress, ':'))
230                         *strchr(calleraddress, ':') = '\0';
231         }
232
233         // get dialing information
234         for(i=0; i<adr.GetSize(); i++)
235                 if (adr[i].GetTag() == H225_AliasAddress::e_dialedDigits)
236                         dialing = H323GetAliasAddressString(adr[i]);
237         if (!dialing)
238                 dialing = "";
239
240         // fill port's information
241         if (calleraddress)
242                 SCPY(callerinfo->voip, (char *)calleraddress);
243         capainfo->bearer_mode = INFO_BMODE_CIRCUIT;
244         capainfo->bearer_info1 = (options.law=='u')?INFO_INFO1_ULAW:INFO_INFO1_ALAW;
245         capainfo->bearer_capa = INFO_BC_SPEECH;
246
247         // change to incoming setup state
248         port->new_state(PORT_STATE_IN_OVERLAP);
249
250         // allocate new endpoint
251         if (!(epoint = new Endpoint(port->p_serial, 0)))
252         {
253                 // error allocating endpoint
254                 PDEBUG(DEBUG_H323, "h323-connection(%s) rejecting call because cannot create epoint for '%s'\n", port->p_name, callerinfo->id);
255                 delete port;
256                 port = NULL;
257                 mutex_h323.Signal();
258                 return AnswerCallDenied;
259         }
260         if (!(epoint->ep_app = new DEFAULT_ENDPOINT_APP(epoint)))
261         {
262                 PERROR("no memory for application\n");
263                 exit(-1);
264         }
265         if (!(port->epointlist_new(epoint->ep_serial)))
266         {
267                 PERROR("no memory for epointlist\n");
268                 exit(-1);
269         }
270         port->set_tone(NULL, "");
271
272         // send setup message to endpoint
273         message = message_create(port->p_serial, ACTIVE_EPOINT(port->p_epointlist), PORT_TO_EPOINT, MESSAGE_SETUP);
274         message->param.setup.port_type = port->p_type;
275
276         // before we start, we may check for h323_gateway entry
277         if (callerip[0])
278         {
279                 extension = parse_h323gateway(callerip, option, sizeof(option));
280                 if (extension)
281                 {
282                         PDEBUG(DEBUG_H323, "h323-connection(%s) gateway '%s' is mapped to extension '%s' (option= '%s')\n", port->p_name, callerip, extension, option);
283                         SCPY(callerinfo->id, extension);
284                         SCPY(callerinfo->intern, extension);
285                         callerinfo->itype = INFO_ITYPE_INTERN;
286                         callerinfo->screen = INFO_SCREEN_NETWORK;
287                 } else
288                 {
289                         PDEBUG(DEBUG_H323, "h323-connection(%s) gateway '%s' is not mapped to any extension. (port_type=0x%x)\n", port->p_name, callerip, port->p_type);
290                         // get the default dialing external dialing string
291                 }
292         }
293
294         // default dialing for extenal calls
295         if (!callerinfo->intern[0] && !dialing[0])
296                 dialing = options.h323_icall_prefix;
297
298         // dialing information
299         if (callerip[0] || dialing[0])
300         {
301                 SCPY(dialinginfo->number, (char *)dialing);
302                 dialinginfo->ntype = INFO_NTYPE_UNKNOWN;
303         }
304
305         memcpy(&message->param.setup.callerinfo, callerinfo, sizeof(struct caller_info));
306         memcpy(&message->param.setup.dialinginfo, dialinginfo, sizeof(struct dialing_info));
307         memcpy(&message->param.setup.redirinfo, redirinfo, sizeof(struct redir_info));
308         memcpy(&message->param.setup.capainfo, capainfo, sizeof(struct capa_info));
309         message->param.setup.dtmf = 1;
310         message_put(message);
311
312         port->p_h323_connect = &(connectPDU.GetQ931());
313
314         mutex_h323.Signal();
315
316         if (!strcasecmp(option, "connect") || !strcasecmp(option, "dtmf"))
317         {
318                 port->new_state(PORT_STATE_CONNECT);
319                 return AnswerCallNow;
320         } else
321         {
322                 return AnswerCallDeferred;
323         }
324 }
325
326
327 //
328 // OnOutgoingCall (outgoing call)
329 //
330 BOOL H323_con::OnOutgoingCall(const H323SignalPDU &connectPDU)
331 {  
332         class H323Port *port;
333         const char *calleraddress;
334         char callerip[32];
335         const unsigned char *token_string = callToken;
336         struct message *message;
337 //      H225_Connect_UUIE &connect_uuie = connectPDU.m_h323_uu_pdu.m_h323_message_body;
338
339         const Q931 connect_q931 = connectPDU.GetQ931();
340         PString connect_number;
341         unsigned type = 0, plan = 0, present = 0, screen = 0;
342         struct connect_info *connectinfo;
343
344         PDEBUG(DEBUG_H323, "H323 connection  outgoing call is connected.\n");
345
346         mutex_h323.Wait();
347
348         if (!(port = (class H323Port *)find_port_with_token((char *)token_string)))
349         {
350                 PERROR(" cannot find port with token '%s'\n", token_string);
351                 mutex_h323.Signal();
352                 return FALSE;
353         }
354         connectinfo = &port->p_connectinfo;
355
356         if (port->p_type == PORT_TYPE_H323_IN)
357         {
358                 PDEBUG(DEBUG_H323, "H323 endpoint  OnConnectionEstablished() incoming port\n");
359         }
360         if (port->p_type == PORT_TYPE_H323_OUT)
361         {
362                 PDEBUG(DEBUG_H323, "H323 endpoint  OnConnectionEstablished() outgoing port\n");
363                 if (port->p_state==PORT_STATE_OUT_SETUP
364                  || port->p_state==PORT_STATE_OUT_OVERLAP
365                  || port->p_state==PORT_STATE_OUT_PROCEEDING
366                  || port->p_state==PORT_STATE_OUT_ALERTING)
367                 {
368                         // get remote party h323-address information
369                         calleraddress = GetRemotePartyAddress();
370                         callerip[0] = '\0';
371                         if (calleraddress)
372                         {
373                                 if (strchr(calleraddress, '$'))
374                                 {
375                                         SCPY(callerip, strchr(calleraddress, '$'));
376                                         callerip[sizeof(callerip)-1] = '\0';
377                                         if (strchr(callerip, ':'))
378                                                 *strchr(callerip, ':') = '\0';
379                                 }
380                                 SCPY(connectinfo->voip, (char *)calleraddress);
381                         }
382
383                         // get COLP
384                         memset(connectinfo, 0, sizeof(struct connect_info));
385                         connectinfo->itype = INFO_ITYPE_H323;
386                         if (connect_q931.GetConnectedNumber(connect_number, &plan, &type, &present, &screen))
387                         {
388                                 SCPY(connectinfo->id, connect_number.GetPointer());
389                                 switch (present)
390                                 {
391                                         case 1:
392                                         connectinfo->present = INFO_PRESENT_RESTRICTED;
393                                         break;
394                                         case 2:
395                                         connectinfo->present = INFO_PRESENT_NOTAVAIL;
396                                         break;
397                                         default:
398                                         connectinfo->present = INFO_PRESENT_ALLOWED;
399                                 }
400                                 switch (type)
401                                 {
402                                         case Q931::InternationalType:
403                                         connectinfo->ntype = INFO_NTYPE_INTERNATIONAL;
404                                         break;
405                                         case Q931::NationalType:
406                                         connectinfo->ntype = INFO_NTYPE_NATIONAL;
407                                         break;
408                                         case Q931::SubscriberType:
409                                         connectinfo->ntype = INFO_NTYPE_SUBSCRIBER;
410                                         break;
411                                         default:
412                                         connectinfo->ntype = INFO_NTYPE_UNKNOWN;
413                                 }
414                                 switch (screen)
415                                 {
416                                         case 0:
417                                         connectinfo->screen = INFO_SCREEN_USER;
418                                         break;
419                                         default:
420                                         connectinfo->screen = INFO_SCREEN_NETWORK;
421                                 }
422                         }
423                         port->new_state(PORT_STATE_CONNECT);
424                         message = message_create(port->p_serial, ACTIVE_EPOINT(port->p_epointlist), PORT_TO_EPOINT, MESSAGE_CONNECT);
425                         memcpy(&message->param.connectinfo, connectinfo, sizeof(struct connect_info));
426                         message_put(message);
427                 }
428         }
429
430         mutex_h323.Signal();
431
432         return H323Connection::OnOutgoingCall(connectPDU);
433 }
434
435
436 //
437 // send setup information to the called h323 user
438 //
439 BOOL H323_con::OnSendSignalSetup(H323SignalPDU &setupPDU)
440 {
441         H225_Setup_UUIE &setup = setupPDU.m_h323_uu_pdu.m_h323_message_body;
442         H225_ArrayOf_AliasAddress &adr = setup.m_sourceAddress;
443         H225_AliasAddress new_alias;
444         PString calling_number;
445         PString calling_alias;
446         PString dialing_number;
447         PString redir_number;
448         int type, present, screen, reason;
449         class H323Port *port;
450         const unsigned char *token_string = callToken;
451
452         struct caller_info *callerinfo;
453         struct dialing_info *dialinginfo;
454         struct capa_info *capainfo;
455         struct redir_info *redirinfo;
456
457         mutex_h323.Wait();
458
459         if (!(port = (class H323Port *)find_port_with_token((char *)token_string)))
460         {
461                 PERROR(" no port with token '%s'\n", token_string);
462                 mutex_h323.Signal();
463                 return FALSE;
464         }
465         callerinfo = &port->p_callerinfo;
466         redirinfo = &port->p_redirinfo;
467         capainfo = &port->p_capainfo;
468         dialinginfo = &port->p_dialinginfo;
469
470         PDEBUG(DEBUG_H323, "H323-connection  sending modified setup signal '%s'->'%s'\n", callerinfo->id, dialinginfo->number);
471
472
473         if (callerinfo->present!=INFO_PRESENT_NULL)
474         {
475                 calling_alias = numberrize_callerinfo(callerinfo->id, callerinfo->ntype);
476                 H323SetAliasAddress(calling_alias, new_alias);
477                 adr.SetSize(adr.GetSize()+1);
478                 adr[adr.GetSize()-1] = new_alias;
479
480                 calling_number = callerinfo->id;
481                 switch(callerinfo->ntype)
482                 {
483                         case INFO_NTYPE_SUBSCRIBER:
484                         type = Q931::SubscriberType;
485                         break;
486                         case INFO_NTYPE_NATIONAL:
487                         type = Q931::NationalType;
488                         break;
489                         case INFO_NTYPE_INTERNATIONAL:
490                         type = Q931::InternationalType;
491                         break;
492                         default: /* INFO_NTYPE_UNKNOWN */
493                         type = Q931::UnknownType;
494                 }
495
496                 switch(callerinfo->present)
497                 {
498                         case INFO_PRESENT_RESTRICTED:
499                         present = 1;
500                         break;
501                         case INFO_PRESENT_NOTAVAIL:
502                         present = 2;
503                         break;
504                         default: /* INFO_PRESENT_ALLOWED */
505                         present = 0;
506                 }
507                 switch(callerinfo->screen)
508                 {
509                         case INFO_SCREEN_USER:
510                         screen = 0;
511                         break;
512                         default: /* INFO_SCREEN_NETWORK */
513                         screen = 3;
514                 }
515
516                 Q931 &new_q931 = setupPDU.GetQ931();
517                 new_q931.SetCallingPartyNumber(calling_number, Q931::ISDNPlan, type, present, screen);
518         }
519
520         if (redirinfo->present!=INFO_PRESENT_NULL)
521         {
522                 if (redirinfo->present==INFO_PRESENT_ALLOWED)
523                 {
524                         redir_number = callerinfo->id;
525                 } else
526                         redir_number = "";
527
528                 switch(redirinfo->ntype)
529                 {
530                         case INFO_NTYPE_SUBSCRIBER:
531                         type = Q931::SubscriberType;
532                         break;
533                         case INFO_NTYPE_NATIONAL:
534                         type = Q931::NationalType;
535                         break;
536                         case INFO_NTYPE_INTERNATIONAL:
537                         type = Q931::InternationalType;
538                         break;
539                         default: /* INFO_TYPE_UNKNOWN */
540                         type = Q931::UnknownType;
541                 }
542
543                 switch(redirinfo->present)
544                 {
545                         case INFO_PRESENT_RESTRICTED:
546                         present = 1;
547                         break;
548                         case INFO_PRESENT_NOTAVAIL:
549                         present = 2;
550                         break;
551                         default: /* INFO_PRESENT_ALLOWED */
552                         present = 0;
553                 }
554
555                 switch(redirinfo->reason)
556                 {
557                         case INFO_REDIR_BUSY:
558                         reason = 1;
559                         break;
560                         case INFO_REDIR_NORESPONSE:
561                         reason = 2;
562                         break;
563                         case INFO_REDIR_UNCONDITIONAL:
564                         reason = 15;
565                         break;
566                         case INFO_REDIR_OUTOFORDER:
567                         reason = 9;
568                         break;
569                         case INFO_REDIR_CALLDEFLECT:
570                         reason = 10;
571                         break;
572                         default: /* INFO_REDIR_UNKNOWN */
573                         reason = 0;
574                 }
575
576                 Q931 &new_q931 = setupPDU.GetQ931();
577                 new_q931.SetRedirectingNumber(redir_number, Q931::ISDNPlan, type, present, screen, reason);
578         }
579
580         if (dialinginfo->number[0])
581         {
582                 dialing_number = dialinginfo->number;
583
584                 Q931 &new_q931 = setupPDU.GetQ931();
585                 new_q931.SetCalledPartyNumber(dialing_number);
586         }
587         
588         mutex_h323.Signal();
589
590         return H323Connection::OnSendSignalSetup(setupPDU);
591 }
592
593
594 //
595 // callback for start of channel
596 //
597 BOOL H323_con::OnStartLogicalChannel(H323Channel &channel)
598 {
599         if (!H323Connection::OnStartLogicalChannel(channel))
600         {
601                 PERROR("starting logical channel failed!\n");
602                 return FALSE;
603         }
604
605         PDEBUG(DEBUG_H323, "H323 connection  starting logical channel using \"%s\" codec %s :%s\n",
606                  channel.GetCapability().GetFormatName().GetPointer(),
607                  (channel.GetDirection()==H323Channel::IsTransmitter)?"transmit":"receive",
608                  callToken.GetPointer());
609
610         return H323Connection::OnStartLogicalChannel(channel);
611 }
612
613
614 //
615 // user input received
616 //
617 void H323_con::OnUserInputString (const PString &value)
618 {
619         class H323Port *port;
620         const unsigned char *token_string = callToken;
621         const unsigned char *value_string = value;
622         struct message *message;
623
624         PDEBUG(DEBUG_H323, "H323-connection  received user input'%s'\n", value_string);
625
626         mutex_h323.Wait();
627
628         if (!(port = (class H323Port *)find_port_with_token((char *)token_string)))
629         {
630                 PERROR("no port with token '%s'\n", token_string);
631         } else
632         {
633                 while(*value_string)
634                 {
635                         message = message_create(port->p_serial, ACTIVE_EPOINT(port->p_epointlist), PORT_TO_EPOINT, MESSAGE_DTMF);
636                         message->param.dtmf = *value_string++;
637                         message_put(message);
638                 }
639 #if 0
640                 message = message_create(port->p_serial, ACTIVE_EPOINT(port->p_epointlist), PORT_TO_EPOINT, MESSAGE_INFORMATION);
641                 SCPY(message->param.information.number, (char *)value_string);
642                 message_put(message);
643 #endif
644         }
645
646         mutex_h323.Signal();
647 }
648