|
|
/***************************************************************************
* * 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. * ***************************************************************************/
#define LINKDLL_EXPORT
#undef _WIN32_WINNT // override bogus platform definition in our common build environment
#pragma warning ( disable : 4115 4201 4214 4514 )
#include "precomp.h"
//#include <winsock.h>
#include "queue.h"
#include "linkapi.h"
#include "incommon.h"
#include "h245ws.h"
#include "tstable.h"
#ifdef FORCE_SERIALIZE_CALL_CONTROL
#include "cclock.h"
#endif
#include "q931.h"
#include "hcall.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)
static HRESULT SocketOpen(PHWSINST pHws, BOOL bSetLinger = TRUE); void Uninitialize();
/*
* Static variables */ static BOOL bInitialized = FALSE; 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(_DEBUG)
#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
};
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 // (_DEBUG)
/***************************************************************************
* * 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; }
static 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); MemFree(pReq); } } pHws->hws_h245RecvCallback(pHws->hws_dwH245Instance, LINK_FLUSH_COMPLETE, NULL, 0); } // SocketFlushRecv()
static 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); MemFree(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 */
static 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()
static 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()
static 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()
static 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; HRESULT hr;
hr = GetLocalAddr(pHws, pLocalAddr); if (FAILED(hr)) { WARNING_OUT(("SocketConnect - failed to get local address w/ error 0x%08x", hr)); pLocalAddr = NULL; } else { hr = GetPeerAddr(pHws, pPeerAddr); if (FAILED(hr)) { WARNING_OUT(("SocketConnect - failed to get remote address w/ error 0x%08x", hr)); pPeerAddr = NULL; } else { // All is OK
hr = LINK_CONNECT_COMPLETE; } }
pHws->hws_h245ConnectCallback(pHws->hws_dwH245Instance, hr, 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()
static 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.
--*/
static 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 APIENTRY WndProc( HWND hWnd, /* window handle */ UINT message, /* type of message */ WPARAM wParam, /* additional information */ LPARAM lParam) /* additional information */ { PHWSINST pHws; DWORD dwPhysicalId;
#ifdef FORCE_SERIALIZE_CALL_CONTROL
CCLOCK_AcquireLock(); #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: { #ifdef FORCE_SERIALIZE_CALL_CONTROL
CCLOCK_RelinquishLock(); #endif
return DefWindowProc(hWnd, message, wParam, lParam); } } #ifdef FORCE_SERIALIZE_CALL_CONTROL
CCLOCK_RelinquishLock(); #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;
LINKDLL VOID H245WSShutdown() { Uninitialize(); }
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; }
//
// LAURABU
// BOGUS BUGBUG
//
// This table code was never stressed by the people who wrote it. It
// totally falls apart when it completely fills up
// * Allocating the last item doesn't work
// * Freeing the last item doesn't work
// * Resizing larger doesn't work
//
// Since it doesn't take a lot of memory, a decent solution is to just
// allocate it maximum+1 sized, and leave the last item free.
//
gpInstanceTable = new TSTable <HWSINST> (257);
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; } InitializeCriticalSection(&SocketToHWSInstanceMapLock);
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; bInitialized = TRUE; }
void Uninitialize() { if(bInitialized) { 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(); } bInitialized = FALSE; } }
/***************************************************************************
* * External entry points * ***************************************************************************/ //MULTITHREAD => dwH245Instance is now an OUTPUT param not an INPUT param.
LINKDLL HRESULT linkLayerInit (DWORD *dwPhysicalId, DWORD_PTR 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)MemAlloc(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(_DEBUG)
pHws->hws_dwMagic = HWSINST_MAGIC; #endif // (_DEBUG)
// 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")); MemFree(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")); QFree(pHws->hws_pRecvQueue); MemFree(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
if(!gpInstanceTable->CreateAndLock(pHws, &pHws->hws_dwPhysicalId)) { Q931HangupPendingCalls(NULL);
if(!gpInstanceTable->CreateAndLock(pHws, &pHws->hws_dwPhysicalId)) { HWSTRACE0(INVALID_PHYS_ID, HWS_WARNING, __TEXT("linkLayerInit: could not add to instance table")); QFree(pHws->hws_pSendQueue); QFree(pHws->hws_pRecvQueue); MemFree(pHws); return LINK_INSTANCE_TABLE_FULL; } } *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); MemFree(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); MemFree(pReq); } QFree(pHws->hws_pSendQueue); pHws->hws_pSendQueue = NULL; }
gpInstanceTable->Unlock(dwPhysicalId);
MemFree(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_PTR 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; }
/***************************************************************************
* * NAME * linkLayerReject - reject an incomming connection request * * DESCRIPTION * This function accepts an incomming connection * request then immediatly closes the new socket. * * PARAMETERS * dwPhysicalId Link layer identifier of the listening socket * * RETURN VALUE * 0 Function succeeded. * n!=0 Error code (see LINKAPI.H for definitions.) * ***************************************************************************/ LINKDLL HRESULT linkLayerReject(DWORD dwPhysicalIdListen) { HRESULT hr = NOERROR; PHWSINST pHwsListen = NULL; SOCKET sockReject = INVALID_SOCKET; SOCKADDR_IN sockAddr; INT sockAddrLen = sizeof(sockAddr);
// Lock the table to get the socket handle
pHwsListen = gpInstanceTable->Lock(dwPhysicalIdListen); if(NULL != pHwsListen) { // Accept incoming conenction then immediately close it
sockReject = accept(pHwsListen->hws_Socket, (SOCKADDR *)&sockAddr, &sockAddrLen); if(INVALID_SOCKET != sockReject) { closesocket(sockReject); } else { hr = MAKE_WINSOCK_ERROR(WSAGetLastError()); } } else { hr = LINK_INVALID_INSTANCE; }
// Unlock the instance table
gpInstanceTable->Unlock(dwPhysicalIdListen);
return hr; }
// 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)
|