Leaked source code of windows server 2003
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.
 
 
 
 
 
 

919 lines
21 KiB

/*****************************************************************************\
* MODULE: inetport.cxx
*
* The module contains routines for handling the INETPP functionality. Use
* of these routines require the locking/unlocking of a critical-section
* to maninpulate the INIMONPORT list. All internal routines assume the
* crit-sect is locked prior to executing. CheckMonCrit() is a debugging
* call to verify the monitor-crit-sect is locked.
*
* NOTE: Each of the Inetmon*, InetMonPort calls must be protected by the
* global-crit-sect.
* If a new routine is added to this module which is to be called from
* another module, be sure to include the call to (semCheckCrit), so
* that the debug-code can catch unprotected access.
*
* Copyright (C) 1996-1997 Microsoft Corporation
* Copyright (C) 1996-1997 Hewlett Packard
*
* History:
* 07-Oct-1996 HWP-Guys Initiated port from win95 to winNT
* 14-Nov-1997 ChrisWil Added local-spooling functionality.
* 10-Jul-1998 WeihaiC Change Authentication Dialog Code
*
\*****************************************************************************/
#include "precomp.h"
#include "priv.h"
CInetMonPort::CInetMonPort (
LPCTSTR lpszPortName,
LPCTSTR lpszDevDesc,
PCPORTMGR pPortMgr):
m_bValid (FALSE),
m_pNext (NULL),
m_cRef (0),
m_cPrinterRef (0),
m_bDeletePending (FALSE),
m_lpszHost (NULL),
m_lpszShare (NULL),
m_pPortMgr (pPortMgr),
m_pGetPrinterCache (NULL),
m_pEnumJobsCache (NULL),
m_bCheckConnection (TRUE),
m_hTerminateEvent (NULL),
m_pjmList (NULL)
{
PCINETMONPORT pIniPort;
PCINETMONPORT pPort;
LPTSTR lpszHost;
LPTSTR lpszShare;
INTERNET_PORT iPort;
BOOL bSecure;
// Parse out the host/share. This call returns allocated
// string-buffers. It is our responsibility to free the
// memory once we're done with it.
//
if (utlParseHostShare(lpszPortName, &lpszHost, &lpszShare, &iPort, &bSecure)) {
// The (lpszDevDesc) could be NULL only if it's PP_REMOTE.
//
if (lpszDevDesc && *lpszDevDesc)
m_lpszDesc = memAllocStr(lpszDevDesc);
else
m_lpszDesc = memAllocStr(lpszPortName);
m_lpszName = memAllocStr (lpszPortName);
// If succeeded, then continue to initialize the port.
//
if (m_lpszDesc && m_lpszName) {
// Initialize the port-elements.
//
m_lpszHost = lpszHost;
m_lpszShare = lpszShare;
DBG_MSG(DBG_LEV_INFO, (TEXT("Info: _inet_create_port: Host(%s) Share(%s)"), lpszHost, lpszShare));
m_pGetPrinterCache = new GetPrinterCache (this);
m_pEnumJobsCache = new EnumJobsCache (this);
if (m_pGetPrinterCache && m_pEnumJobsCache && m_pGetPrinterCache->bValid() && m_pEnumJobsCache->bValid ()) {
m_bValid = TRUE;
}
}
}
}
CInetMonPort::~CInetMonPort ()
{
FreeGetPrinterCache ();
FreeEnumJobsCache ();
// Free the entry and all memory allocated on
// behalf of the entry.
//
memFreeStr(m_lpszDesc);
memFreeStr(m_lpszHost);
memFreeStr(m_lpszShare);
// Remove any job-entries.
//
pjmDelList(m_pjmList);
m_pPortMgr->Remove ();
delete m_pPortMgr;
if (m_hTerminateEvent)
CloseHandle (m_hTerminateEvent);
}
VOID
CInetMonPort::IncRef ()
{
m_cRef++;
}
VOID
CInetMonPort::DecRef ()
{
m_cRef--;
}
VOID
CInetMonPort::IncPrinterRef ()
{
m_cPrinterRef++;
}
VOID
CInetMonPort::DecPrinterRef ()
{
m_cPrinterRef--;
}
/*****************************************************************************\
* _inet_size_entry (Local Routine)
*
* Returns the size of an entry depending upon the print-level.
*
\*****************************************************************************/
DWORD
CInetMonPort::_inet_size_entry(
DWORD dwLevel)
{
DWORD cb;
switch (dwLevel) {
case PRINT_LEVEL_1:
cb = sizeof(PORT_INFO_1) + utlStrSize(m_lpszName);
break;
case PRINT_LEVEL_2:
cb = sizeof(PORT_INFO_2) +
utlStrSize(m_lpszName) +
utlStrSize(m_lpszDesc) +
utlStrSize(g_szLocalPort);
break;
default:
cb = 0;
break;
}
return cb;
}
/*****************************************************************************\
* _inet_copy_entry (Local Routine)
*
* Returns a copy of the port-entry.
*
\*****************************************************************************/
LPBYTE
CInetMonPort::_inet_copy_entry(
DWORD dwLevel,
LPBYTE pPortInfo,
LPBYTE pEnd)
{
LPTSTR SourceStrings[sizeof(PORT_INFO_2) / sizeof(LPTSTR)];
LPTSTR *pSourceStrings=SourceStrings;
DWORD *pOffsets;
static DWORD s_dwPortInfo1Strings[] = {
offsetof(LPPORT_INFO_1A, pName),
0xFFFFFFFF
};
static DWORD s_dwPortInfo2Strings[] = {
offsetof(LPPORT_INFO_2A, pPortName),
offsetof(LPPORT_INFO_2A, pMonitorName),
offsetof(LPPORT_INFO_2A, pDescription),
0xFFFFFFFF
};
//
//
switch (dwLevel) {
case PORT_LEVEL_1:
pOffsets = s_dwPortInfo1Strings;
break;
case PORT_LEVEL_2:
pOffsets = s_dwPortInfo2Strings;
break;
default:
return pEnd;
}
//
//
switch (dwLevel) {
case PORT_LEVEL_1:
*pSourceStrings++ = m_lpszName;
pEnd = utlPackStrings(SourceStrings, pPortInfo, pOffsets, pEnd);
break;
case PORT_LEVEL_2:
*pSourceStrings++ = (LPTSTR)m_lpszName;
*pSourceStrings++ = (LPTSTR)g_szLocalPort;
*pSourceStrings++ = (LPTSTR)m_lpszDesc;
#if 0
((PPORT_INFO_2)pPortInfo)->fPortType = PORT_TYPE_WRITE | PORT_TYPE_NET_ATTACHED;
#else
((PPORT_INFO_2)pPortInfo)->fPortType = PORT_TYPE_WRITE | PORT_TYPE_REDIRECTED;
#endif
((PPORT_INFO_2)pPortInfo)->Reserved = 0;
pEnd = utlPackStrings(SourceStrings, pPortInfo, pOffsets, pEnd);
break;
}
return pEnd;
}
/*****************************************************************************\
* _inet_req_jobstart (Local Routine)
*
* Performs the job-start request. This writes out the header info to the
* spool-job.
*
\*****************************************************************************/
BOOL
CInetMonPort::_inet_req_jobstart(
PIPPREQ_PRTJOB ppj,
PJOBMAP pjmJob)
{
LPBYTE lpIppHdr;
REQINFO ri;
DWORD cbIppHdr;
DWORD dwRet;
DWORD cbWr;
BOOL bRet = FALSE;
// Convert the IPPREQ_PRTJOB to a IPP-stream-header.
//
ZeroMemory(&ri, sizeof(REQINFO));
ri.cpReq = CP_UTF8;
ri.idReq = IPP_REQ_PRINTJOB;
ri.fReq[0] = IPP_REQALL;
ri.fReq[1] = IPP_REQALL;
dwRet = WebIppSndData(IPP_REQ_PRINTJOB,
&ri,
(LPBYTE)ppj,
ppj->cbSize,
&lpIppHdr,
&cbIppHdr);
if (dwRet == WEBIPP_OK) {
bRet = pjmSplWrite(pjmJob, lpIppHdr, cbIppHdr, &cbWr);
WebIppFreeMem(lpIppHdr);
}
return bRet;
}
/*****************************************************************************\
* _inet_IppPrtRsp (Local Routine)
*
* Retrieves a get response from the IPP server.
*
\*****************************************************************************/
BOOL CALLBACK _inet_IppPrtRsp(
CAnyConnection *pConnection,
HINTERNET hJobReq,
PCINETMONPORT pIniPort,
PJOBMAP pjmJob)
{
HANDLE hIpp;
DWORD dwRet;
DWORD cbRd;
LPBYTE lpDta;
DWORD cbDta;
LPIPPRET_JOB lpRsp;
DWORD cbRsp;
BYTE bBuf[MAX_IPP_BUFFER];
BOOL bRet = FALSE;
if (hIpp = WebIppRcvOpen(IPP_RET_PRINTJOB)) {
while (TRUE) {
cbRd = 0;
if (pIniPort->ReadFile (pConnection, hJobReq, (LPVOID)bBuf, sizeof(bBuf), &cbRd) && cbRd) {
dwRet = WebIppRcvData(hIpp, bBuf, cbRd, (LPBYTE*)&lpRsp, &cbRsp, &lpDta, &cbDta);
switch (dwRet) {
case WEBIPP_OK:
if (bRet = lpRsp->bRet) {
// Set the remote-job-id to the job-entry. This
// entry was added at the time the spool-job-file
// was created.
//
semEnterCrit();
pjmSetJobRemote(pjmJob, lpRsp->ji.ji2.JobId, lpRsp->ji.ipp.pJobUri);
semLeaveCrit();
} else {
// If the job failed to open on the server, then
// we will set the last-error from the server
// response.
//
SetLastError(lpRsp->dwLastError);
}
WebIppFreeMem(lpRsp);
goto EndPrtRsp;
case WEBIPP_MOREDATA:
// Need to do another read to fullfill our header-response.
//
break;
default:
DBG_MSG(DBG_LEV_ERROR, (TEXT("_inet_IppPrtRsp - Err : Receive Data Error (dwRet=%d, LE=%d)"),
dwRet, WebIppGetError(hIpp)));
SetLastError(ERROR_INVALID_DATA);
goto EndPrtRsp;
}
} else {
goto EndPrtRsp;
}
}
EndPrtRsp:
WebIppRcvClose(hIpp);
} else {
SetLastError(ERROR_OUTOFMEMORY);
}
return bRet;
}
/*****************************************************************************\
* InetmonSendReq
*
*
\*****************************************************************************/
BOOL
CInetMonPort::SendReq(
LPBYTE lpIpp,
DWORD cbIpp,
IPPRSPPROC pfnRsp,
LPARAM lParam,
BOOL bLeaveCrit)
{
BOOL bRet = FALSE;
CMemStream *pStream;
pStream = new CMemStream (lpIpp, cbIpp);
if (pStream && pStream->bValid ()){
bRet = SendReq (pStream, pfnRsp, lParam, bLeaveCrit);
}
if (pStream) {
delete pStream;
}
return bRet;
}
BOOL
CInetMonPort::SendReq(
CStream *pStream,
IPPRSPPROC pfnRsp,
LPARAM lParam,
BOOL bLeaveCrit)
{
DWORD dwLE = ERROR_SUCCESS;
BOOL bRet = FALSE;
semCheckCrit();
if (bLeaveCrit)
//
// We must increaset the port ref count to make sure the
// port is not deleted.
//
semSafeLeaveCrit(this);
bRet = m_pPortMgr->SendRequest (this, pStream, pfnRsp, lParam);
dwLE = GetLastError();
if (bLeaveCrit)
semSafeEnterCrit(this);
if (!bRet) {
// Need to check connection next time
m_bCheckConnection = TRUE;
}
if ((bRet == FALSE) && (dwLE != ERROR_SUCCESS))
SetLastError(dwLE);
return bRet;
}
/*****************************************************************************\
* InetmonClosePort
*
* Close the internet connection.
*
\*****************************************************************************/
BOOL
CInetMonPort::ClosePort(
HANDLE hPrinter)
{
CLogonUserData* pUser = NULL;
semCheckCrit();
// Now see if this is the last port handle that a user is closing
if (hPrinter != NULL) { // This means we couldn't create the printer handle and
// had to close the port
pUser = m_pPortMgr->GetUserIfLastDecRef (((LPINET_HPRINTER)hPrinter)->hUser);
if (pUser) {
// We need to stop the Cache Manager thread if the same user owns it
DBG_MSG(DBG_LEV_INFO, (TEXT("Info: Last User Close Printer %p."), pUser));
InvalidateGetPrinterCacheForUser(pUser );
InvalidateEnumJobsCacheForUser(pUser );
semLeaveCrit ();
//
// In some cases, wininet takes a long time to clean up the
// browser session, so we have to leave the CS when making
// InternetSetOption calls to wininet
//
EndBrowserSession ();
semEnterCrit ();
delete ( pUser );
}
}
//
// We stop decrease the ref count since we don't increase the
// refcount at Open
//
DecPrinterRef();
return TRUE;
}
/*****************************************************************************\
* InetmonStartDocPort
*
* Start the beginning of a StartDoc call.
*
\*****************************************************************************/
BOOL
CInetMonPort::StartDocPort(
DWORD dwLevel,
LPBYTE pDocInfo,
PJOBMAP pjmJob)
{
LPTSTR lpszUser;
PIPPREQ_PRTJOB ppj;
BOOL bRet = FALSE;
DWORD dwLE;
semCheckCrit();
// We are going to hit the network, so leave the critical section
// To make sure the port will not be deleted, we increase the
// ref count
//
semSafeLeaveCrit(this);
bRet = m_pPortMgr->CheckConnection();
dwLE = GetLastError();
semSafeEnterCrit(this);
if (bRet) {
// Reset the value
bRet = FALSE;
// Get the username.
//
if (lpszUser = GetUserName()) {
// Build a IPP_PRTJOB_REQ struct. This routine assures that
// all strings are in Ascii format.
//
ppj = WebIppCreatePrtJobReq(FALSE,
lpszUser,
((PDOC_INFO_2)pDocInfo)->pDocName,
m_lpszName);
if (ppj) {
// Start the job. This writes out header info to the
// spool-file.
//
bRet = _inet_req_jobstart(ppj, pjmJob);
WebIppFreeMem(ppj);
}
memFreeStr(lpszUser);
}
} else {
m_bCheckConnection = FALSE;
SetLastError (dwLE);
}
if (bRet == FALSE) {
DBG_MSG(DBG_LEV_ERROR, (TEXT("Err : InetmonStartDocPort: Failed %d"), GetLastError()));
}
return bRet;
}
/*****************************************************************************\
* InetmonEndDocPort
*
* Signify the end of writing to a port. This is called after StartDocPort.
*
\*****************************************************************************/
BOOL
CInetMonPort::EndDocPort(
PJOBMAP pjmJob)
{
BOOL bRet = FALSE;
CFileStream *pStream = NULL;
semCheckCrit();
if (pStream = pjmSplLock(pjmJob)) {
bRet = SendReq(pStream, (IPPRSPPROC)_inet_IppPrtRsp, (LPARAM)pjmJob, TRUE);
pjmSplUnlock(pjmJob);
}
return bRet;
}
/*****************************************************************************\
* InetmonWritePort
*
* Write bytes to the port. This goes to the spool-file until the
* InetmonEndDocPort() is called.
*
\*****************************************************************************/
BOOL
CInetMonPort::WritePort(
PJOBMAP pjmJob,
LPBYTE lpData,
DWORD cbData,
LPDWORD pcbWr)
{
BOOL bRet;
semCheckCrit();
bRet = pjmSplWrite(pjmJob, lpData, cbData, pcbWr);
return bRet;
}
/*****************************************************************************\
* InetmonAbortPort
*
* Aborts our print-spooling process.
*
\*****************************************************************************/
BOOL
CInetMonPort::AbortPort(
PJOBMAP pjmJob)
{
semCheckCrit();
return TRUE; //(_inet_validate_port(hPort) ? TRUE : FALSE);
}
/*****************************************************************************\
* InetmonGetPortName
*
* Return the name of the port.
*
\*****************************************************************************/
LPCTSTR
CInetMonPort::GetPortName(
VOID)
{
LPCTSTR lpszName = NULL;
semCheckCrit();
lpszName = (LPCTSTR)m_lpszName;
return lpszName;
}
/*****************************************************************************\
* InetmonGetPJMList
*
*
\*****************************************************************************/
PJOBMAP*
CInetMonPort::GetPJMList(
VOID)
{
PJOBMAP* ppjmList = NULL;
semCheckCrit();
ppjmList = &m_pjmList;
return ppjmList;
}
/*****************************************************************************\
* InetmonIncUserRefCount
*
* Increases the reference count on the port for the given user
*
\*****************************************************************************/
DWORD
CInetMonPort::IncUserRefCount(
PCLOGON_USERDATA hUser )
{
DWORD dwRet = (DWORD) -1;
dwRet = m_pPortMgr->IncreaseUserRefCount (hUser);
return dwRet;
}
VOID
CInetMonPort::FreeGetPrinterCache (
VOID)
{
if (m_pGetPrinterCache) {
semLeaveCrit ();
m_pGetPrinterCache->Shutdown ();
semEnterCrit ();
}
}
BOOL
CInetMonPort::BeginReadGetPrinterCache (
PPRINTER_INFO_2 *ppInfo2)
{
BOOL bRet = FALSE;
if (m_pGetPrinterCache) {
semLeaveCrit ();
bRet = m_pGetPrinterCache->BeginReadCache (ppInfo2);
semEnterCrit ();
}
return bRet;
}
VOID
CInetMonPort::EndReadGetPrinterCache (
VOID)
{
if (m_pGetPrinterCache) {
m_pGetPrinterCache->EndReadCache ();
}
}
VOID
CInetMonPort::InvalidateGetPrinterCache (
VOID)
{
if (m_pGetPrinterCache) {
semLeaveCrit ();
m_pGetPrinterCache->InvalidateCache ();
semEnterCrit ();
}
}
VOID
CInetMonPort::InvalidateGetPrinterCacheForUser(
HANDLE hUser)
/*++
Routine Description:
Close the cache if the current user is currently controlling it.
Arguments:
hUser - The user for which we want to close the cache
Return Value:
None.
--*/
{
CLogonUserData *pUser = (CLogonUserData *)hUser;
if (m_pGetPrinterCache && pUser) {
semLeaveCrit ();
m_pGetPrinterCache->InvalidateCacheForUser (pUser);
semEnterCrit ();
}
}
VOID
CInetMonPort::FreeEnumJobsCache (
VOID)
{
semLeaveCrit ();
m_pEnumJobsCache->Shutdown ();
semEnterCrit ();
}
BOOL
CInetMonPort::BeginReadEnumJobsCache (
LPPPJOB_ENUM *ppje)
{
BOOL bRet = FALSE;
if (m_pEnumJobsCache) {
semLeaveCrit ();
bRet = m_pEnumJobsCache->BeginReadCache(ppje);
semEnterCrit ();
}
return bRet;
}
VOID
CInetMonPort::EndReadEnumJobsCache (
VOID)
{
if (m_pEnumJobsCache) {
m_pEnumJobsCache->EndReadCache();
}
}
VOID
CInetMonPort::InvalidateEnumJobsCache (
VOID)
{
if (m_pEnumJobsCache) {
semLeaveCrit ();
m_pEnumJobsCache->InvalidateCache ();
semEnterCrit ();
}
}
VOID
CInetMonPort::InvalidateEnumJobsCacheForUser(
HANDLE hUser)
/*++
Routine Description:
Close the cache if the current user is currently controlling it.
Arguments:
hUser - The user for which we want to close the cache
Return Value:
None.
--*/
{
if (m_pEnumJobsCache && hUser) {
semLeaveCrit ();
m_pEnumJobsCache->InvalidateCacheForUser ((CLogonUserData *)hUser);
semEnterCrit ();
}
}
BOOL
CInetMonPort::ReadFile (
CAnyConnection *pConnection,
HINTERNET hReq,
LPVOID lpvBuffer,
DWORD cbBuffer,
LPDWORD lpcbRd)
{
return m_pPortMgr->ReadFile (pConnection, hReq, lpvBuffer, cbBuffer, lpcbRd);
}
BOOL
CInetMonPort::GetCurrentConfiguration (
PINET_XCV_CONFIGURATION pXcvConfiguration)
{
return m_pPortMgr->GetCurrentConfiguration(pXcvConfiguration);
}
BOOL
CInetMonPort::ConfigurePort (
PINET_XCV_CONFIGURATION pXcvConfigurePortReqData,
PINET_CONFIGUREPORT_RESPDATA pXcvAddPortRespData,
DWORD cbSize,
PDWORD cbSizeNeeded)
{
return m_pPortMgr->ConfigurePort (pXcvConfigurePortReqData,
pXcvAddPortRespData,
cbSize,
cbSizeNeeded);
}
HANDLE
CInetMonPort::CreateTerminateEvent (
VOID)
{
if (!m_hTerminateEvent) {
//
// Craete a manual reset event since multiple threads may be waiting
//
m_hTerminateEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
}
return m_hTerminateEvent;
}
BOOL
CInetMonPort::WaitForTermination (
DWORD dwWaitTime)
{
BOOL bTerminate = FALSE;
semLeaveCrit();
DWORD dwRet = WaitForSingleObject (m_hTerminateEvent, dwWaitTime);
if (dwRet == WAIT_OBJECT_0 || dwRet == WAIT_FAILED)
bTerminate = TRUE;
semEnterCrit();
return bTerminate;
}