windows-nt/Source/XPSP1/NT/net/tapi/skywalker/h323tsp/line.c
2020-09-26 16:20:57 +08:00

1918 lines
44 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1997 Microsoft Corporation
Module Name:
line.c
Abstract:
TAPI Service Provider functions related to manipulating lines.
TSPI_lineClose
TSPI_lineGetDevCaps
TSPI_lineGetLineDevStatus
TSPI_lineGetNumAddressIDs
TSPI_lineOpen
TSPI_lineSetLineDevStatus
Environment:
User Mode - Win32
--*/
///////////////////////////////////////////////////////////////////////////////
// //
// Include files //
// //
///////////////////////////////////////////////////////////////////////////////
#include "globals.h"
#include "provider.h"
#include "callback.h"
#include "registry.h"
#include "version.h"
#include "line.h"
#include "call.h"
///////////////////////////////////////////////////////////////////////////////
// //
// Global variables //
// //
///////////////////////////////////////////////////////////////////////////////
PH323_LINE_TABLE g_pLineTable = NULL;
DWORD g_dwLineDeviceUniqueID = 0;
///////////////////////////////////////////////////////////////////////////////
// //
// Private procedures //
// //
///////////////////////////////////////////////////////////////////////////////
BOOL
H323ResetLine(
PH323_LINE pLine
)
/*++
Routine Description:
Resets line object to original state for re-use.
Arguments:
pLine - Pointer to line object to reset.
Return Values:
Returns true if successful.
--*/
{
// reset state of line object
pLine->nState = H323_LINESTATE_ALLOCATED;
// line not marked for deletion
pLine->fIsMarkedForDeletion = FALSE;
// reset tapi handles
pLine->hdLine = (HDRVLINE)NULL;
pLine->htLine = (HTAPILINE)NULL;
pLine->dwDeviceID = UNINITIALIZED;
// reset tapi info
pLine->dwTSPIVersion = 0;
pLine->dwMediaModes = 0;
// reset bogus handle count
pLine->dwNextMSPHandle = 0;
// uninitialize listen handle
pLine->hccListen = UNINITIALIZED;
// reset line name
pLine->wszAddr[0] = UNICODE_NULL;
// success
return TRUE;
}
BOOL
H323AllocLine(
PH323_LINE * ppLine
)
/*++
Routine Description:
Allocates line device.
Arguments:
ppLine - Pointer to DWORD-sized value which service provider must
write the newly allocated line.
Return Values:
Returns true if successful.
--*/
{
HRESULT hr;
PH323_LINE pLine;
// allocate object from heap
pLine = H323HeapAlloc(sizeof(H323_LINE));
// validate pointer
if (pLine == NULL) {
H323DBG((
DEBUG_LEVEL_ERROR,
"could not allocate line object.\n"
));
// failure
return FALSE;
}
__try {
// initialize lock (and allocate event immediately)
InitializeCriticalSectionAndSpinCount(&pLine->Lock,H323_SPIN_COUNT);
} __except ((GetExceptionCode() == STATUS_NO_MEMORY)
? EXCEPTION_EXECUTE_HANDLER
: EXCEPTION_CONTINUE_SEARCH
) {
// release object
H323HeapFree(pLine);
// failure
return FALSE;
}
// allocate call table
if (!H323AllocCallTable(&pLine->pCallTable)) {
// release critical section
DeleteCriticalSection(&pLine->Lock);
// release object
H323HeapFree(pLine);
// failure
return FALSE;
}
// initialize rtp/rtcp base port
pLine->dwNextPort = H323_RTPBASEPORT;
// reset line
H323ResetLine(pLine);
// transfer
*ppLine = pLine;
// success
return TRUE;
}
BOOL
H323FreeLine(
PH323_LINE pLine
)
/*++
Routine Description:
Releases line device.
Arguments:
pLine - Pointer to line device to release.
Return Values:
Returns true if successful.
--*/
{
// validate pointer
if (pLine != NULL) {
// release memory for call table
H323FreeCallTable(pLine->pCallTable);
// release critical section
DeleteCriticalSection(&pLine->Lock);
// release line
H323HeapFree(pLine);
}
H323DBG((
DEBUG_LEVEL_VERBOSE,
"line 0x%08lx released.\n",
pLine
));
// success
return TRUE;
}
BOOL
H323OpenLine(
PH323_LINE pLine,
HTAPILINE htLine,
DWORD dwTSPIVersion
)
/*++
Routine Description:
Initiate activities on line device and allocate resources.
Arguments:
pLine - Pointer to line device to open.
htLine - TAPI's handle describing line device to open.
dwTSPIVersion - The TSPI version negotiated through
TSPI_lineNegotiateTSPIVersion under which the Service Provider is
willing to operate.
Return Values:
Returns true if successful.
--*/
{
H323DBG((
DEBUG_LEVEL_TRACE,
"line %d opening.\n",
pLine->dwDeviceID
));
// start listen if necessary
if (H323IsMediaDetectionEnabled(pLine) &&
!H323StartListening(pLine)) {
// failure
return FALSE;
}
// save line variables now
pLine->htLine = htLine;
pLine->dwTSPIVersion = dwTSPIVersion;
// change line device state to opened
pLine->nState = H323_LINESTATE_OPENED;
// success
return TRUE;
}
BOOL
H323CloseLine(
PH323_LINE pLine
)
/*++
Routine Description:
Terminate activities on line device.
Arguments:
pLine - Pointer to line device to close.
Return Values:
Returns true if successful.
--*/
{
H323DBG((
DEBUG_LEVEL_TRACE,
"line %d %s.\n",
pLine->dwDeviceID,
pLine->fIsMarkedForDeletion
? "closing and being removed"
: "closing"
));
// see if we are listening
if (H323IsListening(pLine)) {
// stop listening first
H323StopListening(pLine);
}
// change line device state to closing
pLine->nState = H323_LINESTATE_CLOSING;
// close all calls now in table
H323CloseCallTable(pLine->pCallTable);
// delete line if marked
if (pLine->fIsMarkedForDeletion) {
// remove line device from table
H323FreeLineFromTable(pLine, g_pLineTable);
} else {
// reset variables
pLine->htLine = (HTAPILINE)NULL;
pLine->dwTSPIVersion = 0;
pLine->dwMediaModes = 0;
// change line device state to closed
pLine->nState = H323_LINESTATE_CLOSED;
}
// success
return TRUE;
}
BOOL
H323InitializeLine(
PH323_LINE pLine,
DWORD dwDeviceID
)
/*++
Routine Description:
Updates line device based on changes in registry.
Arguments:
pLine - Pointer to line device to update.
dwDeviceID - Device ID specified in TSPI_providerInit.
Return Values:
Returns true if successful.
--*/
{
DWORD dwSize = sizeof(pLine->wszAddr);
// save line device id
pLine->dwDeviceID = dwDeviceID;
// create displayable address
GetComputerNameW(pLine->wszAddr, &dwSize);
H323DBG((
DEBUG_LEVEL_TRACE,
"line %d initialized (addr=%S).\n",
pLine->dwDeviceID,
pLine->wszAddr
));
// change line device state to closed
pLine->nState = H323_LINESTATE_CLOSED;
// success
return TRUE;
}
///////////////////////////////////////////////////////////////////////////////
// //
// Public procedures //
// //
///////////////////////////////////////////////////////////////////////////////
BOOL
H323GetLineAndLock(
PH323_LINE * ppLine,
HDRVLINE hdLine
)
/*++
Routine Description:
Retrieves pointer to line device given line handle.
Arguments:
ppLine - Specifies a pointer to a DWORD-sized memory location
into which the service provider must write the line device pointer
associated with the given line handle.
hdLine - Specifies the Service Provider's opaque handle to the line.
Return Values:
Returns true if successful.
--*/
{
DWORD i;
PH323_LINE pLine = NULL;
// lock provider
H323LockProvider();
// retrieve line table index
i = H323GetLineTableIndex(PtrToUlong(hdLine));
// validate line table index
if (i >= g_pLineTable->dwNumSlots) {
H323DBG((
DEBUG_LEVEL_ERROR,
"line handle 0x%08lx invalid.\n",
PtrToUlong(hdLine)
));
// unlock provider
H323UnlockProvider();
// failure
return FALSE;
}
// retrieve line pointer from table
pLine = g_pLineTable->pLines[i];
// validate call information
if (!H323IsLineEqual(pLine,hdLine)) {
H323DBG((
DEBUG_LEVEL_ERROR,
"line handle 0x%08lx invalid.\n",
PtrToUlong(hdLine)
));
// unlock provider
H323UnlockProvider();
// failure
return FALSE;
}
// lock line device
H323LockLine(pLine);
// unlock provider
H323UnlockProvider();
// transfer
*ppLine = pLine;
// success
return TRUE;
}
BOOL
H323GetLineFromIDAndLock(
PH323_LINE * ppLine,
DWORD dwDeviceID
)
/*++
Routine Description:
Retrieves pointer to line device given device id.
Arguments:
ppLine - Specifies a pointer to a DWORD-sized memory location
into which the service provider must write the line device pointer
associated with the given device ID.
dwDeviceID - Identifies the line device.
Return Values:
Returns true if successful.
--*/
{
DWORD i;
// lock provider
H323LockProvider();
// loop through each objectin table
for (i = 0; i < g_pLineTable->dwNumSlots; i++) {
// validate object is allocated
if (H323IsLineAllocated(g_pLineTable->pLines[i])) {
// lock line device
H323LockLine(g_pLineTable->pLines[i]);
// compare stored device id with the one specified
if (H323IsLineInUse(g_pLineTable->pLines[i]) &&
(g_pLineTable->pLines[i]->dwDeviceID == dwDeviceID)) {
// transfer line device pointer
*ppLine = g_pLineTable->pLines[i];
// unlock provider
H323UnlockProvider();
// success
return TRUE;
}
// release line device
H323UnlockLine(g_pLineTable->pLines[i]);
}
}
// unlock provider
H323UnlockProvider();
// initialize
*ppLine = NULL;
// failure
return FALSE;
}
BOOL
H323CallListen(
PH323_LINE pLine
)
/*++
Routine Description:
Starts listening for calls on given line device.
Arguments:
pLine - Pointer to line device to start listening.
Return Values:
Returns true if successful.
--*/
{
HRESULT hr;
CC_ADDR ListenAddr;
// construct listen address
ListenAddr.nAddrType = CC_IP_BINARY;
ListenAddr.Addr.IP_Binary.dwAddr = INADDR_ANY;
ListenAddr.Addr.IP_Binary.wPort =
LOWORD(g_RegistrySettings.dwQ931CallSignallingPort);
ListenAddr.bMulticast = FALSE;
// start listening
hr = CC_CallListen(
&pLine->hccListen, // phListen
&ListenAddr, // pListenAddr
NULL, // pLocalAliasNames
PtrToUlong(pLine->hdLine), // dwListenToken
H323ListenCallback // ListenCallback
);
// validate status
if (hr != S_OK) {
H323DBG((
DEBUG_LEVEL_ERROR,
"error 0x%08lx calling CC_CallListen.\n", hr
));
// re-initialize call listen handle
pLine->hccListen = UNINITIALIZED;
// failure
return FALSE;
}
H323DBG((
DEBUG_LEVEL_VERBOSE,
"line %d listening for incoming calls.\n",
pLine->dwDeviceID
));
// success
return TRUE;
}
BOOL
H323StartListening(
PH323_LINE pLine
)
/*++
Routine Description:
Starts listening for calls on given line device.
Arguments:
pLine - Pointer to line device to start listening.
Return Values:
Returns true if successful.
--*/
{
// attempt to post call listen message
if (!H323PostCallListenMessage(pLine->hdLine)) {
H323DBG((
DEBUG_LEVEL_ERROR,
"error 0x%08lx posting call listen.\n",
GetLastError()
));
// failure
return FALSE;
}
// change state to listening
pLine->nState = H323_LINESTATE_LISTENING;
// success
return TRUE;
}
BOOL
H323StopListening(
PH323_LINE pLine
)
/*++
Routine Description:
Stops listening for calls on given line device.
Arguments:
pLine - Pointer to line device to stop listening.
Return Values:
Returns true if successful.
--*/
{
HRESULT hr;
// stop listening
hr = CC_CancelListen(pLine->hccListen);
// validate status
if (hr != S_OK) {
H323DBG((
DEBUG_LEVEL_ERROR,
"error 0x%08lx calling CC_CancelListen.\n", hr
));
//
// Unable to cancel listen on line
// device so uninitialize handle and
// continue...
//
}
// change state to opened
pLine->nState = H323_LINESTATE_OPENED;
// uninitialize listen handle
pLine->hccListen = UNINITIALIZED;
H323DBG((
DEBUG_LEVEL_VERBOSE,
"line %d no longer listening for incoming calls.\n",
pLine->dwDeviceID
));
// success
return TRUE;
}
BOOL
H323AllocLineTable(
PH323_LINE_TABLE * ppLineTable
)
/*++
Routine Description:
Allocates table of line objects.
Arguments:
ppLineTable - Pointer to LPVOID-size memory location in which
service provider will write pointer to line table.
Return Values:
Returns true if successful.
--*/
{
int i;
DWORD dwStatus;
PH323_LINE_TABLE pLineTable;
PH323_LINE pLine;
BOOL fOk = FALSE;
// allocate table from heap
pLineTable = H323HeapAlloc(
sizeof(H323_LINE_TABLE) +
sizeof(PH323_LINE) * H323_DEFLINESPERINST
);
// validate table pointer
if (pLineTable == NULL) {
H323DBG((
DEBUG_LEVEL_ERROR,
"could not allocate line table.\n"
));
// failure
goto cleanup;
}
// initialize number of slots
pLineTable->dwNumSlots = H323_DEFLINESPERINST;
// allocate line device
if (!H323AllocLineFromTable(&pLine,&pLineTable)) {
H323DBG((
DEBUG_LEVEL_ERROR,
"could not allocate default line.\n"
));
// failure
goto cleanup;
}
// transfer pointer
*ppLineTable = pLineTable;
// re-initialize
pLineTable = NULL;
// success
fOk = TRUE;
cleanup:
// validate pointer
if (pLineTable != NULL) {
// free new table
H323FreeLineTable(pLineTable);
}
// done...
return fOk;
}
BOOL
H323FreeLineTable(
PH323_LINE_TABLE pLineTable
)
/*++
Routine Description:
Deallocates table of line objects.
Arguments:
pLineTable - Pointer to line table to release.
Return Values:
Returns true if successful.
--*/
{
DWORD i;
// loop through each object in table
for (i = 0; i < pLineTable->dwNumSlots; i++) {
// validate object has been allocated
if (H323IsLineAllocated(pLineTable->pLines[i])) {
// release memory for object
H323FreeLine(pLineTable->pLines[i]);
}
}
// release memory for table
H323HeapFree(pLineTable);
// success
return TRUE;
}
BOOL
H323CloseLineTable(
PH323_LINE_TABLE pLineTable
)
/*++
Routine Description:
Closes table of line objects.
Arguments:
pLineTable - Pointer to table to close.
Return Values:
Returns true if successful.
--*/
{
DWORD i;
// loop through each objectin table
for (i = 0; i < pLineTable->dwNumSlots; i++) {
// validate object is allocated
if (H323IsLineAllocated(pLineTable->pLines[i])) {
// lock line device
H323LockLine(pLineTable->pLines[i]);
// see if line device in use
if (H323IsLineInUse(pLineTable->pLines[i])) {
// close previously opened object
H323CloseLine(pLineTable->pLines[i]);
}
// release line device
H323UnlockLine(pLineTable->pLines[i]);
}
}
// reset table information
pLineTable->dwNumInUse = 0;
pLineTable->dwNextAvailable = 0;
// success
return TRUE;
}
BOOL
H323AllocLineFromTable(
PH323_LINE * ppLine,
PH323_LINE_TABLE * ppLineTable
)
/*++
Routine Description:
Allocates line object in table.
Arguments:
ppLine - Specifies a pointer to a DWORD-sized value in which the
service provider must write the allocated line object.
ppLineTable - Pointer to pointer to line table in which to
allocate line from (expands table if necessary).
Return Values:
Returns true if successful.
--*/
{
DWORD i;
PH323_LINE pLine = NULL;
PH323_LINE_TABLE pLineTable = *ppLineTable;
// retrieve index to next entry
i = pLineTable->dwNextAvailable;
// see if previously allocated entries available
if (pLineTable->dwNumAllocated > pLineTable->dwNumInUse) {
// search table looking for available entry
while (H323IsLineInUse(pLineTable->pLines[i]) ||
!H323IsLineAllocated(pLineTable->pLines[i])) {
// increment index and adjust to wrap
i = H323GetNextIndex(i, pLineTable->dwNumSlots);
}
// retrieve pointer to object
pLine = pLineTable->pLines[i];
// mark entry as waiting for line device id
pLine->nState = H323_LINESTATE_WAITING_FOR_ID;
// initialize call handle with index
pLine->hdLine = H323CreateLineHandle(i);
// temporary device id
pLine->dwDeviceID = PtrToUlong(pLine->hdLine);
// increment number in use
pLineTable->dwNumInUse++;
// adjust next available index
pLineTable->dwNextAvailable =
H323GetNextIndex(i, pLineTable->dwNumSlots);
// transfer pointer
*ppLine = pLine;
// success
return TRUE;
}
// see if table is full and more slots need to be allocated
if (pLineTable->dwNumAllocated == pLineTable->dwNumSlots) {
// attempt to double table
pLineTable = H323HeapReAlloc(
pLineTable,
sizeof(H323_LINE_TABLE) +
pLineTable->dwNumSlots * 2 * sizeof(PH323_LINE)
);
// validate pointer
if (pLineTable == NULL) {
H323DBG((
DEBUG_LEVEL_ERROR,
"could not expand channel table.\n"
));
// failure
return FALSE;
}
// adjust index into table
i = pLineTable->dwNumSlots;
// adjust number of slots
pLineTable->dwNumSlots *= 2;
// transfer pointer to caller
*ppLineTable = pLineTable;
}
// allocate new object
if (!H323AllocLine(&pLine)) {
// failure
return FALSE;
}
// search table looking for slot with no object allocated
while (H323IsLineAllocated(pLineTable->pLines[i])) {
// increment index and adjust to wrap
i = H323GetNextIndex(i, pLineTable->dwNumSlots);
}
// store pointer to object
pLineTable->pLines[i] = pLine;
// mark entry as being in use
pLine->nState = H323_LINESTATE_CLOSED;
// initialize call handle with index
pLine->hdLine = H323CreateLineHandle(i);
// temporary device id
pLine->dwDeviceID = PtrToUlong(pLine->hdLine);
// increment number in use
pLineTable->dwNumInUse++;
// increment number allocated
pLineTable->dwNumAllocated++;
// adjust next available index
pLineTable->dwNextAvailable =
H323GetNextIndex(i, pLineTable->dwNumSlots);
// transfer pointer
*ppLine = pLine;
// success
return TRUE;
}
BOOL
H323FreeLineFromTable(
PH323_LINE pLine,
PH323_LINE_TABLE pLineTable
)
/*++
Routine Description:
Deallocates line object in table.
Arguments:
pLine - Pointer to object to deallocate.
pLineTable - Pointer to table containing object.
Return Values:
Returns true if successful.
--*/
{
// reset line object
H323ResetLine(pLine);
// decrement entries in use
pLineTable->dwNumInUse--;
// success
return TRUE;
}
BOOL
H323InitializeLineTable(
PH323_LINE_TABLE pLineTable,
DWORD dwLineDeviceIDBase
)
/*++
Routine Description:
Updates line devices based on changes to registry settings.
Arguments:
pLineTable - Pointer to line table to update.
dwLineDeviceIDBase - Device ID specified in TSPI_providerInit.
Return Values:
Returns true if successful.
--*/
{
UINT i;
// loop through line device structures
for (i = 0; i < pLineTable->dwNumSlots; i++) {
// see if line is allocated
if (H323IsLineAllocated(pLineTable->pLines[i])) {
// lock line device
H323LockLine(pLineTable->pLines[i]);
// see if line device is in user
if (H323IsLineInUse(pLineTable->pLines[i])) {
// update settings
H323InitializeLine(
pLineTable->pLines[i],
dwLineDeviceIDBase + g_dwLineDeviceUniqueID++
);
}
// unlock line device
H323UnlockLine(pLineTable->pLines[i]);
}
}
// success
return TRUE;
}
BOOL
H323RemoveLine(
PH323_LINE pLine
)
/*++
Routine Description:
Adds line device to line table.
Arguments:
pLine - Pointer to line device to remove.
Return Values:
Returns true if successful.
--*/
{
// mark line as about to be removed
pLine->fIsMarkedForDeletion = TRUE;
// fire close event
(*g_pfnLineEventProc)(
(HTAPILINE)0, // htLine
(HTAPICALL)0, // htCall
LINE_REMOVE, // dwMsg
pLine->dwDeviceID, // dwParam1
0, // dwParam2
0 // dwParam3
);
// see if line closed
if (H323IsLineClosed(pLine)) {
H323DBG((
DEBUG_LEVEL_TRACE,
"line %d being removed.\n",
pLine->dwDeviceID
));
// remove line device from table
H323FreeLineFromTable(pLine, g_pLineTable);
}
// success
return TRUE;
}
#if defined(DBG) && defined(DEBUG_CRITICAL_SECTIONS)
VOID
H323LockLine(
PH323_LINE pLine
)
/*++
Routine Description:
Locks line device.
Arguments:
pLine - Pointer to line to lock.
Return Values:
None.
--*/
{
H323DBG((
DEBUG_LEVEL_VERBOSE,
"line %d about to be locked.\n",
pLine->dwDeviceID
));
// lock line device
EnterCriticalSection(&pLine->Lock);
H323DBG((
DEBUG_LEVEL_VERBOSE,
"line %d locked.\n",
pLine->dwDeviceID
));
}
VOID
H323UnlockLine(
PH323_LINE pLine
)
/*++
Routine Description:
Unlocks line device.
Arguments:
pLine - Pointer to line to unlock.
Return Values:
None.
--*/
{
// unlock line device
LeaveCriticalSection(&pLine->Lock);
H323DBG((
DEBUG_LEVEL_VERBOSE,
"line %d unlocked.\n",
pLine->dwDeviceID
));
}
#endif // DBG && DEBUG_CRITICAL_SECTIONS
///////////////////////////////////////////////////////////////////////////////
// //
// TSPI procedures //
// //
///////////////////////////////////////////////////////////////////////////////
LONG
TSPIAPI
TSPI_lineClose(
HDRVLINE hdLine
)
/*++
Routine Description:
This function closes the specified open line device after completing or
aborting all outstanding calls and asynchronous operations on the device.
The Service Provider has the responsibility to (eventually) report
completion for every operation it decides to execute asynchronously.
If this procedure is called for a line on which there are outstanding
asynchronous operations, the operations should be reported complete with an
appropriate result or error code before this procedure returns. Generally
the TAPI DLL would wait for these to complete in an orderly fashion.
However, the Service Provider should be prepared to handle an early call to
TSPI_lineClose in "abort" or "emergency shutdown" situtations.
A similar requirement exists for active calls on the line. Such calls must
be dropped, with outstanding operations reported complete with appropriate
result or error codes.
After this procedure returns the Service Provider must report no further
events on the line or calls that were on the line. The Service Provider's
opaque handles for the line and calls on the line become "invalid".
The Service Provider must relinquish non-sharable resources it reserves
while the line is open. For example, closing a line accessed through a
comm port and modem should result in closing the comm port, making it once
available for use by other applications.
This function is presumed to complete successfully and synchronously.
Arguments:
hdLine - Specifies the Service Provider's opaque handle to the line to be
closed. After the line has been successfully closed, this handle is
no longer valid.
Return Values:
Returns zero if the function is successful, or a negative error
number if an error has occurred. Possible error returns are:
LINEERR_INVALLINEHANDLE - The specified device handle is invalid.
LINEERR_OPERATIONFAILED - The specified operation failed for unknown
reasons.
--*/
{
PH323_LINE pLine = NULL;
// retrieve line pointer from handle
if (!H323GetLineAndLock(&pLine, hdLine)) {
// invalid line handle
return LINEERR_INVALLINEHANDLE;
}
// attempt to close line device
if (!H323CloseLine(pLine)) {
// release line device
H323UnlockLine(pLine);
// could not close line device
return LINEERR_OPERATIONFAILED;
}
// release line device
H323UnlockLine(pLine);
// success
return NOERROR;
}
LONG
TSPIAPI
TSPI_lineGetDevCaps(
DWORD dwDeviceID,
DWORD dwTSPIVersion,
DWORD dwExtVersion,
LPLINEDEVCAPS pLineDevCaps
)
/*++
Routine Description:
This function queries a specified line device to determine its telephony
capabilities. The returned information is valid for all addresses on the
line device.
Line device ID numbering for a Service Provider is sequential from the
value set by the function TSPI_lineSetDeviceIDBase.
The dwExtVersion field of pLineDevCaps has already been filled in to
indicate the version number of the Extension information requested. If
it is zero, no Extension information is requested. If it is non-zero it
holds a value that has already been negotiated for this device with the
function TSPI_lineNegotiateExtVersion. The Service Provider should fill
in Extension information according to the Extension version specified.
One of the fields in the LINEDEVCAPS structure returned by this function
contains the number of addresses assigned to the specified line device.
The actual address IDs used to reference individual addresses vary from
zero to one less than the returned number. The capabilities of each
address may be different. Use TSPI_lineGetAddressCaps for each available
<dwDeviceID, dwAddressID> combination to determine the exact capabilities
of each address.
Arguments:
dwDeviceID - Specifies the line device to be queried.
dwTSPIVersion - Specifies the negotiated TSPI version number. This value
has already been negotiated for this device through the
TSPI_lineNegotiateTSPIVersion function.
pLineDevCaps - Specifies a far pointer to a variable sized structure of
type LINEDEVCAPS. Upon successful completion of the request, this
structure is filled with line device capabilities information.
Return Values:
Returns zero if the function is successful or a negative error
number if an error has occurred. Possible error returns are:
LINEERR_BADDEVICEID - The specified line device ID is out of range.
LINEERR_INCOMPATIBLEAPIVERSION - The application requested an API
version or version range that is either incompatible or cannot
be supported by the Telephony API implementation and/or
corresponding service provider.
LINEERR_STRUCTURETOOSMALL - The dwTotalSize member of a structure
does not specify enough memory to contain the fixed portion of
the structure. The dwNeededSize field has been set to the amount
required.
--*/
{
DWORD dwLineNameSize;
DWORD dwProviderInfoSize;
PH323_LINE pLine = NULL;
// make sure this is a version we support
if (!H323ValidateTSPIVersion(dwTSPIVersion)) {
// do not support tspi version
return LINEERR_INCOMPATIBLEAPIVERSION;
}
// make sure this is a version we support
if (!H323ValidateExtVersion(dwExtVersion)) {
// do not support extensions
return LINEERR_INVALEXTVERSION;
}
// retrieve line device pointer from device id
if (!H323GetLineFromIDAndLock(&pLine, dwDeviceID)) {
// invalid line device id
return LINEERR_BADDEVICEID;
}
// determine string lengths
dwProviderInfoSize = H323SizeOfWSZ(g_pwszProviderInfo);
dwLineNameSize = H323SizeOfWSZ(g_pwszLineName);
// calculate number of bytes required
pLineDevCaps->dwNeededSize = sizeof(LINEDEVCAPS) +
dwProviderInfoSize +
dwLineNameSize
;
// make sure buffer is large enough for variable length data
if (pLineDevCaps->dwTotalSize >= pLineDevCaps->dwNeededSize) {
// record amount of memory used
pLineDevCaps->dwUsedSize = pLineDevCaps->dwNeededSize;
// position provider info after fixed portion
pLineDevCaps->dwProviderInfoSize = dwProviderInfoSize;
pLineDevCaps->dwProviderInfoOffset = sizeof(LINEDEVCAPS);
// position line name after device class
pLineDevCaps->dwLineNameSize = dwLineNameSize;
pLineDevCaps->dwLineNameOffset =
pLineDevCaps->dwProviderInfoOffset +
pLineDevCaps->dwProviderInfoSize
;
// copy provider info after fixed portion
memcpy((LPBYTE)pLineDevCaps + pLineDevCaps->dwProviderInfoOffset,
(LPBYTE)g_pwszProviderInfo,
pLineDevCaps->dwProviderInfoSize
);
// copy line name after device class
memcpy((LPBYTE)pLineDevCaps + pLineDevCaps->dwLineNameOffset,
(LPBYTE)g_pwszLineName,
pLineDevCaps->dwLineNameSize
);
} else if (pLineDevCaps->dwTotalSize >= sizeof(LINEDEVCAPS)) {
H323DBG((
DEBUG_LEVEL_WARNING,
"linedevcaps structure too small for strings.\n"
));
// structure only contains fixed portion
pLineDevCaps->dwUsedSize = sizeof(LINEDEVCAPS);
} else {
H323DBG((
DEBUG_LEVEL_WARNING,
"linedevcaps structure too small.\n"
));
// release line device
H323UnlockLine(pLine);
// structure is too small
return LINEERR_STRUCTURETOOSMALL;
}
H323DBG((
DEBUG_LEVEL_VERBOSE,
"line %d capabilities requested.\n",
pLine->dwDeviceID
));
// construct permanent line identifier
pLineDevCaps->dwPermanentLineID = (DWORD)MAKELONG(
dwDeviceID - g_dwLineDeviceIDBase,
g_dwPermanentProviderID
);
// notify tapi that strings returned are in unicode
pLineDevCaps->dwStringFormat = STRINGFORMAT_UNICODE;
// initialize line device capabilities
pLineDevCaps->dwNumAddresses = H323_MAXADDRSPERLINE;
pLineDevCaps->dwMaxNumActiveCalls = H323_MAXCALLSPERLINE;
pLineDevCaps->dwAddressModes = H323_LINE_ADDRESSMODES;
pLineDevCaps->dwBearerModes = H323_LINE_BEARERMODES;
pLineDevCaps->dwDevCapFlags = H323_LINE_DEVCAPFLAGS;
pLineDevCaps->dwLineFeatures = H323_LINE_LINEFEATURES;
pLineDevCaps->dwMaxRate = H323_LINE_MAXRATE;
pLineDevCaps->dwMediaModes = H323_LINE_MEDIAMODES;
pLineDevCaps->dwRingModes = 0;
// initialize address types to include phone numbers
pLineDevCaps->dwAddressTypes = H323_LINE_ADDRESSTYPES;
// line guid
memcpy(
&pLineDevCaps->PermanentLineGuid,
&LINE_H323,
sizeof(GUID)
);
// modify GUID to be unique for each line
pLineDevCaps->PermanentLineGuid.Data1 +=
dwDeviceID - g_dwLineDeviceIDBase;
// protocol guid
memcpy(
&pLineDevCaps->ProtocolGuid,
&TAPIPROTOCOL_H323,
sizeof(GUID)
);
// add dtmf support via H.245 user input messages
pLineDevCaps->dwGenerateDigitModes = LINEDIGITMODE_DTMF;
pLineDevCaps->dwMonitorDigitModes = LINEDIGITMODE_DTMF;
// release line device
H323UnlockLine(pLine);
// success
return NOERROR;
}
LONG
TSPIAPI
TSPI_lineGetLineDevStatus(
HDRVLINE hdLine,
LPLINEDEVSTATUS pLineDevStatus
)
/*++
Routine Description:
This operation enables the TAPI DLL to query the specified open line
device for its current status.
The TAPI DLL uses TSPI_lineGetLineDevStatus to query the line device
for its current line status. This status information applies globally
to all addresses on the line device. Use TSPI_lineGetAddressStatus to
determine status information about a specific address on a line.
Arguments:
hdLine - Specifies the Service Provider's opaque handle to the line
to be queried.
pLineDevStatus - Specifies a far pointer to a variable sized data
structure of type LINEDEVSTATUS. Upon successful completion of
the request, this structure is filled with the line's device status.
Return Values:
Returns zero if the function is successful or a negative error
number if an error has occurred. Possible error returns are:
LINEERR_INVALLINEHANDLE - The specified line device handle is invalid.
LINEERR_STRUCTURETOOSMALL - The dwTotalSize member of a structure does
not specify enough memory to contain the fixed portion of the
structure. The dwNeededSize field has been set to the amount
required.
--*/
{
PH323_LINE pLine = NULL;
// retrieve line device pointer from handle
if (!H323GetLineAndLock(&pLine, hdLine)) {
// invalid line device handle
return LINEERR_INVALLINEHANDLE;
}
// determine number of bytes needed
pLineDevStatus->dwNeededSize = sizeof(LINEDEVSTATUS);
// see if allocated structure is large enough
if (pLineDevStatus->dwTotalSize < pLineDevStatus->dwNeededSize) {
H323DBG((
DEBUG_LEVEL_ERROR,
"linedevstatus structure too small.\n"
));
// release line device
H323UnlockLine(pLine);
// structure too small
return LINEERR_STRUCTURETOOSMALL;
}
// record number of bytes used
pLineDevStatus->dwUsedSize = pLineDevStatus->dwNeededSize;
// initialize supported line device status fields
pLineDevStatus->dwLineFeatures = H323_LINE_LINEFEATURES;
pLineDevStatus->dwDevStatusFlags = H323_LINE_DEVSTATUSFLAGS;
// determine number of active calls on the line device
pLineDevStatus->dwNumActiveCalls = pLine->pCallTable->dwNumInUse;
// release line device
H323UnlockLine(pLine);
// success
return NOERROR;
}
LONG
TSPIAPI
TSPI_lineGetNumAddressIDs(
HDRVLINE hdLine,
LPDWORD pdwNumAddressIDs
)
/*++
Routine Description:
Retrieves the number of address IDs supported on the indicated line.
This function is called by TAPI.DLL in response to an application calling
lineSetNumRings, lineGetNumRings, or lineGetNewCalls. TAPI.DLL uses the
retrieved value to determine if the specified address ID is within the
range supported by the service provider.
Arguments:
hdLine - Specifies the handle to the line for which the number of address
IDs is to be retrieved.
pdwNumAddressIDs - Specifies a far pointer to a DWORD. The location is
filled with the number of address IDs supported on the indicated line.
The value should be one or larger.
Return Values:
Returns zero if the function is successful, or a negative error number
if an error has occurred. Possible return values are as follows:
LINEERR_INVALLINEHANDLE - The specified line device handle is invalid.
--*/
{
PH323_LINE pLine = NULL;
// retrieve line device pointer from handle
if (!H323GetLineAndLock(&pLine, hdLine)) {
// invalid line device handle
return LINEERR_INVALLINEHANDLE;
}
// transfer number of addresses
*pdwNumAddressIDs = H323_MAXADDRSPERLINE;
// release line device
H323UnlockLine(pLine);
// success
return NOERROR;
}
LONG
TSPIAPI
TSPI_lineOpen(
DWORD dwDeviceID,
HTAPILINE htLine,
LPHDRVLINE phdLine,
DWORD dwTSPIVersion,
LINEEVENT pfnEventProc
)
/*++
Routine Description:
This function opens the line device whose device ID is given, returning
the Service Provider's opaque handle for the device and retaining the TAPI
DLL's opaque handle for the device for use in subsequent calls to the
LINEEVENT procedure.
Opening a line entitles the TAPI DLL to make further requests on the line.
The line becomes "active" in the sense that the TAPI DLL can initiate
outbound calls and the Service Provider can report inbound calls. The
Service Provider reserves whatever non-sharable resources are required to
manage the line. For example, opening a line accessed through a comm port
and modem should result in opening the comm port, making it no longer
available for use by other applications.
If the function is successful, both the TAPI DLL and the Service Provider
become committed to operating under the specified interface version number
for this open device. Subsquent operations and events identified using
the exchanged opaque line handles conform to that interface version. This
commitment and the validity of the handles remain in effect until the TAPI
DLL closes the line using the TSPI_lineClose operation or the Service
Provider reports the LINE_CLOSE event. If the function is not successful,
no such commitment is made and the handles are not valid.
Arguments:
dwDeviceID - Identifies the line device to be opened. The value
LINE_MAPPER for a device ID is not permitted.
htLine - Specifies the TAPI DLL's opaque handle for the line device to be
used in subsequent calls to the LINEEVENT callback procedure to
identify the device.
phdLine - A far pointer to a HDRVLINE where the Service Provider fills in
its opaque handle for the line device to be used by the TAPI DLL in
subsequent calls to identify the device.
dwTSPIVersion - The TSPI version negotiated through
TSPI_lineNegotiateTSPIVersion under which the Service Provider is
willing to operate.
pfnEventProc - A far pointer to the LINEEVENT callback procedure supplied
by the TAPI DLL that the Service Provider will call to report
subsequent events on the line.
Return Values:
Returns zero if the function is successful, or a negative error number
if an error has occurred. Possible return values are as follows:
LINEERR_BADDEVICEID - The specified line device ID is out of range.
LINEERR_INCOMPATIBLEAPIVERSION - The passed TSPI version or version
range did not match an interface version definition supported by
the service provider.
LINEERR_INUSE - The line device is in use and cannot currently be
configured, allow a party to be added, allow a call to be
answered, or allow a call to be placed.
LINEERR_OPERATIONFAILED - The operation failed for an unspecified or
unknown reason.
--*/
{
PH323_LINE pLine = NULL;
// make sure this is a version we support
if (!H323ValidateTSPIVersion(dwTSPIVersion)) {
// failure
return LINEERR_INCOMPATIBLEAPIVERSION;
}
// retrieve pointer to line device from device id
if (!H323GetLineFromIDAndLock(&pLine, dwDeviceID)) {
// do not recognize device
return LINEERR_BADDEVICEID;
}
// see if line device is closed
if (!H323IsLineClosed(pLine) &&
!pLine->fIsMarkedForDeletion) {
// see if line device is open
if (H323IsLineOpen(pLine)) {
H323DBG((
DEBUG_LEVEL_ERROR,
"line %d already opened.\n",
pLine->dwDeviceID
));
// release line device
H323UnlockLine(pLine);
// line already in use
return LINEERR_INUSE;
}
// release line device
H323UnlockLine(pLine);
// line not intialized
return LINEERR_INVALLINESTATE;
}
// attempt to open line device
if (!H323OpenLine(pLine, htLine, dwTSPIVersion)) {
// release line device
H323UnlockLine(pLine);
// could not open line device
return LINEERR_OPERATIONFAILED;
}
// retrurn line handle
*phdLine = pLine->hdLine;
// release line device
H323UnlockLine(pLine);
// success
return NOERROR;
}
LONG
TSPIAPI
TSPI_lineCreateMSPInstance(
HDRVLINE hdLine,
DWORD dwAddressID,
HTAPIMSPLINE htMSPLine,
LPHDRVMSPLINE phdMSPLine
)
{
PH323_LINE pLine = NULL;
// retrieve line pointer from handle
if (!H323GetLineAndLock(&pLine, hdLine)) {
// invalid line handle
return LINEERR_INVALLINEHANDLE;
}
// We are not keeping the msp handles. Just fake a handle here.
*phdMSPLine = (HDRVMSPLINE)pLine->dwNextMSPHandle++;
// release line device
H323UnlockLine(pLine);
// success
return NOERROR;
}
LONG
TSPIAPI
TSPI_lineCloseMSPInstance(
HDRVMSPLINE hdMSPLine
)
{
// success
return NOERROR;
}