458 lines
15 KiB
C++
458 lines
15 KiB
C++
/***************************************************************************
|
|
*
|
|
* File: h245wsrx.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: h245wsrx.cpp $
|
|
* $Revision: 2.4 $
|
|
* $Modtime: 30 Jan 1997 17:15:58 $
|
|
* $Log: S:/STURGEON/SRC/H245WS/VCS/h245wsrx.cpv $
|
|
*
|
|
* Rev 2.4 30 Jan 1997 17:17:16 EHOWARDX
|
|
* Fixed bug in trace message - need to do trace before
|
|
* calling shutdown() sent shutdown clears error retrieved
|
|
* by WSAGetLastError().
|
|
*
|
|
* Rev 2.3 14 Jan 1997 15:48:04 EHOWARDX
|
|
* Changed TryRecv() and TrySend() to check for WSAECONNRESET and
|
|
* WSAECONNABORT return from recv() and send() and act accordingly.
|
|
*
|
|
* Rev 2.2 19 Dec 1996 18:54:54 SBELL1
|
|
* took out tag comments
|
|
*
|
|
* Rev 2.1 Dec 13 1996 17:31:00 plantz
|
|
* moved #ifdef _cplusplus to after include files
|
|
//
|
|
// Rev 1.1 13 Dec 1996 12:11:34 SBELL1
|
|
// moved #ifdef _cplusplus to after include files
|
|
//
|
|
// Rev 1.0 11 Dec 1996 13:41:52 SBELL1
|
|
// Initial revision.
|
|
*
|
|
* Rev 1.19 08 Jul 1996 19:27:44 unknown
|
|
* Second experiment to try to fix Q.931 shutdown problem.
|
|
*
|
|
* Rev 1.18 01 Jul 1996 16:45:12 EHOWARDX
|
|
*
|
|
* Moved Call to SocketCloseEvent from TryRecv() to ProcessQueuedRecvs().
|
|
* TryRecv() now returns LINK_RECV_CLOSED to trigger ProcessQueuedRecvs()
|
|
* to call SocketCloseEvent().
|
|
*
|
|
* Rev 1.17 May 28 1996 18:14:36 plantz
|
|
* Change error codes to use HRESULT. Propogate Winsock errors where appropriate
|
|
*
|
|
* Rev 1.16 17 May 1996 16:49:32 EHOWARDX
|
|
* Shutdown fix.
|
|
*
|
|
* Rev 1.15 09 May 1996 18:33:16 EHOWARDX
|
|
*
|
|
* Changes to build with new LINKAPI.H.
|
|
*
|
|
* Rev 1.14 29 Apr 1996 16:53:16 EHOWARDX
|
|
*
|
|
* Added trace statement.
|
|
*
|
|
* Rev 1.13 Apr 29 1996 14:04:20 plantz
|
|
* Call NotifyRead instead of ProcessQueuedRecvs.
|
|
*
|
|
* Rev 1.12 Apr 29 1996 12:14:06 plantz
|
|
* Change tpkt header to include header size in packet length.
|
|
* Assert that message length does not exceed INT_MAX.
|
|
* .
|
|
*
|
|
* Rev 1.11 27 Apr 1996 14:07:32 EHOWARDX
|
|
* Parenthesized return from TryRecv().
|
|
*
|
|
* Rev 1.10 Apr 25 1996 21:15:12 plantz
|
|
* Check state of connection before attemting to call recv.
|
|
*
|
|
* Rev 1.9 Apr 24 1996 16:39:34 plantz
|
|
* Merge 1.5.1.0 with 1.8 (changes for winsock 1)
|
|
*
|
|
* Rev 1.5.1.0 Apr 24 1996 16:23:00 plantz
|
|
* Change to not use overlapped I/O (for winsock 1).
|
|
*
|
|
* Rev 1.5 01 Apr 1996 14:20:12 unknown
|
|
* Shutdown redesign.
|
|
*
|
|
* Rev 1.4 19 Mar 1996 20:18:16 EHOWARDX
|
|
*
|
|
* Redesigned shutdown.
|
|
*
|
|
* Rev 1.3 18 Mar 1996 19:08:32 EHOWARDX
|
|
* Fixed shutdown; eliminated TPKT/WSCB dependencies.
|
|
* Define TPKT to put TPKT/WSCB dependencies back in.
|
|
*
|
|
* Rev 1.2 14 Mar 1996 17:01:58 EHOWARDX
|
|
*
|
|
* NT4.0 testing; got rid of HwsAssert(); got rid of TPKT/WSCB.
|
|
*
|
|
* Rev 1.1 09 Mar 1996 21:12:02 EHOWARDX
|
|
* Fixes as result of testing.
|
|
*
|
|
* Rev 1.0 08 Mar 1996 20:20:18 unknown
|
|
* Initial revision.
|
|
*
|
|
***************************************************************************/
|
|
|
|
#define LINKDLL_EXPORT
|
|
|
|
#pragma warning ( disable : 4115 4201 4214 4514 )
|
|
#undef _WIN32_WINNT // override bogus platform definition in our common build environment
|
|
|
|
|
|
#include "precomp.h"
|
|
|
|
#include <limits.h>
|
|
//#include <winsock.h>
|
|
#include "queue.h"
|
|
#include "linkapi.h"
|
|
#include "h245ws.h"
|
|
#include "tstable.h"
|
|
|
|
#if defined(__cplusplus)
|
|
extern "C"
|
|
{
|
|
#endif // (__cplusplus)
|
|
|
|
|
|
// If we are not using the Unicode version of the ISR display utility, then redefine
|
|
// the __TEXT macro to do nothing.
|
|
|
|
#ifndef UNICODE_TRACE
|
|
#undef __TEXT
|
|
#define __TEXT(x) x
|
|
#endif
|
|
|
|
extern TSTable<HWSINST>* gpInstanceTable; // global ptr to the instance table
|
|
|
|
#define GetTpktLength(pReq) (((pReq)->req_TpktHeader[2] << 8) + (pReq)->req_TpktHeader[3])
|
|
|
|
|
|
/*++
|
|
|
|
Description:
|
|
Start a receive
|
|
|
|
Arguments:
|
|
pHws - Pointer to context for "connection"
|
|
pReq - Pointer to I/O request structure
|
|
|
|
Return Value:
|
|
SUCCESS - Successfully started receive.
|
|
LINK_RECV_ERROR_WOULD_BLOCK -
|
|
Winsock error
|
|
|
|
--*/
|
|
|
|
static HRESULT
|
|
TryRecv(IN PHWSINST pHws, IN char *data, IN int length, IN OUT int *total_bytes_done)
|
|
{
|
|
int requested_length = length - *total_bytes_done;
|
|
int recv_result = recv(pHws->hws_Socket, data+*total_bytes_done, requested_length, 0);
|
|
|
|
if (recv_result == SOCKET_ERROR)
|
|
{
|
|
int err = WSAGetLastError();
|
|
switch (err)
|
|
{
|
|
case WSAEWOULDBLOCK:
|
|
return LINK_RECV_WOULD_BLOCK;
|
|
|
|
case WSAECONNABORTED:
|
|
case WSAECONNRESET:
|
|
HWSTRACE1(pHws->hws_dwPhysicalId, HWS_WARNING,
|
|
__TEXT("TryRecv: recv() returned %s"),
|
|
SocketErrorText());
|
|
if (pHws->hws_uState == HWS_CONNECTED)
|
|
{
|
|
HWSTRACE0(pHws->hws_dwPhysicalId, HWS_TRACE,
|
|
__TEXT("TryRecv: calling shutdown"));
|
|
if (shutdown(pHws->hws_Socket, 1) == SOCKET_ERROR)
|
|
{
|
|
HWSTRACE1(pHws->hws_dwPhysicalId, HWS_WARNING,
|
|
__TEXT("TryRecv: shutdown() returned %s"),
|
|
SocketErrorText());
|
|
}
|
|
pHws->hws_uState = HWS_CLOSING;
|
|
}
|
|
return MAKE_WINSOCK_ERROR(err);
|
|
|
|
default:
|
|
HWSTRACE1(pHws->hws_dwPhysicalId, HWS_WARNING,
|
|
__TEXT("TryRecv: recv() returned %s"),
|
|
SocketErrorText());
|
|
return MAKE_WINSOCK_ERROR(err);
|
|
} // switch
|
|
}
|
|
|
|
HWSTRACE1(pHws->hws_dwPhysicalId, HWS_TRACE, __TEXT("TryRecv: recv returned %d"), recv_result);
|
|
if (recv_result == 0)
|
|
{
|
|
return LINK_RECV_CLOSED;
|
|
}
|
|
|
|
*total_bytes_done += recv_result;
|
|
return (recv_result == requested_length) ? NOERROR : LINK_RECV_WOULD_BLOCK;
|
|
}
|
|
|
|
|
|
static HRESULT
|
|
RecvStart(IN PHWSINST pHws, IN PREQUEST pReq)
|
|
{
|
|
HRESULT nResult = NOERROR;
|
|
|
|
// Sanity checks
|
|
HWSASSERT(pHws != NULL);
|
|
HWSASSERT(pHws->hws_dwMagic == HWSINST_MAGIC);
|
|
HWSASSERT(pReq != NULL);
|
|
HWSASSERT(pReq->req_dwMagic == RECV_REQUEST_MAGIC);
|
|
HWSASSERT(pReq->req_pHws == pHws);
|
|
|
|
// Get the header first; if that succeeds get the client data
|
|
if (pReq->req_header_bytes_done < TPKT_HEADER_SIZE)
|
|
{
|
|
nResult = TryRecv(pHws,
|
|
(char *)pReq->req_TpktHeader,
|
|
TPKT_HEADER_SIZE,
|
|
&pReq->req_header_bytes_done);
|
|
}
|
|
|
|
if (nResult == NOERROR)
|
|
{
|
|
long int tpkt_length = GetTpktLength(pReq) - TPKT_HEADER_SIZE;
|
|
if (pReq->req_TpktHeader[0] != TPKT_VERSION || tpkt_length <= 0)
|
|
{
|
|
// Invalid header version
|
|
HWSTRACE0(pHws->hws_dwPhysicalId, HWS_CRITICAL,
|
|
__TEXT("RecvComplete: bad header version; available data discarded"));
|
|
// Should this be reported to the client??
|
|
|
|
// Read and discard all available data
|
|
// The client's buffer is used as a temporary buffer.
|
|
while (recv(pHws->hws_Socket, (char *)pReq->req_client_data, pReq->req_client_length, 0) > 0)
|
|
;
|
|
|
|
// Mark the header for this request as unread; it
|
|
// will be read again when additional data is received.
|
|
pReq->req_header_bytes_done = 0;
|
|
nResult = LINK_RECV_ERROR;
|
|
}
|
|
else if (tpkt_length > pReq->req_client_length)
|
|
{
|
|
// Packet too large
|
|
int request_length;
|
|
int result;
|
|
|
|
HWSTRACE0(pHws->hws_dwPhysicalId, HWS_CRITICAL,
|
|
__TEXT("RecvComplete: packet too large; packet discarded"));
|
|
// Should this be reported to the client??
|
|
|
|
// Read and discard the packet
|
|
// The client's buffer is used as a temporary buffer.
|
|
do {
|
|
request_length = pReq->req_client_length;
|
|
if (request_length > tpkt_length)
|
|
request_length = tpkt_length;
|
|
result = recv(pHws->hws_Socket, (char *)pReq->req_client_data, request_length, 0);
|
|
} while (result > 0 && (tpkt_length -= result) > 0);
|
|
|
|
if (result == SOCKET_ERROR && WSAGetLastError() == WSAEWOULDBLOCK)
|
|
{
|
|
//TODO: packet too large handling
|
|
// Adjust the header so that the rest of this packet will be read, but
|
|
// flag it so that it is known to be an error and will not be returned
|
|
// to the client.
|
|
}
|
|
else
|
|
{
|
|
// Mark the header for this request as unread; it
|
|
// will be read again for the next packet received.
|
|
pReq->req_header_bytes_done = 0;
|
|
}
|
|
|
|
nResult = LINK_RECV_ERROR;
|
|
}
|
|
else
|
|
{
|
|
// Normal case
|
|
// The current implementation of TryRecv requires that the requested
|
|
// size fit in a signed int (because that is what Winsock supports
|
|
// in a single recv). This is guaranteed at this point regardless
|
|
// of the originator of the packets, because we don't allow a buffer
|
|
// to be posted that is larger than that (see ASSERT below). If the
|
|
// packet were larger than the buffer, it would have been caught above.
|
|
// If TryRecv is changed to remove the restriction on buffer size and
|
|
// accept a parameter of type long int, this ASSERT may be removed.
|
|
HWSASSERT(tpkt_length <= INT_MAX);
|
|
nResult = TryRecv(pHws,
|
|
(char *)pReq->req_client_data,
|
|
(int)tpkt_length,
|
|
&pReq->req_client_bytes_done);
|
|
}
|
|
}
|
|
|
|
return nResult;
|
|
} // RecvStart()
|
|
|
|
|
|
void
|
|
ProcessQueuedRecvs(IN PHWSINST pHws)
|
|
{
|
|
register PREQUEST pReq;
|
|
register DWORD dwPhysicalId = pHws->hws_dwPhysicalId;
|
|
|
|
HWSASSERT(pHws != NULL);
|
|
HWSASSERT(pHws->hws_dwMagic == HWSINST_MAGIC);
|
|
HWSASSERT(pHws->hws_uState <= HWS_CLOSING);
|
|
HWSTRACE0(pHws->hws_dwPhysicalId, HWS_TRACE, __TEXT("ProcessQueuedRecvs"));
|
|
|
|
while ((pReq = (PREQUEST) QRemove(pHws->hws_pRecvQueue)) != NULL)
|
|
{
|
|
switch (RecvStart(pHws, pReq))
|
|
{
|
|
case NOERROR:
|
|
// Call Recv callback
|
|
pHws->hws_h245RecvCallback(pHws->hws_dwH245Instance,
|
|
LINK_RECV_DATA,
|
|
pReq->req_client_data,
|
|
pReq->req_client_bytes_done);
|
|
|
|
// Free the I/O request structure
|
|
MemFree(pReq);
|
|
|
|
// Check to see if callback deallocated our instance or state changed
|
|
|
|
// 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 in a higher level function).
|
|
|
|
if(gpInstanceTable->Lock(dwPhysicalId) == NULL)
|
|
return;
|
|
gpInstanceTable->Unlock(dwPhysicalId);
|
|
if(pHws->hws_uState > HWS_CONNECTED)
|
|
return;
|
|
|
|
break;
|
|
|
|
default:
|
|
HWSTRACE0(pHws->hws_dwPhysicalId, HWS_WARNING,
|
|
__TEXT("ProcessQueuedRecvs: RecvStart() failed"));
|
|
|
|
// Fall-through to next case is intentional
|
|
|
|
case LINK_RECV_WOULD_BLOCK:
|
|
// The receive would have blocked; we need to requeue the I/O request
|
|
// and wait for a FD_READ network event.
|
|
// If any part of the data was received, the bytes_done field has been updated.
|
|
if (QInsertAtHead(pHws->hws_pRecvQueue, pReq) == FALSE)
|
|
{
|
|
HWSTRACE0(pHws->hws_dwPhysicalId, HWS_CRITICAL,
|
|
__TEXT("ProcessQueuedRecvs: QInsertAtHead() failed"));
|
|
}
|
|
return;
|
|
|
|
case LINK_RECV_CLOSED:
|
|
if (QInsertAtHead(pHws->hws_pRecvQueue, pReq) == FALSE)
|
|
{
|
|
HWSTRACE0(pHws->hws_dwPhysicalId, HWS_CRITICAL,
|
|
__TEXT("ProcessQueuedRecvs: QInsertAtHead() failed"));
|
|
}
|
|
SocketCloseEvent(pHws);
|
|
return;
|
|
|
|
} // switch
|
|
} // while
|
|
} // ProcessQueuedRecvs()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**************************************************************************
|
|
** Function : datalinkReceiveRequest
|
|
** Description : Fills header/tail of buffer and posts buffer to H.223
|
|
***************************************************************************/
|
|
LINKDLL HRESULT datalinkReceiveRequest( DWORD dwPhysicalId,
|
|
PBYTE pbyDataBuf,
|
|
DWORD dwLength)
|
|
{
|
|
register PHWSINST pHws;
|
|
register PREQUEST pReq;
|
|
|
|
HWSTRACE0(dwPhysicalId, HWS_TRACE, __TEXT("datalinkReceiveRequest"));
|
|
|
|
pHws = gpInstanceTable->Lock(dwPhysicalId);
|
|
|
|
if (pHws == NULL)
|
|
{
|
|
HWSTRACE0(dwPhysicalId, HWS_ERROR,
|
|
__TEXT("datalinkReceiveRequest: dwPhysicalId not found"));
|
|
return LINK_INVALID_INSTANCE;
|
|
}
|
|
|
|
if (pHws->hws_uState > HWS_CONNECTED)
|
|
{
|
|
HWSTRACE1(dwPhysicalId, HWS_ERROR,
|
|
__TEXT("datalinkReceiveRequest: state = %d"), pHws->hws_uState);
|
|
gpInstanceTable->Unlock(dwPhysicalId);
|
|
return LINK_INVALID_STATE;
|
|
}
|
|
|
|
// Allocate request structure
|
|
pReq = (PREQUEST) MemAlloc(sizeof(*pReq));
|
|
if (pReq == NULL)
|
|
{
|
|
HWSTRACE0(dwPhysicalId, HWS_WARNING,
|
|
__TEXT("datalinkReceiveRequest: could not allocate request buffer"));
|
|
gpInstanceTable->Unlock(dwPhysicalId);
|
|
return LINK_MEM_FAILURE;
|
|
}
|
|
|
|
// The current implementation requires that the size of each message
|
|
// fit in a signed int (because that is what Winsock supports in a
|
|
// single recv). If it is necessary to receive larger messages,
|
|
// TryRecv and RecvStart must be changed to limit the size in each
|
|
// recv call, and loop until all the data is received.
|
|
// This ASSERT could then be removed.
|
|
HWSASSERT(dwLength <= INT_MAX);
|
|
|
|
pReq->req_pHws = pHws;
|
|
pReq->req_header_bytes_done= 0;
|
|
pReq->req_client_data = pbyDataBuf;
|
|
pReq->req_client_length = (int)dwLength;
|
|
pReq->req_client_bytes_done= 0;
|
|
pReq->req_dwMagic = RECV_REQUEST_MAGIC;
|
|
|
|
if (QInsert(pHws->hws_pRecvQueue, pReq) == FALSE)
|
|
{
|
|
HWSTRACE0(pHws->hws_dwPhysicalId, HWS_CRITICAL,
|
|
__TEXT("datalinkReceiveRequest: QInsert() failed"));
|
|
gpInstanceTable->Unlock(dwPhysicalId);
|
|
return LINK_RECV_NOBUFF;
|
|
}
|
|
|
|
if (pHws->hws_uState == HWS_CONNECTED)
|
|
NotifyRead(pHws);
|
|
|
|
HWSTRACE0(dwPhysicalId, HWS_TRACE, __TEXT("datalinkReceiveRequest: succeeded"));
|
|
gpInstanceTable->Unlock(dwPhysicalId);
|
|
return NOERROR;
|
|
} // datalinkReceiveRequest()
|
|
|
|
|
|
|
|
#if defined(__cplusplus)
|
|
}
|
|
#endif // (__cplusplus)
|