/*************************************************************************** * * 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 #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* 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 #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 (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)