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.

617 lines
14 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name:
  4. view.cxx
  5. Abstract:
  6. Functions to manage VIEW 'object's
  7. Contents:
  8. CreateView
  9. (DestroyView)
  10. FindViewByHandle
  11. ReferenceView
  12. DereferenceView
  13. DereferenceViewByHandle
  14. Author:
  15. Richard L Firth (rfirth) 17-Oct-1994
  16. Environment:
  17. Win/32 user-mode DLL
  18. Revision History:
  19. 17-Oct-1994 rfirth
  20. Created
  21. --*/
  22. #include <wininetp.h>
  23. #include "gfrapih.h"
  24. //
  25. // private prototypes
  26. //
  27. PRIVATE
  28. VOID
  29. DestroyView(
  30. IN LPVIEW_INFO ViewInfo
  31. );
  32. //
  33. // private data
  34. //
  35. DEBUG_DATA(LONG, NumberOfViews, 0);
  36. //
  37. // functions
  38. //
  39. LPVIEW_INFO
  40. CreateView(
  41. IN LPSESSION_INFO SessionInfo,
  42. IN VIEW_TYPE ViewType,
  43. IN LPSTR Request,
  44. OUT LPDWORD Error,
  45. OUT LPBOOL Cloned
  46. )
  47. /*++
  48. Routine Description:
  49. Creates or clones a VIEW_INFO. There will only ever be one VIEW_INFO for a
  50. particular request to the same server. Other requests for the same data
  51. just reference the first view
  52. Arguments:
  53. SessionInfo - pointer to SESSION_INFO describing gopher server
  54. ViewType - type of view - ViewTypeFile or ViewTypeFind
  55. Request - gopher request string
  56. Error - returned error
  57. Cloned - returned TRUE if we cloned the view
  58. Return Value:
  59. LPVIEW_INFO
  60. Success - pointer to created or cloned view; check Cloned
  61. Failure - NULL
  62. --*/
  63. {
  64. LPVIEW_INFO viewInfo;
  65. DWORD error;
  66. DEBUG_ENTER((DBG_GOPHER,
  67. Pointer,
  68. "CreateView",
  69. "%x, %x, %q, %x, %x",
  70. SessionInfo,
  71. ViewType,
  72. Request,
  73. Error,
  74. Cloned
  75. ));
  76. //
  77. // in both cases, we need a new VIEW_INFO
  78. //
  79. viewInfo = NEW(VIEW_INFO);
  80. if (viewInfo != NULL) {
  81. error = AllocateHandle((LPVOID)viewInfo, &viewInfo->Handle);
  82. if (error == ERROR_SUCCESS) {
  83. viewInfo->Request = NEW_STRING(Request);
  84. viewInfo->RequestLength = strlen(Request);
  85. if (viewInfo->Request != NULL) {
  86. InitializeListHead(&viewInfo->List);
  87. viewInfo->ViewType = ViewType;
  88. } else {
  89. error = ERROR_NOT_ENOUGH_MEMORY;
  90. }
  91. }
  92. } else {
  93. error = ERROR_NOT_ENOUGH_MEMORY;
  94. }
  95. //
  96. // now search for an already existing view
  97. //
  98. if (error == ERROR_SUCCESS) {
  99. PLIST_ENTRY listPtr;
  100. PLIST_ENTRY list;
  101. PLIST_ENTRY listAddress;
  102. BOOL found;
  103. LPBUFFER_INFO bufferInfo;
  104. AcquireViewLock(SessionInfo, ViewType);
  105. //
  106. // new scheme: we now only buffer Find views: we always create a new
  107. // file request because file requests go straight to the user buffer
  108. // (keeping the connection alive until the caller finishes reading)
  109. //
  110. found = FALSE;
  111. if (ViewType == ViewTypeFind) {
  112. // list = SessionInfo->FindList.List.Flink;
  113. listAddress = &SessionInfo->FindList.List;
  114. // for (listPtr = list; listPtr != listAddress; listPtr = listPtr->Flink) {
  115. // if (!STRICMP(((LPVIEW_INFO)listPtr)->Request, Request)) {
  116. // found = TRUE;
  117. // break;
  118. // }
  119. // }
  120. } else {
  121. listAddress = &SessionInfo->FileList.List;
  122. }
  123. //
  124. // create a buffer info, or get a pointer to the current buffer info
  125. // depending on whether we located a view of the same request at the
  126. // same server
  127. //
  128. /* N.B. found is never true because the above code is commented out. */
  129. if (found) {
  130. // bufferInfo = ((LPVIEW_INFO)listPtr)->BufferInfo;
  131. //
  132. // this is a clone. If there is a thread which is concurrently
  133. // requesting the data - right now - then we must wait on the
  134. // RequestEvent until gives us the green light. If there is no
  135. // RequestEvent then the data has already been received and
  136. // some kind soul has seen fit to close the request handle. I.e.
  137. // we don't have to wait
  138. //
  139. // if (bufferInfo->RequestEvent != NULL) {
  140. // ++bufferInfo->RequestWaiters;
  141. // }
  142. *Cloned = TRUE;
  143. } else {
  144. bufferInfo = CreateBuffer(&error);
  145. if (bufferInfo != NULL) {
  146. *Cloned = FALSE;
  147. }
  148. }
  149. if (error == ERROR_SUCCESS) {
  150. //
  151. // whilst holding the view lock, we add the view to the list, set
  152. // the view's reference count to 1, increment the session's
  153. // reference count, and point the view at the session
  154. //
  155. viewInfo->ReferenceCount = 1;
  156. viewInfo->BufferInfo = bufferInfo;
  157. viewInfo->SessionInfo = SessionInfo;
  158. //
  159. // also whilst holding the view lock, we increment the reference
  160. // count on the buffer info
  161. //
  162. ReferenceBuffer(bufferInfo);
  163. InsertHeadList(listAddress, &viewInfo->List);
  164. //
  165. // N.B. this will acquire the session list lock (then release it)
  166. //
  167. ReferenceSession(SessionInfo);
  168. VIEW_CREATED();
  169. }
  170. ReleaseViewLock(SessionInfo, ViewType);
  171. }
  172. if (error != ERROR_SUCCESS) {
  173. if (viewInfo != NULL) {
  174. viewInfo = DereferenceView(viewInfo);
  175. INET_ASSERT(viewInfo == NULL);
  176. }
  177. }
  178. DEBUG_PRINT(VIEW,
  179. INFO,
  180. ("ViewInfo %x is %scloned\n",
  181. viewInfo,
  182. (*Cloned == TRUE) ? "" : "NOT "
  183. ));
  184. DEBUG_ERROR(SESSION, error);
  185. *Error = error;
  186. DEBUG_LEAVE(viewInfo);
  187. return viewInfo;
  188. }
  189. PRIVATE
  190. VOID
  191. DestroyView(
  192. IN LPVIEW_INFO ViewInfo
  193. )
  194. /*++
  195. Routine Description:
  196. Destroys a VIEW_INFO after freeing all resources that it owns. ViewInfo
  197. must have been removed from the relevant session view list by the time
  198. this function is called
  199. Arguments:
  200. ViewInfo - pointer to VIEW_INFO to destroy
  201. Return Value:
  202. None.
  203. --*/
  204. {
  205. DEBUG_ENTER((DBG_GOPHER,
  206. None,
  207. "DestroyView",
  208. "%x",
  209. ViewInfo
  210. ));
  211. INET_ASSERT(ViewInfo != NULL);
  212. INET_ASSERT(ViewInfo->ReferenceCount == 0);
  213. if (ViewInfo->Handle) {
  214. DWORD error;
  215. error = FreeHandle(ViewInfo->Handle);
  216. INET_ASSERT(error == ERROR_SUCCESS);
  217. }
  218. if (ViewInfo->Request) {
  219. DEL_STRING(ViewInfo->Request);
  220. }
  221. DEL(ViewInfo);
  222. VIEW_DESTROYED();
  223. DEBUG_LEAVE(0);
  224. }
  225. LPVIEW_INFO
  226. FindViewByHandle(
  227. IN HANDLE Handle,
  228. IN VIEW_TYPE ViewType
  229. )
  230. /*++
  231. Routine Description:
  232. Finds a VIEW_INFO given a handle. If found, the VIEW_INFO reference count
  233. is incremented
  234. Arguments:
  235. Handle - handle associated with VIEW_INFO
  236. ViewType - identifies which list to look on
  237. Return Value:
  238. LPVIEW_INFO
  239. Success - pointer to VIEW_INFO; Session points at SESSION_INFO
  240. Failure - NULL
  241. --*/
  242. {
  243. LPVIEW_INFO viewInfo;
  244. LPSESSION_INFO sessionInfo;
  245. BOOL found = FALSE;
  246. DEBUG_ENTER((DBG_GOPHER,
  247. Pointer,
  248. "FindViewByHandle",
  249. "%x, %x",
  250. Handle,
  251. ViewType
  252. ));
  253. AcquireSessionLock();
  254. sessionInfo = (LPSESSION_INFO)SessionList.List.Flink;
  255. while (sessionInfo != (LPSESSION_INFO)&SessionList.List) {
  256. PLIST_ENTRY endOfList;
  257. PLIST_ENTRY list;
  258. AcquireViewLock(sessionInfo, ViewType);
  259. INET_ASSERT((ViewType == ViewTypeFile) || (ViewType == ViewTypeFind));
  260. if (ViewType == ViewTypeFile) {
  261. list = sessionInfo->FileList.List.Flink;
  262. endOfList = &sessionInfo->FileList.List;
  263. } else {
  264. list = sessionInfo->FindList.List.Flink;
  265. endOfList = &sessionInfo->FindList.List;
  266. }
  267. for (viewInfo = (LPVIEW_INFO)list;
  268. viewInfo != (LPVIEW_INFO)endOfList;
  269. viewInfo = (LPVIEW_INFO)(viewInfo->List.Flink)) {
  270. if (viewInfo->Handle == Handle) {
  271. //
  272. // we found the one we were looking for. Make sure that we
  273. // increase the reference count before we release the lock
  274. //
  275. INET_ASSERT(viewInfo->ViewType == ViewType);
  276. ReferenceView(viewInfo);
  277. found = TRUE;
  278. break; // out of for()
  279. }
  280. }
  281. ReleaseViewLock(sessionInfo, ViewType);
  282. if (found) {
  283. break; // out of while()
  284. } else {
  285. sessionInfo = (LPSESSION_INFO)sessionInfo->List.Flink;
  286. }
  287. }
  288. if (!found) {
  289. viewInfo = NULL;
  290. }
  291. ReleaseSessionLock();
  292. DEBUG_LEAVE(viewInfo);
  293. return viewInfo;
  294. }
  295. VOID
  296. ReferenceView(
  297. IN LPVIEW_INFO ViewInfo
  298. )
  299. /*++
  300. Routine Description:
  301. Increments reference count on VIEW_INFO
  302. Arguments:
  303. ViewInfo - pointer to VIEW_INFO to reference
  304. Return Value:
  305. None.
  306. --*/
  307. {
  308. INET_ASSERT(ViewInfo != NULL);
  309. InterlockedIncrement(&ViewInfo->ReferenceCount);
  310. DEBUG_PRINT(REFCOUNT,
  311. INFO,
  312. ("ReferenceView(): ViewInfo{%x}->ReferenceCount = %d\n",
  313. ViewInfo,
  314. ViewInfo->ReferenceCount
  315. ));
  316. }
  317. LPVIEW_INFO
  318. DereferenceView(
  319. IN LPVIEW_INFO ViewInfo
  320. )
  321. /*++
  322. Routine Description:
  323. Reduces the reference count of a VIEW_INFO by 1. If it goes to zero, the
  324. VIEW_INFO is removed from its owner's list and is deallocated
  325. Arguments:
  326. ViewInfo - pointer to VIEW_INFO to dereference
  327. Return Value:
  328. LPVIEW_INFO
  329. NULL - ViewInfo was deleted
  330. !NULL - Reference count still >0
  331. --*/
  332. {
  333. BOOL deleteViewInfo;
  334. DEBUG_ENTER((DBG_GOPHER,
  335. Pointer,
  336. "DereferenceView",
  337. "%x",
  338. ViewInfo
  339. ));
  340. INET_ASSERT(ViewInfo != NULL);
  341. INET_ASSERT(ViewInfo->ReferenceCount >= 1);
  342. deleteViewInfo = FALSE;
  343. if (InterlockedDecrement(&ViewInfo->ReferenceCount) == 0) {
  344. //
  345. // perform any reference count manipulation within the view lock
  346. //
  347. AcquireViewLock(ViewInfo->SessionInfo, ViewInfo->ViewType);
  348. //
  349. // if the reference count is still zero, then it is safe to remove it
  350. // from the SESSION_INFO, and delete
  351. //
  352. if (ViewInfo->ReferenceCount == 0) {
  353. RemoveEntryList(&ViewInfo->List);
  354. INET_ASSERT(ViewInfo->BufferInfo != NULL);
  355. //
  356. // perform buffer info reference count manipulation within the view
  357. // lock
  358. //
  359. DereferenceBuffer(ViewInfo->BufferInfo);
  360. deleteViewInfo = TRUE;
  361. }
  362. ReleaseViewLock(ViewInfo->SessionInfo, ViewInfo->ViewType);
  363. } else {
  364. DEBUG_PRINT(REFCOUNT,
  365. INFO,
  366. ("DereferenceView(): ViewInfo{%x}->ReferenceCount = %d\n",
  367. ViewInfo,
  368. ViewInfo->ReferenceCount
  369. ));
  370. }
  371. //
  372. // safe to delete this view info outside of the view lock
  373. //
  374. if (deleteViewInfo) {
  375. LPSESSION_INFO sessionInfo;
  376. sessionInfo = ViewInfo->SessionInfo;
  377. DestroyView(ViewInfo);
  378. ViewInfo = NULL;
  379. DereferenceSession(sessionInfo);
  380. }
  381. DEBUG_LEAVE(ViewInfo);
  382. return ViewInfo;
  383. }
  384. DWORD
  385. DereferenceViewByHandle(
  386. IN HINTERNET Handle,
  387. IN VIEW_TYPE ViewType
  388. )
  389. /*++
  390. Routine Description:
  391. Atomically searches for the VIEW_INFO identified by Handle and if found
  392. dereferences it. This may cause the VIEW_INFO to be deleted
  393. Arguments:
  394. Handle - identifying VIEW_INFO to dereference
  395. ViewType - identifies which list to look on
  396. Return Value:
  397. DWORD
  398. Success - ERROR_SUCCESS
  399. Handle was dereferenced, but not necessarily deleted
  400. Failure - ERROR_INVALID_HANDLE
  401. Couldn't find Handle
  402. --*/
  403. {
  404. LPVIEW_INFO viewInfo;
  405. DWORD error;
  406. DEBUG_ENTER((DBG_GOPHER,
  407. Dword,
  408. "DereferenceViewByHandle",
  409. "%x",
  410. Handle
  411. ));
  412. //
  413. // we have to perform this operation whilst holding the session lock. We
  414. // find the VIEW_INFO then dereference it twice - once to counteract the
  415. // reference added by FindViewByHandle(), and once for the reference we
  416. // were asked to remove by the caller.
  417. //
  418. // Since we are holding the Session lock, no other thread can dereference
  419. // the VIEW_INFO or SESSION_INFO. The second derereference may cause the
  420. // SESSION_INFO to be destroyed
  421. //
  422. AcquireSessionLock();
  423. viewInfo = FindViewByHandle(Handle, ViewType);
  424. if (viewInfo != NULL) {
  425. DereferenceView(viewInfo);
  426. DereferenceView(viewInfo);
  427. error = ERROR_SUCCESS;
  428. } else {
  429. error = ERROR_INVALID_HANDLE;
  430. }
  431. ReleaseSessionLock();
  432. DEBUG_LEAVE(error);
  433. return error;
  434. }