windows-nt/Source/XPSP1/NT/net/tapi/skywalker/cc/h245ws/h245ws.cpp
2020-09-26 16:20:57 +08:00

1906 lines
58 KiB
C++

/***************************************************************************
*
* File: h245ws.c
*
* INTEL Corporation Proprietary Information
* Copyright (c) 1996 Intel Corporation.
*
* This listing is supplied under the terms of a license agreement
* with INTEL Corporation and may not be used, copied, nor disclosed
* except in accordance with the terms of that agreement.
*
***************************************************************************
*
*
* $Workfile: h245ws.cpp $
* $Revision: 2.11 $
* $Modtime: 31 Jan 1997 19:22:28 $
* $Log: S:\sturgeon\src\h245ws\vcs\h245ws.cpv $
*
* Rev 2.11 31 Jan 1997 20:24:34 SBELL1
* Relinquished CallControl Stack lock before DefWindowProc
*
* Rev 2.10 31 Jan 1997 14:54:12 EHOWARDX
* Added CCLOCK support.
*
* Rev 2.9 20 Jan 1997 20:42:34 SBELL1
* Fixed GPF when shutting down.
*
* Rev 2.8 07 Jan 1997 11:51:48 EHOWARDX
*
* Fixed "assignment within conditional expression" warning
* in GetLinkLayerInstance().
*
* Rev 2.7 03 Jan 1997 13:15:18 EHOWARDX
* Attempt at workaround for #1718 linkLayerListen() returns WSAENOBUFS.
*
* Rev 2.6 23 Dec 1996 15:30:16 EHOWARDX
*
* Set window to zero after call to destroy window -- Uninitialize seems
* to be called more than once.
*
* Rev 2.5 20 Dec 1996 17:49:10 SBELL1
* changed to blocking mode before closesocket in SocketClose.
* This makes the linger work.
*
* Rev 2.4 19 Dec 1996 19:03:18 SBELL1
* Moved Initialize to linkLayerInit
* Set linger option on accept socket
* reversed "new" change
*
* Rev 2.3 Dec 13 1996 17:12:36 plantz
* fixed string for UNICODE.
//
// Rev 1.3 13 Dec 1996 14:32:10 SBELL1
// fixed string for UNICODE.
//
// Rev 1.1 12 Dec 1996 17:59:02 SBELL1
// Fixed bug in lingering on Q.931 Listen socket.
//
// Rev 1.0 11 Dec 1996 13:41:14 SBELL1
// Initial revision.
*
* Rev 1.46 18 Oct 1996 16:46:12 EHOWARDX
*
* Changed GetIpAddress to take wide char cAddr field.
*
* Rev 1.45 Oct 01 1996 14:29:56 EHOWARDX
* Moved Initialize() and Unitialize() calls to DllMain().
*
* Rev 1.44 26 Sep 1996 18:52:10 EHOWARDX
*
* Moved some initialization around to prevent possible assertion failure
* in SocketClose().
*
* Rev 1.43 15 Aug 1996 13:59:00 rodellx
*
* Added additional address validation for DOMAIN_NAME addresses
* which cannot be resolved, but are used with SocketBind().
*
* Rev 1.42 Aug 07 1996 14:38:00 mandrews
* Set bMulticast field of CC_ADDR structures correctly.
*
* Rev 1.41 24 Jul 1996 11:53:02 EHOWARDX
* Changed ADDR to CC_ADDR, IP_XXX to CC_IP_XXX.
* Fixed bug in SocketCloseEvent - needed to revalidate pHws after callback.
*
* Rev 1.40 08 Jul 1996 19:27:18 unknown
* Second experiment to try to fix Q.931 shutdown problem.
*
* Rev 1.39 02 Jul 1996 16:23:02 EHOWARDX
* Backed out experimental change.
*
* Rev 1.37 28 Jun 1996 18:06:50 unknown
* Added breaks to GetPort.
*
* Rev 1.36 27 Jun 1996 14:06:06 EHOWARDX
* Byte-swapped port number for debug trace in linkLayerListen & linkLayerConn
*
* Rev 1.35 21 Jun 1996 18:52:14 unknown
* Fixed yet another shutdown bug - linkLayerShutdown re-entrancy check.
*
* Rev 1.34 18 Jun 1996 16:56:20 EHOWARDX
* Added check to see if callback deallocated our instance to SocketConnect().
*
* Rev 1.33 17 Jun 1996 13:23:48 EHOWARDX
* Workaround for PostQuitMessage() bug.
*
* Rev 1.32 12 Jun 1996 11:43:26 EHOWARDX
* Changed linkLayerConnect errors from HWS_CRITICAL to HWS_WARNING.
*
* Rev 1.31 May 28 1996 18:14:00 plantz
* Change error codes to use HRESULT. Propogate Winsock errors where appropriate
*
* Rev 1.30 May 28 1996 10:38:08 plantz
* Change sprintf to wsprintf.
*
* Rev 1.29 17 May 1996 16:49:24 EHOWARDX
* Shutdown fix.
*
* Rev 1.28 16 May 1996 13:09:18 EHOWARDX
* Made reporting of IP Addres and port consistent between linkLayerListen
* and LinkLayerConnect.
*
* Rev 1.27 14 May 1996 11:31:50 EHOWARDX
* Fixed bug with doing another connect on instance that failed previous
* connect. Instance now returns LINK_INVALID_STATE, and must be closed
* and reopened.
*
* Rev 1.26 09 May 1996 18:33:22 EHOWARDX
*
* Changes to build with new LINKAPI.H.
*
* Rev 1.25 Apr 29 1996 19:06:48 plantz
* Reenable code to try to send all messages when shutting down.
*
* Rev 1.24 Apr 29 1996 14:02:58 plantz
* Add NotifyRead and NotifyWrite functions.
* Delete unused function FindH245Instance.
* .
*
* Rev 1.23 Apr 25 1996 21:16:26 plantz
* Add connect callback parameter to linkLayerAccept.
* Pass message type to connect callback.
*
* Rev 1.22 Apr 24 1996 20:49:30 plantz
* Listen on address passed to linkLayerListen; use INADDR_ANY if it is 0.
* Return the result of getsockname after listening.
* Add a callback parameter to linkLayerConnect. Call it when FD_CONNECT event
* occurs and after calling accept, passing error code and local and peer
* addresses.
*
* Rev 1.21 Apr 24 1996 16:55:20 plantz
* Merge 1.15.1.0 with 1.20 (winsock 1 changes)
*
* Rev 1.20 19 Apr 1996 18:28:50 EHOWARDX
* Changed Send and receive flush to call send and receive callback with
* LINK_FLUSH_COMPLETE message to more accurately emulate behavior
* of H245SRP.DLL.
*
* Rev 1.19 19 Apr 1996 10:34:26 EHOWARDX
* Updated to latest LINKAPI.H - WINAPI keywork eliminated.
*
* Rev 1.18 12 Apr 1996 19:17:02 unknown
* Removed annoying trace message.
*
* Rev 1.17 11 Apr 1996 14:53:22 EHOWARDX
* Changed to include INCOMMON.H instead of CALLCONT.H.
*
* Rev 1.16 04 Apr 1996 12:35:04 EHOWARDX
* Valiantly trying to track never-ending changes to Link Layer API
* (Thanks Dan! Changing linkLayerGetInstId to linkLayerGetInstance() --
* what a stroke of genius!)
*
* Rev 1.15.1.0 Apr 24 1996 16:23:02 plantz
* Change to use winsock 1.
*
* Rev 1.15 03 Apr 1996 16:35:46 EHOWARDX
* CLOSED state no longer implies that we have a thread;
* replaced assert with if statement.
*
* Rev 1.14 03 Apr 1996 14:52:24 EHOWARDX
* Fixed yet another shutdown problem.
*
* Rev 1.13 02 Apr 1996 18:28:50 EHOWARDX
* Added ProcessQueuedRecvs() to SocketAccept().
*
* Rev 1.12 01 Apr 1996 16:25:46 EHOWARDX
* Experiment with calling ProcessRecvQueue on FD_WRITE event.
*
* Rev 1.11 01 Apr 1996 14:20:40 unknown
* Shutdown redesign.
*
* Rev 1.10 29 Mar 1996 11:12:56 EHOWARDX
* Added line to SocketClose to set state to HWS_CLOSED.
*
* Rev 1.9 27 Mar 1996 13:00:30 EHOWARDX
* Added dwThreadId to H245WS instance structure.
* Reversed shutdown loop to check state first BEFORE checking send queue.
*
* Rev 1.8 22 Mar 1996 10:54:20 unknown
*
* Minor change in trace text.
*
* Rev 1.7 20 Mar 1996 14:11:20 unknown
* Added Sleep(0) to bind retry loop.
*
* Rev 1.6 19 Mar 1996 20:21:56 EHOWARDX
* Redesigned shutdown.
*
* Rev 1.4 18 Mar 1996 19:08:28 EHOWARDX
* Fixed shutdown; eliminated TPKT/WSCB dependencies.
* Define TPKT to put TPKT/WSCB dependencies back in.
*
* Rev 1.3 14 Mar 1996 17:01:46 EHOWARDX
*
* NT4.0 testing; got rid of HwsAssert(); got rid of TPKT/WSCB.
*
* Rev 1.2 09 Mar 1996 21:12:26 EHOWARDX
* Fixes as result of testing.
*
* Rev 1.1 08 Mar 1996 20:24:24 unknown
* This is the real version of the main h245ws.dll code.
* Version 1.0 was a stub version created by Mike Andrews.
*
***************************************************************************/
#ifndef STRICT
#define STRICT
#endif // not defined STRICT
#define LINKDLL_EXPORT
#pragma warning ( disable : 4115 4201 4214 4514 )
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include "queue.h"
#include "linkapi.h"
#include "incommon.h"
#include "h245ws.h"
#include "tstable.h"
#include "provider.h"
#if defined(__cplusplus)
extern "C"
{
#endif // (__cplusplus)
// REVIEW: Should we use the newer definition from winsock2.h ?
#undef FD_ALL_EVENTS
#define FD_ALL_EVENTS (FD_READ|FD_WRITE|FD_OOB|FD_ACCEPT|FD_CONNECT|FD_CLOSE)
#define WINSOCK_EVENT_MSG (WM_USER+1)
HRESULT SocketOpen(PHWSINST pHws, BOOL bSetLinger = TRUE);
/*
* Static variables
*/
static HWND window = 0;
TSTable<HWSINST>* gpInstanceTable; // global ptr to the instance table
static CRITICAL_SECTION SocketToHWSInstanceMapLock;
static SOCKET_TO_INSTANCE *pSocketToHWSInstanceMap = NULL;
// If we are not using the Unicode enabled tracing, then undefine the __TEXT macro.
// Do not place anything that should be a Unicode constant string between this #undef
// and the corresponding redefinition of the macro
#if defined(DBG)
#ifndef UNICODE_TRACE
#undef __TEXT
#define __TEXT(x) x
static const char * StateMap[] =
#else
static const LPTSTR StateMap[] =
#endif
{
__TEXT("HWS_START"), // 0 Initial state
__TEXT("HWS_LISTENING"), // 1 Waiting for FD_ACCEPT
__TEXT("HWS_CONNECTING"), // 2 Waiting for FD_CONNECT
__TEXT("HWS_CONNECTED"), // 3 Data transfer state
__TEXT("HWS_CLOSING"), // 4 Waiting for FD_CLOSE
__TEXT("HWS_CLOSED"), // 5 Waiting for linkLayerShutdown()
__TEXT("HWS_SHUTDOWN"), // 6 linkLayerShutdown() called from callback
};
typedef struct _ERROR_MAP
{
int nErrorCode;
#ifdef UNICODE_TRACE
LPCTSTR pszErrorText;
#else
const char *pszErrorText;
#endif
} ERROR_MAP;
static const ERROR_MAP ErrorMap[] =
{
0, __TEXT("OK"),
WSAEINTR, __TEXT("WSAEINTR - Interrupted function call"),
WSAEBADF, __TEXT("WSAEBADF"),
WSAEACCES, __TEXT("WSAEACCES - Permission denied"),
WSAEFAULT, __TEXT("WSAEFAULT - Bad address"),
WSAEINVAL, __TEXT("WSAEINVAL - Invalid argument"),
WSAEMFILE, __TEXT("WSAEMFILE - Too many open files"),
WSAEWOULDBLOCK, __TEXT("WSAEWOULDBLOCK - Resource temporarily unavailable"),
WSAEINPROGRESS, __TEXT("WSAEINPROGRESS - Operation now in progress"),
WSAEALREADY, __TEXT("WSAEALREADY - Operation already in progress"),
WSAENOTSOCK, __TEXT("WSAENOTSOCK - Socket operation on non-socket"),
WSAEDESTADDRREQ, __TEXT("WSAEDESTADDRREQ - Destination address required"),
WSAEMSGSIZE, __TEXT("WSAEMSGSIZE - Message too long"),
WSAEPROTOTYPE, __TEXT("WSAEPROTOTYPE - Protocol wrong type for socket"),
WSAENOPROTOOPT, __TEXT("WSAENOPROTOOPT - Bad protocol option"),
WSAEPROTONOSUPPORT, __TEXT("WSAEPROTONOSUPPORT - Protocol not supported"),
WSAESOCKTNOSUPPORT, __TEXT("WSAESOCKTNOSUPPORT - Socket type not supported"),
WSAEOPNOTSUPP, __TEXT("WSAEOPNOTSUPP - Operation not supported"),
WSAEPFNOSUPPORT, __TEXT("WSAEPFNOSUPPORT - Protocol family not supported"),
WSAEAFNOSUPPORT, __TEXT("WSAEAFNOSUPPORT - Address family not supported by protocol family"),
WSAEADDRINUSE, __TEXT("WSAEADDRINUSE - Address already in use"),
WSAEADDRNOTAVAIL, __TEXT("WSAEADDRNOTAVAIL - Cannot assign requested address"),
WSAENETDOWN, __TEXT("WSAENETDOWN - Network is down"),
WSAENETUNREACH, __TEXT("WSAENETUNREACH - Network is unreachable"),
WSAENETRESET, __TEXT("WSAENETRESET - Network dropped connection on reset"),
WSAECONNABORTED, __TEXT("WSAECONNABORTED - Software caused connection abort"),
WSAECONNRESET, __TEXT("WSAECONNRESET - Connection reset by peer"),
WSAENOBUFS, __TEXT("WSAENOBUFS - No buffer space available"),
WSAEISCONN, __TEXT("WSAEISCONN - Socket is already connected"),
WSAENOTCONN, __TEXT("WSAENOTCONN - Socket is not connected"),
WSAESHUTDOWN, __TEXT("WSAESHUTDOWN - Cannot send after socket shutdown"),
WSAETOOMANYREFS, __TEXT("WSAETOOMANYREFS"),
WSAETIMEDOUT, __TEXT("WSAETIMEDOUT - Connection timed out"),
WSAECONNREFUSED, __TEXT("WSAECONNREFUSED - Connection refused"),
WSAELOOP, __TEXT("WSAELOOP"),
WSAENAMETOOLONG, __TEXT("WSAENAMETOOLONG"),
WSAEHOSTDOWN, __TEXT("WSAEHOSTDOWN - Host is down"),
WSAEHOSTUNREACH, __TEXT("WSAEHOSTUNREACH - No route to host"),
WSAENOTEMPTY, __TEXT("WSAENOTEMPTY"),
WSAEPROCLIM, __TEXT("WSAEPROCLIM - Too many processes"),
WSAEUSERS, __TEXT("WSAEUSERS"),
WSAEDQUOT, __TEXT("WSAEDQUOT"),
WSAESTALE, __TEXT("WSAESTALE"),
WSAEREMOTE, __TEXT("WSAEREMOTE"),
WSASYSNOTREADY, __TEXT("WSASYSNOTREADY - Network subsystem is unavailable"),
WSAVERNOTSUPPORTED, __TEXT("WSAVERNOTSUPPORTED - WINSOCK.DLL version out of range"),
WSANOTINITIALISED, __TEXT("WSANOTINITIALISED - Successful WSAStartup() not yet performed"),
WSAEDISCON, __TEXT("WSAEDISCON - Graceful shutdown in progress"),
WSAHOST_NOT_FOUND, __TEXT("WSAHOST_NOT_FOUND - Host not found"),
WSATRY_AGAIN, __TEXT("WSATRY_AGAIN - Non-authoritative host not found"),
WSANO_RECOVERY, __TEXT("WSANO_RECOVERY - This is a non-recoverable error"),
WSANO_DATA, __TEXT("WSANO_DATA - Valid name, no data record of requested type"),
// WSA_INVALID_HANDLE, __TEXT("WSA_INVALID_HANDLE - Specified event object handle is invalid"),
// WSA_INVALID_PARAMETER, __TEXT("WSA_INVALID_PARAMETER - One or more parameters are invalid"),
// WSA_IO_PENDING, __TEXT("WSA_IO_PENDING - Overlapped operations will complete later"),
// WSA_IO_INCOMPLETE, __TEXT("WSA_IO_INCOMPLETE - Overlapped I/O event object not in signaled state"),
// WSA_NOT_ENOUGH_MEMORY, __TEXT("WSA_NOT_ENOUGH_MEMORY - Insufficient memory available"),
// WSA_OPERATION_ABORTED, __TEXT("WSA_OPERATION_ABORTED - Overlapped operation aborted"),
};
//
// Function Definitions
//
#include <string.h>
#ifdef UNICODE_TRACE
static const LPTSTR
#else
static const char *
#endif
SocketStateText(UINT uState)
{
#ifdef UNICODE_TRACE
static TCHAR szSocketStateText[80];
#else
static char szSocketStateText[80];
#endif
if (uState <= HWS_SHUTDOWN)
return StateMap[uState];
wsprintf(szSocketStateText, __TEXT("Unknown state %d"), uState);
return szSocketStateText;
} // SocketStateText()
#ifdef UNICODE_TRACE
static LPCTSTR
#else
static const char *
#endif
SocketErrorText1(int nErrorCode)
{
register int nIndex = sizeof(ErrorMap) / sizeof(ErrorMap[0]);
#ifdef UNICODE_TRACE
static TCHAR szSocketErrorText[80];
#else
static char szSocketErrorText[80];
#endif
while (nIndex > 0)
{
if (ErrorMap[--nIndex].nErrorCode == nErrorCode)
{
return ErrorMap[nIndex].pszErrorText;
}
}
wsprintf(szSocketErrorText, __TEXT("Unknown error 0x%x"), nErrorCode);
return szSocketErrorText;
} // SocketErrorText1()
#ifdef UNICODE_TRACE
LPCTSTR
#else
const char *
#endif
SocketErrorText(void)
{
return SocketErrorText1(WSAGetLastError());
} // SocketErrorText()
#endif // (DBG)
/***************************************************************************
*
* Local routines
*
***************************************************************************/
static DWORD
HashSocket(SOCKET socket)
{
return (DWORD)((socket >> 2) % SOCK_TO_PHYSID_TABLE_SIZE);
}
DWORD
SocketToPhysicalId(SOCKET socket)
{
// hash the socket to get an index into the SocketToHWSInstanceMap table
DWORD idx = HashSocket(socket);
if(pSocketToHWSInstanceMap == NULL)
return(INVALID_PHYS_ID);
EnterCriticalSection(&SocketToHWSInstanceMapLock);
// idx indicates the entry point in the array, now traverse the linked list
PSOCKET_TO_INSTANCE pEntry = &pSocketToHWSInstanceMap[idx];
while(pEntry != NULL)
{
if(pEntry->socket == socket)
{
LeaveCriticalSection(&SocketToHWSInstanceMapLock);
return(pEntry->dwPhysicalId);
} else
{
pEntry = pEntry->next;
}
}
LeaveCriticalSection(&SocketToHWSInstanceMapLock);
return(INVALID_PHYS_ID);
} // SocketToPhysicalId()
BOOL
CreateSocketToPhysicalIdMapping(SOCKET socket, DWORD dwPhysicalId)
{
// hash the socket to get an index into the SocketToHWSInstanceMap table
DWORD idx = HashSocket(socket);
EnterCriticalSection(&SocketToHWSInstanceMapLock);
// idx indicates the entry point in the array, now traverse the linked list
PSOCKET_TO_INSTANCE pEntry = &pSocketToHWSInstanceMap[idx];
PSOCKET_TO_INSTANCE pNewEntry;
if (pEntry->socket == INVALID_SOCKET)
{
pNewEntry = pEntry;
} else
{
pNewEntry = new SOCKET_TO_INSTANCE;
if (pNewEntry == NULL)
{
LeaveCriticalSection(&SocketToHWSInstanceMapLock);
return(FALSE);
}
pNewEntry->next = pEntry->next;
pEntry->next = pNewEntry;
}
pNewEntry->socket = socket;
pNewEntry->dwPhysicalId = dwPhysicalId;
LeaveCriticalSection(&SocketToHWSInstanceMapLock);
return(TRUE);
}
BOOL
RemoveSocketToPhysicalIdMapping(SOCKET socket)
{
if (socket == INVALID_SOCKET)
return(FALSE);
// hash the socket to get an index into the SocketToHWSInstanceMap table
DWORD idx = HashSocket(socket);
BOOL bFound = FALSE;
EnterCriticalSection(&SocketToHWSInstanceMapLock);
// idx indicates the entry point in the array, now traverse the linked list
PSOCKET_TO_INSTANCE pEntry = &pSocketToHWSInstanceMap[idx];
if (pEntry->socket == socket)
{
pEntry->socket = INVALID_SOCKET;
bFound = TRUE;
} else
{
PSOCKET_TO_INSTANCE pNextEntry;
pNextEntry = pEntry->next;
while (bFound == FALSE && pNextEntry != NULL)
{
if(pNextEntry->socket == socket)
{
pEntry->next = pNextEntry->next;
delete pNextEntry;
bFound = TRUE;
} else
{
pEntry = pNextEntry;
pNextEntry = pNextEntry->next;
}
}
}
LeaveCriticalSection(&SocketToHWSInstanceMapLock);
return(bFound);
}
static unsigned short GetPort (CC_ADDR *pAddr)
{
unsigned short int port = 0;
switch (pAddr->nAddrType)
{
case CC_IP_DOMAIN_NAME:
port = pAddr->Addr.IP_DomainName.wPort;
break;
case CC_IP_DOT:
port = pAddr->Addr.IP_Dot.wPort;
break;
case CC_IP_BINARY:
port = pAddr->Addr.IP_Binary.wPort;
break;
} // switch
return htons(port);
} // GetPort()
static unsigned long GetIPAddress (CC_ADDR *pAddr)
{
struct hostent * pHostEnt;
char szAddr[256];
switch (pAddr->nAddrType)
{
case CC_IP_DOMAIN_NAME:
WideCharToMultiByte(CP_ACP, // code page
0, // dwFlags
pAddr->Addr.IP_DomainName.cAddr,
-1, // Unicode string length (bytes)
szAddr, // ASCII string
sizeof(szAddr), // max ASCII string length
NULL, // default character
NULL); // default character used
pHostEnt = gethostbyname(szAddr);
if (pHostEnt == NULL || pHostEnt->h_addr_list == NULL)
return 0;
return *((unsigned long *)pHostEnt->h_addr_list[0]);
case CC_IP_DOT:
WideCharToMultiByte(CP_ACP, // code page
0, // dwFlags
pAddr->Addr.IP_Dot.cAddr,
-1, // Unicode string length (bytes)
szAddr, // ASCII string
sizeof(szAddr), // max ASCII string length
NULL, // default character
NULL); // default character used
return inet_addr(szAddr);
case CC_IP_BINARY:
return pAddr->Addr.IP_Binary.dwAddr == 0 ? INADDR_ANY : htonl(pAddr->Addr.IP_Binary.dwAddr);
} // switch
return 0;
} // GetIPAddress()
static HRESULT GetLocalAddr(PHWSINST pHws, CC_ADDR *pAddr)
{
SOCKADDR_IN sockaddr;
int len = sizeof(sockaddr);
if (getsockname(pHws->hws_Socket,
(struct sockaddr *)&sockaddr,
&len) == SOCKET_ERROR)
{
return MAKE_WINSOCK_ERROR(WSAGetLastError());
}
pAddr->nAddrType = CC_IP_BINARY;
pAddr->bMulticast = FALSE;
pAddr->Addr.IP_Binary.wPort = ntohs(sockaddr.sin_port);
pAddr->Addr.IP_Binary.dwAddr = ntohl(sockaddr.sin_addr.S_un.S_addr);
return NOERROR;
}
static HRESULT GetPeerAddr(PHWSINST pHws, CC_ADDR *pAddr)
{
SOCKADDR_IN sockaddr;
int len = sizeof(sockaddr);
if (getpeername(pHws->hws_Socket,
(struct sockaddr *)&sockaddr,
&len) == SOCKET_ERROR)
{
return MAKE_WINSOCK_ERROR(WSAGetLastError());
}
pAddr->nAddrType = CC_IP_BINARY;
pAddr->bMulticast = FALSE;
pAddr->Addr.IP_Binary.wPort = ntohs(sockaddr.sin_port);
pAddr->Addr.IP_Binary.dwAddr = ntohl(sockaddr.sin_addr.S_un.S_addr);
return NOERROR;
}
void
SocketFlushRecv(PHWSINST pHws)
{
register PREQUEST pReq;
if (pHws->hws_pRecvQueue)
{
while ((pReq = (PREQUEST) QRemove(pHws->hws_pRecvQueue)) != NULL)
{
pHws->hws_h245RecvCallback(pHws->hws_dwH245Instance,
LINK_RECV_ABORT,
pReq->req_client_data,
0);
HWSFREE(pReq);
}
}
pHws->hws_h245RecvCallback(pHws->hws_dwH245Instance,
LINK_FLUSH_COMPLETE,
NULL,
0);
} // SocketFlushRecv()
void
SocketFlushSend(PHWSINST pHws)
{
register PREQUEST pReq;
if (pHws->hws_pSendQueue)
{
while ((pReq = (PREQUEST) QRemove(pHws->hws_pSendQueue)) != NULL)
{
pHws->hws_h245SendCallback(pHws->hws_dwH245Instance,
LINK_SEND_ABORT,
pReq->req_client_data,
0);
HWSFREE(pReq);
}
}
pHws->hws_h245SendCallback(pHws->hws_dwH245Instance,
LINK_FLUSH_COMPLETE,
NULL,
0);
} // SocketFlushSend()
void
SocketCloseEvent(PHWSINST pHws)
{
HWSTRACE0(pHws->hws_dwPhysicalId, HWS_TRACE, __TEXT("SocketCloseEvent"));
if (pHws->hws_uState == HWS_CONNECTED)
{
register DWORD dwPhysicalId = pHws->hws_dwPhysicalId;
pHws->hws_h245RecvCallback(pHws->hws_dwH245Instance,LINK_RECV_CLOSED,0,0);
// Check to see if callback deallocated our instance or state changed
if(gpInstanceTable->Validate(dwPhysicalId) == FALSE)
return;
HWSTRACE0(pHws->hws_dwPhysicalId, HWS_TRACE,
__TEXT("SocketCloseEvent: calling shutdown"));
if (shutdown(pHws->hws_Socket, 1) == SOCKET_ERROR)
{
HWSTRACE1(pHws->hws_dwPhysicalId, HWS_WARNING,
__TEXT("HandleNetworkEvent: shutdown() returned %s"),
SocketErrorText());
}
}
pHws->hws_uState = HWS_CLOSED;
} // SocketCloseEvent()
/*
* DESCRIPTION
* Deallocate all allocated objects except for task handle
*/
void
SocketClose(PHWSINST pHws)
{
HWSASSERT(pHws != NULL);
HWSASSERT(pHws->hws_dwMagic == HWSINST_MAGIC);
HWSTRACE0(pHws->hws_dwPhysicalId, HWS_TRACE, __TEXT("SocketClose"));
pHws->hws_uState = HWS_CLOSED;
RemoveSocketToPhysicalIdMapping(pHws->hws_Socket);
// Close the socket
if (pHws->hws_Socket != INVALID_SOCKET)
{
// To make the linger work, turn off WSAAsyncSelect to turn off
// non-blocking via ioctlsocket, to close the socket.
unsigned long blocking = 0;
HWSTRACE0(pHws->hws_dwPhysicalId, HWS_TRACE,
__TEXT("SocketClose: calling closesocket"));
WSAAsyncSelect(pHws->hws_Socket,
window, WINSOCK_EVENT_MSG,
0);
ioctlsocket(pHws->hws_Socket, FIONBIO,&blocking);
if (closesocket(pHws->hws_Socket) == SOCKET_ERROR)
{
HWSTRACE1(pHws->hws_dwPhysicalId, HWS_WARNING,
__TEXT("SocketClose: closesocket() returned %s"),
SocketErrorText());
}
pHws->hws_Socket = INVALID_SOCKET;
}
} // SocketClose()
HRESULT
SocketOpen(PHWSINST pHws, BOOL bSetLinger)
{
HWSASSERT(pHws != NULL);
HWSASSERT(pHws->hws_dwMagic == HWSINST_MAGIC);
HWSTRACE0(pHws->hws_dwPhysicalId, HWS_TRACE, __TEXT("SocketOpen"));
// Create a socket
pHws->hws_Socket = socket(AF_INET, SOCK_STREAM, 0);
if (pHws->hws_Socket == INVALID_SOCKET)
{
// WSASocket() failed
int err = WSAGetLastError();
HWSTRACE1(pHws->hws_dwPhysicalId, HWS_WARNING,
__TEXT("SocketOpen: socket() returned %s"),
SocketErrorText1(err));
SocketClose(pHws);
return MAKE_WINSOCK_ERROR(err);
}
/*
** Request notification messages for all events on this socket.
** Note that this call automatically puts the socket into non-blocking
** mode, as if we had called WSAIoctl with the FIONBIO flag.
**/
if (WSAAsyncSelect(pHws->hws_Socket,
window, WINSOCK_EVENT_MSG,
FD_ALL_EVENTS) == SOCKET_ERROR)
{
int err = WSAGetLastError();
HWSTRACE1(pHws->hws_dwPhysicalId, HWS_WARNING,
__TEXT("SocketOpen: WSAASyncSelect() returned %s"),
SocketErrorText1(err));
SocketClose(pHws);
return MAKE_WINSOCK_ERROR(err);
}
if(bSetLinger == TRUE)
{
// Set a linger structure for the socket so that closesocket will block for a period of time (until all
// data is sent or the timeout value) before actually killing the connection.
// This change is being made in order to get rid of the PeekMessage() loops in linklayerShutdown().
struct linger sockLinger;
sockLinger.l_onoff = 1; // yes we want to linger (wait for FIN ACK after sending data and FIN)
sockLinger.l_linger = 1; // linger for up to 1 second
if(setsockopt (pHws->hws_Socket,
SOL_SOCKET,
SO_LINGER,
(const char*) &sockLinger,
sizeof(sockLinger)) == SOCKET_ERROR)
{
int err = WSAGetLastError();
HWSTRACE1(pHws->hws_dwPhysicalId, HWS_WARNING,
__TEXT("SocketOpen: setsockopt returned %s"),
SocketErrorText1(err));
SocketClose(pHws);
return MAKE_WINSOCK_ERROR(err);
}
}
// add an entry in the socket to instance map
if(CreateSocketToPhysicalIdMapping(pHws->hws_Socket, pHws->hws_dwPhysicalId) != TRUE)
{
HWSTRACE0(pHws->hws_dwPhysicalId, HWS_WARNING,
__TEXT("SocketOpen: CreateSocketToPhysicalIdMapping() failed"));
SocketClose(pHws);
return(LINK_MEM_FAILURE);
}
return NOERROR;
} // SocketOpen()
HRESULT
SocketBind(PHWSINST pHws, CC_ADDR *pAddr)
{
HWSASSERT(pHws != NULL);
HWSASSERT(pHws->hws_dwMagic == HWSINST_MAGIC);
HWSASSERT(pAddr != NULL);
HWSTRACE0(pHws->hws_dwPhysicalId, HWS_TRACE, __TEXT("SocketBind"));
// Get a local address to bind the socket to
pHws->hws_SockAddr.sin_family = AF_INET;
pHws->hws_SockAddr.sin_port = GetPort(pAddr);
pHws->hws_SockAddr.sin_addr.S_un.S_addr = GetIPAddress(pAddr);
if ((pAddr->nAddrType == CC_IP_DOMAIN_NAME) &&
(pHws->hws_SockAddr.sin_addr.S_un.S_addr == 0))
{
return LINK_UNKNOWN_ADDR;
}
// Bind the socket
while (bind(pHws->hws_Socket, // s
(const struct sockaddr *)&pHws->hws_SockAddr, // name
sizeof(pHws->hws_SockAddr)) == SOCKET_ERROR) // namelen
{
// bind() failed
int err = WSAGetLastError();
HWSTRACE1(pHws->hws_dwPhysicalId, HWS_WARNING,
__TEXT("SocketBind: bind() returned %s"),
SocketErrorText1(err));
if (err != WSAENOBUFS)
{
return MAKE_WINSOCK_ERROR(err);
}
Sleep(0);
}
return NOERROR;
} // SocketBind()
void
SocketConnect(PHWSINST pHws, int error)
{
HWSASSERT(pHws != NULL);
HWSASSERT(pHws->hws_dwMagic == HWSINST_MAGIC);
HWSTRACE0(pHws->hws_dwPhysicalId, HWS_TRACE, __TEXT("SocketConnect"));
if (error == 0)
{
pHws->hws_uState = HWS_CONNECTED;
if (pHws->hws_h245ConnectCallback)
{
CC_ADDR LocalAddr;
CC_ADDR PeerAddr;
PCC_ADDR pLocalAddr = &LocalAddr;
PCC_ADDR pPeerAddr = &PeerAddr;
DWORD dwPhysicalId = pHws->hws_dwPhysicalId;
if (GetLocalAddr(pHws, pLocalAddr) != NOERROR)
pLocalAddr = NULL;
if (GetPeerAddr(pHws, pPeerAddr) != NOERROR)
pPeerAddr = NULL;
pHws->hws_h245ConnectCallback(pHws->hws_dwH245Instance,
LINK_CONNECT_COMPLETE, pLocalAddr, pPeerAddr);
// Check to see if callback deallocated our instance - this can be done
// by attempting a lock - which will now fail if the entry has been marked
// for deletion. Thus, if the lock succeeds, then just unlock it (since we
// already have a lock on it).
if(gpInstanceTable->Validate(dwPhysicalId) == FALSE)
return;
}
NotifyWrite(pHws);
NotifyRead(pHws);
}
else
{
if (pHws->hws_h245ConnectCallback)
{
pHws->hws_h245ConnectCallback(pHws->hws_dwH245Instance,
MAKE_WINSOCK_ERROR(error), NULL, NULL);
}
}
} // SocketConnect()
HRESULT
SocketAccept(PHWSINST pHwsListen, PHWSINST pHwsAccept)
{
SOCKET listen_socket = pHwsListen->hws_Socket;
struct linger sockLinger;
sockLinger.l_onoff = 1; // yes we want to linger (wait for FIN ACK after sending data and FIN)
sockLinger.l_linger = 1; // linger for up to 1 second
// Accept the connection.
pHwsAccept->hws_uSockAddrLen = sizeof(pHwsAccept->hws_SockAddr);
pHwsAccept->hws_Socket = accept(pHwsListen->hws_Socket,
(struct sockaddr *)&pHwsAccept->hws_SockAddr,
(int *)&pHwsAccept->hws_uSockAddrLen);
if (pHwsAccept->hws_Socket == INVALID_SOCKET)
{
int err = WSAGetLastError();
HWSTRACE1(pHwsAccept->hws_dwPhysicalId, HWS_WARNING,
__TEXT("linkLayerAccept: accept() returned %s"),
SocketErrorText1(err));
SocketConnect(pHwsAccept, err);
return MAKE_WINSOCK_ERROR(err);
}
if (pHwsListen == pHwsAccept)
{
HWSTRACE0(pHwsListen->hws_dwPhysicalId, HWS_TRACE,
__TEXT("SocketClose: calling closesocket"));
closesocket(listen_socket);
RemoveSocketToPhysicalIdMapping(listen_socket);
}
// Set a linger structure for the socket so that closesocket will block for a period of time (until all
// data is sent or the timeout value) before actually killing the connection.
// This change is being made in order to get rid of the PeekMessage() loops in linklayerShutdown().
if(setsockopt (pHwsAccept->hws_Socket,
SOL_SOCKET,
SO_LINGER,
(const char*) &sockLinger,
sizeof(sockLinger)) == SOCKET_ERROR)
{
int err = WSAGetLastError();
HWSTRACE1(pHwsAccept->hws_dwPhysicalId, HWS_WARNING,
__TEXT("SocketAccept: setsockopt returned %s"),
SocketErrorText1(err));
SocketClose(pHwsAccept);
return MAKE_WINSOCK_ERROR(err);
}
// add the new socket to the socket to phys id map
CreateSocketToPhysicalIdMapping(pHwsAccept->hws_Socket, pHwsAccept->hws_dwPhysicalId);
SocketConnect(pHwsAccept, 0);
return NOERROR;
} // SocketAccept()
/*++
Description:
Handles network events that may occur on a connected socket.
The events handled by this function are FD_ACCEPT, FD_CLOSE, FD_READ, and
FD_WRITE.
Arguments:
pHws - pointer to data for the connection on which the event happened.
event - event that occurred
error - error code accompanying the event
Return Value:
SUCCESS - The network event was successfully handled.
LINK_FATAL_ERROR - Some kind of error occurred while handling the
event, and the connection should be closed.
LINK_RECV_CLOSED - The connection has been gracefully closed.
--*/
void
HandleNetworkEvent(PHWSINST pHws, int event, int error)
{
HWSASSERT(pHws != NULL);
HWSASSERT(pHws->hws_dwMagic == HWSINST_MAGIC);
HWSTRACE0(pHws->hws_dwPhysicalId, HWS_TRACE, __TEXT("HandleNetworkEvent"));
if (error == WSAENETDOWN)
{
HWSTRACE0(pHws->hws_dwPhysicalId, HWS_NOTIFY,
__TEXT("HandleSocketEvent: Connection error"));
pHws->hws_uState = HWS_CLOSED;
return;
}
switch (event)
{
case FD_READ:
HWSTRACE1(pHws->hws_dwPhysicalId, HWS_NOTIFY,
__TEXT("HandleNetworkEvent: FD_READ %s"),
SocketErrorText1(error));
if (error == 0 && pHws->hws_uState <= HWS_CLOSING)
{
ProcessQueuedRecvs(pHws);
}
break;
case FD_WRITE:
HWSTRACE1(pHws->hws_dwPhysicalId, HWS_NOTIFY,
__TEXT("HandleNetworkEvent: FD_WRITE %s"),
SocketErrorText1(error));
if (error == 0 && pHws->hws_uState <= HWS_CONNECTED)
{
ProcessQueuedSends(pHws);
}
break;
case FD_OOB:
HWSTRACE1(pHws->hws_dwPhysicalId, HWS_NOTIFY,
__TEXT("HandleNetworkEvent: FD_OOB %s"),
SocketErrorText1(error));
break;
case FD_ACCEPT:
HWSTRACE1(pHws->hws_dwPhysicalId, HWS_NOTIFY,
__TEXT("HandleNetworkEvent: FD_ACCEPT %s"),
SocketErrorText1(error));
if (pHws->hws_h245ConnectCallback != NULL)
{
if (error == 0)
{
pHws->hws_h245ConnectCallback(pHws->hws_dwH245Instance,
LINK_CONNECT_REQUEST, NULL, NULL);
}
else
{
pHws->hws_h245ConnectCallback(pHws->hws_dwH245Instance,
MAKE_WINSOCK_ERROR(error), NULL, NULL);
}
}
else if (error == 0)
{
// If the client did not specify a callback, accept the call using the same physical
// Id as the listen. This will result in the listen socket being closed.
SocketAccept(pHws, pHws);
}
break;
case FD_CONNECT:
HWSTRACE1(pHws->hws_dwPhysicalId, HWS_NOTIFY,
__TEXT("HandleNetworkEvent: FD_CONNECT %s"),
SocketErrorText1(error));
SocketConnect(pHws, error);
break;
case FD_CLOSE:
HWSTRACE1(pHws->hws_dwPhysicalId, HWS_NOTIFY,
__TEXT("HandleNetworkEvent: FD_CLOSE %s"),
SocketErrorText1(error));
SocketCloseEvent(pHws);
break;
}
} // HandleNetworkEvent()
LRESULT CALLBACK WndProc(
HWND hWnd, /* window handle */
UINT message, /* type of message */
WPARAM wParam, /* additional information */
LPARAM lParam) /* additional information */
{
PHWSINST pHws;
DWORD dwPhysicalId;
#if defined(USE_PROVIDER_LOCK)
H323LockProvider();
#endif
switch (message)
{
case WINSOCK_EVENT_MSG:
if (((dwPhysicalId=SocketToPhysicalId((SOCKET)wParam)) == INVALID_PHYS_ID) ||
((pHws=gpInstanceTable->Lock(dwPhysicalId)) == NULL))
{
HWSTRACE1(0, HWS_WARNING,
__TEXT("WndProc: Winsock event on unknown socket 0x%x"),
wParam);
break;
}
HandleNetworkEvent(pHws, WSAGETSELECTEVENT(lParam), WSAGETSELECTERROR(lParam));
gpInstanceTable->Unlock(dwPhysicalId);
break;
default:
{
#if defined(USE_PROVIDER_LOCK)
H323UnlockProvider();
#endif
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
#if defined(USE_PROVIDER_LOCK)
H323UnlockProvider();
#endif
return (0);
}
void NotifyRead(PHWSINST pHws)
{
PostMessage(window, WINSOCK_EVENT_MSG, (WPARAM)pHws->hws_Socket, (LPARAM)MAKELONG(FD_READ, 0));
}
void NotifyWrite(PHWSINST pHws)
{
PostMessage(window, WINSOCK_EVENT_MSG, (WPARAM)pHws->hws_Socket, (LPARAM)MAKELONG(FD_WRITE, 0));
}
/*++
Description:
Calls WSAStartup, makes sure we have a good version of WinSock
Arguments:
None.
Return Value:
0 WinSock DLL successfully started up.
LINK_FATAL_ERROR Error starting up WinSock DLL.
--*/
static const TCHAR CLASS_NAME[] = __TEXT("H245WSWndClass");
int WinsockInitError = -1;
HRESULT InitializeStatus = LINK_INVALID_STATE;
void Initialize()
{
WORD wVersion = MAKEWORD(1, 1);
WSADATA WsaData; // receives data from WSAStartup
WNDCLASS wndclass = { 0, WndProc, 0, 0, 0, 0, 0, 0, NULL, CLASS_NAME };
DWORD dwIndex;
// Caveat: We can't use WSAGetLastError() for WSAStartup failure!
if ((WinsockInitError = WSAStartup(wVersion, &WsaData)) != 0)
{
HWSTRACE0(0, HWS_WARNING, __TEXT("linkLayerInit: WSAStartup() failed"));
InitializeStatus = MAKE_WINSOCK_ERROR(WinsockInitError);
return;
}
if (LOBYTE(WsaData.wVersion) != 1 ||
HIBYTE(WsaData.wVersion) != 1)
{
HWSTRACE0(0, HWS_WARNING, __TEXT("linkLayerInit: Winsock version mismatch"));
InitializeStatus = MAKE_WINSOCK_ERROR(WSAVERNOTSUPPORTED);
return;
}
// Create window to receive Winsock messages
if (RegisterClass(&wndclass) == 0
|| (window = CreateWindow(CLASS_NAME, __TEXT(""), WS_OVERLAPPED, 0, 0, 0, 0, 0, 0, 0, NULL)) == 0)
{
HWSTRACE0(0, HWS_WARNING, __TEXT("linkLayerInit: error creating window"));
InitializeStatus = HRESULT_FROM_WIN32(GetLastError());
return;
}
gpInstanceTable = new TSTable <HWSINST> (30); // note: table will resize automatically
if(gpInstanceTable == NULL || gpInstanceTable->IsInitialized() == FALSE)
{
InitializeStatus = LINK_MEM_FAILURE;
return;
}
pSocketToHWSInstanceMap = new SOCKET_TO_INSTANCE[SOCK_TO_PHYSID_TABLE_SIZE];
if(pSocketToHWSInstanceMap == NULL)
{
InitializeStatus = LINK_MEM_FAILURE;
return;
}
__try {
// initialize lock (and allocate event immediately)
InitializeCriticalSectionAndSpinCount(&SocketToHWSInstanceMapLock,H323_SPIN_COUNT);
} __except ((GetExceptionCode() == STATUS_NO_MEMORY)
? EXCEPTION_EXECUTE_HANDLER
: EXCEPTION_CONTINUE_SEARCH
) {
// report memory failure
InitializeStatus = LINK_MEM_FAILURE;
return;
}
memset(pSocketToHWSInstanceMap, 0, sizeof(SOCKET_TO_INSTANCE) * SOCK_TO_PHYSID_TABLE_SIZE);
// Init the sockets to a bad value
for (dwIndex = 0; dwIndex < SOCK_TO_PHYSID_TABLE_SIZE; dwIndex++)
{
pSocketToHWSInstanceMap[dwIndex].socket = INVALID_SOCKET;
}
InitializeStatus = NOERROR;
}
void Uninitialize()
{
if (WinsockInitError == 0)
{
if (window)
{
DestroyWindow(window);
window = 0;
UnregisterClass(CLASS_NAME, 0);
if (gpInstanceTable)
{
delete gpInstanceTable;
if (InitializeStatus == NOERROR)
{
EnterCriticalSection(&SocketToHWSInstanceMapLock);
delete pSocketToHWSInstanceMap;
LeaveCriticalSection(&SocketToHWSInstanceMapLock);
DeleteCriticalSection(&SocketToHWSInstanceMapLock);
}
}
}
WSACleanup();
}
}
/***************************************************************************
*
* External entry points
*
***************************************************************************/
//MULTITHREAD => dwH245Instance is now an OUTPUT param not an INPUT param.
LINKDLL HRESULT linkLayerInit (DWORD *dwPhysicalId,
DWORD dwH245Instance,
H245SRCALLBACK cbReceiveComplete,
H245SRCALLBACK cbTransmitComplete)
{
register PHWSINST pHws;
*dwPhysicalId = INVALID_PHYS_ID; // Just in case...
// Put Initialize back in here so we know everything we need is up and
// running.
if (InitializeStatus == LINK_INVALID_STATE)
Initialize();
if (InitializeStatus != NOERROR)
return InitializeStatus;
pHws = (PHWSINST)HWSMALLOC(sizeof(*pHws));
if (pHws == NULL)
{
// couldn't allocate our context. Return
HWSTRACE0(INVALID_PHYS_ID, HWS_WARNING, __TEXT("linkLayerInit: could not allocate context"));
return LINK_MEM_FAILURE;
}
memset(pHws, 0, sizeof(*pHws));
pHws->hws_Socket = INVALID_SOCKET;
#if defined(DBG)
pHws->hws_dwMagic = HWSINST_MAGIC;
#endif // (DBG)
// Create and initialize the Receive queue
pHws->hws_pRecvQueue = QCreate();
if (pHws->hws_pRecvQueue == NULL)
{
HWSTRACE0(INVALID_PHYS_ID, HWS_WARNING, __TEXT("linkLayerInit: could not allocate Receive queue"));
SocketClose(pHws);
HWSFREE(pHws);
return LINK_MEM_FAILURE;
}
// Create and initialize the Send queue
pHws->hws_pSendQueue = QCreate();
if (pHws->hws_pSendQueue == NULL)
{
HWSTRACE0(INVALID_PHYS_ID, HWS_WARNING, __TEXT("linkLayerInit: could not allocate Send queue"));
SocketClose(pHws);
HWSFREE(pHws);
return LINK_MEM_FAILURE;
}
// Save intance identifiers and callback pointers
pHws->hws_uState = HWS_START;
pHws->hws_dwH245Instance = dwH245Instance;
pHws->hws_h245RecvCallback = cbReceiveComplete;
pHws->hws_h245SendCallback = cbTransmitComplete;
// Open Channel 0 for the Forward and Reverse Directions
// TBD
// Add instance to instance list
gpInstanceTable->CreateAndLock(pHws, &pHws->hws_dwPhysicalId);
*dwPhysicalId = pHws->hws_dwPhysicalId;
gpInstanceTable->Unlock(pHws->hws_dwPhysicalId);
HWSTRACE2(*dwPhysicalId, HWS_TRACE,
__TEXT("linkLayerInit(%d, %d) succeeded"), dwPhysicalId, dwH245Instance);
return NOERROR;
} // linkLayerInit()
LINKDLL HRESULT linkLayerShutdown(DWORD dwPhysicalId)
{
register PHWSINST pHws;
UINT uRetryCount;
register PREQUEST pReq;
if (InitializeStatus != NOERROR)
return InitializeStatus;
if ((dwPhysicalId == INVALID_PHYS_ID) ||
(!(pHws = gpInstanceTable->Lock(dwPhysicalId))))
{
HWSTRACE0(dwPhysicalId, HWS_ERROR,
__TEXT("linkLayerShutdown: dwPhysicalId not found"));
return LINK_INVALID_INSTANCE;
}
// mark this instance as deleted so we don't process anymore messages for it -
// note: the FALSE indicates to the TSTable class to NOT do the deletion of memory
// once the last unlock has completed (which is at the end of this function)
gpInstanceTable->Delete(dwPhysicalId, FALSE);
RemoveSocketToPhysicalIdMapping(pHws->hws_Socket);
switch (pHws->hws_uState)
{
case HWS_START:
case HWS_LISTENING:
case HWS_CONNECTING:
break;
case HWS_CONNECTED:
// Try to send all messages waiting on send queue
HWSASSERT(pHws->hws_pSendQueue != NULL);
ProcessQueuedSends(pHws);
uRetryCount = 0;
while ( pHws->hws_uState == HWS_CONNECTED &&
IsQEmpty(pHws->hws_pSendQueue) == FALSE &&
++uRetryCount <= 5)
{
HWSTRACE1(pHws->hws_dwPhysicalId, HWS_NOTIFY,
__TEXT("linkLayerShutdown: Waiting for send %d"), uRetryCount);
ProcessQueuedSends(pHws);
Sleep(100);
}
if (pHws->hws_uState == HWS_CONNECTED)
{
HWSTRACE0(pHws->hws_dwPhysicalId, HWS_TRACE,
__TEXT("linkLayerShutdown: calling shutdown"));
if (shutdown(pHws->hws_Socket, 1) == SOCKET_ERROR)
{
HWSTRACE1(pHws->hws_dwPhysicalId, HWS_WARNING,
__TEXT("linkLayerShutdown: shutdown() returned %s"),
SocketErrorText());
}
pHws->hws_uState = HWS_CLOSING;
}
case HWS_CLOSING:
break;
case HWS_CLOSED:
break;
default:
HWSASSERT(FALSE);
} // switch
// Deallocate instance objects
SocketClose(pHws);
// Deallocate Receive queue
if (pHws->hws_pRecvQueue)
{
while ((pReq = (PREQUEST) QRemove(pHws->hws_pRecvQueue)) != NULL)
{
pHws->hws_h245RecvCallback(pHws->hws_dwH245Instance,
LINK_RECV_ABORT,
pReq->req_client_data,
0);
HWSFREE(pReq);
}
QFree(pHws->hws_pRecvQueue);
pHws->hws_pRecvQueue = NULL;
}
// Deallocate Send queue
if (pHws->hws_pSendQueue)
{
while ((pReq = (PREQUEST) QRemove(pHws->hws_pSendQueue)) != NULL)
{
pHws->hws_h245SendCallback(pHws->hws_dwH245Instance,
LINK_SEND_ABORT,
pReq->req_client_data,
0);
HWSFREE(pReq);
}
QFree(pHws->hws_pSendQueue);
pHws->hws_pSendQueue = NULL;
}
gpInstanceTable->Unlock(dwPhysicalId);
HWSFREE(pHws);
HWSTRACE0(dwPhysicalId, HWS_TRACE, __TEXT("linkLayerShutdown: succeeded"));
return NOERROR;
} // linkLayerShutdown
/***************************************************************************
*
* NAME
* linkLayerGetInstance - return instance id corresponding to physical id
*
* SYNOPSIS
* LINKDLL DWORD linkLayerGetInstance(DWORD dwPhysicalId);
*
* DESCRIPTION
* Returns the Instance identifier corresponding to dwPhysId.
*
* PARAMETERS
* dwPhysicalId Physical identifier to search for
*
* RETURN VALUE
//MULTITHREAD
* INVALID_PHYS_ID (-1)No instance corresponding to dwPhysicalId found
* n>0 Instance Id corresponding to dwPhysicalId
*
***************************************************************************/
LINKDLL DWORD linkLayerGetInstance(DWORD dwPhysicalId)
{
if (InitializeStatus == NOERROR &&
dwPhysicalId != INVALID_PHYS_ID &&
gpInstanceTable->Lock(dwPhysicalId) != NULL)
{
HWSTRACE0(dwPhysicalId, HWS_TRACE, __TEXT("linkLayerGetInstance: succeeded"));
gpInstanceTable->Unlock(dwPhysicalId);
return dwPhysicalId;
}
HWSTRACE0(dwPhysicalId, HWS_ERROR, __TEXT("linkLayerGetInstance: failed"));
return INVALID_PHYS_ID; // return failure
} // linkLayerGetInstance()
/***************************************************************************
*
* NAME
* linkLayerFlushChannel - flush transmit and/or receive channels
*
* DESCRIPTION
* This is a dummy function required only for compatibility with the SRP API.
*
* RETURN VALUE
* 0 Function succeeded.
* n!=0 Link error code (see LINKAPI.H for definitions.)
*
***************************************************************************/
LINKDLL HRESULT linkLayerFlushChannel(DWORD dwPhysicalId, DWORD dwDirectionMask)
{
if (InitializeStatus != NOERROR)
return InitializeStatus;
PHWSINST pHws;
if ((dwPhysicalId == INVALID_PHYS_ID) ||
(!(pHws = gpInstanceTable->Lock(dwPhysicalId))))
{
HWSTRACE0(dwPhysicalId, HWS_ERROR,
__TEXT("linkLayerFlushChannel: dwPhysicalId not found"));
return LINK_INVALID_INSTANCE;
}
switch (dwDirectionMask & (DATALINK_RECEIVE | DATALINK_TRANSMIT))
{
case DATALINK_TRANSMIT | DATALINK_RECEIVE:
// Flush both receive and transmit
// Caveat: H.245 expects us to flush receive first!
SocketFlushRecv(pHws);
// Fall through to next case
case DATALINK_TRANSMIT:
// Flush transmit
// SockFlushSend() just removes the entries from the queue - it doesn't send them.
// So instead, call ProcessQueuedSends() to actually empty the send queue.
// SocketFlushSend(pHws);
ProcessQueuedSends(pHws);
break;
case DATALINK_RECEIVE:
// Flush receive
SocketFlushRecv(pHws);
break;
} // switch
gpInstanceTable->Unlock(dwPhysicalId);
HWSTRACE2(dwPhysicalId, HWS_TRACE,
__TEXT("linkLayerFlushChannel(%d, 0x%X) succeeded"),
dwPhysicalId, dwDirectionMask);
return NOERROR;
} // linkLayerFlushChannel()
/***************************************************************************
*
* NAME
* linkLayerFlushAll - flush transmit and receive channels
*
* DESCRIPTION
* This is a dummy function required only for compatibility with the SRP API.
*
* RETURN VALUE
* 0 Function succeeded.
* n!=0 Link error code (see LINKAPI.H for definitions.)
*
***************************************************************************/
LINKDLL HRESULT linkLayerFlushAll(DWORD dwPhysicalId)
{
if (InitializeStatus != NOERROR)
return InitializeStatus;
PHWSINST pHws;
if ((dwPhysicalId == INVALID_PHYS_ID) ||
(!(pHws = gpInstanceTable->Lock(dwPhysicalId))))
{
HWSTRACE0(dwPhysicalId, HWS_ERROR,
__TEXT("linkLayerFlushAll: dwPhysicalId not found"));
return LINK_INVALID_INSTANCE;
}
// Flush both receive and transmit
// Caveat: H.245 expects us to flush receive first!
SocketFlushRecv(pHws);
SocketFlushSend(pHws);
gpInstanceTable->Unlock(dwPhysicalId);
HWSTRACE0(dwPhysicalId, HWS_TRACE, __TEXT("linkLayerFlushAll succeeded"));
return NOERROR;
} // linkLayerFlushAll()
/*++
Description:
Initiates a call to a remote node.
1) Create a socket.
2) Set the socket up for windows message notification of FD_CONNECT events.
3) Attempt a connection
Arguments:
pHws - Pointer to context data from connection.
Return Value:
SUCCESS - A connection attempt was successfully initiated.
LINK_FATAL_ERROR - Error occurred while attempting to initiate a connection.
--*/
LINKDLL HRESULT linkLayerConnect(DWORD dwPhysicalId, CC_ADDR *pAddr, H245CONNECTCALLBACK callback)
{
register PHWSINST pHws;
CC_ADDR Addr;
HRESULT hr;
if (InitializeStatus != NOERROR)
return InitializeStatus;
HWSTRACE5(dwPhysicalId, HWS_TRACE, __TEXT("linkLayerConnect: connecting to %d.%d.%d.%d/%d"),
GetIPAddress(pAddr) & 0xFF,
(GetIPAddress(pAddr) >> 8) & 0xFF,
(GetIPAddress(pAddr) >> 16) & 0xFF,
GetIPAddress(pAddr) >> 24,
ntohs(GetPort(pAddr)));
if ((dwPhysicalId == INVALID_PHYS_ID) ||
(!(pHws = gpInstanceTable->Lock(dwPhysicalId))))
{
HWSTRACE0(dwPhysicalId, HWS_ERROR, __TEXT("linkLayerConnect: dwPhysicalId not found"));
return LINK_INVALID_INSTANCE;
}
if (pHws->hws_uState != HWS_START)
{
HWSTRACE1(dwPhysicalId, HWS_ERROR, __TEXT("linkLayerConnect: State = %s"),
SocketStateText(pHws->hws_uState));
gpInstanceTable->Unlock(dwPhysicalId);
return LINK_INVALID_STATE;
}
pHws->hws_h245ConnectCallback = callback;
// Create a socket, bind to a local address and initiate a connection.
if ((hr = SocketOpen(pHws)) != NOERROR)
{
HWSTRACE0(dwPhysicalId, HWS_WARNING,
__TEXT("linkLayerConnect: SocketOpen() failed"));
pHws->hws_uState = HWS_START;
gpInstanceTable->Unlock(dwPhysicalId);
return hr;
}
Addr.nAddrType = CC_IP_BINARY;
Addr.bMulticast = FALSE;
Addr.Addr.IP_Binary.wPort = 0;
Addr.Addr.IP_Binary.dwAddr = 0;
if ((hr = SocketBind(pHws, &Addr)) != NOERROR)
{
HWSTRACE0(dwPhysicalId, HWS_WARNING,
__TEXT("linkLayerConnect: SocketBind() failed"));
pHws->hws_uState = HWS_START;
gpInstanceTable->Unlock(dwPhysicalId);
return hr;
}
// Reminder: WinSock requires that we pass a struct sockaddr *
// to connect; however, the service provider is free to
// interpret the pointer as an arbitrary chunk of data of size
// uSockAddrLen.
pHws->hws_SockAddr.sin_port = GetPort(pAddr);
pHws->hws_SockAddr.sin_addr.S_un.S_addr = GetIPAddress(pAddr);
if (connect(pHws->hws_Socket, // s
(const struct sockaddr *)&pHws->hws_SockAddr, // name
sizeof(pHws->hws_SockAddr)) == SOCKET_ERROR) // namelen
{
int err = WSAGetLastError();
switch (err)
{
case WSAEWOULDBLOCK:
break;
default:
HWSTRACE1(dwPhysicalId, HWS_WARNING,
__TEXT("linkLayerConnect: WSAConnect() returned %s"),
SocketErrorText1(err));
SocketClose(pHws);
pHws->hws_uState = HWS_START;
gpInstanceTable->Unlock(dwPhysicalId);
return MAKE_WINSOCK_ERROR(err);
} // switch
} // if
else
{
HWSTRACE0(dwPhysicalId, HWS_TRACE, __TEXT("connect() succeeded"));
SocketConnect(pHws, 0);
gpInstanceTable->Unlock(dwPhysicalId);
return NOERROR;
} // else
pHws->hws_uState = HWS_CONNECTING;
HWSTRACE0(dwPhysicalId, HWS_TRACE, __TEXT("linkLayerConnect: succeeded"));
gpInstanceTable->Unlock(dwPhysicalId);
return NOERROR;
} // linkLayerConnect()
/***************************************************************************
*
* NAME
* linkLayerListen - start listen on connection
*
* DESCRIPTION
* This function creates a socket,
* binds to a local address, and listens on the created socket.
* The address being listened to is returned in the structure
* pointed to by pAddr.
*
* PARAMETERS
* dwPhysicalId Link layer identifier returned by linkLayerGetInstance().
* pAddr Pointer to address structure (defined in CALLCONT.H.)
*
* RETURN VALUE
* 0 Function succeeded.
* n!=0 Error code (see LINKAPI.H for definitions.)
*
***************************************************************************/
//MULTITHREAD => dwPhysicalID was INPUT now it's OUTPUT
LINKDLL HRESULT linkLayerListen (DWORD *dwPhysicalId, DWORD dwH245Instance, CC_ADDR *pAddr, H245CONNECTCALLBACK callback)
{
HRESULT hr;
register PHWSINST pHws;
if (InitializeStatus == LINK_INVALID_STATE)
Initialize();
if (InitializeStatus != NOERROR)
return InitializeStatus;
if ((*dwPhysicalId == INVALID_PHYS_ID) ||
(!(pHws = gpInstanceTable->Lock(*dwPhysicalId))))
{
if ((hr = linkLayerInit(dwPhysicalId, dwH245Instance, NULL, NULL)) != NOERROR)
return hr;
pHws = gpInstanceTable->Lock(*dwPhysicalId);
HWSASSERT(pHws != NULL);
}
else
{
HWSASSERT(pHws->hws_dwH245Instance == dwH245Instance);
}
if (pHws->hws_uState != HWS_START)
{
HWSTRACE1(*dwPhysicalId, HWS_ERROR, __TEXT("linkLayerListen: State = %s"),
SocketStateText(pHws->hws_uState));
gpInstanceTable->Unlock(*dwPhysicalId);
return LINK_INVALID_STATE;
}
pHws->hws_h245ConnectCallback = callback;
if ((hr = SocketOpen(pHws, FALSE)) != NOERROR)
{
HWSTRACE0(*dwPhysicalId, HWS_WARNING, __TEXT("linkLayerListen: SocketBind() failed"));
pHws->hws_uState = HWS_START;
gpInstanceTable->Unlock(*dwPhysicalId);
return hr;
}
if ((hr = SocketBind(pHws, pAddr)) != NOERROR)
{
HWSTRACE0(*dwPhysicalId, HWS_WARNING, __TEXT("linkLayerListen: SocketBind() failed"));
pHws->hws_uState = HWS_START;
gpInstanceTable->Unlock(*dwPhysicalId);
return hr;
}
// Listen for incoming connection requests on the socket.
int nBacklog = SOMAXCONN;
while (listen(pHws->hws_Socket, nBacklog) == SOCKET_ERROR)
{
int err = WSAGetLastError();
HWSTRACE1(*dwPhysicalId,
HWS_WARNING,
__TEXT("linkLayerListen: listen() returned %s"),
SocketErrorText1(err));
if (nBacklog == SOMAXCONN)
nBacklog = 10;
if (err != WSAENOBUFS || --nBacklog == 0)
{
SocketClose(pHws);
pHws->hws_uState = HWS_START;
gpInstanceTable->Unlock(*dwPhysicalId);
return MAKE_WINSOCK_ERROR(err);
}
Sleep(0);
}
if ((hr = GetLocalAddr(pHws, pAddr)) != NOERROR)
{
// getsockname() failed
HWSTRACE1(pHws->hws_dwPhysicalId, HWS_WARNING,
__TEXT("linkLayerListen: getsockname() returned %s"),
SocketErrorText());
SocketClose(pHws);
pHws->hws_uState = HWS_START;
gpInstanceTable->Unlock(*dwPhysicalId);
return hr;
}
HWSTRACE5(*dwPhysicalId, HWS_TRACE, __TEXT("linkLayerListen: listening on %d.%d.%d.%d/%d"),
GetIPAddress(pAddr) & 0xFF,
(GetIPAddress(pAddr) >> 8) & 0xFF,
(GetIPAddress(pAddr) >> 16) & 0xFF,
GetIPAddress(pAddr) >> 24,
ntohs(GetPort(pAddr)));
pHws->hws_uState = HWS_LISTENING;
HWSTRACE0(*dwPhysicalId, HWS_TRACE, __TEXT("linkLayerListen: succeeded"));
gpInstanceTable->Unlock(*dwPhysicalId);
return NOERROR;
} // linkLayerListen()
LINKDLL HRESULT
linkLayerAccept(DWORD dwPhysicalIdListen, DWORD dwPhysicalIdAccept, H245CONNECTCALLBACK callback)
{
PHWSINST pHwsListen;
PHWSINST pHwsAccept;
HRESULT rc;
if (InitializeStatus != NOERROR)
return InitializeStatus;
HWSTRACE0(dwPhysicalIdAccept, HWS_TRACE, __TEXT("linkLayerAccept"));
if ((dwPhysicalIdListen == INVALID_PHYS_ID) ||
(!(pHwsListen = gpInstanceTable->Lock(dwPhysicalIdListen))))
{
HWSTRACE0(dwPhysicalIdListen, HWS_ERROR, __TEXT("linkLayerAccept: dwPhysicalIdListen not found"));
return LINK_INVALID_INSTANCE;
}
pHwsAccept = gpInstanceTable->Lock(dwPhysicalIdAccept);
if (pHwsAccept == NULL)
{
HWSTRACE0(dwPhysicalIdAccept, HWS_ERROR, __TEXT("linkLayerAccept: dwPhysicalIdAccept not found"));
gpInstanceTable->Unlock(dwPhysicalIdListen);
return LINK_INVALID_INSTANCE;
}
HWSASSERT(pHwsListen->hws_uState == HWS_LISTENING);
HWSASSERT(pHwsAccept == pHwsListen || pHwsAccept->hws_uState == HWS_START);
pHwsAccept->hws_h245ConnectCallback = callback;
rc = SocketAccept(pHwsListen, pHwsAccept);
gpInstanceTable->Unlock(dwPhysicalIdListen);
gpInstanceTable->Unlock(dwPhysicalIdAccept);
return rc;
}
// Here is the corresponding redefinition of the __TEXT macro
#ifndef UNICODE_TRACE
#undef __TEXT
#define __TEXT(x) L##x
#endif
#if defined(__cplusplus)
}
#endif // (__cplusplus)