344 lines
9.6 KiB
C++
344 lines
9.6 KiB
C++
/*****************************************************************************\
|
|
** **
|
|
** PBX4Linux **
|
|
** **
|
|
**---------------------------------------------------------------------------**
|
|
** Copyright: Andreas Eversberg **
|
|
** **
|
|
** h323 port **
|
|
** **
|
|
\*****************************************************************************/
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <poll.h>
|
|
#include <errno.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#include "main.h"
|
|
|
|
|
|
/*
|
|
* initialize h323 port
|
|
*/
|
|
H323Port::H323Port(int type, char *portname, struct port_settings *settings) : Port(type, portname, settings)
|
|
{
|
|
p_h323_channel_in = p_h323_channel_out = NULL;
|
|
p_h323_connect = NULL;
|
|
|
|
/* configure device */
|
|
switch (type)
|
|
{
|
|
case PORT_TYPE_H323_IN:
|
|
break;
|
|
case PORT_TYPE_H323_OUT:
|
|
SPRINT(p_name, "H323_outgoing_port_#%lu", p_serial);
|
|
break;
|
|
}
|
|
if (options.law == 'u')
|
|
{
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* destructor
|
|
*/
|
|
H323Port::~H323Port()
|
|
{
|
|
}
|
|
|
|
|
|
/*
|
|
* endpoint sends messages to the interface
|
|
*/
|
|
int H323Port::message_epoint(unsigned long epoint_id, int message_id, union parameter *param)
|
|
{
|
|
H323Connection *connection;
|
|
H323Connection::CallEndReason h323_cause;
|
|
char name[sizeof(p_name)];
|
|
|
|
if (Port::message_epoint(epoint_id, message_id, param))
|
|
return(1);
|
|
|
|
switch(message_id)
|
|
{
|
|
case MESSAGE_mISDNSIGNAL: /* isdn command */
|
|
PDEBUG(DEBUG_H323, "H323Port(%s) mISDN signal not supported.\n", p_name);
|
|
break;
|
|
|
|
case MESSAGE_INFORMATION: /* additional digits from endpoint */
|
|
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);
|
|
/* queue to be done */
|
|
if (p_state != PORT_STATE_OUT_OVERLAP)
|
|
{
|
|
PERROR("H323Port(%s) additinal digits are only possible in outgoing overlap state.\n", p_name);
|
|
break;
|
|
}
|
|
if (strlen(param->information.number)>30)
|
|
{
|
|
PERROR("H323Port(%s) information string too long.\n", p_name);
|
|
break;
|
|
}
|
|
SCAT((char *)p_dialinginfo.number, param->information.number);
|
|
break;
|
|
|
|
case MESSAGE_PROCEEDING: /* call of endpoint is proceeding */
|
|
PDEBUG(DEBUG_H323, "H323Port(%s) h323 port with (caller id %s) received proceeding\n", p_name, p_callerinfo.id);
|
|
if (p_state != PORT_STATE_IN_OVERLAP)
|
|
{
|
|
PERROR("H323Port(%s) proceeding command only possible in setup state.\n", p_name);
|
|
break;
|
|
}
|
|
p_state = PORT_STATE_IN_PROCEEDING;
|
|
break;
|
|
|
|
case MESSAGE_ALERTING: /* call of endpoint is ringing */
|
|
PDEBUG(DEBUG_H323, "H323Port(%s) h323 port with (caller id %s) received alerting\n", p_name, p_callerinfo.id);
|
|
if (p_state != PORT_STATE_IN_OVERLAP
|
|
&& p_state != PORT_STATE_IN_PROCEEDING)
|
|
{
|
|
PERROR("H323Port(%s) alerting command only possible in setup or proceeding state.\n", p_name);
|
|
break;
|
|
}
|
|
p_state = PORT_STATE_IN_ALERTING;
|
|
UCPY(name, p_name);
|
|
mutex_h323.Signal();
|
|
connection = h323_ep->FindConnectionWithLock(name);
|
|
if (connection)
|
|
{
|
|
if (options.h323_ringconnect && !p_callerinfo.intern[0])
|
|
{
|
|
connection->AnsweringCall(H323Connection::AnswerCallNow);
|
|
p_state = PORT_STATE_CONNECT;
|
|
} else
|
|
connection->AnsweringCall(H323Connection::AnswerCallPending);
|
|
connection->Unlock();
|
|
}
|
|
mutex_h323.Wait();
|
|
break;
|
|
|
|
case MESSAGE_CONNECT: /* call of endpoint is connected */
|
|
PDEBUG(DEBUG_H323, "H323Port(%s) h323 port with (caller id %s) received connect\n", p_name, p_callerinfo.id);
|
|
if (p_state != PORT_STATE_IN_OVERLAP
|
|
&& p_state != PORT_STATE_IN_PROCEEDING
|
|
&& p_state != PORT_STATE_IN_ALERTING)
|
|
{
|
|
PDEBUG(DEBUG_H323, "H323Port(%s) connect command only possible in setup, proceeding or alerting state.\n", p_name);
|
|
break;
|
|
}
|
|
new_state(PORT_STATE_CONNECT);
|
|
/* copy connected information */
|
|
memcpy(&p_connectinfo, ¶m->connectinfo, sizeof(p_connectinfo));
|
|
p_connectinfo.itype = INFO_ITYPE_H323;
|
|
UCPY(name, p_name);
|
|
mutex_h323.Signal();
|
|
connection = h323_ep->FindConnectionWithLock(name);
|
|
if (connection)
|
|
{
|
|
int type, present, screen;
|
|
PString connect_number;
|
|
/* modify connectinfo (COLP) */
|
|
if (p_connectinfo.present!=INFO_PRESENT_NULL)
|
|
{
|
|
connect_number = p_connectinfo.id;
|
|
switch(p_connectinfo.ntype)
|
|
{
|
|
case INFO_NTYPE_SUBSCRIBER:
|
|
type = Q931::SubscriberType;
|
|
break;
|
|
case INFO_NTYPE_NATIONAL:
|
|
type = Q931::NationalType;
|
|
break;
|
|
case INFO_NTYPE_INTERNATIONAL:
|
|
type = Q931::InternationalType;
|
|
break;
|
|
default: /* INFO_TYPE_UNKNOWN */
|
|
type = Q931::UnknownType;
|
|
}
|
|
switch(p_connectinfo.present)
|
|
{
|
|
case INFO_PRESENT_RESTRICTED:
|
|
present = 1;
|
|
break;
|
|
case INFO_PRESENT_NOTAVAIL:
|
|
present = 2;
|
|
break;
|
|
default: /* INFO_PRESENT_ALLOWED */
|
|
present = 0;
|
|
}
|
|
switch(p_connectinfo.screen)
|
|
{
|
|
case INFO_SCREEN_USER:
|
|
screen = 0;
|
|
break;
|
|
default: /* INFO_SCREEN_NETWORK */
|
|
screen = 3;
|
|
}
|
|
#if 0
|
|
if (p_h323_connect)
|
|
{
|
|
//PDEBUG(DEBUG_H323, "DDDEBUG: number %s, type=%d, present %d, screen %d\n", p_connectinfo.id, type, present, screen);
|
|
((Q931 *)p_h323_connect)->SetConnectedNumber(connect_number, Q931::ISDNPlan, type, present, screen);
|
|
}
|
|
else
|
|
PERROR("missing p_h323_connect\n");
|
|
#endif
|
|
}
|
|
|
|
connection->AnsweringCall(H323Connection::AnswerCallNow);
|
|
connection->Unlock();
|
|
}
|
|
mutex_h323.Wait();
|
|
break;
|
|
|
|
case MESSAGE_DISCONNECT: /* call has been disconnected */
|
|
#if 0
|
|
PDEBUG(DEBUG_H323, "H323Port(%s) h323 port with (caller id %s) received disconnect cause=%d\n", p_name, p_callerinfo.id, param->disconnectinfo.cause);
|
|
/* we just play what we hear from the remote site */
|
|
if (p_state == PORT_STATE_IN_OVERLAP
|
|
|| p_state == PORT_STATE_IN_PROCEEDING)
|
|
{
|
|
/* copy connected information */
|
|
memcpy(&p_connectinfo, ¶m->connectinfo, sizeof(p_connectinfo));
|
|
UCPY(name, p_name);
|
|
mutex_h323.Signal();
|
|
connection = h323_ep->FindConnectionWithLock(name);
|
|
if (connection)
|
|
{
|
|
connection->AnsweringCall(H323Connection::AnswerCallNow);
|
|
connection->Unlock();
|
|
}
|
|
mutex_h323.Wait();
|
|
}
|
|
new_state(PORT_STATE_DISCONNECT);
|
|
break;
|
|
#endif
|
|
|
|
case MESSAGE_RELEASE: /* release h323 port */
|
|
PDEBUG(DEBUG_H323, "H323Port(%s) h323 port with (caller id %s) received disconnect cause=%d\n", p_name, p_callerinfo.id, param->disconnectinfo.cause);
|
|
if (p_state != PORT_STATE_IN_OVERLAP
|
|
&& p_state != PORT_STATE_IN_PROCEEDING
|
|
&& p_state != PORT_STATE_IN_ALERTING
|
|
&& p_state != PORT_STATE_OUT_SETUP
|
|
&& p_state != PORT_STATE_OUT_OVERLAP
|
|
&& p_state != PORT_STATE_OUT_PROCEEDING
|
|
&& p_state != PORT_STATE_OUT_ALERTING
|
|
&& p_state != PORT_STATE_CONNECT)
|
|
{
|
|
PERROR("H323Port(%s) disconnect command only possible in setup, proceeding, alerting or connect state.\n", p_name);
|
|
break;
|
|
}
|
|
|
|
switch(param->disconnectinfo.cause)
|
|
{
|
|
case 1:
|
|
h323_cause = H323Connection::EndedByNoUser;
|
|
break;
|
|
|
|
case 2:
|
|
case 3:
|
|
case 5:
|
|
h323_cause = H323Connection::EndedByUnreachable;
|
|
break;
|
|
|
|
case 17:
|
|
h323_cause = H323Connection::EndedByRemoteBusy;
|
|
break;
|
|
|
|
case 18:
|
|
h323_cause = H323Connection::EndedByNoEndPoint;
|
|
break;
|
|
|
|
case 19:
|
|
h323_cause = H323Connection::EndedByNoAnswer;
|
|
break;
|
|
|
|
case 21:
|
|
h323_cause = H323Connection::EndedByRefusal;
|
|
break;
|
|
|
|
case 27:
|
|
h323_cause = H323Connection::EndedByHostOffline;
|
|
break;
|
|
|
|
case 47:
|
|
h323_cause = H323Connection::EndedByConnectFail;
|
|
break;
|
|
|
|
case 65:
|
|
h323_cause = H323Connection::EndedByCapabilityExchange;
|
|
break;
|
|
|
|
case 42:
|
|
h323_cause = H323Connection::EndedByRemoteCongestion;
|
|
break;
|
|
|
|
case 41:
|
|
h323_cause = H323Connection::EndedByTemporaryFailure;
|
|
break;
|
|
|
|
default:
|
|
h323_cause = H323Connection::EndedByRemoteUser;
|
|
break;
|
|
}
|
|
UCPY(name, p_name);
|
|
mutex_h323.Signal();
|
|
h323_ep->ClearCall(name, h323_cause);
|
|
mutex_h323.Wait();
|
|
|
|
delete this;
|
|
break;
|
|
|
|
case MESSAGE_SETUP: /* dial-out command received from epoint */
|
|
PDEBUG(DEBUG_H323, "H323Port(%s) h323 port received setup from '%s' to '%s'\n", p_name, param->setup.callerinfo.id, param->setup.dialinginfo.number);
|
|
if (p_type!=PORT_TYPE_H323_OUT)
|
|
{
|
|
PERROR("H323Port(%s) cannot dial because h323 port not of outgoing type.\n", p_name);
|
|
break;
|
|
}
|
|
if (p_state != PORT_STATE_IDLE)
|
|
{
|
|
PERROR("H323Port(%s) error: dialing command only possible in idle state.\n", p_name);
|
|
break;
|
|
}
|
|
|
|
/* link relation */
|
|
if (p_epointlist)
|
|
{
|
|
PERROR("H323Port(%s) software error: epoint pointer is set in idle state, how bad!! exitting.\n", p_name);
|
|
exit(-1);
|
|
}
|
|
if (!(epointlist_new(epoint_id)))
|
|
{
|
|
PERROR("no memory for epointlist\n");
|
|
exit(-1);
|
|
}
|
|
|
|
/* copy setup infos to port */
|
|
memcpy(&p_callerinfo, ¶m->setup.callerinfo, sizeof(p_callerinfo));
|
|
memcpy(&p_dialinginfo, ¶m->setup.dialinginfo, sizeof(p_dialinginfo));
|
|
memcpy(&p_capainfo, ¶m->setup.capainfo, sizeof(p_capainfo));
|
|
memcpy(&p_redirinfo, ¶m->setup.redirinfo, sizeof(p_redirinfo));
|
|
|
|
p_state = PORT_STATE_OUT_SETUP;
|
|
|
|
UCPY(name, p_name);
|
|
mutex_h323.Signal();
|
|
h323_ep->Call(name, param->setup.callerinfo.id, param->setup.dialinginfo.number);
|
|
mutex_h323.Wait();
|
|
break;
|
|
|
|
default:
|
|
PDEBUG(DEBUG_H323, "H323Port(%s) h323 port with (caller id %s) received an unsupported message: %d\n", p_name, p_callerinfo.id, message_id);
|
|
}
|
|
|
|
return(1);
|
|
}
|
|
|
|
|