1 ///////////////////////////////////////////////////////////////////////////////
5 //---------------------------------------------------------------------------//
6 // Copyright: Andreas Eversberg //
8 // h323_con connection class //
10 ///////////////////////////////////////////////////////////////////////////////
13 #include <sys/types.h>
24 H323_con::H323_con(H323_ep &endpoint, unsigned callReference) : H323Connection(endpoint, callReference)
26 PDEBUG(DEBUG_H323, "H323 connection constuctor\n");
28 SetAudioJitterDelay(0, 0);
38 const unsigned char *token_string = callToken;
39 struct message *message;
44 port = (class H323Port *)find_port_with_token((char *)token_string);
47 PERROR("no port with token '%s'\n", token_string);
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;
59 PDEBUG(DEBUG_H323, "H323 connection destuctor\n");
64 // AnswerCallResponse (incoming call)
66 H323Connection::AnswerCallResponse H323_con::OnAnswerCall(const PString &, const H323SignalPDU &setupPDU, H323SignalPDU &connectPDU)
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;
75 const unsigned char *token_string = callToken;
76 struct message *message;
77 class Endpoint *epoint;
79 const Q931 setup_q931 = setupPDU.GetQ931();
80 PString calling_number;
82 unsigned type, plan, present, screen, reason;
84 struct caller_info *callerinfo;
85 struct dialing_info *dialinginfo;
86 struct capa_info *capainfo;
87 struct redir_info *redirinfo;
90 PDEBUG(DEBUG_H323, "H323 connection incoming call\n");
94 // alloc new h323 port structure
95 if (!(port = new H323Port(PORT_TYPE_H323_IN, (char *)token_string, NULL)))
98 return AnswerCallDenied;
100 callerinfo = &port->p_callerinfo;
101 redirinfo = &port->p_redirinfo;
102 capainfo = &port->p_capainfo;
103 dialinginfo = &port->p_dialinginfo;
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));
110 callerinfo->itype = INFO_ITYPE_H323;
112 // get calling party information
113 if (setup_q931.GetCallingPartyNumber(calling_number, &plan, &type, &present, &screen))
115 SCPY(callerinfo->id, calling_number.GetPointer());
119 callerinfo->present = INFO_PRESENT_RESTRICTED;
122 callerinfo->present = INFO_PRESENT_NOTAVAIL;
125 callerinfo->present = INFO_PRESENT_ALLOWED;
130 case Q931::InternationalType:
131 callerinfo->ntype = INFO_NTYPE_INTERNATIONAL;
133 case Q931::NationalType:
134 callerinfo->ntype = INFO_NTYPE_NATIONAL;
136 case Q931::SubscriberType:
137 callerinfo->ntype = INFO_NTYPE_SUBSCRIBER;
140 callerinfo->ntype = INFO_NTYPE_UNKNOWN;
146 callerinfo->screen = INFO_SCREEN_USER;
149 callerinfo->screen = INFO_SCREEN_NETWORK;
153 redirinfo->itype = INFO_ITYPE_H323;
154 // get redirecting number information
155 if (setup_q931.GetRedirectingNumber(redir_number, &plan, &type, &present, &screen, &reason))
157 SCPY(redirinfo->id, redir_number.GetPointer());
161 redirinfo->present = INFO_PRESENT_RESTRICTED;
164 redirinfo->present = INFO_PRESENT_NOTAVAIL;
167 redirinfo->present = INFO_PRESENT_ALLOWED;
172 case Q931::InternationalType:
173 redirinfo->ntype = INFO_NTYPE_INTERNATIONAL;
175 case Q931::NationalType:
176 redirinfo->ntype = INFO_NTYPE_NATIONAL;
178 case Q931::SubscriberType:
179 redirinfo->ntype = INFO_NTYPE_SUBSCRIBER;
182 redirinfo->ntype = INFO_NTYPE_UNKNOWN;
188 redirinfo->screen = INFO_SCREEN_USER;
191 redirinfo->screen = INFO_SCREEN_NETWORK;
197 redirinfo->reason = INFO_REDIR_BUSY;
200 redirinfo->reason = INFO_REDIR_NORESPONSE;
203 redirinfo->reason = INFO_REDIR_UNCONDITIONAL;
206 redirinfo->reason = INFO_REDIR_CALLDEFLECT;
209 redirinfo->reason = INFO_REDIR_OUTOFORDER;
212 redirinfo->reason = INFO_REDIR_UNKNOWN;
217 // get remote party h323-address information
218 calleraddress = GetRemotePartyAddress();
222 if (strstr(calleraddress, "ip$"))
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);
229 if (strchr(calleraddress, ':'))
230 *strchr(calleraddress, ':') = '\0';
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]);
240 // fill port's information
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;
247 // change to incoming setup state
248 port->new_state(PORT_STATE_IN_OVERLAP);
250 // allocate new endpoint
251 if (!(epoint = new Endpoint(port->p_serial, 0)))
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);
258 return AnswerCallDenied;
260 if (!(epoint->ep_app = new DEFAULT_ENDPOINT_APP(epoint)))
262 PERROR("no memory for application\n");
265 if (!(port->epointlist_new(epoint->ep_serial)))
267 PERROR("no memory for epointlist\n");
270 port->set_tone(NULL, "");
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;
276 // before we start, we may check for h323_gateway entry
279 extension = parse_h323gateway(callerip, option, sizeof(option));
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;
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
294 // default dialing for extenal calls
295 if (!callerinfo->intern[0] && !dialing[0])
296 dialing = options.h323_icall_prefix;
298 // dialing information
299 if (callerip[0] || dialing[0])
301 SCPY(dialinginfo->number, (char *)dialing);
302 dialinginfo->ntype = INFO_NTYPE_UNKNOWN;
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);
312 port->p_h323_connect = &(connectPDU.GetQ931());
316 if (!strcasecmp(option, "connect") || !strcasecmp(option, "dtmf"))
318 port->new_state(PORT_STATE_CONNECT);
319 return AnswerCallNow;
322 return AnswerCallDeferred;
328 // OnOutgoingCall (outgoing call)
330 BOOL H323_con::OnOutgoingCall(const H323SignalPDU &connectPDU)
332 class H323Port *port;
333 const char *calleraddress;
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;
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;
344 PDEBUG(DEBUG_H323, "H323 connection outgoing call is connected.\n");
348 if (!(port = (class H323Port *)find_port_with_token((char *)token_string)))
350 PERROR(" cannot find port with token '%s'\n", token_string);
354 connectinfo = &port->p_connectinfo;
356 if (port->p_type == PORT_TYPE_H323_IN)
358 PDEBUG(DEBUG_H323, "H323 endpoint OnConnectionEstablished() incoming port\n");
360 if (port->p_type == PORT_TYPE_H323_OUT)
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)
368 // get remote party h323-address information
369 calleraddress = GetRemotePartyAddress();
373 if (strchr(calleraddress, '$'))
375 SCPY(callerip, strchr(calleraddress, '$'));
376 callerip[sizeof(callerip)-1] = '\0';
377 if (strchr(callerip, ':'))
378 *strchr(callerip, ':') = '\0';
380 SCPY(connectinfo->voip, (char *)calleraddress);
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))
388 SCPY(connectinfo->id, connect_number.GetPointer());
392 connectinfo->present = INFO_PRESENT_RESTRICTED;
395 connectinfo->present = INFO_PRESENT_NOTAVAIL;
398 connectinfo->present = INFO_PRESENT_ALLOWED;
402 case Q931::InternationalType:
403 connectinfo->ntype = INFO_NTYPE_INTERNATIONAL;
405 case Q931::NationalType:
406 connectinfo->ntype = INFO_NTYPE_NATIONAL;
408 case Q931::SubscriberType:
409 connectinfo->ntype = INFO_NTYPE_SUBSCRIBER;
412 connectinfo->ntype = INFO_NTYPE_UNKNOWN;
417 connectinfo->screen = INFO_SCREEN_USER;
420 connectinfo->screen = INFO_SCREEN_NETWORK;
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);
432 return H323Connection::OnOutgoingCall(connectPDU);
437 // send setup information to the called h323 user
439 BOOL H323_con::OnSendSignalSetup(H323SignalPDU &setupPDU)
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;
452 struct caller_info *callerinfo;
453 struct dialing_info *dialinginfo;
454 struct capa_info *capainfo;
455 struct redir_info *redirinfo;
459 if (!(port = (class H323Port *)find_port_with_token((char *)token_string)))
461 PERROR(" no port with token '%s'\n", token_string);
465 callerinfo = &port->p_callerinfo;
466 redirinfo = &port->p_redirinfo;
467 capainfo = &port->p_capainfo;
468 dialinginfo = &port->p_dialinginfo;
470 PDEBUG(DEBUG_H323, "H323-connection sending modified setup signal '%s'->'%s'\n", callerinfo->id, dialinginfo->number);
473 if (callerinfo->present!=INFO_PRESENT_NULL)
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;
480 calling_number = callerinfo->id;
481 switch(callerinfo->ntype)
483 case INFO_NTYPE_SUBSCRIBER:
484 type = Q931::SubscriberType;
486 case INFO_NTYPE_NATIONAL:
487 type = Q931::NationalType;
489 case INFO_NTYPE_INTERNATIONAL:
490 type = Q931::InternationalType;
492 default: /* INFO_NTYPE_UNKNOWN */
493 type = Q931::UnknownType;
496 switch(callerinfo->present)
498 case INFO_PRESENT_RESTRICTED:
501 case INFO_PRESENT_NOTAVAIL:
504 default: /* INFO_PRESENT_ALLOWED */
507 switch(callerinfo->screen)
509 case INFO_SCREEN_USER:
512 default: /* INFO_SCREEN_NETWORK */
516 Q931 &new_q931 = setupPDU.GetQ931();
517 new_q931.SetCallingPartyNumber(calling_number, Q931::ISDNPlan, type, present, screen);
520 if (redirinfo->present!=INFO_PRESENT_NULL)
522 if (redirinfo->present==INFO_PRESENT_ALLOWED)
524 redir_number = callerinfo->id;
528 switch(redirinfo->ntype)
530 case INFO_NTYPE_SUBSCRIBER:
531 type = Q931::SubscriberType;
533 case INFO_NTYPE_NATIONAL:
534 type = Q931::NationalType;
536 case INFO_NTYPE_INTERNATIONAL:
537 type = Q931::InternationalType;
539 default: /* INFO_TYPE_UNKNOWN */
540 type = Q931::UnknownType;
543 switch(redirinfo->present)
545 case INFO_PRESENT_RESTRICTED:
548 case INFO_PRESENT_NOTAVAIL:
551 default: /* INFO_PRESENT_ALLOWED */
555 switch(redirinfo->reason)
557 case INFO_REDIR_BUSY:
560 case INFO_REDIR_NORESPONSE:
563 case INFO_REDIR_UNCONDITIONAL:
566 case INFO_REDIR_OUTOFORDER:
569 case INFO_REDIR_CALLDEFLECT:
572 default: /* INFO_REDIR_UNKNOWN */
576 Q931 &new_q931 = setupPDU.GetQ931();
577 new_q931.SetRedirectingNumber(redir_number, Q931::ISDNPlan, type, present, screen, reason);
580 if (dialinginfo->number[0])
582 dialing_number = dialinginfo->number;
584 Q931 &new_q931 = setupPDU.GetQ931();
585 new_q931.SetCalledPartyNumber(dialing_number);
590 return H323Connection::OnSendSignalSetup(setupPDU);
595 // callback for start of channel
597 BOOL H323_con::OnStartLogicalChannel(H323Channel &channel)
599 if (!H323Connection::OnStartLogicalChannel(channel))
601 PERROR("starting logical channel failed!\n");
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());
610 return H323Connection::OnStartLogicalChannel(channel);
615 // user input received
617 void H323_con::OnUserInputString (const PString &value)
619 class H323Port *port;
620 const unsigned char *token_string = callToken;
621 const unsigned char *value_string = value;
622 struct message *message;
624 PDEBUG(DEBUG_H323, "H323-connection received user input'%s'\n", value_string);
628 if (!(port = (class H323Port *)find_port_with_token((char *)token_string)))
630 PERROR("no port with token '%s'\n", token_string);
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);
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);