You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3165 lines
85 KiB
3165 lines
85 KiB
/* File: D:\WACKER\comwsock\comwsock.c (Created: 12/26/95)
|
|
*
|
|
* Copyright 1996 by Hilgraeve Inc. -- Monroe, MI
|
|
* All rights reserved
|
|
*
|
|
* $Revision: 22 $
|
|
* $Date: 7/08/02 6:31p $
|
|
*
|
|
* $Log: /Products/wacker/Comwsock/Comwsock.c $
|
|
*
|
|
* 22 7/08/02 6:31p Dans
|
|
* Replaced StrCharCopy to StrCharCopyN to protect against buffer
|
|
* overruns.
|
|
*
|
|
* 21 5/31/02 3:48p Ronv
|
|
* fAnswer is a flag i n the ST_STDCOM structure. This revision makes
|
|
* sure the value is set to FALSE (this did not cause any problems in the
|
|
* past since FALSE is defined as 0 on Windows).
|
|
*
|
|
* 19 4/30/02 4:02p Ronv
|
|
* Handles to events should not use INVALID_HANDLE_VALUE since that is
|
|
* just a value to be used for file handles.
|
|
*
|
|
* 18 4/16/02 2:36p Ronv
|
|
* No need to register the window class again if it is already registered.
|
|
*
|
|
* 17 4/10/02 3:12p Ronv
|
|
* Now using INVALID_HANDLE_VALUE to make sure the Com handles (event
|
|
* handles) are released and freed correctly.
|
|
*
|
|
* 16 4/05/02 4:26p Ronv
|
|
* Cleaned up some logic in WsckSndBufrSend() to release the critical
|
|
* section as soon as possible so that we don't get into a thread lock.
|
|
*
|
|
* 15 3/22/02 1:53p Ronv
|
|
*
|
|
* 14 3/20/02 11:45a Ronv
|
|
* Revisions per MS to cleaning up the use of handles outside of crital
|
|
* locks (MS security review).
|
|
*
|
|
* 13 2/25/02 1:17p Ronv
|
|
* 02-19-2002 MS Source Code Drop
|
|
*
|
|
* 12 1/18/02 4:59p Ronv
|
|
* Made sure the serial port defaults are used when the serial port is
|
|
* selected for the first time, or the serial port selected is not the
|
|
* same as what is currently set in the session.
|
|
*
|
|
* Also, changed to using the StrCharxxx() functions in HTCHAR.H for
|
|
* maintainability.
|
|
*
|
|
* 11 11/08/01 11:05a Ronv
|
|
* Revisions to use the COM_PORT defines for the states of the connection
|
|
* to be consistent with serial and other TAPI devices.
|
|
*
|
|
* 10 5/09/01 4:43p Ronv
|
|
* Changed tcahr.h to htchar.h per MS request to resolve some build
|
|
* issues. Also other misc. #include revisions.
|
|
*
|
|
* 9 3/22/01 11:26a Ronv
|
|
* Removed previous revisions needed (include shfusion.h) for Windows XP
|
|
* Themeing.
|
|
*
|
|
* 8 2/27/01 5:45p Ronv
|
|
* Revisions needed (include shfusion.h) for Windows XP Themeing.
|
|
*
|
|
* 7 2/16/01 4:01p Ronv
|
|
* Fix for not dereferencing a null pointer.
|
|
*
|
|
* 6 12/21/00 11:15a Ronv
|
|
* Corrected usage of sizeof().
|
|
*
|
|
* 5 11/07/00 12:06p Ronv
|
|
* Fix for setting character in a TCHAR array to correct NULL character.
|
|
*
|
|
* Fix for setting character in a TCHAR array to correct NULL character.
|
|
*
|
|
* Using StrCharCopyN() instead of StrCharCopy() to make sure there is not
|
|
* a buffer overrun.
|
|
*
|
|
*
|
|
* 4 9/20/00 4:54p Ronv
|
|
* Fix for buffer overrun in with WINSOCK sessions when the URL was > 116
|
|
* characters. We will now truncate the URL to 127 characters to make
|
|
* sure we don't overwrite the buffer allocated for the URL.
|
|
*
|
|
* 3 11/16/99 9:56a Johnh
|
|
* Fixed bug reported by IBM that isolated, unsupported NVT control
|
|
* sequences (when sent alone) caused cursor movement.
|
|
*
|
|
* 2 2/05/99 3:20p Supervisor
|
|
* 64-bit changes and bug fixes for Microsoft
|
|
*
|
|
* 1 10/05/98 1:02p Supervisor
|
|
* Revision 1.16 1998/09/11 11:41:41 JKH
|
|
* none
|
|
*
|
|
* Revision 1.15 1998/09/10 14:54:58 bld
|
|
* none
|
|
*
|
|
* Revision 1.14 1998/09/10 11:04:39 bld
|
|
* none
|
|
*
|
|
* Revision 1.13 1998/09/09 16:15:37 rev
|
|
* none
|
|
*
|
|
* Revision 1.12 1998/08/28 15:24:13 rev
|
|
* none
|
|
*
|
|
* Revision 1.11 1998/08/28 10:31:23 bld
|
|
* none
|
|
*
|
|
* Revision 1.10 1998/06/17 16:04:17 JKH
|
|
* none
|
|
*
|
|
* Revision 1.9 1998/03/10 15:49:00 bld
|
|
* none
|
|
*
|
|
* Revision 1.8 1997/03/24 09:53:07 JKH
|
|
* Added Telnet break and command line telnet port selection
|
|
*
|
|
* Revision 1.7 1997/02/26 09:34:37 dmn
|
|
* none
|
|
*
|
|
* Revision 1.6 1996/11/21 14:15:43 cab
|
|
* Added call answering
|
|
*
|
|
* Revision 1.5 1996/02/22 14:24:07 jmh
|
|
* Winsock com driver now uses same private data structure as standard com.
|
|
*
|
|
* Revision 1.4 1996/02/22 11:22:39 mcc
|
|
* none
|
|
*
|
|
* Revision 1.3 1996/02/22 10:20:19 mcc
|
|
* none
|
|
*
|
|
* Revision 1.2 1996/02/05 14:17:12 mcc
|
|
* none
|
|
*
|
|
* Revision 1.1 1996/01/31 15:52:15 mcc
|
|
* Winsock Comm driver
|
|
*
|
|
|
|
*Design Overview =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
|
|
This module would do Dr. Frankenstein proud ... it's basic structure is
|
|
taken from WACKER's COMSTD module, but the internal logic is taken from
|
|
HAWIN. (I tried to port NPORT's OS/2 code but there is apparently some
|
|
flaw in Win95's support for threaded Winsock apps, anyway I could not
|
|
get it to work). This code is preserved here (controlled by #ifdef
|
|
MULTITHREAD), it would be interesting to see if it works under Windows NT.
|
|
|
|
A few random bits from NPORT are stitched in too ...
|
|
|
|
This driver gets its remote address and port number settings from the
|
|
connection driver via DeviceSpecial calls. It stores nothing in
|
|
the session file, so those load/save calls are stubs.
|
|
|
|
Tidbits of possibly useful information:
|
|
|
|
Sometimes a send() appears to succeed but no data appears at the other
|
|
end. It appears that sometimes Winsock is internally waiting forever
|
|
for something to happen, and never actually sends the data. This
|
|
might be caused by a recv() call outstanding that asks for
|
|
a large amount of data, and maybe the send() call can't get enough
|
|
memory until it completes (but it never WILL complete because the
|
|
other system is waiting for data). Also, I've seen this happening
|
|
with the MULTITHREAD code, possibly due to a Winsock bug
|
|
under Win95.
|
|
|
|
The EscFF business is because Telnet (a protocol on top of TCP/IP
|
|
that we will often encounter) uses FF as a command character,
|
|
and sends FF FF as a literal FF. Thus, file transfers to
|
|
a system running Telnet must escape FF characters in a file
|
|
by doubling them.
|
|
|
|
The STDCOM drivers work by activating the port then sending
|
|
data out to dial the modem, thus there is no ComConnect
|
|
call in the high-level Com API. For better or worse, TCP/IP
|
|
requires that the IP address and Port number be supplied
|
|
by the CNCT driver (via ComDeviceSpecial calls) before
|
|
ComActivatePort is called so that activating the port actually
|
|
establishes the link to the other system. In this kinda kludgy
|
|
non-threaded implementation, ComActivatePort cannot block, so
|
|
it will return success if it can successfully send out a
|
|
connection request. If the request ultimately fails, this
|
|
driver will call ComNotify to let the CNCT driver know that there
|
|
is a connection status change, and it must pick up the pieces.
|
|
|
|
|
|
|
|
*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
|
|
|
|
//#define DEBUGSTR
|
|
|
|
#include <windows.h>
|
|
#pragma hdrstop
|
|
|
|
#include <tdll\stdtyp.h>
|
|
|
|
#if defined(INCL_WINSOCK)
|
|
|
|
#include <tdll\session.h>
|
|
#include <tdll\mc.h>
|
|
#include <tdll\sf.h>
|
|
#include <tdll\timers.h>
|
|
#include <tdll\com.h>
|
|
#include <tdll\comdev.h>
|
|
#include <comstd\comstd.hh>
|
|
#include "comwsock.hh"
|
|
#include <tdll\assert.h>
|
|
#include <tdll\statusbr.h>
|
|
#include <tdll\htchar.h>
|
|
#include <tdll\com.hh>
|
|
|
|
BOOL WINAPI _CRT_INIT(HINSTANCE hInstDll, DWORD fdwReason, LPVOID lpReserved);
|
|
int wsckResolveAddress(TCHAR *pszRemote, unsigned long *pulAddr);
|
|
LRESULT FAR PASCAL WndSockWndProc(HWND hWnd, UINT uiMsg, WPARAM uiPar1, LPARAM lPar2);
|
|
BOOL WinSockCreateEventWindow (ST_STDCOM *pstPrivate);
|
|
int FAR PASCAL sndQueueAppend(ST_STDCOM *pstPrivate,
|
|
VOID FAR *pvBufr, int nBytesToAppend);
|
|
int WinSockConnectSpecial(ST_STDCOM *pstPrivate);
|
|
int WinSockAnswerSpecial(ST_STDCOM *pstPrivate);
|
|
|
|
LONG WinSockConnectEvent(ST_STDCOM* pstPrivate, LPARAM lPar);
|
|
LONG WinSockReadEvent(ST_STDCOM* pstPrivate, LPARAM lPar);
|
|
LONG WinSockWriteEvent(ST_STDCOM*pstPrivate, LPARAM lPar);
|
|
LONG WinSockResolveEvent(ST_STDCOM* pstPrivate, LPARAM lPar);
|
|
LONG WinSockCloseEvent(ST_STDCOM* pstPrivate, LPARAM lPar);
|
|
LONG WinSockAcceptEvent(ST_STDCOM*pstPrivate, LPARAM lPar);
|
|
|
|
/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
* FUNCTION:
|
|
* ComLoadWinsockDriver
|
|
*
|
|
* DESCRIPTION:
|
|
* Loads the COM handle with pointers to the Winsock driver functions
|
|
*
|
|
* ARGUMENTS:
|
|
*
|
|
* RETURNS:
|
|
* COM_OK if successful
|
|
* COM_FAILED otherwise
|
|
*
|
|
* AUTHOR:
|
|
* mcc 12/26/95
|
|
*/
|
|
int ComLoadWinsockDriver(HCOM pstCom)
|
|
{
|
|
|
|
int iRetVal = COM_OK;
|
|
|
|
if ( !pstCom )
|
|
return COM_FAILED;
|
|
|
|
pstCom->pfPortActivate = WsckPortActivate;
|
|
pstCom->pfPortDeactivate = WsckPortDeactivate;
|
|
pstCom->pfPortConnected = WsckPortConnected;
|
|
pstCom->pfRcvRefill = WsckRcvRefill;
|
|
pstCom->pfRcvClear = WsckRcvClear;
|
|
pstCom->pfSndBufrSend = WsckSndBufrSend;
|
|
pstCom->pfSndBufrIsBusy = WsckSndBufrIsBusy;
|
|
pstCom->pfSndBufrClear = WsckSndBufrClear;
|
|
pstCom->pfSndBufrQuery = WsckSndBufrQuery;
|
|
pstCom->pfDeviceSpecial = WsckDeviceSpecial;
|
|
pstCom->pfPortConfigure = WsckPortConfigure;
|
|
|
|
return iRetVal;
|
|
}
|
|
|
|
/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
* FUNCTION:
|
|
* WsckComWinsockEntry
|
|
*
|
|
* DESCRIPTION:
|
|
* Currently, just initializes the C-Runtime library but may be used
|
|
* for other things later.
|
|
*
|
|
* ARGUMENTS:
|
|
* hInstDll - Instance of this DLL
|
|
* fdwReason - Why this entry point is called
|
|
* lpReserved - reserved
|
|
*
|
|
* RETURNS:
|
|
* BOOL
|
|
*
|
|
* AUTHOR:
|
|
* mcc 12/26/95
|
|
*/
|
|
BOOL WINAPI WsckComWinsockEntry(HINSTANCE hInst, DWORD fdwReason, LPVOID lpReserved)
|
|
{
|
|
hinstDLL = hInst;
|
|
return _CRT_INIT(hInst, fdwReason, lpReserved);
|
|
}
|
|
|
|
|
|
/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
* FUNCTION: WsckDeviceInitialize
|
|
*
|
|
* DESCRIPTION:
|
|
* Called whenever the driver is being loaded
|
|
*
|
|
* ARGUMENTS:
|
|
* hCom -- A copy of the com handle. Can be used in the
|
|
* driver code to call com services
|
|
* usInterfaceVersion -- A version number identifying the version of the
|
|
* driver interface
|
|
* ppvDriverData -- A place to put the pointer to our private data.
|
|
* This value will be passed back to us in all
|
|
* subsequent calls.
|
|
*
|
|
* RETURNS:
|
|
* COM_OK if all is hunky dory
|
|
* COM_DEVICE_VERSION_ERROR if Wacker expects a different interface version.
|
|
* COM_NOT_ENOUGH_MEMORY
|
|
* COM_DEVICE_ERROR if anything else goes wrong
|
|
*
|
|
* AUTHOR:
|
|
* mcc 12/26/95
|
|
*/
|
|
int WINAPI WsckDeviceInitialize(HCOM hCom,
|
|
unsigned nInterfaceVersion,
|
|
void **ppvDriverData)
|
|
{
|
|
int iRetVal = COM_OK;
|
|
int ix;
|
|
ST_STDCOM *pstPrivate = NULL;
|
|
|
|
// Check version number and compatibility
|
|
|
|
if (nInterfaceVersion != COM_VERSION)
|
|
{
|
|
// This error is reported by Com Routines. We cannot report errors
|
|
// until after DeviceInitialize has completed.
|
|
return COM_DEVICE_VERSION_ERROR;
|
|
}
|
|
|
|
if (*ppvDriverData)
|
|
{
|
|
pstPrivate = (ST_STDCOM*) *ppvDriverData;
|
|
}
|
|
else
|
|
{
|
|
// Allocate our private storage structure
|
|
if ((pstPrivate = malloc(sizeof(*pstPrivate))) == NULL)
|
|
{
|
|
return COM_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
*ppvDriverData = pstPrivate;
|
|
|
|
// These members are common to both com drivers
|
|
//
|
|
pstPrivate->hCom = hCom;
|
|
pstPrivate->fNotifyRcv = TRUE;
|
|
pstPrivate->dwEventMask = 0;
|
|
pstPrivate->fSending = FALSE;
|
|
pstPrivate->lSndTimer = 0L;
|
|
pstPrivate->lSndLimit = 0L;
|
|
pstPrivate->lSndStuck = 0L;
|
|
pstPrivate->hwndEvents = (HWND)0;
|
|
pstPrivate->nRBufrSize = WSOCK_SIZE_INQ;
|
|
pstPrivate->pbBufrStart = NULL;
|
|
pstPrivate->fHaltThread = TRUE;
|
|
|
|
InitializeCriticalSection(&pstPrivate->csect);
|
|
for (ix = 0; ix < EVENT_COUNT; ++ix)
|
|
{
|
|
pstPrivate->ahEvent[ix] = CreateEvent(NULL,
|
|
TRUE, // must be manually reset
|
|
FALSE, // create unsignalled
|
|
NULL); // unnamed
|
|
if (pstPrivate->ahEvent[ix] == NULL)
|
|
{
|
|
iRetVal = COM_FAILED;
|
|
//
|
|
// Make sure to initialize the rest of the event handles to NULL;
|
|
//
|
|
for (++ix; ix < EVENT_COUNT; ++ix)
|
|
{
|
|
pstPrivate->ahEvent[ix] = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Setup up reasonable default device values in case this type of
|
|
// device has not been used in a session before
|
|
pstPrivate->hSocket = INVALID_SOCKET;
|
|
pstPrivate->nPort = 23;
|
|
pstPrivate->fConnected = COM_PORT_NOT_OPEN;
|
|
pstPrivate->hComReadThread = NULL;
|
|
pstPrivate->hComWriteThread = NULL;
|
|
pstPrivate->fEscapeFF = TRUE;
|
|
#ifdef INCL_CALL_ANSWERING
|
|
pstPrivate->fAnswer = FALSE;
|
|
#endif
|
|
|
|
if (iRetVal != COM_OK)
|
|
{
|
|
if (pstPrivate)
|
|
{
|
|
free(pstPrivate);
|
|
pstPrivate = NULL;
|
|
}
|
|
}
|
|
|
|
return iRetVal;
|
|
}
|
|
|
|
|
|
/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
* FUNCTION: WsckDeviceClose
|
|
*
|
|
* DESCRIPTION:
|
|
* Called when Wacker is done with this driver and is about to release .DLL
|
|
*
|
|
* ARGUMENTS:
|
|
* pstPrivate -- Pointer to our private data structure
|
|
*
|
|
* RETURNS:
|
|
* COM_OK
|
|
*
|
|
* AUTHOR:
|
|
* mcc 01/19/96
|
|
*/
|
|
int WINAPI WsckDeviceClose(void *pvPrivate)
|
|
{
|
|
ST_STDCOM *pstPrivate = (ST_STDCOM *) pvPrivate;
|
|
int ix;
|
|
|
|
// Driver is about to be let go, do any cleanup
|
|
// Port should have been deactivated before we are called, but
|
|
// check anyway.
|
|
WsckPortDeactivate(pstPrivate);
|
|
|
|
for (ix = 0; ix < EVENT_COUNT; ++ix)
|
|
{
|
|
if (pstPrivate->ahEvent[ix])
|
|
{
|
|
CloseHandle(pstPrivate->ahEvent[ix]);
|
|
pstPrivate->ahEvent[ix] = NULL;
|
|
}
|
|
}
|
|
DeleteCriticalSection(&pstPrivate->csect);
|
|
// Free our private data area
|
|
free(pstPrivate);
|
|
pstPrivate = NULL;
|
|
|
|
DbgOutStr("WsckDeviceClose complete", 0,0,0,0,0);
|
|
|
|
return COM_OK;
|
|
}
|
|
|
|
|
|
|
|
/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
* FUNCTION: WsckDeviceSpecial
|
|
*
|
|
* DESCRIPTION:
|
|
* The means for others to control any special features in this driver
|
|
* that are not supported by all drivers.
|
|
*
|
|
* ARGUMENTS:
|
|
*
|
|
*
|
|
* RETURNS:
|
|
* COM_NOT_SUPPORTED if the instruction string was not recognized
|
|
* otherwise depends on instruction string
|
|
*
|
|
* AUTHOR:
|
|
* mcc 12/26/95 (ported from NPORT)
|
|
*/
|
|
int WINAPI WsckDeviceSpecial(void *pvPrivate, const TCHAR *pszInstructions,
|
|
TCHAR *pszResult, int nBufrSize)
|
|
{
|
|
ST_STDCOM *pstPrivate = (ST_STDCOM *) pvPrivate;
|
|
int iRetVal = COM_NOT_SUPPORTED;
|
|
unsigned long ulSetVal;
|
|
TCHAR *pszEnd;
|
|
//
|
|
// MAX_IP_ADDR_LEN+11+1 = buffer size of pstPrivate->szRemoteAddr +
|
|
// settings string "SET IPADDR=" + 1 for the terminating NULL
|
|
// character. REV 09/20/2000
|
|
//
|
|
TCHAR achInstructions[MAX_IP_ADDR_LEN+11+1];
|
|
TCHAR *pszToken = achInstructions;
|
|
int iIndex;
|
|
TCHAR szResult[MAX_IP_ADDR_LEN+11+1];
|
|
//ULONG dwThreadID;
|
|
|
|
static TCHAR *apszItems[] =
|
|
{
|
|
"IPADDR",
|
|
"PORTNUM",
|
|
"ISCONNECTED",
|
|
"ESC_FF", /* 3 */
|
|
"ANSWER",
|
|
NULL
|
|
};
|
|
|
|
// supported instruction strings:
|
|
// "Set xxx=vv"
|
|
// "Query xxx"
|
|
|
|
|
|
if (!pszInstructions || !*pszInstructions)
|
|
return COM_FAILED;
|
|
|
|
//DbgOutStr("DevSpec: %s", pszInstructions, 0,0,0,0);
|
|
|
|
if (sizeof(achInstructions)/sizeof(TCHAR) < (size_t)(StrCharGetStrLength(pszInstructions) + 1))
|
|
return COM_NOT_SUPPORTED;
|
|
|
|
StrCharCopyN(achInstructions, (LPTSTR)pszInstructions, MAX_IP_ADDR_LEN+11+1);
|
|
|
|
if (pszResult)
|
|
*pszResult = TEXT('\0');
|
|
|
|
pszToken = strtok(achInstructions, " ");
|
|
if (!pszToken)
|
|
return COM_NOT_SUPPORTED;
|
|
|
|
EnterCriticalSection(&pstPrivate->csect);
|
|
|
|
if (StrCharCmpi(pszToken, "SET") == 0)
|
|
{
|
|
iRetVal = COM_OK;
|
|
pszToken = strtok(NULL, " =");
|
|
if (!pszToken)
|
|
pszToken = "";
|
|
|
|
// Look up the item to set.
|
|
for (iIndex = 0; apszItems[iIndex]; ++iIndex)
|
|
if (StrCharCmpi(pszToken, apszItems[iIndex]) == 0)
|
|
break;
|
|
|
|
// Isolate the new value to be set
|
|
pszToken = strtok(NULL, "\n");
|
|
|
|
if (pszToken && *pszToken)
|
|
{
|
|
// Several items take numeric values
|
|
ulSetVal = strtoul(pszToken, &pszEnd, 0);
|
|
|
|
switch(iIndex)
|
|
{
|
|
case 0: // IPADDR
|
|
ulSetVal = (unsigned) StrCharGetByteCount(pszToken);
|
|
if ( ulSetVal < sizeof(pstPrivate->szRemoteAddr))
|
|
{
|
|
StrCharCopyN(pstPrivate->szRemoteAddr, pszToken, IP_ADDR_LEN);
|
|
iRetVal = 0;
|
|
}
|
|
else
|
|
iRetVal = -1;
|
|
break;
|
|
|
|
case 1: // PORTNUM
|
|
pstPrivate->nPort = (short) ulSetVal;
|
|
iRetVal = 0;
|
|
break;
|
|
|
|
case 3: // ESC_FF
|
|
pstPrivate->fEscapeFF = (int) atoi(pszToken);
|
|
//DbgOutStr("set fEscapeFF = %d (%d) %s %d",
|
|
//pstPrivate->fEscapeFF,ulSetVal,pszToken,
|
|
//(int) atoi(pszToken),0);
|
|
break;
|
|
|
|
case 4: // ANSWER
|
|
#ifdef INCL_CALL_ANSWERING
|
|
pstPrivate->fAnswer = ulSetVal;
|
|
iRetVal = 0;
|
|
#else
|
|
iRetVal = COM_FAILED;
|
|
#endif
|
|
break;
|
|
|
|
default:
|
|
iRetVal = COM_FAILED;
|
|
//DbgOutStr("DevSpec: Unrecognized instructions!", 0,0,0,0,0);
|
|
break;
|
|
}
|
|
}
|
|
else // if (pszToken && *pszToken)
|
|
{
|
|
assert(0);
|
|
iRetVal = COM_NOT_SUPPORTED;
|
|
}
|
|
}
|
|
else if (StrCharCmpi(pszToken, "QUERY") == 0)
|
|
{
|
|
iRetVal = COM_OK;
|
|
pszToken = strtok(NULL, "\n");
|
|
szResult[0] = TEXT('\0');
|
|
|
|
// Look up the item to query
|
|
for (iIndex = 0; apszItems[iIndex]; ++iIndex)
|
|
if (StrCharCmpi(pszToken, apszItems[iIndex]) == 0)
|
|
break;
|
|
|
|
if (*pszToken)
|
|
{
|
|
switch(iIndex)
|
|
{
|
|
case 0: // IPADDR
|
|
StrCharCopyN(szResult, pstPrivate->szRemoteAddr, (sizeof(szResult)/sizeof(TCHAR)));
|
|
szResult[sizeof(szResult)/sizeof(TCHAR) - 1] = TEXT('\0');
|
|
iRetVal = 0;
|
|
break;
|
|
|
|
case 1: // PORTNUM
|
|
wsprintf(szResult, "%d", pstPrivate->nPort);
|
|
iRetVal = 0;
|
|
break;
|
|
|
|
case 2: // ISCONNECTED
|
|
wsprintf(szResult, "%d", pstPrivate->fConnected);
|
|
iRetVal = 0;
|
|
break;
|
|
|
|
case 4: // ANSWER
|
|
#ifdef INCL_CALL_ANSWERING
|
|
wsprintf(szResult, "%d", pstPrivate->fAnswer);
|
|
iRetVal = 0;
|
|
#else
|
|
iRetVal = COM_FAILED;
|
|
#endif
|
|
break;
|
|
|
|
default:
|
|
iRetVal = COM_FAILED;
|
|
break;
|
|
}
|
|
|
|
if ( iRetVal == 0 && StrCharGetByteCount(szResult) < nBufrSize )
|
|
{
|
|
StrCharCopyN(pszResult, szResult, nBufrSize);
|
|
}
|
|
else
|
|
{
|
|
iRetVal = COM_FAILED;
|
|
}
|
|
}
|
|
}
|
|
else if (StrCharCmpi(pszInstructions, "Send Break") == 0)
|
|
{
|
|
// This is the telent "Break" key processing. When
|
|
// the user presses Ctrl-Break on the terminal sreen
|
|
// with a WinSOck connection, we arrive here.
|
|
//
|
|
// Please refer to RFC 854 for specifics on this
|
|
// implementation. Basically, we need to..
|
|
// send the IAC BREAK signal (0xFF 0xF3)
|
|
unsigned char ach[2];
|
|
|
|
ach[0] = IAC;
|
|
ach[1] = BREAK;
|
|
|
|
if (send(pstPrivate->hSocket, ach, 2, 0) != 2)
|
|
{
|
|
assert(0);
|
|
}
|
|
|
|
iRetVal = COM_OK;
|
|
}
|
|
else if (StrCharCmpi(pszInstructions, "Send IP") == 0)
|
|
{
|
|
// This is the telent Interrupt Process. When
|
|
// the user presses Alt-Break on the terminal sreen
|
|
// with a WinSock connection, we arrive here.
|
|
//
|
|
// Please refer to RFC 854 for specifics on this
|
|
// implementation. Basically, we need to..
|
|
//
|
|
// Send the Telnet IP (Interrupt Processs)
|
|
// sequence (0xFF 0xF4).
|
|
//
|
|
// Send the Telnet SYNC sequence. That is,
|
|
// send the Data Mark (DM) as the only character
|
|
// is a TCP urgent mode send operation (the mode
|
|
// flag MSG_OOB does this for us).
|
|
//
|
|
unsigned char ach[2];
|
|
|
|
SndBufrClear(pstPrivate);
|
|
|
|
ach[0] = IAC;
|
|
ach[1] = IP;
|
|
|
|
if (send(pstPrivate->hSocket, ach, 2, 0) != 2)
|
|
{
|
|
assert(0);
|
|
}
|
|
|
|
ach[0] = IAC;
|
|
ach[1] = DM;
|
|
|
|
if (send(pstPrivate->hSocket, ach, 2, MSG_OOB) != 2)
|
|
{
|
|
assert(0);
|
|
}
|
|
|
|
|
|
iRetVal = COM_OK;
|
|
}
|
|
else if (StrCharCmpi(pszInstructions, "Update Terminal Size") == 0)
|
|
{
|
|
// The dimensions of the terminal have changed. If we have negotiated
|
|
// to use the Telnet NAWS option, (Negotiate About Terminal Size), then
|
|
// we must send the new terminal size to the server. This method will
|
|
// only send data out if the option has been enabled.
|
|
WinSockSendNAWS( pstPrivate );
|
|
}
|
|
|
|
//
|
|
// This is necessary to get the default settings on COM ports. REV: 08/22/2001
|
|
//
|
|
else if (StrCharCmpi(pszInstructions, "GET Defaults") == 0)
|
|
{
|
|
iRetVal = PortDefaultSettings(pstPrivate);
|
|
}
|
|
|
|
LeaveCriticalSection(&pstPrivate->csect);
|
|
|
|
return iRetVal;
|
|
}
|
|
|
|
|
|
/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
* FUNCTION:
|
|
* WsckDeviceLoadHdl
|
|
*
|
|
* DESCRIPTION:
|
|
* We need a function that appears to load/save to the session file,
|
|
* returning SF_OK, but actually doing nothing since this driver saves
|
|
* no settings.
|
|
*
|
|
* ARGUMENTS:
|
|
* pstPrivate -- dummy (not used)
|
|
* sfHdl -- dummy (not used)
|
|
*
|
|
* RETURNS:
|
|
*
|
|
* AUTHOR:
|
|
* mcc 01/19/95
|
|
*/
|
|
int WINAPI WsckDeviceLoadHdl(void *pvPrivate, SF_HANDLE sfHdl)
|
|
{
|
|
return SF_OK;
|
|
}/*lint !e715 */
|
|
|
|
|
|
/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
* FUNCTION:
|
|
* WsckDeviceSaveStub
|
|
*
|
|
* DESCRIPTION:
|
|
* We need a function that appears to Save/save to the session file,
|
|
* returning SF_OK, but actually doing nothing since this driver saves
|
|
* no settings.
|
|
*
|
|
* ARGUMENTS:
|
|
* pstPrivate -- dummy (not used)
|
|
* sfHdl -- dummy (not used)
|
|
*
|
|
* RETURNS:
|
|
*
|
|
* AUTHOR:
|
|
* mcc 01/19/95
|
|
*/
|
|
int WINAPI WsckDeviceSaveHdl(void *pvPrivate, SF_HANDLE sfHdl)
|
|
{
|
|
return SF_OK;
|
|
}/*lint !e715 */
|
|
|
|
|
|
|
|
/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
* FUNCTION: WsckDeviceStub
|
|
*
|
|
* DESCRIPTION:
|
|
* Stub that returns COM_OK (unlike default stubs)
|
|
*
|
|
* ARGUMENTS:
|
|
* pstPrivate -- not used
|
|
*
|
|
* RETURNS:
|
|
* COM_OK if port is configured successfully
|
|
*
|
|
* AUTHOR:
|
|
* mcc 12/26/95
|
|
*/
|
|
int WINAPI WsckDeviceStub(void *pvPrivate)
|
|
{
|
|
int iRetVal = COM_OK;
|
|
|
|
return iRetVal;
|
|
} /*lint !e715 */
|
|
|
|
|
|
/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
* FUNCTION: WsckPortConfigure
|
|
*
|
|
* DESCRIPTION:
|
|
* Configures an open port with the current set of user settings
|
|
*
|
|
* ARGUMENTS:
|
|
* pstPrivate -- The driver data structure
|
|
*
|
|
* RETURNS:
|
|
* COM_OK if port is configured successfully
|
|
* COM_DEVICE_ERROR if API errors are encountered
|
|
* COM_DEVICE_INVALID_SETTING if some user settings are not valid
|
|
*/
|
|
int WINAPI WsckPortConfigure(void *pvPrivate)
|
|
{
|
|
ST_STDCOM *pstPrivate = (ST_STDCOM *) pvPrivate;
|
|
int iRetVal = COM_OK;
|
|
unsigned uOverrides = 0;
|
|
|
|
// Check for overrides
|
|
ComQueryOverride(pstPrivate->hCom, &uOverrides);
|
|
if (bittest(uOverrides, COM_OVERRIDE_8BIT))
|
|
{
|
|
DbgOutStr("Requesting binary Telnet mode\n", 0,0,0,0,0);
|
|
// Ask the other side to send binary data (default
|
|
// is 7-bit ASCII), and inform them that we will
|
|
// be sending binary data.
|
|
WinSockSendMessage(pstPrivate, DO, TELOPT_BINARY);
|
|
WinSockSendMessage(pstPrivate, WILL, TELOPT_BINARY);
|
|
}
|
|
|
|
return iRetVal;
|
|
}
|
|
|
|
/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
* FUNCTION: WsckPortConnected
|
|
*
|
|
* DESCRIPTION:
|
|
* Determines whether the driver is currently connected to a host system.
|
|
* (Sort of like having a "carrier" in the STDCOM drivers)
|
|
*
|
|
* ARGUMENTS:
|
|
* pstPrivate -- Our private data structure
|
|
*
|
|
* RETURNS:
|
|
* TRUE if we have an active connection
|
|
* FALSE otherwise
|
|
*
|
|
* AUTHOR:
|
|
* mcc 01/19/96
|
|
*/
|
|
int WINAPI WsckPortConnected(void *pvPrivate)
|
|
{
|
|
ST_STDCOM *pstPrivate = (ST_STDCOM *) pvPrivate;
|
|
|
|
return pstPrivate->fConnected;
|
|
}
|
|
|
|
/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
* FUNCTION: WsckSndBufrIsBusy
|
|
*
|
|
* DESCRIPTION:
|
|
* Determines whether the driver is available to transmit a buffer of
|
|
* data or not.
|
|
*
|
|
* ARGUMENTS:
|
|
* pstPrivate -- address of com driver's data structure
|
|
*
|
|
* RETURNS:
|
|
* COM_OK if data can be transmitted
|
|
* COM_BUSY if driver is still working on a previous buffer
|
|
*
|
|
* AUTHOR:
|
|
* mcc 12/26/95
|
|
*/
|
|
int WINAPI WsckSndBufrIsBusy(void *pvPrivate)
|
|
{
|
|
ST_STDCOM *pstPrivate = (ST_STDCOM *) pvPrivate;
|
|
int iRetVal = COM_OK;
|
|
|
|
EnterCriticalSection(&pstPrivate->csect);
|
|
|
|
if (pstPrivate->fSending)
|
|
{
|
|
iRetVal = COM_BUSY;
|
|
}
|
|
|
|
LeaveCriticalSection(&pstPrivate->csect);
|
|
|
|
// DBG_WRITE((iRetVal==COM_BUSY)?"Snd Bufr Busy\r\n":"Snd Bufr Ready\r\n",
|
|
// 0,0,0,0,0);
|
|
|
|
return iRetVal;
|
|
}
|
|
|
|
/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
* FUNCTION:
|
|
* WsckSndBufrQuery
|
|
*
|
|
* DESCRIPTION:
|
|
* A stub; I'm not really sure what else it COULD do in TCP/IP
|
|
*
|
|
* ARGUMENTS:
|
|
* ignored
|
|
*
|
|
* RETURNS:
|
|
* COM_OK
|
|
*
|
|
* AUTHOR:
|
|
* mcc 12/26/95
|
|
*/
|
|
int WINAPI WsckSndBufrQuery(void *pvPrivate,
|
|
unsigned *pafStatus,
|
|
long *plHandshakeDelay)
|
|
{
|
|
int iRetVal = COM_OK;
|
|
|
|
return iRetVal;
|
|
}
|
|
|
|
|
|
#if !defined(MULTITHREAD)
|
|
// WINSOCK the way we know and love it from Win3.1 days
|
|
|
|
/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
* FUNCTION: WsckPortActivate
|
|
*
|
|
* DESCRIPTION:
|
|
* Called to activate the port and connect to destination
|
|
*
|
|
* ARGUMENTS:
|
|
* pstPrivate -- driver data structure
|
|
* pszPortName -- not used
|
|
* dwMediaHdl -- not used (stub used only by TAPI-aware drivers)
|
|
*
|
|
* RETURNS:
|
|
* COM_OK if port is successfully activated
|
|
* COM_NOT_ENOUGH_MEMORY if there in insufficient memory for data storage
|
|
* COM_NOT_FOUND if named port cannot be opened
|
|
* COM_DEVICE_ERROR if API errors are encountered
|
|
*
|
|
* AUTHOR:
|
|
* mcc 12/26/95
|
|
*/
|
|
int WINAPI WsckPortActivate(void *pvPrivate,
|
|
TCHAR *pszPortName,
|
|
DWORD_PTR dwMediaHdl)
|
|
{
|
|
ST_STDCOM *pstPrivate = (ST_STDCOM *) pvPrivate;
|
|
int iRetVal = COM_OK;
|
|
WNDCLASSEX wc;
|
|
ST_COM_CONTROL *pstComCntrl;
|
|
|
|
// Make sure we can get enough memory for buffers before opening device
|
|
pstPrivate->pbBufrStart = malloc((size_t)pstPrivate->nRBufrSize);
|
|
|
|
if (pstPrivate->pbBufrStart == NULL)
|
|
{
|
|
iRetVal = COM_NOT_ENOUGH_MEMORY;
|
|
//* DeviceReportError(pstPrivate, SID_ERR_NOMEM, 0, TRUE);
|
|
goto checkout;
|
|
}
|
|
|
|
pstPrivate->pbBufrEnd = pstPrivate->pbBufrStart + pstPrivate->nRBufrSize;
|
|
pstPrivate->pbReadEnd = pstPrivate->pbBufrStart;
|
|
pstPrivate->pbComStart = pstPrivate->pbComEnd = pstPrivate->pbBufrStart;
|
|
pstPrivate->fBufrEmpty = TRUE;
|
|
pstPrivate->nSendBufrLen = 0;
|
|
|
|
|
|
if (iRetVal == COM_OK)
|
|
{
|
|
pstComCntrl = (ST_COM_CONTROL *)pstPrivate->hCom;
|
|
pstComCntrl->puchRBData =
|
|
pstComCntrl->puchRBDataLimit =
|
|
pstPrivate->pbBufrStart;
|
|
|
|
pstPrivate->dwEventMask = EV_ERR | EV_RLSD;
|
|
pstPrivate->fNotifyRcv = TRUE;
|
|
pstPrivate->fBufrEmpty = TRUE;
|
|
}
|
|
|
|
memset(&wc, 0, sizeof(WNDCLASSEX));
|
|
wc.cbSize = sizeof(WNDCLASSEX);
|
|
|
|
if (GetClassInfoEx(hinstDLL, WINSOCK_EVENT_WINDOW_CLASS, &wc) == FALSE)
|
|
{
|
|
// Register event window class to handle Winsock asynchronous
|
|
// notifications
|
|
wc.style = CS_GLOBALCLASS;
|
|
wc.lpfnWndProc = WndSockWndProc;
|
|
wc.cbClsExtra = 0;
|
|
wc.cbWndExtra = sizeof(ST_STDCOM*);
|
|
wc.hInstance = hinstDLL;
|
|
wc.hIcon = NULL;
|
|
wc.hCursor = NULL;
|
|
wc.hbrBackground = NULL;
|
|
wc.lpszMenuName = NULL;
|
|
wc.lpszClassName = WINSOCK_EVENT_WINDOW_CLASS;
|
|
wc.hIconSm = NULL;
|
|
|
|
// Register the class, we don't check for failure because the driver
|
|
// can operate without it if it has to
|
|
RegisterClassEx(&wc);
|
|
}
|
|
|
|
WinSockCreateNVT(pstPrivate);
|
|
|
|
|
|
if (!WinSockCreateEventWindow(pstPrivate))
|
|
{
|
|
iRetVal = COM_DEVICE_ERROR;
|
|
goto checkout;
|
|
}
|
|
|
|
// Kick off Winsock processing
|
|
PostMessage(pstPrivate->hwndEvents, WM_WINSOCK_STARTUP,
|
|
0, 0L);
|
|
|
|
|
|
checkout:
|
|
if (iRetVal != COM_OK)
|
|
WsckPortDeactivate(pstPrivate);
|
|
|
|
return iRetVal;
|
|
} /*lint !e715 */
|
|
|
|
|
|
/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
* FUNCTION: WsckPortDeactivate
|
|
*
|
|
* DESCRIPTION:
|
|
* Deactivates and closes an open port
|
|
*
|
|
* ARGUMENTS:
|
|
* pstPrivate -- Driver data structure
|
|
*
|
|
* RETURNS:
|
|
* COM_OK
|
|
*
|
|
* AUTHOR:
|
|
* mcc 12/26/95
|
|
*/
|
|
int WINAPI WsckPortDeactivate(void *pvPrivate)
|
|
{
|
|
ST_STDCOM *pstPrivate = (ST_STDCOM *) pvPrivate;
|
|
int iRetVal = COM_OK;
|
|
|
|
|
|
// Shut down socket and WINSOCK
|
|
shutdown(pstPrivate->hSocket, 2);
|
|
closesocket(pstPrivate->hSocket);
|
|
WSACleanup();
|
|
pstPrivate->hSocket = INVALID_SOCKET;
|
|
|
|
// Destroy the WINSOCK event window
|
|
if (pstPrivate->hwndEvents)
|
|
{
|
|
DestroyWindow(pstPrivate->hwndEvents);
|
|
pstPrivate->hwndEvents = 0;
|
|
}
|
|
|
|
// Destroy the read buffer
|
|
if (pstPrivate->pbBufrStart)
|
|
{
|
|
free(pstPrivate->pbBufrStart);
|
|
pstPrivate->pbBufrStart = NULL;
|
|
}
|
|
|
|
return iRetVal;
|
|
}
|
|
|
|
/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
* FUNCTION: WsckRcvRefill
|
|
*
|
|
* DESCRIPTION:
|
|
* Called when the receive buffer is empty to refill it. This routine
|
|
* should attempt to refill the buffer and return the first character.
|
|
* It is important that this function be implemented efficiently.
|
|
*
|
|
* ARGUMENTS:
|
|
* pstPrivate -- the driver data structure
|
|
*
|
|
* RETURNS:
|
|
* TRUE if data is put in the receive buffer
|
|
* FALSE if there is no new incoming data
|
|
*
|
|
* AUTHOR:
|
|
* mcc 01/18/95 (from HAWIN)
|
|
*/
|
|
int WINAPI WsckRcvRefill(void *pvPrivate)
|
|
{
|
|
ST_STDCOM *pstPrivate = (ST_STDCOM *) pvPrivate;
|
|
int nIndx;
|
|
int iBytesRead = 0;
|
|
int nNVTRes;
|
|
int nBytesCopied;
|
|
ST_COM_CONTROL FAR *pstComCntrl;
|
|
int iReturn = TRUE;
|
|
|
|
if (pstPrivate->fConnected == COM_PORT_NOT_OPEN)
|
|
return FALSE;
|
|
|
|
//for (nIndx = 0; nIndx < (int)pstPrivate->usRBufrSize; nIndx += 1)
|
|
//pstPrivate->puchRBufr[nIndx] = 0;
|
|
|
|
// Read up to pstPrivate->usRBufrSize bytes into pstPrivate->puchRBufr
|
|
// and set iBytesRead to the number read.
|
|
iBytesRead = 0;
|
|
iBytesRead = recv(pstPrivate->hSocket,
|
|
(LPSTR)pstPrivate->pbBufrStart,
|
|
(int)pstPrivate->nRBufrSize,
|
|
0);
|
|
if (iBytesRead == SOCKET_ERROR)
|
|
{
|
|
int iErr;
|
|
|
|
iBytesRead = 0;
|
|
iErr = WSAGetLastError();
|
|
if (iErr != WSAEWOULDBLOCK)
|
|
DbgOutStr("Refill: error %d reading %d bytes on socket %d\n", iErr,
|
|
pstPrivate->nRBufrSize,
|
|
pstPrivate->hSocket,0,0);
|
|
}
|
|
|
|
if (iBytesRead == 0)
|
|
{
|
|
ComNotify(pstPrivate->hCom, NODATA);
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
// update the com handle with info on new data. This is implemented
|
|
// this way to allow HA to access these characters quickly
|
|
nBytesCopied = 0;
|
|
for (nIndx = 0; nIndx < iBytesRead; nIndx++)
|
|
{
|
|
|
|
if (pstPrivate->pbBufrStart == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// If we have an FF or we are in the middle of a Telnet
|
|
// command, run this character thru the NVT. Unless the
|
|
// says to discard the character, we then copy it to the
|
|
// output position.
|
|
if (pstPrivate->pbBufrStart[nIndx] == 0xFF ||
|
|
pstPrivate->NVTstate != NVT_THRU)
|
|
{
|
|
nNVTRes = WinSockNetworkVirtualTerminal(
|
|
(ECHAR) pstPrivate->pbBufrStart[nIndx],
|
|
(void far *) pstPrivate);
|
|
//DbgOutStr("NVT returns %d\n", nNVTRes, 0,0,0,0);
|
|
}
|
|
else
|
|
nNVTRes = NVT_KEEP;
|
|
|
|
if (nNVTRes != NVT_DISCARD)
|
|
{
|
|
pstPrivate->pbBufrStart[nBytesCopied] = pstPrivate->pbBufrStart[nIndx];
|
|
nBytesCopied++;
|
|
}
|
|
}
|
|
|
|
// if we got no data (perhaps because data were "eaten" by NVT),
|
|
// make sure we return -1
|
|
if (nBytesCopied == 0)
|
|
{
|
|
*(pstPrivate->pbBufrStart) = (char) -1;
|
|
iReturn = FALSE;
|
|
}
|
|
|
|
pstComCntrl = (ST_COM_CONTROL *)pstPrivate->hCom;
|
|
pstComCntrl->puchRBData = pstPrivate->pbBufrStart;
|
|
pstComCntrl->puchRBDataLimit = pstPrivate->pbBufrStart + nBytesCopied;
|
|
|
|
return iReturn;
|
|
}
|
|
|
|
/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
* FUNCTION: WsckRcvClear
|
|
*
|
|
* DESCRIPTION:
|
|
* Clears the receiver of all received data.
|
|
*
|
|
* ARGUMENTS:
|
|
* hCom -- a comm handle returned by an earlier call to ComCreateHandle
|
|
*
|
|
* RETURNS:
|
|
* COM_OK if data is cleared
|
|
* COM_DEVICE_ERROR if Windows com device driver returns an error
|
|
*
|
|
* AUTHOR:
|
|
* mcc 01/18/96 (taken almost entirely from HAWIN)
|
|
*/
|
|
int WINAPI WsckRcvClear(void *pvPrivate)
|
|
{
|
|
CHAR ch[128];
|
|
ST_STDCOM *pstPrivate = (ST_STDCOM *) pvPrivate;
|
|
ST_COM_CONTROL *pstComCntrl = (ST_COM_CONTROL *)pstPrivate->hCom;
|
|
|
|
if (pstPrivate->fConnected == COM_PORT_NOT_OPEN)
|
|
return COM_DEVICE_ERROR;
|
|
|
|
pstComCntrl->puchRBData = pstComCntrl->puchRBDataLimit =
|
|
pstPrivate->pbBufrStart;
|
|
|
|
// Do whatever is necessary to remove any buffered data from the com port
|
|
|
|
while (recv(pstPrivate->hSocket, ch, 128, 0) != SOCKET_ERROR)
|
|
{
|
|
}
|
|
|
|
return COM_OK;
|
|
}
|
|
|
|
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
* FUNCTION: WsckSndBufrSend
|
|
*
|
|
* DESCRIPTION:
|
|
* Transmits a buffer of characters. This routine need only queue up a
|
|
* buffer to be transmitted. If the com device supports interrupt-driven
|
|
* or hardware-controlled transmission, this function should start the
|
|
* process but should not wait until all the data has actually been sent.
|
|
*
|
|
* ARGUMENTS:
|
|
* pstPrivate -- Pointer to driver data structure
|
|
* pvBufr -- Pointer to data to send
|
|
* nSize -- Number of bytes to send
|
|
*
|
|
* RETURNS:
|
|
* COM_OK
|
|
* or appropriate error code
|
|
*
|
|
* AUTHOR:
|
|
* mcc 01/19/96
|
|
*/
|
|
int WINAPI WsckSndBufrSend(void *pvPrivate, void *pvBufr, int nBytesToSend)
|
|
{
|
|
ST_STDCOM *pstPrivate = (ST_STDCOM *) pvPrivate;
|
|
int nCount;
|
|
int nError;
|
|
int nSize; // num bytes to send during this pass
|
|
int usReturnValue = COM_OK;
|
|
unsigned char *pszPtr = (unsigned char *)pvBufr;
|
|
unsigned char *pcThisPassData;
|
|
int fGotFF = FALSE; // TRUE if last char detected was an FF
|
|
int nOffset;
|
|
LPSTR puchRemains;
|
|
int fQueueing = FALSE;
|
|
|
|
assert(pvBufr != (VOID FAR *)0);
|
|
assert(nBytesToSend <= WSOCK_SIZE_OUTQ);
|
|
|
|
if (pstPrivate->fSending)
|
|
{
|
|
DbgOutStr("SBS: Busy = %d\n", pstPrivate->fSending, 0,0,0,0);
|
|
return COM_BUSY;
|
|
}
|
|
|
|
assert(pstPrivate->nSendBufrLen == 0);
|
|
|
|
if (pstPrivate->fConnected == COM_PORT_NOT_OPEN)
|
|
return COM_DEVICE_ERROR;
|
|
|
|
|
|
// If we are escaping FF characters by sending them as FFFF,
|
|
// things are a bit tricky because we have no extra room in the buffer
|
|
// for the doubled characters. The idea here is to send the buffer
|
|
// in several passes; if an FF character is found, it is sent once
|
|
// at the end of one pass and again at the beginning of the next
|
|
// At the end of each pass, we decrement nBytesToSend by the
|
|
// number of bytes sent during the pass (nSize), and keep looping
|
|
// until all the data are sent
|
|
nOffset = 0;
|
|
ComNotify(pstPrivate->hCom, SEND_STARTED);
|
|
while (nBytesToSend > 0 && usReturnValue == COM_OK)
|
|
{
|
|
if (pstPrivate->fEscapeFF)
|
|
{
|
|
pcThisPassData = &pszPtr[nOffset];
|
|
|
|
// If we are processing an FF that was found on the
|
|
// last pass, send it out again by itself. Otherwise,
|
|
// search for the next FF and send everything up to and
|
|
// including it.
|
|
if (fGotFF)
|
|
{
|
|
//DbgOutStr("SndBufrSend: 2nd FF\n", 0,0,0,0,0);
|
|
nSize = 1;
|
|
nOffset++;
|
|
fGotFF = FALSE;
|
|
}
|
|
else
|
|
{
|
|
nSize = 0;
|
|
while (pszPtr[nOffset] != 0xFF && nOffset < nBytesToSend)
|
|
{
|
|
nSize++, nOffset++;
|
|
}
|
|
|
|
// If no FF's were found, send everything
|
|
if (nOffset >= nBytesToSend)
|
|
{
|
|
nBytesToSend = 0;
|
|
fGotFF = 0;
|
|
}
|
|
// otherwise, send data up to and including FF
|
|
else
|
|
{
|
|
nSize++; // include the FF!
|
|
fGotFF = TRUE; // Send the 2nd FF on next pass
|
|
//DbgOutStr("SndBufrSend: 1st FF ...", 0,0,0,0,0);
|
|
}
|
|
}
|
|
}
|
|
else // send everything in one pass
|
|
{
|
|
nSize = nBytesToSend;
|
|
nBytesToSend = 0;
|
|
pcThisPassData = pvBufr;
|
|
}
|
|
// If we already have data queued, don't try to send directly, since
|
|
// it might get out before the queued data do.
|
|
if (fQueueing)
|
|
{
|
|
DbgOutStr("SBS queueing output. Queueing %d bytes\n",
|
|
nSize,0,0,0,0);
|
|
if (sndQueueAppend(pstPrivate,pcThisPassData,nSize) != COM_OK)
|
|
usReturnValue = COM_DEVICE_ERROR;
|
|
}
|
|
else
|
|
{
|
|
// Pass data to TCP/IP
|
|
nCount = 0;
|
|
nCount = send(pstPrivate->hSocket,
|
|
pcThisPassData, (int)nSize, 0);
|
|
|
|
// If we got a "would block" error, copy the data to send
|
|
// to pstPrivate->auchSndBufr. (Since the FF processing may
|
|
// cause this block of code to be executed multiple times in
|
|
// one SndBufrSend call, we will append new data to existing
|
|
// data in the buffer).
|
|
if (nCount == SOCKET_ERROR)
|
|
{
|
|
nError = WSAGetLastError();
|
|
|
|
if (nError == WSAEWOULDBLOCK)
|
|
{
|
|
// Winsock won't accept data, so queue it up for
|
|
// WinSockWriteEvent to handle. Also, lock the handle
|
|
// until we are done so that WinSockWriteEvent can't get in
|
|
// there.
|
|
fQueueing = TRUE;
|
|
|
|
DbgOutStr("SBS would block. Queueing %d bytes\n",
|
|
nSize,0,0,0,0);
|
|
EnterCriticalSection(&pstPrivate->csect);
|
|
|
|
if (sndQueueAppend(pstPrivate,pcThisPassData,nSize) != COM_OK)
|
|
{
|
|
usReturnValue = COM_DEVICE_ERROR;
|
|
}
|
|
LeaveCriticalSection(&pstPrivate->csect);
|
|
}
|
|
else
|
|
{
|
|
DbgOutStr("WinSock send error %d\r\n", nError, 0,0,0,0);
|
|
//DeviceReportError(pstPrivate, (UINT)nError, 0, FALSE);
|
|
usReturnValue = COM_DEVICE_ERROR;
|
|
DbgOutStr("SBS: Bad error\n", 0,0,0,0,0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ComNotify(pstPrivate->hCom, SEND_DONE);
|
|
if (nCount < (int)nSize)
|
|
{
|
|
/*
|
|
* Set stuff up for next time through
|
|
*/
|
|
DbgOutStr("SBS send incomplete.. Queueing %d bytes\n",
|
|
(int)nSize-nCount,0,0,0,0);
|
|
|
|
// Get pointer to remaining data and queue it up
|
|
puchRemains = pcThisPassData + nCount;
|
|
if (sndQueueAppend(pstPrivate, puchRemains,
|
|
(nSize - nCount)) != COM_OK)
|
|
{
|
|
usReturnValue = COM_DEVICE_ERROR;
|
|
DbgOutStr("SBS: Bad error\n", 0,0,0,0,0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return usReturnValue;
|
|
}
|
|
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
* FUNCTION: sndQueueAppend
|
|
*
|
|
* DESCRIPTION:
|
|
* Appends new data to any data that have been queued up for
|
|
* re-transmission by WinSockWriteEvent
|
|
*
|
|
* ARGUMENTS:
|
|
* pstPrivate -- address of com driver's data structure
|
|
* pvBufr -- address of new data block to queue up
|
|
* nBytesToAppend -- size of new data block to append
|
|
*
|
|
* RETURNS:
|
|
* COM_OK if data can be transmitted
|
|
* COM_BUSY if no more room for data to queue up
|
|
*
|
|
* AUTHOR:
|
|
* mcc 01/19/96 (from HAWIN)
|
|
*/
|
|
|
|
int FAR PASCAL sndQueueAppend(ST_STDCOM* pstPrivate,
|
|
VOID FAR *pvBufr, int nBytesToAppend)
|
|
|
|
{
|
|
LPSTR puchEnd;
|
|
USHORT usReturns = COM_OK;
|
|
|
|
assert( pstPrivate != NULL );
|
|
assert( pvBufr != NULL );
|
|
|
|
//jkh 9/11/98 to avoid memcpy with invalid params
|
|
if ( pstPrivate && pvBufr && nBytesToAppend > 0 )
|
|
{
|
|
if (pstPrivate->nSendBufrLen + nBytesToAppend >
|
|
(int) sizeof(pstPrivate->abSndBufr))
|
|
{
|
|
DbgOutStr("SQAPP: buffer full", 0,0,0,0,0);
|
|
return COM_BUSY;
|
|
}
|
|
|
|
// Set the flag that SndBufrIsBusy looks at; we are
|
|
// in the middle of a send until the buffer is cleared
|
|
// by WinSockWriteEvent
|
|
pstPrivate->fSending = TRUE;
|
|
|
|
pstPrivate->pbSendBufr = pstPrivate->abSndBufr;
|
|
puchEnd = pstPrivate->pbSendBufr + pstPrivate->nSendBufrLen;
|
|
|
|
DbgOutStr("sQA: appending %d bytes to addr = %lx. Existing buffer is %d bytes at %lx\n",
|
|
nBytesToAppend, puchEnd, pstPrivate->nSendBufrLen, pstPrivate->pbSendBufr,0);
|
|
pstPrivate->nSendBufrLen += nBytesToAppend;
|
|
MemCopy(puchEnd, (LPSTR) pvBufr, (unsigned) nBytesToAppend);
|
|
}
|
|
|
|
DbgOutStr("sQA: copy done\n", 0,0,0,0,0);
|
|
return usReturns;
|
|
}
|
|
|
|
|
|
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
* FUNCTION: WsckSndBufrClear
|
|
*
|
|
* DESCRIPTION:
|
|
* Clear any data waiting to be transmitted
|
|
*
|
|
* ARGUMENTS:
|
|
* pstPrivate -- pointer to driver data structure
|
|
*
|
|
* RETURNS:
|
|
* COM_OK
|
|
* or appropriate error code
|
|
*
|
|
* AUTHOR
|
|
* mcc 01/19/96 (from HAWIN)
|
|
*/
|
|
int WINAPI WsckSndBufrClear(ST_STDCOM *pstPrivate)
|
|
{
|
|
USHORT usReturnValue = COM_OK;
|
|
|
|
DbgOutStr("SndBufrClear called", 0,0,0,0,0);
|
|
|
|
if (WsckSndBufrIsBusy(pstPrivate))
|
|
{
|
|
pstPrivate->nSendBufrLen = 0;
|
|
pstPrivate->pbSendBufr = 0;
|
|
}
|
|
|
|
// Call SndBufrIsBusy again to clear flags, timers, etc.
|
|
WsckSndBufrIsBusy(pstPrivate);
|
|
return usReturnValue;
|
|
}
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
* FUNCTION: WndSockWndProc
|
|
*
|
|
* DESCRIPTION:
|
|
* This is the window procedure for the window that is used to receive event
|
|
* messages from the WinSock interface. It uses this to get around the pesky
|
|
* problem of blocking vs. non-blocking requirements and expectations.
|
|
*
|
|
* ARGUEMENTS:
|
|
* The usual stuff for a window procedure.
|
|
*
|
|
* RETURNS:
|
|
* The usual stuff for a window procedure.
|
|
*
|
|
* AUTHOR
|
|
* mcc 01/19/96 (from HAWIN)
|
|
*/
|
|
LRESULT FAR PASCAL WndSockWndProc(HWND hWnd, UINT uiMsg, WPARAM uiPar1, LPARAM lPar2)
|
|
{
|
|
ST_STDCOM*pstPrivate;
|
|
WORD wVersion;
|
|
WSADATA stWsaData;
|
|
|
|
switch (uiMsg)
|
|
{
|
|
case WM_WINSOCK_STARTUP:
|
|
pstPrivate = (ST_STDCOM*)GetWindowLongPtr(hWnd, 0);
|
|
if (pstPrivate == (ST_STDCOM*)0)
|
|
break;
|
|
|
|
DbgOutStr("Calling WSAStartup\n", 0,0,0,0,0);
|
|
/*
|
|
* Initialize the Windows Socket DLL
|
|
*/
|
|
wVersion = 0x0101; // The version of WinSock that we want
|
|
if (WSAStartup(wVersion, &stWsaData) != 0)
|
|
{
|
|
/* No DLL was available */
|
|
return COM_DEVICE_ERROR;
|
|
}
|
|
DbgOutStr("Done calling WSAStartup\n", 0,0,0,0,0);
|
|
// pstPrivate->fActive = TRUE;
|
|
|
|
/* Confirm that the Windows Socket DLL supports 1.1. */
|
|
/* Note that if the DLL supports versions greater */
|
|
/* than 1.1 in addition to 1.1, it will still return */
|
|
/* 1.1 in wVersion since that is the version we */
|
|
/* requested */
|
|
if ((LOBYTE(stWsaData.wVersion) != 1) &&
|
|
(HIBYTE(stWsaData.wVersion) != 1))
|
|
{
|
|
/* No acceptable DLL was available */
|
|
return COM_DEVICE_ERROR;
|
|
}
|
|
|
|
/*
|
|
* Create a socket for later use.
|
|
*/
|
|
DbgOutStr("Calling socket\n", 0,0,0,0,0);
|
|
|
|
pstPrivate->hSocket = socket(PF_INET, SOCK_STREAM, 0);
|
|
if (pstPrivate->hSocket == INVALID_SOCKET)
|
|
{
|
|
return COM_DEVICE_ERROR;
|
|
}
|
|
DbgOutStr("Done calling socket\n", 0,0,0,0,0);
|
|
|
|
#ifdef INCL_CALL_ANSWERING
|
|
if (pstPrivate->fAnswer)
|
|
{
|
|
WinSockAnswerSpecial(pstPrivate);
|
|
}
|
|
else
|
|
{
|
|
WinSockConnectSpecial(pstPrivate);
|
|
}
|
|
#else
|
|
WinSockConnectSpecial(pstPrivate);
|
|
#endif
|
|
break;
|
|
|
|
case WM_WINSOCK_NOTIFY:
|
|
{
|
|
pstPrivate = (ST_STDCOM*)GetWindowLongPtr(hWnd, 0);
|
|
if (pstPrivate == (ST_STDCOM*)0)
|
|
break;
|
|
|
|
switch(LOWORD(lPar2))
|
|
{
|
|
case FD_READ:
|
|
return WinSockReadEvent(pstPrivate, lPar2);
|
|
|
|
case FD_WRITE:
|
|
return WinSockWriteEvent(pstPrivate, lPar2);
|
|
|
|
case FD_CLOSE:
|
|
//DbgOutStr("FD_CLOSE\r\n", 0,0,0,0,0);
|
|
return WinSockCloseEvent(pstPrivate, lPar2);
|
|
|
|
case FD_CONNECT:
|
|
//DbgOutStr("FD_CONNECT\r\n", 0,0,0,0,0);
|
|
return WinSockConnectEvent(pstPrivate, lPar2);
|
|
|
|
case FD_ACCEPT:
|
|
//DbgOutStr("FD_ACCEPT\r\n", 0,0,0,0,0);
|
|
return WinSockAcceptEvent(pstPrivate, lPar2);
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case WM_WINSOCK_RESOLVE:
|
|
{
|
|
/* We get here after a call to WSAAsyncGetHostByName */
|
|
pstPrivate = (ST_STDCOM*)GetWindowLongPtr(hWnd, 0);
|
|
if (pstPrivate == (ST_STDCOM*)0)
|
|
break;
|
|
|
|
return WinSockResolveEvent(pstPrivate, lPar2);
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return DefWindowProc(hWnd, uiMsg, uiPar1, lPar2);
|
|
}
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
* FUNCTION: WndSockCreateEventWindow
|
|
*
|
|
* DESCRIPTION:
|
|
* Creates the event window used to process messages sent by the WinSock DLL.
|
|
*
|
|
* ARGUMENTS:
|
|
* pstPrivate pointer to private data structure; attach to window
|
|
*
|
|
* RETURNS:
|
|
* TRUE if everything is OK, otherwise FALSE.
|
|
*
|
|
* AUTHOR
|
|
* mcc 01/19/96 (from HAWIN)
|
|
*/
|
|
BOOL WinSockCreateEventWindow (ST_STDCOM *pstPrivate)
|
|
{
|
|
BOOL fRetVal = TRUE;
|
|
|
|
if (fRetVal)
|
|
{
|
|
pstPrivate->hwndEvents = CreateWindow(
|
|
WINSOCK_EVENT_WINDOW_CLASS,
|
|
TEXT(""),
|
|
WS_OVERLAPPEDWINDOW,
|
|
0, 0, 0, 0,
|
|
HWND_DESKTOP,
|
|
NULL,
|
|
hinstDLL,
|
|
NULL);
|
|
fRetVal = (pstPrivate->hwndEvents != (HWND)0);
|
|
}
|
|
|
|
if (fRetVal)
|
|
{
|
|
SetWindowLongPtr(pstPrivate->hwndEvents, 0, (LONG_PTR)pstPrivate);
|
|
}
|
|
|
|
return fRetVal;
|
|
}
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
|
* FUNCTION:
|
|
* WinSockSendBreak
|
|
*
|
|
* DESCRIPTION:
|
|
* This function attempts to send a break condition to the NVT on the other
|
|
* end of the connection. See RFC854 for details and good luck.
|
|
*
|
|
* PARAMETERS:
|
|
* pstPrivate Driver's private data structure
|
|
*
|
|
* RETURNS:
|
|
*
|
|
* AUTHOR
|
|
* mcc 01/19/96 (from HAWIN)
|
|
*/
|
|
VOID WinSockSendBreak(ST_STDCOM*pstPrivate)
|
|
{
|
|
UCHAR acSendBreak[2];
|
|
|
|
//DbgOutStr("WinSockSendBreak\r\n", 0,0,0,0,0);
|
|
|
|
acSendBreak[0] = 255;
|
|
acSendBreak[1] = 243;
|
|
send(pstPrivate->hSocket, acSendBreak, 2, 0);
|
|
}
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
* FUNCTION:
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
* RETURNS:
|
|
*/
|
|
USHORT WinSockSendBreakSpecial(ST_STDCOM *pstPrivate,
|
|
LPSTR pszData,
|
|
UINT uiSize)
|
|
{
|
|
if (pstPrivate->nSendBufrLen > 0)
|
|
{
|
|
/* Can't do it now, wait until next time */
|
|
pstPrivate->fSndBreak = TRUE;
|
|
}
|
|
else
|
|
{
|
|
WinSockSendBreak(pstPrivate);
|
|
}
|
|
|
|
return 0;
|
|
} /*lint !e715 */
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
* FUNCTION:
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
* RETURNS:
|
|
*
|
|
* AUTHOR
|
|
* mcc 01/19/96 (from HAWIN)
|
|
*/
|
|
int WinSockConnectSpecial(ST_STDCOM*pstPrivate)
|
|
{
|
|
USHORT usRetVal;
|
|
int nIndx;
|
|
int nError;
|
|
unsigned long ulAddr;
|
|
struct sockaddr_in srv_addr;
|
|
struct sockaddr_in cli_addr;
|
|
HANDLE hReturn;
|
|
|
|
usRetVal = COM_OK;
|
|
|
|
cli_addr.sin_family = AF_INET;
|
|
cli_addr.sin_addr.s_addr = INADDR_ANY;
|
|
cli_addr.sin_port = 0;
|
|
|
|
// Bind the socket to any internet address. Ignore errors;
|
|
// real ones will be detected later, and this WILL fail
|
|
// if the socket is already bound.
|
|
usRetVal = (USHORT)bind(pstPrivate->hSocket, (LPSOCKADDR)&cli_addr,
|
|
sizeof(cli_addr));
|
|
DbgOutStr("Socket %d bind returns %d\n", pstPrivate->hSocket, usRetVal, 0,0,0);
|
|
|
|
// See if the remote address has been entered in numeric form. If not,
|
|
// we will have to call WSAAsynchGetHostByName to translate it; in that
|
|
// case, the EventWindow handler will call connect.
|
|
ulAddr = inet_addr(pstPrivate->szRemoteAddr);
|
|
if ((ulAddr == INADDR_NONE) || (ulAddr == 0))
|
|
{
|
|
DbgOutStr("WSCnctSp: calling WSA...HostByName\n", 0,0,0,0,0);
|
|
/* We take the long way around */
|
|
hReturn = WSAAsyncGetHostByName(
|
|
pstPrivate->hwndEvents,
|
|
WM_WINSOCK_RESOLVE,
|
|
pstPrivate->szRemoteAddr,
|
|
(char *) &pstPrivate->stHostBuf,
|
|
MAXGETHOSTSTRUCT);
|
|
|
|
if (hReturn == 0)
|
|
nError = WSAGetLastError();
|
|
else
|
|
nError = 0 ;
|
|
DbgOutStr("WSAAsynchGetHostByName returns %lx (err = %d)\n", hReturn,
|
|
nError,0,0,0);
|
|
goto WSCSexit;
|
|
}
|
|
|
|
/*
|
|
* This is the alternate pathway for the connect. We go thru here if
|
|
* the address was in the form of a 123.456.789.123 address.
|
|
*/
|
|
srv_addr.sin_family = AF_INET;
|
|
srv_addr.sin_addr.s_addr = ulAddr;
|
|
srv_addr.sin_port = htons((USHORT)pstPrivate->nPort);
|
|
|
|
nIndx = WSAAsyncSelect(pstPrivate->hSocket,
|
|
pstPrivate->hwndEvents,
|
|
WM_WINSOCK_NOTIFY,
|
|
FD_CONNECT | FD_READ | FD_WRITE | FD_CLOSE
|
|
);
|
|
|
|
if (nIndx != 0)
|
|
{
|
|
/* Oops, something goofed */
|
|
usRetVal = COM_DEVICE_ERROR;
|
|
DbgOutStr("WSAAsyncSelect failed\n", 0,0,0,0,0);
|
|
goto WSCSexit;
|
|
}
|
|
|
|
if (connect(pstPrivate->hSocket,
|
|
(LPSOCKADDR)&srv_addr,
|
|
sizeof(srv_addr)) == SOCKET_ERROR)
|
|
{
|
|
nIndx = WSAGetLastError();
|
|
if (nIndx != WSAEWOULDBLOCK)
|
|
{
|
|
usRetVal = COM_DEVICE_ERROR;
|
|
//DeviceReportError(pstPrivate, (UINT)nIndx, 0, FALSE);
|
|
DbgOutStr("Connect failed (err = %d)\n", nIndx, 0,0,0,0);
|
|
goto WSCSexit;
|
|
}
|
|
}
|
|
|
|
WSCSexit:
|
|
//DbgOutStr(" returns %d\r\n", usRetVal, 0,0,0,0);
|
|
if (usRetVal != COM_OK)
|
|
{
|
|
closesocket(pstPrivate->hSocket);
|
|
}
|
|
|
|
return usRetVal;
|
|
}
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
* FUNCTION:
|
|
* WinSockAnswerSpecial
|
|
*
|
|
* DESCRIPTION:
|
|
* Sets up WinSock to answer a call.
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
* RETURNS:
|
|
*
|
|
* AUTHOR: C. Baumgartner, 11/19/96 (ported from HAWin16)
|
|
*/
|
|
int WinSockAnswerSpecial(ST_STDCOM*pstPrivate)
|
|
{
|
|
int nError = 0;
|
|
USHORT usRetVal = COM_OK;
|
|
struct sockaddr_in host_addr;
|
|
|
|
// Create our local internet address.
|
|
//
|
|
host_addr.sin_family = AF_INET;
|
|
host_addr.sin_addr.s_addr = INADDR_ANY;
|
|
host_addr.sin_port = htons((USHORT)pstPrivate->nPort);
|
|
|
|
// Bind the socket to our local address.
|
|
//
|
|
nError = bind(pstPrivate->hSocket, (LPSOCKADDR)&host_addr,
|
|
sizeof(host_addr));
|
|
DbgOutStr("Socket %d bind returns %d\n", pstPrivate->hSocket, nError, 0,0,0);
|
|
|
|
if (nError != 0)
|
|
{
|
|
usRetVal = COM_DEVICE_ERROR;
|
|
goto WSASexit;
|
|
}
|
|
|
|
// Tell the socket to notify us of events that we are interested
|
|
// in (like when somebody connects to us).
|
|
//
|
|
nError = WSAAsyncSelect(pstPrivate->hSocket, pstPrivate->hwndEvents,
|
|
WM_WINSOCK_NOTIFY, FD_ACCEPT | FD_READ | FD_WRITE | FD_CLOSE);
|
|
|
|
if (nError != 0)
|
|
{
|
|
usRetVal = COM_DEVICE_ERROR;
|
|
goto WSASexit;
|
|
}
|
|
|
|
// Tell the socket to wait for incoming calls.
|
|
//
|
|
if (listen(pstPrivate->hSocket, 1) != 0)
|
|
{
|
|
usRetVal = COM_DEVICE_ERROR;
|
|
goto WSASexit;
|
|
}
|
|
|
|
WSASexit:
|
|
if (usRetVal != COM_OK)
|
|
{
|
|
closesocket(pstPrivate->hSocket);
|
|
}
|
|
|
|
return usRetVal;
|
|
}
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
* FUNCTION:
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
* RETURNS:
|
|
*
|
|
* AUTHOR
|
|
* mcc 01/19/96 (from HAWIN)
|
|
USHORT WinSockDisconnectSpecial(ST_STDCOM*pstPrivate,
|
|
LPSTR pszData,
|
|
UINT uiSize)
|
|
{
|
|
|
|
if (pstPrivate->hSocket != INVALID_SOCKET)
|
|
{
|
|
closesocket(pstPrivate->hSocket);
|
|
pstPrivate->hSocket = INVALID_SOCKET;
|
|
}
|
|
|
|
pstPrivate->fConnected = COM_PORT_NOT_OPEN;
|
|
|
|
return COM_OK;
|
|
} /*lint !e715 */
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
* FUNCTION:
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
* RETURNS:
|
|
*
|
|
* AUTHOR
|
|
* mcc 01/19/96 (from HAWIN)
|
|
*/
|
|
LONG WinSockCloseEvent(ST_STDCOM*pstPrivate, LPARAM lPar)
|
|
{
|
|
pstPrivate->fConnected = COM_PORT_NOT_OPEN;
|
|
ComNotify(pstPrivate->hCom, CONNECT);
|
|
|
|
return 0;
|
|
} /*lint !e715 */
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
* FUNCTION:
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* PARAMETERS:
|
|
* pstPrivate Driver's private data structure
|
|
* lPar status code from Winsock
|
|
*
|
|
* RETURNS:
|
|
*/
|
|
LONG WinSockConnectEvent(ST_STDCOM*pstPrivate, LPARAM lPar)
|
|
{
|
|
int status;
|
|
status = (int)HIWORD(lPar);
|
|
if (status)
|
|
{
|
|
pstPrivate->fConnected = COM_PORT_NOT_OPEN;
|
|
ComNotify(pstPrivate->hCom, CONNECT);
|
|
}
|
|
else
|
|
{
|
|
pstPrivate->fConnected = COM_PORT_OPEN;
|
|
ComNotify(pstPrivate->hCom, CONNECT);
|
|
}
|
|
return 0;
|
|
} /*lint !e715 */
|
|
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
* FUNCTION:
|
|
* WinSockAcceptEvent
|
|
*
|
|
* DESCRIPTION:
|
|
* Accepts an incoming call.
|
|
*
|
|
* PARAMETERS:
|
|
* pstPrivate Driver's private data structure
|
|
* lPar status code from Winsock
|
|
*
|
|
* RETURNS:
|
|
*
|
|
* AUTHOR: C. Baumgartner, 11/19/96 (ported from HAWin16)
|
|
*/
|
|
LONG WinSockAcceptEvent(ST_STDCOM*pstPrivate, LPARAM lPar)
|
|
{
|
|
int status = HIWORD(lPar);
|
|
SOCKET hAnswer = INVALID_SOCKET;
|
|
SOCKET hOldSocket = INVALID_SOCKET;
|
|
|
|
// We aren't connected yet.
|
|
//
|
|
pstPrivate->fConnected = COM_PORT_NOT_OPEN;
|
|
|
|
// Attempt to accept the call.
|
|
//
|
|
hAnswer = accept(pstPrivate->hSocket, NULL, 0);
|
|
|
|
if (hAnswer != INVALID_SOCKET)
|
|
{
|
|
// Now we are connected.
|
|
//
|
|
pstPrivate->fConnected = COM_PORT_OPEN;
|
|
|
|
// Get the newly accepted socket.
|
|
//
|
|
hOldSocket = pstPrivate->hSocket;
|
|
pstPrivate->hSocket = hAnswer;
|
|
|
|
// Now close the old socket because we don't want to
|
|
// be listening when we are connected.
|
|
//
|
|
closesocket(hOldSocket);
|
|
}
|
|
|
|
// Let the rest of the world know that we are connected.
|
|
//
|
|
ComNotify(pstPrivate->hCom, CONNECT);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
* FUNCTION:
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* PARAMETERS:
|
|
* pstPrivate Driver's private data structure
|
|
* lPar status code from Winsock
|
|
*
|
|
* RETURNS:
|
|
*
|
|
* AUTHOR
|
|
* mcc 01/19/96 (from HAWIN)
|
|
*/
|
|
LONG WinSockReadEvent(ST_STDCOM*pstPrivate, LPARAM lPar)
|
|
{
|
|
|
|
ComNotify(pstPrivate->hCom, DATA_RECEIVED);
|
|
return 0;
|
|
} /*lint !e715 */
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
* FUNCTION:
|
|
* WinSockWriteEvent
|
|
*
|
|
* DESCRIPTION:
|
|
* Called back by Winsock when write completes; updates data structures
|
|
* to allow another write to take place
|
|
*
|
|
* PARAMETERS:
|
|
* pstPrivate Driver's private data structure
|
|
* lPar status code from Winsock
|
|
*
|
|
* RETURNS:
|
|
*
|
|
* AUTHOR
|
|
* mcc 01/19/96 (from HAWIN)
|
|
*/
|
|
LONG WinSockWriteEvent(ST_STDCOM *pstPrivate, LPARAM lPar)
|
|
{
|
|
int nCount;
|
|
int nError;
|
|
|
|
|
|
DbgOutStr("WinSockWriteEvent called to handle %d bytes ...",
|
|
pstPrivate->nSendBufrLen,0,0,0,0);
|
|
|
|
if (pstPrivate->fConnected == COM_PORT_NOT_OPEN)
|
|
return 0;
|
|
|
|
if (pstPrivate->fSndBreak)
|
|
{
|
|
WinSockSendBreak(pstPrivate);
|
|
pstPrivate->fSndBreak = FALSE;
|
|
}
|
|
|
|
if (pstPrivate->nSendBufrLen)
|
|
{
|
|
// This is done to keep the "main thread" from updating the buffer
|
|
// while we send it. OK, I think, since send won't block.
|
|
EnterCriticalSection(&pstPrivate->csect);
|
|
|
|
nCount = send(pstPrivate->hSocket,
|
|
pstPrivate->pbSendBufr,
|
|
(int)pstPrivate->nSendBufrLen,
|
|
0);
|
|
LeaveCriticalSection(&pstPrivate->csect);
|
|
|
|
|
|
// DbgOutStr("WinSock send returned %d\r\n", nCount, 0,0,0,0);
|
|
|
|
// assert((int)pstPrivate->SendBufrLen == nCount);
|
|
|
|
if (nCount == SOCKET_ERROR)
|
|
{
|
|
nError = WSAGetLastError();
|
|
|
|
if (nError == WSAEWOULDBLOCK)
|
|
{
|
|
DbgOutStr(" still blocked\n", 0,0,0,0,0);
|
|
/*
|
|
* Nothing to do in this case
|
|
*/
|
|
}
|
|
else
|
|
{
|
|
// Got some weird error. Notify interested parties
|
|
// that our connection is suspect
|
|
DbgOutStr(" got error %d\r\n", nError, 0,0,0,0);
|
|
pstPrivate->nSendBufrLen = 0;
|
|
pstPrivate->pbSendBufr = 0;
|
|
ComNotify(pstPrivate->hCom, CONNECT);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DbgOutStr("%d bytes sent.\n", nCount, 0,0,0,0);
|
|
|
|
if (nCount < (int)pstPrivate->nSendBufrLen)
|
|
{
|
|
pstPrivate->nSendBufrLen -= (USHORT)nCount;
|
|
pstPrivate->pbSendBufr += nCount;
|
|
}
|
|
else
|
|
{
|
|
pstPrivate->nSendBufrLen = 0;
|
|
pstPrivate->pbSendBufr = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pstPrivate->nSendBufrLen == 0)
|
|
{
|
|
pstPrivate->fSending = FALSE;
|
|
|
|
|
|
//DbgOutStr("Sending WM_COM_SEND_DONE in WinSockWriteEvent\n",0,0,0,0,0);
|
|
ComNotify(pstPrivate->hCom, SEND_DONE);
|
|
}
|
|
|
|
return 0;
|
|
} /*lint !e715 */
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
* FUNCTION:
|
|
* WinSockResolveEvent
|
|
*
|
|
* DESCRIPTION:
|
|
* Called once WSAAsynchGetHostByName has done its dirty work to actually
|
|
* generate a connect call
|
|
*
|
|
* PARAMETERS:
|
|
* pstPrivate Driver's private data structure
|
|
* lPar returned from previous Winsock call
|
|
*
|
|
* RETURNS:
|
|
* 0
|
|
*
|
|
* AUTHOR
|
|
* mcc 01/18/96 (borrowed from HAWIN)
|
|
*/
|
|
LONG WinSockResolveEvent(ST_STDCOM *pstPrivate, LPARAM lPar)
|
|
{
|
|
int nError;
|
|
struct sockaddr_in srv_addr;
|
|
LPHOSTENT pstHost;
|
|
ULONG *pulAddress;
|
|
|
|
DbgOutStr("WinSockResolveEvent called\n", 0,0,0,0,0);
|
|
|
|
nError = HIWORD(lPar);
|
|
if (nError)
|
|
{
|
|
// Notify the connection driver that a change in status may
|
|
// have taken place. It will follow up and display
|
|
// an appropriate message
|
|
DbgOutStr("Resolve: hiword of lpar = %d\n", nError,0,0,0,0);
|
|
|
|
ComNotify(pstPrivate->hCom, CONNECT);
|
|
pstPrivate->fConnected = COM_PORT_NOT_OPEN;
|
|
|
|
return 0;
|
|
}
|
|
|
|
pstHost = (LPHOSTENT) &pstPrivate->stHostBuf;
|
|
pulAddress = (ULONG FAR *)*(pstHost->h_addr_list);
|
|
|
|
nError = WSAAsyncSelect(pstPrivate->hSocket,
|
|
pstPrivate->hwndEvents,
|
|
WM_WINSOCK_NOTIFY,
|
|
FD_CONNECT | FD_READ | FD_WRITE | FD_CLOSE
|
|
);
|
|
|
|
if (nError != 0)
|
|
{
|
|
DbgOutStr("Resolve: WSAAsyncSelect failed\n", 0,0,0,0,0);
|
|
ComNotify(pstPrivate->hCom, CONNECT);
|
|
return 0;
|
|
}
|
|
|
|
|
|
srv_addr.sin_family = AF_INET;
|
|
srv_addr.sin_addr.s_addr = *pulAddress;
|
|
srv_addr.sin_port = (short) htons(pstPrivate->nPort);
|
|
|
|
if (connect(pstPrivate->hSocket,
|
|
(LPSOCKADDR)&srv_addr,
|
|
sizeof(srv_addr)) == SOCKET_ERROR)
|
|
{
|
|
nError = WSAGetLastError();
|
|
if (nError != WSAEWOULDBLOCK)
|
|
{
|
|
DbgOutStr("Resolve: connect failed, code = %d\n", nError,
|
|
0,0,0,0);
|
|
//DeviceReportError(pstPrivate, (UINT)nError, 0, FALSE);
|
|
ComNotify(pstPrivate->hCom, CONNECT);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
|
* FUNCTION:
|
|
* WinSockSendMessage
|
|
*
|
|
* DESCRIPTION:
|
|
* Used to send a Telnet option message. This calls send() directly so
|
|
* that data can go out while SndBufrSend is reporting COM_BUSY.
|
|
*
|
|
* PARAMETERS:
|
|
* pstPrivate Com driver private data
|
|
* nMsg The message number , e.g. DO, WILL, WONT, (see comwsock.hh)
|
|
* nChar The message data, e.g. TELOPT_BINARY (see comwsock.hh)
|
|
*
|
|
* RETURNS:
|
|
* void
|
|
*
|
|
* AUTHOR
|
|
* mcc 02/06/96
|
|
*/
|
|
VOID WinSockSendMessage(ST_STDCOM * pstPrivate, INT nMsg, INT nChar)
|
|
{
|
|
unsigned char acMsg[3];
|
|
|
|
#if defined(_DEBUG)
|
|
char *nNames[] = {"WILL", "WONT", "DO", "DONT"};
|
|
assert( nMsg >= WILL && nMsg <= DONT );
|
|
DbgOutStr("Send %s: %lx\r\n", nNames[nMsg - WILL], nChar,0,0,0);
|
|
#endif
|
|
acMsg[0] = IAC;
|
|
acMsg[1] = (UCHAR) nMsg;
|
|
acMsg[2] = (UCHAR) nChar;
|
|
|
|
|
|
WinSockSendBuffer(pstPrivate, 3, acMsg);
|
|
|
|
}
|
|
|
|
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
|
* FUNCTION:
|
|
* WinSockSendBuffer
|
|
*
|
|
* DESCRIPTION:
|
|
* Used to send an arbitrary string of data (e.g., a terminal type)
|
|
* during Telnet option negotiation
|
|
*
|
|
* PARAMETERS:
|
|
* pstPrivate Winsock Com driver private data
|
|
* nSize Number of bytes to send
|
|
* pszBuffer Pointer to data to send
|
|
*
|
|
* RETURNS:
|
|
* void
|
|
*
|
|
* AUTHOR
|
|
* mcc 02/06/96
|
|
*/
|
|
VOID WinSockSendBuffer(ST_STDCOM * pstPrivate, INT nSize, LPSTR pszBuffer)
|
|
{
|
|
int nCount, nError;
|
|
|
|
nCount = send(pstPrivate->hSocket, pszBuffer, nSize,0);
|
|
|
|
if (nCount == SOCKET_ERROR)
|
|
{
|
|
nError = WSAGetLastError();
|
|
|
|
if (nError == WSAEWOULDBLOCK)
|
|
{
|
|
DbgOutStr("WSSB would block. Queueing 3 bytes\n",
|
|
0,0,0,0,0);
|
|
if (sndQueueAppend(pstPrivate,pszBuffer, 3) != COM_OK)
|
|
ComNotify(pstPrivate->hCom, CONNECT);
|
|
}
|
|
else
|
|
ComNotify(pstPrivate->hCom, CONNECT);
|
|
|
|
}
|
|
else
|
|
{
|
|
int i;
|
|
DbgOutStr("%4d >> ", nCount,0,0,0,0);
|
|
for (i = 0; i < nCount; i++)
|
|
DbgOutStr("%x ", pszBuffer[i],0,0,0,0);
|
|
DbgOutStr("\n", 0,0,0,0,0);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
#endif // !defined(MULTITHREAD)
|
|
|
|
|
|
|
|
#ifdef MULTITHREAD
|
|
// This is essentially the NPORT TCPCOM driver ported to
|
|
// Win32. It uses different threads for reading and
|
|
// writing to the TCP socket.
|
|
// This code is deadwood at the moment, but might prove
|
|
// useful in Upper Wacker if someone can figure out
|
|
// why it does not work reliably under Win95. (send() calls
|
|
// would often appear to work but no data would come out
|
|
// over the socket.)
|
|
|
|
/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
* FUNCTION: WsckPortActivate
|
|
*
|
|
* DESCRIPTION:
|
|
* Called to activate the port and connect to destination
|
|
*
|
|
* ARGUMENTS:
|
|
* pstPrivate -- driver data structure
|
|
* pszPortName -- not used
|
|
*
|
|
* RETURNS:
|
|
* COM_OK if port is successfully activated
|
|
* COM_NOT_ENOUGH_MEMORY if there in insufficient memory for data storage
|
|
* COM_NOT_FOUND if named port cannot be opened
|
|
* COM_DEVICE_ERROR if API errors are encountered
|
|
*
|
|
* AUTHOR:
|
|
* mcc 12/26/95
|
|
*/
|
|
int WINAPI WsckPortActivate(void *pvPrivate,
|
|
TCHAR *pszPortName,
|
|
DWORD_PTR dwMediaHdl)
|
|
{
|
|
ST_STDCOM *pstPrivate = (ST_STDCOM *) pvPrivate;
|
|
int iRetVal = COM_OK;
|
|
ST_COM_CONTROL *pstComCntrl;
|
|
DWORD dwThreadID;
|
|
WORD wVersion;
|
|
WSADATA stWsaData;
|
|
struct sockaddr_in cli_addr;
|
|
|
|
|
|
|
|
/*
|
|
* Initialize the Windows Socket DLL
|
|
*/
|
|
wVersion = 0x0101; // The version of WinSock that we want
|
|
if (WSAStartup(wVersion, &stWsaData) != 0)
|
|
{
|
|
/* No DLL was available */
|
|
iRetVal = COM_DEVICE_ERROR;
|
|
goto checkout;
|
|
}
|
|
DbgOutStr("Done calling WSAStartup\n", 0,0,0,0,0);
|
|
|
|
/* Confirm that the Windows Socket DLL supports 1.1. */
|
|
/* Note that if the DLL supports versions greater */
|
|
/* than 1.1 in addition to 1.1, it will still return */
|
|
/* 1.1 in wVersion since that is the version we */
|
|
/* requested */
|
|
if ((LOBYTE(stWsaData.wVersion) != 1) &&
|
|
(HIBYTE(stWsaData.wVersion) != 1))
|
|
{
|
|
/* No acceptable DLL was available */
|
|
iRetVal = COM_DEVICE_ERROR;
|
|
goto checkout;
|
|
}
|
|
|
|
/*
|
|
* Create a socket for later use.
|
|
*/
|
|
pstPrivate->hSocket = socket(PF_INET, SOCK_STREAM, 0);
|
|
if (pstPrivate->hSocket == INVALID_SOCKET)
|
|
{
|
|
iRetVal = WSAGetLastError();
|
|
DbgOutStr("Error %d creating socket\n", iRetVal, 0,0,0,0);
|
|
iRetVal = COM_DEVICE_ERROR;
|
|
goto checkout;
|
|
}
|
|
DbgOutStr("Done creating socket %d \n", pstPrivate->hSocket,0,0,0,0);
|
|
|
|
|
|
|
|
|
|
cli_addr.sin_family = AF_INET;
|
|
cli_addr.sin_addr.s_addr = INADDR_ANY;
|
|
cli_addr.sin_port = 0;
|
|
|
|
// Bind the socket to any internet address. Ignore errors;
|
|
// real ones will be detected later, and this WILL fail
|
|
// if the socket is already bound.
|
|
iRetVal = bind(pstPrivate->hSocket, (LPSOCKADDR)&cli_addr,
|
|
sizeof(cli_addr));
|
|
DbgOutStr("Socket %d bind returns %d\n", pstPrivate->hSocket, iRetVal, 0,0,0);
|
|
|
|
// Make sure we can get enough memory for buffers before opening device
|
|
pstPrivate->pbBufrStart = malloc((size_t)pstPrivate->nRBufrSize);
|
|
|
|
if (pstPrivate->pbBufrStart == NULL)
|
|
{
|
|
iRetVal = COM_NOT_ENOUGH_MEMORY;
|
|
//* DeviceReportError(pstPrivate, SID_ERR_NOMEM, 0, TRUE);
|
|
goto checkout;
|
|
}
|
|
|
|
pstPrivate->pbBufrEnd = pstPrivate->pbBufrStart + pstPrivate->nRBufrSize;
|
|
pstPrivate->pbReadEnd = pstPrivate->pbBufrStart;
|
|
pstPrivate->pbComStart = pstPrivate->pbComEnd = pstPrivate->pbBufrStart;
|
|
pstPrivate->fBufrEmpty = TRUE;
|
|
|
|
|
|
if (iRetVal == COM_OK)
|
|
{
|
|
pstComCntrl = (ST_COM_CONTROL *)pstPrivate->hCom;
|
|
pstComCntrl->puchRBData =
|
|
pstComCntrl->puchRBDataLimit =
|
|
pstPrivate->pbBufrStart;
|
|
|
|
pstPrivate->dwEventMask = EV_ERR | EV_RLSD;
|
|
pstPrivate->fNotifyRcv = TRUE;
|
|
pstPrivate->fBufrEmpty = TRUE;
|
|
|
|
|
|
// Start thread to handle Reading, Writing (& 'rithmetic) & events
|
|
pstPrivate->fHaltThread = FALSE;
|
|
pstPrivate->hComReadThread = CreateThread((LPSECURITY_ATTRIBUTES)0,
|
|
16384, WsckComReadThread, pstPrivate, 0, &dwThreadID);
|
|
DBG_THREAD("CreateThread (Read Thread) returned %08X %08X\r\n",
|
|
pstPrivate->hComReadThread,0,0,0,0);
|
|
|
|
pstPrivate->hComWriteThread = CreateThread((LPSECURITY_ATTRIBUTES)0,
|
|
16384, WsckComWriteThread, pstPrivate, 0, &dwThreadID);
|
|
DBG_THREAD("CreateThread (Write Thread) returned %08X %08X\r\n",
|
|
pstPrivate->hComWriteThread,0,0,0,0);
|
|
|
|
// TODO discuss with JKH what thread priorities should be
|
|
|
|
// Make sure that we have a valid address to connect to
|
|
if ( wsckResolveAddress(pstPrivate->szRemoteAddr, &pstPrivate->ulAddr) != COM_OK )
|
|
{
|
|
pstPrivate->fConnected = COM_PORT_NOT_OPEN;
|
|
ComNotify(pstPrivate->hCom, CONNECT);
|
|
iRetVal = COM_NOT_FOUND;
|
|
goto checkout;
|
|
}
|
|
|
|
// Connect to the specified host
|
|
pstPrivate->stHost.sin_family = AF_INET;
|
|
pstPrivate->stHost.sin_addr.s_addr = pstPrivate->ulAddr;
|
|
pstPrivate->stHost.sin_port = htons(pstPrivate->nPort);
|
|
//DbgOutStr("About to call connect", 0,0,0,0,0);
|
|
iRetVal = connect(pstPrivate->hSocket,
|
|
(struct sockaddr *) &pstPrivate->stHost,
|
|
sizeof(pstPrivate->stHost));
|
|
if ( iRetVal == COM_OK )
|
|
{
|
|
pstPrivate->fConnected = COM_PORT_OPEN;
|
|
// Turn loose the read thread
|
|
DbgOutStr("connect OK", 0,0,0,0,0);
|
|
SetEvent(pstPrivate->ahEvent[EVENT_READ]);
|
|
SetEvent(pstPrivate->ahEvent[EVENT_WRITE]);
|
|
}
|
|
else
|
|
{
|
|
iRetVal = WSAGetLastError();
|
|
DbgOutStr(" connect() failed, rc = %d",iRetVal, 0,0,0,0);
|
|
iRetVal = COM_NOT_FOUND;
|
|
pstPrivate->fConnected = COM_PORT_NOT_OPEN;
|
|
ComNotify(pstPrivate->hCom, CONNECT);
|
|
}
|
|
}
|
|
|
|
checkout:
|
|
if (iRetVal != COM_OK)
|
|
WsckPortDeactivate(pstPrivate);
|
|
|
|
return iRetVal;
|
|
} /*lint !e715 */
|
|
|
|
|
|
/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
* FUNCTION: WsckPortDeactivate
|
|
*
|
|
* DESCRIPTION:
|
|
* Deactivates and closes an open port
|
|
*
|
|
* ARGUMENTS:
|
|
* pstPrivate -- Driver data structure
|
|
*
|
|
* RETURNS:
|
|
* COM_OK
|
|
*
|
|
* AUTHOR:
|
|
* mcc 12/26/95
|
|
*/
|
|
int WINAPI WsckPortDeactivate(void *pvPrivate)
|
|
{
|
|
ST_STDCOM *pstPrivate = (ST_STDCOM *) pvPrivate;
|
|
int iRetVal = COM_OK;
|
|
|
|
if (pstPrivate->hComReadThread || pstPrivate->hComWriteThread)
|
|
{
|
|
// Halt the thread by setting a flag for the thread to detect and then
|
|
// forcing WaitCommEvent to return by changing the event mask
|
|
DBG_THREAD("DBG_THREAD: Shutting down ComWinsock thread\r\n", 0,0,0,0,0);
|
|
pstPrivate->fHaltThread = TRUE;
|
|
|
|
// Read thread should exit now, it's handle will signal when it has exited
|
|
CloseHandle(pstPrivate->hComReadThread);
|
|
WaitForSingleObject(pstPrivate->hComReadThread, 5000);
|
|
|
|
pstPrivate->hComReadThread = NULL;
|
|
DBG_THREAD("DBG_THREAD: ComWinsock thread has shut down\r\n", 0,0,0,0,0);
|
|
|
|
// Write thread should exit now, it's handle will signal when it has exited
|
|
CloseHandle(pstPrivate->hComWriteThread);
|
|
WaitForSingleObject(pstPrivate->hComWriteThread, 5000);
|
|
|
|
pstPrivate->hComWriteThread = NULL;
|
|
DBG_THREAD("DBG_THWrite: ComWriteThread has shut down\r\n", 0,0,0,0,0);
|
|
}
|
|
|
|
if (pstPrivate->pbBufrStart)
|
|
{
|
|
free(pstPrivate->pbBufrStart);
|
|
pstPrivate->pbBufrStart = NULL;
|
|
}
|
|
|
|
|
|
// Shut down socket and WINSOCK
|
|
closesocket(pstPrivate->hSocket);
|
|
|
|
|
|
WSACleanup();
|
|
|
|
pstPrivate->hSocket = INVALID_SOCKET;
|
|
|
|
return iRetVal;
|
|
}
|
|
|
|
|
|
|
|
/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
* FUNCTION: WsckRcvRefill
|
|
*
|
|
* DESCRIPTION:
|
|
* Called when the receive buffer is empty to refill it. This routine
|
|
* should attempt to refill the buffer and return the first character.
|
|
* It is important that this function be implemented efficiently.
|
|
*
|
|
* ARGUMENTS:
|
|
* pstPrivate -- the driver data structure
|
|
*
|
|
* RETURNS:
|
|
* TRUE if data is put in the receive buffer
|
|
* FALSE if there is no new incoming data
|
|
*
|
|
* AUTHOR:
|
|
* mcc 12/26/95 (taken almost entirely from comstd.c)
|
|
*/
|
|
int WINAPI WsckRcvRefill(void *pvPrivate)
|
|
{
|
|
ST_STDCOM *pstPrivate = (ST_STDCOM *) pvPrivate;
|
|
int fRetVal = FALSE;
|
|
ST_COM_CONTROL *pstComCntrl;
|
|
|
|
EnterCriticalSection(&pstPrivate->csect);
|
|
|
|
pstPrivate->pbComStart = (pstPrivate->pbComEnd == pstPrivate->pbBufrEnd) ?
|
|
pstPrivate->pbBufrStart :
|
|
pstPrivate->pbComEnd;
|
|
pstPrivate->pbComEnd = (pstPrivate->pbReadEnd >= pstPrivate->pbComStart) ?
|
|
pstPrivate->pbReadEnd :
|
|
pstPrivate->pbBufrEnd;
|
|
DBG_READ("DBG_READ: Refill ComStart==%x, ComEnd==%x (ReadEnd==%x)\r\n",
|
|
pstPrivate->pbComStart, pstPrivate->pbComEnd,
|
|
pstPrivate->pbReadEnd, 0,0);
|
|
if (pstPrivate->fBufrFull)
|
|
{
|
|
DBG_READ("DBG_READ: Refill Signalling EVENT_READ\r\n", 0,0,0,0,0);
|
|
SetEvent(pstPrivate->ahEvent[EVENT_READ]);
|
|
}
|
|
if (pstPrivate->pbComStart == pstPrivate->pbComEnd)
|
|
{
|
|
DBG_READ("DBG_READ: Refill setting fBufrEmpty = TRUE\r\n", 0,0,0,0,0);
|
|
pstPrivate->fBufrEmpty = TRUE;
|
|
ComNotify(pstPrivate->hCom, NODATA);
|
|
}
|
|
else
|
|
{
|
|
pstComCntrl = (ST_COM_CONTROL *)pstPrivate->hCom;
|
|
pstComCntrl->puchRBData = pstPrivate->pbComStart;
|
|
pstComCntrl->puchRBDataLimit = pstPrivate->pbComEnd;
|
|
fRetVal = TRUE;
|
|
}
|
|
|
|
LeaveCriticalSection(&pstPrivate->csect);
|
|
return fRetVal;
|
|
}
|
|
|
|
|
|
/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
* FUNCTION: WsckRcvClear
|
|
*
|
|
* DESCRIPTION:
|
|
* Clears the receiver of all received data.
|
|
*
|
|
* ARGUMENTS:
|
|
* hCom -- a comm handle returned by an earlier call to ComCreateHandle
|
|
*
|
|
* RETURNS:
|
|
* COM_OK if data is cleared
|
|
* COM_DEVICE_ERROR if Windows com device driver returns an error
|
|
*
|
|
* AUTHOR:
|
|
* mcc 12/26/95 (taken almost entirely from comstd.c)
|
|
*/
|
|
int WINAPI WsckRcvClear(void *pvPrivate)
|
|
{
|
|
ST_STDCOM *pstPrivate = (ST_STDCOM *) pvPrivate;
|
|
int iRetVal = COM_OK;
|
|
ST_COM_CONTROL *pstComCntrl;
|
|
|
|
EnterCriticalSection(&pstPrivate->csect);
|
|
pstComCntrl = (ST_COM_CONTROL *)pstPrivate->hCom;
|
|
|
|
// Set buffer pointers to clear out any data we might have queued
|
|
pstComCntrl->puchRBData = pstPrivate->pbBufrStart;
|
|
pstComCntrl->puchRBDataLimit = pstPrivate->pbBufrStart;
|
|
pstPrivate->pbReadEnd = pstPrivate->pbBufrStart;
|
|
pstPrivate->pbComStart = pstPrivate->pbBufrStart;
|
|
pstPrivate->pbComEnd = pstPrivate->pbBufrStart;
|
|
|
|
LeaveCriticalSection(&pstPrivate->csect);
|
|
return iRetVal;
|
|
}
|
|
|
|
|
|
|
|
// Buffered send routines
|
|
|
|
|
|
/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
* FUNCTION: WsckSndBufrSend
|
|
*
|
|
* DESCRIPTION:
|
|
* Sends a buffer over the socket
|
|
*
|
|
* ARGUMENTS:
|
|
* pstPrivate Driver's private data structure
|
|
* pvBufr Pointer to data to send
|
|
* nSize Number of bytes to send
|
|
*
|
|
* RETURNS:
|
|
* COM_OK if successful
|
|
* COM_FAILED otherwise
|
|
*
|
|
*
|
|
* AUTHOR:
|
|
* mcc 12/26/95
|
|
*/
|
|
int WINAPI WsckSndBufrSend(void *pvPrivate, void *pvBufr, int nSize)
|
|
{
|
|
ST_STDCOM *pstPrivate = (ST_STDCOM *) pvPrivate;
|
|
int iRetVal = COM_OK;
|
|
int iCode;
|
|
|
|
assert(pvBufr != (void *)0);
|
|
assert(nSize <= WSOCK_SIZE_OUTQ);
|
|
|
|
if (pstPrivate->fSending)
|
|
{
|
|
DbgOutStr("SBS: Busy", 0,0,0,0,0);
|
|
return COM_BUSY;
|
|
}
|
|
else if (nSize > 0)
|
|
{
|
|
ComNotify(pstPrivate->hCom, SEND_STARTED);
|
|
EnterCriticalSection(&pstPrivate->csect);
|
|
pstPrivate->pbSendBufr = pvBufr;
|
|
pstPrivate->nSendBufrLen = nSize;
|
|
pstPrivate->fSending = TRUE;
|
|
|
|
|
|
LeaveCriticalSection(&pstPrivate->csect);
|
|
|
|
// Tell the write thread to run
|
|
iCode = SetEvent(pstPrivate->ahEvent[EVENT_WRITE]);
|
|
DbgOutStr("SBS: %d bytes in buffer. SetEvent returns %d", nSize,
|
|
iCode,0,0,0);
|
|
|
|
}
|
|
|
|
return iRetVal;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
* FUNCTION: WsckSndBufrClear
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
*
|
|
* ARGUMENTS:
|
|
*
|
|
*
|
|
* RETURNS:
|
|
*
|
|
* AUTHOR:
|
|
* mcc 12/26/95
|
|
*/
|
|
int WINAPI WsckSndBufrClear(void *pvPrivate)
|
|
{
|
|
ST_STDCOM *pstPrivate = (ST_STDCOM *) pvPrivate;
|
|
int iRetVal = COM_OK;
|
|
|
|
EnterCriticalSection(&pstPrivate->csect);
|
|
if (WsckSndBufrIsBusy(pstPrivate))
|
|
{
|
|
pstPrivate->fClearSendBufr = TRUE;
|
|
}
|
|
LeaveCriticalSection(&pstPrivate->csect);
|
|
|
|
return iRetVal;
|
|
}
|
|
|
|
|
|
|
|
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
* FUNCTION: WsckComWriteThread
|
|
*
|
|
* DESCRIPTION:
|
|
* One of the "main" threads of the comm driver ...
|
|
* Waits on an "anything to write?" semaphore
|
|
* When awakened, writes the write buffer in the driver data structure
|
|
* to the comm port and resets the semaphore
|
|
*
|
|
* ARGUMENTS
|
|
* pvData Address of driver data structure
|
|
*
|
|
*
|
|
* RETURNS:
|
|
* Nothing
|
|
*
|
|
* AUTHOR
|
|
* mcc 12/27/95 (stolen from Northport)
|
|
*/
|
|
DWORD WINAPI WsckComWriteThread(void *pvData)
|
|
{
|
|
ST_STDCOM *pstPrivate = (ST_STDCOM *)pvData;
|
|
int nBytesWritten;
|
|
unsigned uSize, nBytesToSend, nBytesSent;
|
|
int fRunning = TRUE;
|
|
DWORD iResult = COM_OK;
|
|
char *pchData;
|
|
int iCode;
|
|
|
|
|
|
|
|
DBG_THREAD("DBG_THREAD: ComWriteThread starting",0,0,0,0,0);
|
|
|
|
// Initialize the "Something to write" semaphore to Reset, so that
|
|
// we will wait for SndBufrSend to hand something to us
|
|
if (! ResetEvent(pstPrivate->ahEvent[EVENT_WRITE]))
|
|
{
|
|
assert(0);
|
|
}
|
|
|
|
while (fRunning)
|
|
{
|
|
// Wait on a semaphore for something to write
|
|
iCode = WaitForSingleObject(pstPrivate->ahEvent[EVENT_WRITE],
|
|
(unsigned long) 60000);
|
|
|
|
DBG_WRITE("WrThread: Got EVENT_WRITE %d\n", iCode,0,0,0,0);
|
|
|
|
// Has anybody told us to shut down?
|
|
//
|
|
if (pstPrivate->fHaltThread)
|
|
{
|
|
DBG_WRITE(" WrThread: fHaltThread==TRUE, shutting down", 0,0,0,0,0);
|
|
ExitThread(0);
|
|
}
|
|
|
|
else
|
|
{
|
|
iResult = COM_OK;
|
|
EnterCriticalSection(&pstPrivate->csect);
|
|
pchData = pstPrivate->pbSendBufr;
|
|
nBytesToSend = (unsigned) pstPrivate->nSendBufrLen;
|
|
|
|
nBytesSent = 0;
|
|
if (nBytesToSend > 0)
|
|
{
|
|
DbgOutStr("WriteThrd: %d to send\n", nBytesToSend, 0,0,0,0);
|
|
|
|
// Loop until we send all the requested data
|
|
while ( fRunning && nBytesSent < nBytesToSend )
|
|
{
|
|
uSize = nBytesToSend - nBytesSent;
|
|
LeaveCriticalSection(&pstPrivate->csect);
|
|
assert(uSize > 0 && uSize < 32767);
|
|
nBytesWritten = send(pstPrivate->hSocket,
|
|
pchData,(int) uSize, 0);
|
|
DbgOutStr("WriteThrd: %d bytes of %d sent. 1st 3 = %x %x %x\n",
|
|
nBytesWritten, uSize, pchData[0], pchData[1], pchData[2]);
|
|
|
|
// We have an error -- probably the connection got dropped
|
|
// report it to the various interested parties
|
|
if ( nBytesWritten == -1 )
|
|
{
|
|
iResult = (unsigned) WSAGetLastError();
|
|
DbgOutStr("WriteThrd: error %d sending %d bytes (%d - %d). Byebye.\n",
|
|
iResult, (int) uSize, nBytesToSend,nBytesSent,0);
|
|
ComNotify(pstPrivate->hCom, CONNECT);
|
|
pstPrivate->fConnected = COM_PORT_NOT_OPEN;
|
|
fRunning = 0;
|
|
}
|
|
nBytesSent += (unsigned) nBytesWritten;
|
|
if (nBytesSent < nBytesToSend )
|
|
{
|
|
DbgOutStr("WrtThrd: can't send all data to socket\n",
|
|
0,0,0,0,0);
|
|
pchData += nBytesWritten;
|
|
}
|
|
}
|
|
EnterCriticalSection(&pstPrivate->csect);
|
|
//DbgOutStr(" WrThread: Wrote %u bytes, %lu written, ret=%lu\n",
|
|
//uSize, nBytesWritten, 0, 0, 0);
|
|
|
|
// We've sent the buffer, so clear the Sending flag
|
|
pstPrivate->fSending = FALSE;
|
|
|
|
pstPrivate->nSendBufrLen = 0;
|
|
pstPrivate->pbSendBufr = NULL;
|
|
pstPrivate->fClearSendBufr = FALSE;
|
|
|
|
//DBG_WRITE(" WrThread: posting EVENT_SENT", 0,0,0,0,0);
|
|
// TOCO:mcc 12/29/95 SetEvent(pstPrivate->ahEvent[EVENT_SENT]);
|
|
}
|
|
if (pstPrivate->fHaltThread)
|
|
{
|
|
DBG_WRITE(" WrThread: fHaltThread==TRUE, shutting down", 0,0,0,0,0);
|
|
ExitThread(0);
|
|
}
|
|
DbgOutStr(" WrThread: setting fSending=FALSE, resetting EVENT_WRITE\n",
|
|
0,0,0,0,0);
|
|
if (!ResetEvent(pstPrivate->ahEvent[EVENT_WRITE]))
|
|
{
|
|
assert(0);
|
|
}
|
|
LeaveCriticalSection(&pstPrivate->csect);
|
|
ComNotify(pstPrivate->hCom, SEND_DONE);
|
|
}
|
|
}
|
|
|
|
DbgOutStr("WriteThread exiting ...", 0,0,0,0,0);
|
|
ExitThread(0);
|
|
return (iResult);
|
|
}
|
|
|
|
/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
* FUNCTION: WsckComReadThread
|
|
*
|
|
* DESCRIPTION:
|
|
* One of the main threads of the comm driver ...
|
|
* Reads data from the comm port as long as we have a place to put it
|
|
* If the buffer fills up, go to sleep until RcvRefill takes some data
|
|
* out of the buffer
|
|
*
|
|
*
|
|
* ARGUMENTS:
|
|
* pvData address of our private data structure
|
|
*
|
|
* RETURNS:
|
|
* nothing
|
|
*
|
|
* AUTHOR
|
|
* mcc 12/27/95 (stolen from Northport)
|
|
*/
|
|
DWORD WINAPI WsckComReadThread(void *pvData)
|
|
{
|
|
ST_STDCOM *pstPrivate = (ST_STDCOM *)pvData;
|
|
int fRunning = TRUE;
|
|
int fReading = TRUE;
|
|
char *pbReadFrom, *pOut;
|
|
unsigned nReadSize;
|
|
long lBytesRead, nFFs;
|
|
int iResult;
|
|
int nIndx;
|
|
DWORD rc;
|
|
|
|
|
|
DBG_THREAD("DBG_THREAD: ComtcpReadThread starting",0,0,0,0,0);
|
|
EnterCriticalSection(&pstPrivate->csect);
|
|
|
|
// Set Read event to reset so we don't read until the connection is up
|
|
// By setting fBufrFull TRUE, the thread will think it is being
|
|
// reawakened from a full buffer condition when PortActivate posts the
|
|
// semaphore
|
|
pstPrivate->fBufrFull = TRUE;
|
|
ResetEvent(pstPrivate->ahEvent[EVENT_READ]);
|
|
LeaveCriticalSection(&pstPrivate->csect);
|
|
|
|
pstPrivate->fSeenFF = 0;
|
|
while ( fRunning )
|
|
{
|
|
|
|
// Wait for a wakeup call if we put ourself to sleep
|
|
//DbgOutStr("ReadThread: Waiting for EVENT_READ", 0,0,0,0,0);
|
|
rc = WaitForSingleObject(pstPrivate->ahEvent[EVENT_READ], 60000);
|
|
if ( rc != 0 )
|
|
{
|
|
DbgOutStr("ReadThread: EVENT_READ timed out. fBufFull=%d",
|
|
pstPrivate->fBufrFull,0,0,0,0);
|
|
}
|
|
else
|
|
{
|
|
//DbgOutStr("ReadThread: Got EVENT_READ.", 0,0,0,0,0);
|
|
}
|
|
|
|
// To get this thread to exit, the deactivate routine forces a
|
|
// fake com event by posting EVENT_READ
|
|
if (pstPrivate->fHaltThread)
|
|
{
|
|
DBG_THREAD("DBG_THREAD: Comtcp exiting thread",0,0,0,0,0);
|
|
fRunning = FALSE;
|
|
}
|
|
else
|
|
{
|
|
EnterCriticalSection(&pstPrivate->csect);
|
|
if (pstPrivate->fBufrFull)
|
|
{
|
|
//DbgOutStr("ReadThread: fBufrFull = FALSE", 0,0,0,0,0);
|
|
pstPrivate->fBufrFull = FALSE;
|
|
fReading = TRUE;
|
|
}
|
|
LeaveCriticalSection(&pstPrivate->csect);
|
|
|
|
// Do reads until we fill the buffer
|
|
while (fReading && fRunning)
|
|
{
|
|
// Check for wrap around in circular buffer
|
|
pbReadFrom = (pstPrivate->pbReadEnd >= pstPrivate->pbBufrEnd) ?
|
|
pstPrivate->pbBufrStart : pstPrivate->pbReadEnd;
|
|
|
|
nReadSize = (unsigned) (pbReadFrom < pstPrivate->pbComStart) ?
|
|
(unsigned) (pstPrivate->pbComStart - pbReadFrom - 1) :
|
|
(unsigned) (pstPrivate->pbBufrEnd - pbReadFrom);
|
|
|
|
if (nReadSize > WSOCK_MAX_READSIZE)
|
|
nReadSize = WSOCK_MAX_READSIZE;
|
|
|
|
if (!nReadSize)
|
|
{
|
|
DBG_READ("Read Thread -- fBufrFull = TRUE, unsignalling EVENT_READ\r\n",
|
|
0,0,0,0,0);
|
|
pstPrivate->fBufrFull = TRUE;
|
|
ResetEvent(pstPrivate->ahEvent[EVENT_READ]);
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
DBG_READ("ReadThread posting a recv\n", 0,0,0,0,0);
|
|
lBytesRead = recv(pstPrivate->hSocket, pbReadFrom,
|
|
(int)nReadSize, 0);
|
|
if (lBytesRead > 0)
|
|
{
|
|
pstPrivate->pbReadEnd += lBytesRead;
|
|
|
|
if (pstPrivate->pbReadEnd >= pstPrivate->pbBufrEnd)
|
|
pstPrivate->pbReadEnd = pstPrivate->pbBufrStart;
|
|
|
|
DBG_READ("DBG_READ: Thread -- recv completed synchronously,"
|
|
" lBytesRead==%ld, ReadEnd==%x\r\n",
|
|
lBytesRead, pstPrivate->pbReadEnd,0,0,0);
|
|
|
|
if (pstPrivate->fBufrEmpty)
|
|
{
|
|
DBG_READ("DBG_READ: Thread -- fBufrEmpty = FALSE\r\n", 0,0,0,0,0);
|
|
pstPrivate->fBufrEmpty = FALSE;
|
|
ComNotify(pstPrivate->hCom, DATA_RECEIVED);
|
|
}
|
|
|
|
if (pstPrivate->fEscapeFF)
|
|
{
|
|
// The sender escaped FF characters by doubling
|
|
// them. Copy the received data buffer onto itself,
|
|
// skipping every other FF
|
|
pOut = pbReadFrom;
|
|
nFFs = 0;
|
|
for (nIndx = 0; nIndx < lBytesRead; nIndx += 1)
|
|
{
|
|
if (pstPrivate->fSeenFF)
|
|
{
|
|
if (pbReadFrom[nIndx] == 0xFF)
|
|
{
|
|
// Skip this one
|
|
nFFs++;
|
|
}
|
|
else
|
|
{
|
|
// This should not happen, but copy
|
|
// anyway
|
|
*pOut = pbReadFrom[nIndx];
|
|
pOut++;
|
|
}
|
|
pstPrivate->fSeenFF = FALSE;
|
|
}
|
|
else
|
|
{
|
|
// Test to see if this is an FF; copy
|
|
// input to output.
|
|
if (pbReadFrom[nIndx] == 0xFF)
|
|
{
|
|
pstPrivate->fSeenFF = TRUE;
|
|
}
|
|
*pOut = pbReadFrom[nIndx];
|
|
pOut++;
|
|
}
|
|
}
|
|
// Decrement the number of bytes read by the
|
|
// number of duplicate FF's we tossed.
|
|
lBytesRead -= nFFs;
|
|
}
|
|
|
|
// Notify application that we got some data
|
|
// if buffer had been empty
|
|
EnterCriticalSection(&pstPrivate->csect);
|
|
if (pstPrivate->fBufrEmpty)
|
|
{
|
|
DBG_READ("DBG_READ: Thread -- fBufrEmpty = FALSE", 0,0,0,0,0);
|
|
pstPrivate->fBufrEmpty = FALSE;
|
|
}
|
|
LeaveCriticalSection(&pstPrivate->csect);
|
|
ComNotify(pstPrivate->hCom, DATA_RECEIVED);
|
|
|
|
}
|
|
else
|
|
{
|
|
|
|
// 0 value from recv indicates that the connection is closed;
|
|
// -1 indicates another error. Notify CNCT driver.
|
|
// (re-set the connection status
|
|
// if the error code indicates that the connection is down)
|
|
iResult = WSAGetLastError();
|
|
DbgOutStr("ReadThread: Got no data, err=%d", iResult, 0,0,0,0);
|
|
EnterCriticalSection(&pstPrivate->csect);
|
|
if ( lBytesRead == 0 ||
|
|
iResult == WSAENETDOWN ||
|
|
iResult == WSAENOTCONN ||
|
|
iResult == WSAEHOSTDOWN ||
|
|
iResult == WSAETIMEDOUT)
|
|
{
|
|
// Wait until we are told to shut down; don't try to read
|
|
// anymore!
|
|
ResetEvent(pstPrivate->ahEvent[EVENT_READ]);
|
|
pstPrivate->fConnected = COM_PORT_NOT_OPEN;
|
|
}
|
|
|
|
LeaveCriticalSection(&pstPrivate->csect);
|
|
ComNotify(pstPrivate->hCom, DATA_RECEIVED);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
if (pstPrivate->fHaltThread)
|
|
{
|
|
DBG_THREAD("DBG_THREAD: Comtcp exiting thread",0,0,0,0,0);
|
|
fRunning = FALSE;
|
|
}
|
|
} // end of fReading && fRunning
|
|
}
|
|
|
|
} // end of fRunning loop
|
|
|
|
EnterCriticalSection(&pstPrivate->csect);
|
|
pstPrivate->hComReadThread = 0;
|
|
LeaveCriticalSection(&pstPrivate->csect);
|
|
DbgOutStr("ReadThread exiting ...", 0,0,0,0,0);
|
|
ExitThread(0);
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
* FUNCTION:
|
|
* wsckResolveAddress
|
|
*
|
|
* DESCRIPTION:
|
|
* Takes a numeric or symbolic net address string and returns
|
|
* a valid binary internet address.
|
|
*
|
|
* ARGUMENTS:
|
|
* pszRemote The remote system's address as a string
|
|
* pulAddr Pointer to binary internet address
|
|
*
|
|
* RETURNS:
|
|
* COM_OK If successful
|
|
* COM_NOT_FOUND If the address is invalid
|
|
*
|
|
* AUTHOR
|
|
* mcc 01/09/96 (stolen from Northport)
|
|
*/
|
|
int wsckResolveAddress(TCHAR *pszRemote, unsigned long *pulAddr)
|
|
{
|
|
int iRetVal = COM_NOT_FOUND;
|
|
struct hostent *pstHost;
|
|
|
|
assert(pszRemote);
|
|
assert(pulAddr);
|
|
|
|
if (pszRemote && pulAddr)
|
|
{
|
|
|
|
// Convert pszRemote to an internet address. If not successful,
|
|
// assume that the string is a host NAME and try to turn
|
|
// that into an address
|
|
*pulAddr = inet_addr(pszRemote);
|
|
if ((*pulAddr == INADDR_NONE) || (*pulAddr == 0))
|
|
{
|
|
// If not a valid network address, it should be a name, so
|
|
// look that up (in the hosts file or via a name server)
|
|
pstHost = gethostbyname(pszRemote);
|
|
if ( pstHost)
|
|
*pulAddr = *((unsigned long *)pstHost->h_addr);
|
|
}
|
|
if ((*pulAddr != INADDR_NONE) && (*pulAddr != 0))
|
|
iRetVal = COM_OK;
|
|
else
|
|
iRetVal = COM_NOT_FOUND;
|
|
}
|
|
|
|
return iRetVal;
|
|
}
|
|
|
|
|
|
#endif // MULTITHREAD
|
|
#endif // INCL_WINSOCK
|