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.
617 lines
14 KiB
617 lines
14 KiB
/*++
|
|
|
|
Copyright (c) 1994 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
view.cxx
|
|
|
|
Abstract:
|
|
|
|
Functions to manage VIEW 'object's
|
|
|
|
Contents:
|
|
CreateView
|
|
(DestroyView)
|
|
FindViewByHandle
|
|
ReferenceView
|
|
DereferenceView
|
|
DereferenceViewByHandle
|
|
|
|
Author:
|
|
|
|
Richard L Firth (rfirth) 17-Oct-1994
|
|
|
|
Environment:
|
|
|
|
Win/32 user-mode DLL
|
|
|
|
Revision History:
|
|
|
|
17-Oct-1994 rfirth
|
|
Created
|
|
|
|
--*/
|
|
|
|
#include <wininetp.h>
|
|
#include "gfrapih.h"
|
|
|
|
//
|
|
// private prototypes
|
|
//
|
|
|
|
PRIVATE
|
|
VOID
|
|
DestroyView(
|
|
IN LPVIEW_INFO ViewInfo
|
|
);
|
|
|
|
//
|
|
// private data
|
|
//
|
|
|
|
DEBUG_DATA(LONG, NumberOfViews, 0);
|
|
|
|
//
|
|
// functions
|
|
//
|
|
|
|
|
|
LPVIEW_INFO
|
|
CreateView(
|
|
IN LPSESSION_INFO SessionInfo,
|
|
IN VIEW_TYPE ViewType,
|
|
IN LPSTR Request,
|
|
OUT LPDWORD Error,
|
|
OUT LPBOOL Cloned
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Creates or clones a VIEW_INFO. There will only ever be one VIEW_INFO for a
|
|
particular request to the same server. Other requests for the same data
|
|
just reference the first view
|
|
|
|
Arguments:
|
|
|
|
SessionInfo - pointer to SESSION_INFO describing gopher server
|
|
|
|
ViewType - type of view - ViewTypeFile or ViewTypeFind
|
|
|
|
Request - gopher request string
|
|
|
|
Error - returned error
|
|
|
|
Cloned - returned TRUE if we cloned the view
|
|
|
|
Return Value:
|
|
|
|
LPVIEW_INFO
|
|
Success - pointer to created or cloned view; check Cloned
|
|
|
|
Failure - NULL
|
|
|
|
--*/
|
|
|
|
{
|
|
LPVIEW_INFO viewInfo;
|
|
DWORD error;
|
|
|
|
DEBUG_ENTER((DBG_GOPHER,
|
|
Pointer,
|
|
"CreateView",
|
|
"%x, %x, %q, %x, %x",
|
|
SessionInfo,
|
|
ViewType,
|
|
Request,
|
|
Error,
|
|
Cloned
|
|
));
|
|
|
|
//
|
|
// in both cases, we need a new VIEW_INFO
|
|
//
|
|
|
|
viewInfo = NEW(VIEW_INFO);
|
|
if (viewInfo != NULL) {
|
|
error = AllocateHandle((LPVOID)viewInfo, &viewInfo->Handle);
|
|
if (error == ERROR_SUCCESS) {
|
|
viewInfo->Request = NEW_STRING(Request);
|
|
viewInfo->RequestLength = strlen(Request);
|
|
if (viewInfo->Request != NULL) {
|
|
InitializeListHead(&viewInfo->List);
|
|
viewInfo->ViewType = ViewType;
|
|
} else {
|
|
error = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
}
|
|
} else {
|
|
error = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
//
|
|
// now search for an already existing view
|
|
//
|
|
|
|
if (error == ERROR_SUCCESS) {
|
|
|
|
PLIST_ENTRY listPtr;
|
|
PLIST_ENTRY list;
|
|
PLIST_ENTRY listAddress;
|
|
BOOL found;
|
|
LPBUFFER_INFO bufferInfo;
|
|
|
|
AcquireViewLock(SessionInfo, ViewType);
|
|
|
|
//
|
|
// new scheme: we now only buffer Find views: we always create a new
|
|
// file request because file requests go straight to the user buffer
|
|
// (keeping the connection alive until the caller finishes reading)
|
|
//
|
|
|
|
found = FALSE;
|
|
if (ViewType == ViewTypeFind) {
|
|
// list = SessionInfo->FindList.List.Flink;
|
|
listAddress = &SessionInfo->FindList.List;
|
|
// for (listPtr = list; listPtr != listAddress; listPtr = listPtr->Flink) {
|
|
// if (!STRICMP(((LPVIEW_INFO)listPtr)->Request, Request)) {
|
|
// found = TRUE;
|
|
// break;
|
|
// }
|
|
// }
|
|
} else {
|
|
listAddress = &SessionInfo->FileList.List;
|
|
}
|
|
|
|
//
|
|
// create a buffer info, or get a pointer to the current buffer info
|
|
// depending on whether we located a view of the same request at the
|
|
// same server
|
|
//
|
|
/* N.B. found is never true because the above code is commented out. */
|
|
if (found) {
|
|
// bufferInfo = ((LPVIEW_INFO)listPtr)->BufferInfo;
|
|
|
|
//
|
|
// this is a clone. If there is a thread which is concurrently
|
|
// requesting the data - right now - then we must wait on the
|
|
// RequestEvent until gives us the green light. If there is no
|
|
// RequestEvent then the data has already been received and
|
|
// some kind soul has seen fit to close the request handle. I.e.
|
|
// we don't have to wait
|
|
//
|
|
|
|
// if (bufferInfo->RequestEvent != NULL) {
|
|
// ++bufferInfo->RequestWaiters;
|
|
// }
|
|
|
|
*Cloned = TRUE;
|
|
} else {
|
|
bufferInfo = CreateBuffer(&error);
|
|
if (bufferInfo != NULL) {
|
|
*Cloned = FALSE;
|
|
}
|
|
}
|
|
|
|
if (error == ERROR_SUCCESS) {
|
|
|
|
//
|
|
// whilst holding the view lock, we add the view to the list, set
|
|
// the view's reference count to 1, increment the session's
|
|
// reference count, and point the view at the session
|
|
//
|
|
|
|
viewInfo->ReferenceCount = 1;
|
|
viewInfo->BufferInfo = bufferInfo;
|
|
viewInfo->SessionInfo = SessionInfo;
|
|
|
|
//
|
|
// also whilst holding the view lock, we increment the reference
|
|
// count on the buffer info
|
|
//
|
|
|
|
ReferenceBuffer(bufferInfo);
|
|
InsertHeadList(listAddress, &viewInfo->List);
|
|
|
|
//
|
|
// N.B. this will acquire the session list lock (then release it)
|
|
//
|
|
|
|
ReferenceSession(SessionInfo);
|
|
|
|
VIEW_CREATED();
|
|
|
|
}
|
|
|
|
ReleaseViewLock(SessionInfo, ViewType);
|
|
}
|
|
|
|
if (error != ERROR_SUCCESS) {
|
|
if (viewInfo != NULL) {
|
|
viewInfo = DereferenceView(viewInfo);
|
|
|
|
INET_ASSERT(viewInfo == NULL);
|
|
|
|
}
|
|
}
|
|
|
|
DEBUG_PRINT(VIEW,
|
|
INFO,
|
|
("ViewInfo %x is %scloned\n",
|
|
viewInfo,
|
|
(*Cloned == TRUE) ? "" : "NOT "
|
|
));
|
|
|
|
DEBUG_ERROR(SESSION, error);
|
|
|
|
*Error = error;
|
|
|
|
DEBUG_LEAVE(viewInfo);
|
|
|
|
return viewInfo;
|
|
}
|
|
|
|
|
|
PRIVATE
|
|
VOID
|
|
DestroyView(
|
|
IN LPVIEW_INFO ViewInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Destroys a VIEW_INFO after freeing all resources that it owns. ViewInfo
|
|
must have been removed from the relevant session view list by the time
|
|
this function is called
|
|
|
|
Arguments:
|
|
|
|
ViewInfo - pointer to VIEW_INFO to destroy
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
DEBUG_ENTER((DBG_GOPHER,
|
|
None,
|
|
"DestroyView",
|
|
"%x",
|
|
ViewInfo
|
|
));
|
|
|
|
INET_ASSERT(ViewInfo != NULL);
|
|
INET_ASSERT(ViewInfo->ReferenceCount == 0);
|
|
|
|
if (ViewInfo->Handle) {
|
|
|
|
DWORD error;
|
|
|
|
error = FreeHandle(ViewInfo->Handle);
|
|
|
|
INET_ASSERT(error == ERROR_SUCCESS);
|
|
|
|
}
|
|
|
|
if (ViewInfo->Request) {
|
|
DEL_STRING(ViewInfo->Request);
|
|
}
|
|
|
|
DEL(ViewInfo);
|
|
|
|
VIEW_DESTROYED();
|
|
|
|
DEBUG_LEAVE(0);
|
|
}
|
|
|
|
|
|
LPVIEW_INFO
|
|
FindViewByHandle(
|
|
IN HANDLE Handle,
|
|
IN VIEW_TYPE ViewType
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Finds a VIEW_INFO given a handle. If found, the VIEW_INFO reference count
|
|
is incremented
|
|
|
|
Arguments:
|
|
|
|
Handle - handle associated with VIEW_INFO
|
|
|
|
ViewType - identifies which list to look on
|
|
|
|
Return Value:
|
|
|
|
LPVIEW_INFO
|
|
Success - pointer to VIEW_INFO; Session points at SESSION_INFO
|
|
|
|
Failure - NULL
|
|
|
|
--*/
|
|
|
|
{
|
|
LPVIEW_INFO viewInfo;
|
|
LPSESSION_INFO sessionInfo;
|
|
BOOL found = FALSE;
|
|
|
|
DEBUG_ENTER((DBG_GOPHER,
|
|
Pointer,
|
|
"FindViewByHandle",
|
|
"%x, %x",
|
|
Handle,
|
|
ViewType
|
|
));
|
|
|
|
AcquireSessionLock();
|
|
|
|
sessionInfo = (LPSESSION_INFO)SessionList.List.Flink;
|
|
while (sessionInfo != (LPSESSION_INFO)&SessionList.List) {
|
|
|
|
PLIST_ENTRY endOfList;
|
|
PLIST_ENTRY list;
|
|
|
|
AcquireViewLock(sessionInfo, ViewType);
|
|
|
|
INET_ASSERT((ViewType == ViewTypeFile) || (ViewType == ViewTypeFind));
|
|
|
|
if (ViewType == ViewTypeFile) {
|
|
list = sessionInfo->FileList.List.Flink;
|
|
endOfList = &sessionInfo->FileList.List;
|
|
} else {
|
|
list = sessionInfo->FindList.List.Flink;
|
|
endOfList = &sessionInfo->FindList.List;
|
|
}
|
|
|
|
for (viewInfo = (LPVIEW_INFO)list;
|
|
viewInfo != (LPVIEW_INFO)endOfList;
|
|
viewInfo = (LPVIEW_INFO)(viewInfo->List.Flink)) {
|
|
|
|
if (viewInfo->Handle == Handle) {
|
|
|
|
//
|
|
// we found the one we were looking for. Make sure that we
|
|
// increase the reference count before we release the lock
|
|
//
|
|
|
|
INET_ASSERT(viewInfo->ViewType == ViewType);
|
|
|
|
ReferenceView(viewInfo);
|
|
found = TRUE;
|
|
break; // out of for()
|
|
}
|
|
}
|
|
|
|
ReleaseViewLock(sessionInfo, ViewType);
|
|
|
|
if (found) {
|
|
break; // out of while()
|
|
} else {
|
|
sessionInfo = (LPSESSION_INFO)sessionInfo->List.Flink;
|
|
}
|
|
}
|
|
if (!found) {
|
|
viewInfo = NULL;
|
|
}
|
|
|
|
ReleaseSessionLock();
|
|
|
|
DEBUG_LEAVE(viewInfo);
|
|
|
|
return viewInfo;
|
|
}
|
|
|
|
|
|
VOID
|
|
ReferenceView(
|
|
IN LPVIEW_INFO ViewInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Increments reference count on VIEW_INFO
|
|
|
|
Arguments:
|
|
|
|
ViewInfo - pointer to VIEW_INFO to reference
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
INET_ASSERT(ViewInfo != NULL);
|
|
|
|
InterlockedIncrement(&ViewInfo->ReferenceCount);
|
|
|
|
DEBUG_PRINT(REFCOUNT,
|
|
INFO,
|
|
("ReferenceView(): ViewInfo{%x}->ReferenceCount = %d\n",
|
|
ViewInfo,
|
|
ViewInfo->ReferenceCount
|
|
));
|
|
}
|
|
|
|
|
|
LPVIEW_INFO
|
|
DereferenceView(
|
|
IN LPVIEW_INFO ViewInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Reduces the reference count of a VIEW_INFO by 1. If it goes to zero, the
|
|
VIEW_INFO is removed from its owner's list and is deallocated
|
|
|
|
Arguments:
|
|
|
|
ViewInfo - pointer to VIEW_INFO to dereference
|
|
|
|
Return Value:
|
|
|
|
LPVIEW_INFO
|
|
NULL - ViewInfo was deleted
|
|
|
|
!NULL - Reference count still >0
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOL deleteViewInfo;
|
|
|
|
DEBUG_ENTER((DBG_GOPHER,
|
|
Pointer,
|
|
"DereferenceView",
|
|
"%x",
|
|
ViewInfo
|
|
));
|
|
|
|
INET_ASSERT(ViewInfo != NULL);
|
|
INET_ASSERT(ViewInfo->ReferenceCount >= 1);
|
|
|
|
deleteViewInfo = FALSE;
|
|
if (InterlockedDecrement(&ViewInfo->ReferenceCount) == 0) {
|
|
|
|
//
|
|
// perform any reference count manipulation within the view lock
|
|
//
|
|
|
|
AcquireViewLock(ViewInfo->SessionInfo, ViewInfo->ViewType);
|
|
|
|
//
|
|
// if the reference count is still zero, then it is safe to remove it
|
|
// from the SESSION_INFO, and delete
|
|
//
|
|
|
|
if (ViewInfo->ReferenceCount == 0) {
|
|
|
|
RemoveEntryList(&ViewInfo->List);
|
|
|
|
INET_ASSERT(ViewInfo->BufferInfo != NULL);
|
|
|
|
//
|
|
// perform buffer info reference count manipulation within the view
|
|
// lock
|
|
//
|
|
|
|
DereferenceBuffer(ViewInfo->BufferInfo);
|
|
deleteViewInfo = TRUE;
|
|
}
|
|
|
|
ReleaseViewLock(ViewInfo->SessionInfo, ViewInfo->ViewType);
|
|
} else {
|
|
|
|
DEBUG_PRINT(REFCOUNT,
|
|
INFO,
|
|
("DereferenceView(): ViewInfo{%x}->ReferenceCount = %d\n",
|
|
ViewInfo,
|
|
ViewInfo->ReferenceCount
|
|
));
|
|
|
|
}
|
|
|
|
//
|
|
// safe to delete this view info outside of the view lock
|
|
//
|
|
|
|
if (deleteViewInfo) {
|
|
|
|
LPSESSION_INFO sessionInfo;
|
|
|
|
sessionInfo = ViewInfo->SessionInfo;
|
|
|
|
DestroyView(ViewInfo);
|
|
ViewInfo = NULL;
|
|
DereferenceSession(sessionInfo);
|
|
}
|
|
|
|
DEBUG_LEAVE(ViewInfo);
|
|
|
|
return ViewInfo;
|
|
}
|
|
|
|
|
|
DWORD
|
|
DereferenceViewByHandle(
|
|
IN HINTERNET Handle,
|
|
IN VIEW_TYPE ViewType
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Atomically searches for the VIEW_INFO identified by Handle and if found
|
|
dereferences it. This may cause the VIEW_INFO to be deleted
|
|
|
|
Arguments:
|
|
|
|
Handle - identifying VIEW_INFO to dereference
|
|
|
|
ViewType - identifies which list to look on
|
|
|
|
Return Value:
|
|
|
|
DWORD
|
|
Success - ERROR_SUCCESS
|
|
Handle was dereferenced, but not necessarily deleted
|
|
|
|
Failure - ERROR_INVALID_HANDLE
|
|
Couldn't find Handle
|
|
|
|
--*/
|
|
|
|
{
|
|
LPVIEW_INFO viewInfo;
|
|
DWORD error;
|
|
|
|
DEBUG_ENTER((DBG_GOPHER,
|
|
Dword,
|
|
"DereferenceViewByHandle",
|
|
"%x",
|
|
Handle
|
|
));
|
|
|
|
//
|
|
// we have to perform this operation whilst holding the session lock. We
|
|
// find the VIEW_INFO then dereference it twice - once to counteract the
|
|
// reference added by FindViewByHandle(), and once for the reference we
|
|
// were asked to remove by the caller.
|
|
//
|
|
// Since we are holding the Session lock, no other thread can dereference
|
|
// the VIEW_INFO or SESSION_INFO. The second derereference may cause the
|
|
// SESSION_INFO to be destroyed
|
|
//
|
|
|
|
AcquireSessionLock();
|
|
|
|
viewInfo = FindViewByHandle(Handle, ViewType);
|
|
if (viewInfo != NULL) {
|
|
DereferenceView(viewInfo);
|
|
DereferenceView(viewInfo);
|
|
error = ERROR_SUCCESS;
|
|
} else {
|
|
error = ERROR_INVALID_HANDLE;
|
|
}
|
|
|
|
ReleaseSessionLock();
|
|
|
|
DEBUG_LEAVE(error);
|
|
|
|
return error;
|
|
}
|