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.

981 lines
21 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name:
  4. session.cxx
  5. Abstract:
  6. Contains functions for maintaining the global session list and SESSION_INFO
  7. specific functions
  8. Contents:
  9. AcquireSessionLock
  10. ReleaseSessionLock
  11. CleanupSessions
  12. (CleanupViewList)
  13. FindOrCreateSession
  14. (CreateSession)
  15. (DestroySession)
  16. ReferenceSession
  17. DereferenceSession
  18. AcquireViewLock
  19. ReleaseViewLock
  20. GopherTransaction
  21. IsServerGopherPlus
  22. IsGopherPlusSession
  23. SearchSessionsForAttribute
  24. Author:
  25. Richard L Firth (rfirth) 19-Oct-1994
  26. Environment:
  27. Win32 DLL
  28. Revision History:
  29. 19-Oct-1994 rfirth
  30. Created
  31. --*/
  32. #include <wininetp.h>
  33. #include "gfrapih.h"
  34. //
  35. // manifests
  36. //
  37. #define NULL_HANDLE ((HANDLE)0)
  38. //
  39. // private prototypes
  40. //
  41. PRIVATE
  42. VOID
  43. CleanupViewList(
  44. IN LPSESSION_INFO SessionInfo,
  45. IN VIEW_TYPE ViewType
  46. );
  47. PRIVATE
  48. LPSESSION_INFO
  49. CreateSession(
  50. IN LPSTR Host,
  51. IN DWORD Port,
  52. OUT LPDWORD Error
  53. );
  54. PRIVATE
  55. VOID
  56. DestroySession(
  57. IN LPSESSION_INFO SessionInfo
  58. );
  59. //
  60. // data
  61. //
  62. PUBLIC SERIALIZED_LIST SessionList;
  63. DEBUG_DATA(LONG, NumberOfSessions, 0);
  64. //
  65. // functions
  66. //
  67. VOID
  68. AcquireSessionLock(
  69. VOID
  70. )
  71. /*++
  72. Routine Description:
  73. Acquires the SESSION_INFO list lock
  74. Arguments:
  75. None.
  76. Return Value:
  77. None.
  78. --*/
  79. {
  80. LockSerializedList(&SessionList);
  81. }
  82. VOID
  83. ReleaseSessionLock(
  84. VOID
  85. )
  86. /*++
  87. Routine Description:
  88. Releases the SESSION_INFO list lock
  89. Arguments:
  90. None.
  91. Return Value:
  92. None.
  93. --*/
  94. {
  95. UnlockSerializedList(&SessionList);
  96. }
  97. VOID
  98. CleanupSessions(
  99. VOID
  100. )
  101. /*++
  102. Routine Description:
  103. Tries to Remove all SESSION_INFOs from the session list, and terminate all
  104. active operations
  105. Arguments:
  106. None.
  107. Return Value:
  108. None.
  109. --*/
  110. {
  111. DEBUG_ENTER((DBG_GOPHER,
  112. None,
  113. "CleanupSessions",
  114. NULL
  115. ));
  116. while (1) {
  117. LPSESSION_INFO sessionInfo;
  118. //
  119. // find the next SESSION_INFO to delete. Because we may cause the entry
  120. // currently at the head of the list to be deleted during this loop, we
  121. // must walk the list each time. We may also end up with a list of items
  122. // that are marked for delete, but cannot be deleted until the threads
  123. // that own them complete their current operations
  124. //
  125. AcquireSessionLock();
  126. for (sessionInfo = (LPSESSION_INFO)HeadOfSerializedList(&SessionList);
  127. (sessionInfo != (LPSESSION_INFO)&SessionList.List.Flink)
  128. && !(sessionInfo->Flags & SI_CLEANUP);
  129. sessionInfo = (LPSESSION_INFO)sessionInfo->List.Flink) {
  130. //
  131. // empty loop
  132. //
  133. }
  134. if (sessionInfo == (LPSESSION_INFO)&SessionList.List.Flink) {
  135. DEBUG_PRINT(SESSION,
  136. INFO,
  137. ("end of list\n"
  138. ));
  139. ReleaseSessionLock();
  140. break;
  141. }
  142. //
  143. // mark this SESSION_INFO as being cleaned up, in case it does not get
  144. // removed from the list (some other thread is accessing it)
  145. //
  146. sessionInfo->Flags |= SI_CLEANUP;
  147. //
  148. // increment the reference count so that we can release the list lock
  149. //
  150. ReferenceSession(sessionInfo);
  151. ReleaseSessionLock();
  152. //
  153. // now we have a pointer to a SESSION_INFO that cannot be deleted until
  154. // after we have dereferenced it. Dereference any items in the Find and
  155. // File lists. Note that had we not referenced the SESSION_INFO above,
  156. // it might have gotten deleted after cleaning up the Find list, and we
  157. // would be in danger of passing a bogus pointer to the second cleanup
  158. // view list call below
  159. //
  160. CleanupViewList(sessionInfo, ViewTypeFind);
  161. CleanupViewList(sessionInfo, ViewTypeFile);
  162. //
  163. // finally, dereference the session. This may cause it to be deleted,
  164. // and for the list to be changed
  165. //
  166. DereferenceSession(sessionInfo);
  167. }
  168. DEBUG_LEAVE(0);
  169. }
  170. PRIVATE
  171. VOID
  172. CleanupViewList(
  173. IN LPSESSION_INFO SessionInfo,
  174. IN VIEW_TYPE ViewType
  175. )
  176. /*++
  177. Routine Description:
  178. Cleans up a VIEW_INFO list on a SESSION_INFO
  179. Arguments:
  180. SessionInfo - pointer to SESSION_INFO we are cleaning up
  181. ViewType - identifies which VIEW_INFO list to clean up
  182. Return Value:
  183. None.
  184. --*/
  185. {
  186. DEBUG_ENTER((DBG_GOPHER,
  187. None,
  188. "CleanupViewList",
  189. "%x, %x",
  190. SessionInfo,
  191. ViewType
  192. ));
  193. //
  194. // walk this VIEW_INFO list trying to delete everything by dereferencing
  195. //
  196. while (1) {
  197. LPSERIALIZED_LIST viewList;
  198. LPVIEW_INFO viewInfo;
  199. HINTERNET handle;
  200. AcquireViewLock(SessionInfo, ViewType);
  201. viewList = &SessionInfo->FindList;
  202. for (viewInfo = (LPVIEW_INFO)HeadOfSerializedList(viewList);
  203. (viewInfo != (LPVIEW_INFO)&viewList->List.Flink)
  204. && !(viewInfo->Flags & VI_CLEANUP);
  205. viewInfo = (LPVIEW_INFO)viewInfo->List.Flink) {
  206. //
  207. // empty loop
  208. //
  209. }
  210. if (viewInfo == (LPVIEW_INFO)&viewList->List.Flink) {
  211. DEBUG_PRINT(SESSION,
  212. INFO,
  213. ("end of list\n"
  214. ));
  215. ReleaseViewLock(SessionInfo, ViewType);
  216. break;
  217. }
  218. //
  219. // mark this VIEW_INFO as being cleaned-up, so we don't hit it again if
  220. // we don't delete it from the list this time
  221. //
  222. viewInfo->Flags |= VI_CLEANUP;
  223. //
  224. // safe to release the view lock
  225. //
  226. ReleaseViewLock(SessionInfo, ViewType);
  227. //
  228. // now dereference the VIEW_INFO. This may destroy it, but cannot
  229. // destroy the SESSION_INFO, since we added an extra reference in
  230. // CleanupSessions()
  231. //
  232. DereferenceView(viewInfo);
  233. }
  234. DEBUG_LEAVE(0);
  235. }
  236. LPSESSION_INFO
  237. FindOrCreateSession(
  238. IN LPSTR Host,
  239. IN DWORD Port,
  240. OUT LPDWORD Error
  241. )
  242. /*++
  243. Routine Description:
  244. Locates a SESSION_INFO that contains (Host, Port), or creates a new
  245. SESSION_INFO
  246. BUGBUG - need to do the following:
  247. resolve the host name
  248. find host by name/port or address/port
  249. Arguments:
  250. Host - pointer to host name where gopher server lives
  251. Port - port at which gopher server listens
  252. Error - place to return error
  253. Return Value:
  254. LPSESSION_INFO
  255. Success - pointer to session info. Created contains TRUE if we created
  256. the SESSION_INFO, else FALSE
  257. Failure - NULL
  258. Error contains reason for failure
  259. --*/
  260. {
  261. LPSESSION_INFO sessionInfo;
  262. BOOL found;
  263. AcquireSessionLock();
  264. found = FALSE;
  265. for (sessionInfo = (LPSESSION_INFO)SessionList.List.Flink;
  266. sessionInfo != (LPSESSION_INFO)&SessionList.List;
  267. sessionInfo = (LPSESSION_INFO)(sessionInfo->List.Flink)) {
  268. if (!stricmp(sessionInfo->Host, Host) && (sessionInfo->Port == Port)) {
  269. found = TRUE;
  270. break;
  271. }
  272. }
  273. if (!found) {
  274. sessionInfo = CreateSession(Host, Port, Error);
  275. if (sessionInfo != NULL) {
  276. InsertAtHeadOfSerializedList(&SessionList, &sessionInfo->List);
  277. }
  278. }
  279. if (sessionInfo != NULL) {
  280. //
  281. // the reference count will be at least 2
  282. //
  283. ReferenceSession(sessionInfo);
  284. }
  285. ReleaseSessionLock();
  286. return sessionInfo;
  287. }
  288. PRIVATE
  289. LPSESSION_INFO
  290. CreateSession(
  291. IN LPSTR Host,
  292. IN DWORD Port,
  293. OUT LPDWORD Error
  294. )
  295. /*++
  296. Routine Description:
  297. Creates and initializes a SESSION_INFO 'object'
  298. Arguments:
  299. Host - pointer to host name/ip address
  300. Port - host port
  301. Error - place to return reason for failure
  302. Return Value:
  303. LPSESSION_INFO
  304. Success - pointer to initialized session info
  305. Failure - NULL
  306. Error contains reason for failure
  307. --*/
  308. {
  309. LPSESSION_INFO sessionInfo;
  310. LPSTR hostName = NULL;
  311. DWORD error;
  312. DEBUG_ENTER((DBG_GOPHER,
  313. Pointer,
  314. "CreateSession",
  315. "%q, %d, %x",
  316. Host,
  317. Port,
  318. Error
  319. ));
  320. sessionInfo = NEW(SESSION_INFO);
  321. if (sessionInfo != NULL) {
  322. hostName = NEW_STRING(Host);
  323. if (hostName != NULL) {
  324. error = AllocateHandle((LPVOID)sessionInfo, &sessionInfo->Handle);
  325. if (error == ERROR_SUCCESS) {
  326. InitializeListHead(&sessionInfo->List);
  327. sessionInfo->Host = hostName;
  328. sessionInfo->Port = Port;
  329. InitializeSerializedList(&sessionInfo->FindList);
  330. InitializeSerializedList(&sessionInfo->FileList);
  331. SESSION_CREATED();
  332. }
  333. } else {
  334. error = ERROR_NOT_ENOUGH_MEMORY;
  335. }
  336. } else {
  337. error = ERROR_NOT_ENOUGH_MEMORY;
  338. }
  339. if (error != ERROR_SUCCESS) {
  340. if (hostName != NULL) {
  341. DEL_STRING(hostName);
  342. }
  343. if (sessionInfo != NULL) {
  344. DEL(sessionInfo);
  345. }
  346. sessionInfo = NULL;
  347. }
  348. DEBUG_ERROR(SESSION, error);
  349. *Error = error;
  350. DEBUG_LEAVE(sessionInfo);
  351. return sessionInfo;
  352. }
  353. PRIVATE
  354. VOID
  355. DestroySession(
  356. IN LPSESSION_INFO SessionInfo
  357. )
  358. /*++
  359. Routine Description:
  360. Opposite of CreateSession - removes a SESSION_INFO from SessionList and
  361. frees all resources owned by the SESSION_INFO and finally frees the memory
  362. Assumes: 1. SessionListLock is held
  363. 2. SessionInfo is not on any lists
  364. 3. The SERIALIZED_LISTs have already been created
  365. Arguments:
  366. SessionInfo - pointer to SESSION_INFO to delete
  367. Return Value:
  368. None.
  369. --*/
  370. {
  371. DEBUG_ENTER((DBG_GOPHER,
  372. None,
  373. "DestroySession",
  374. "%x",
  375. SessionInfo
  376. ));
  377. INET_DEBUG_ASSERT(SessionInfo->List.Flink == NULL);
  378. INET_DEBUG_ASSERT(SessionInfo->List.Blink == NULL);
  379. INET_ASSERT(SessionInfo->ReferenceCount == 0);
  380. INET_ASSERT(IsSerializedListEmpty(&SessionInfo->FindList));
  381. INET_DEBUG_ASSERT(!IsLockHeld(&SessionInfo->FindList));
  382. INET_ASSERT(IsSerializedListEmpty(&SessionInfo->FileList));
  383. INET_DEBUG_ASSERT(!IsLockHeld(&SessionInfo->FileList));
  384. if (SessionInfo->Handle) {
  385. FreeHandle(SessionInfo->Handle);
  386. }
  387. if (SessionInfo->Host != NULL) {
  388. DEL(SessionInfo->Host);
  389. }
  390. TerminateSerializedList(&SessionInfo->FindList);
  391. TerminateSerializedList(&SessionInfo->FileList);
  392. DEL(SessionInfo);
  393. SESSION_DESTROYED();
  394. DEBUG_LEAVE(0);
  395. }
  396. VOID
  397. ReferenceSession(
  398. IN LPSESSION_INFO SessionInfo
  399. )
  400. /*++
  401. Routine Description:
  402. Increases the reference count of a SESSION_INFO
  403. Arguments:
  404. Session - pointer to SESSION_INFO to reference
  405. Return Value:
  406. None.
  407. --*/
  408. {
  409. INET_ASSERT(SessionInfo != NULL);
  410. InterlockedIncrement(&SessionInfo->ReferenceCount);
  411. }
  412. LPSESSION_INFO
  413. DereferenceSession(
  414. IN LPSESSION_INFO SessionInfo
  415. )
  416. /*++
  417. Routine Description:
  418. Reduces the reference count of a SESSION_INFO. If it goes to zero, the
  419. SESSION_INFO is removed from the SessionList and is deallocated
  420. Arguments:
  421. SessionInfo - pointer to SESSION_INFO to dereference
  422. Return Value:
  423. LPSESSION_INFO
  424. NULL - SessionInfo was deleted
  425. !NULL - Reference count still >0
  426. --*/
  427. {
  428. INET_ASSERT(SessionInfo);
  429. INET_ASSERT(SessionInfo->ReferenceCount >= 1);
  430. //
  431. // use InterlockedDecrement to dereference the session. If it goes to zero
  432. // acquire the session lock, check if the reference count is still zero,
  433. // and if so, remove the session from the session list
  434. //
  435. if (InterlockedDecrement(&SessionInfo->ReferenceCount) == 0) {
  436. AcquireSessionLock();
  437. if (SessionInfo->ReferenceCount == 0) {
  438. RemoveFromSerializedList(&SessionList, (PLIST_ENTRY)SessionInfo);
  439. DestroySession(SessionInfo);
  440. SessionInfo = NULL;
  441. }
  442. ReleaseSessionLock();
  443. }
  444. return SessionInfo;
  445. }
  446. VOID
  447. AcquireViewLock(
  448. IN LPSESSION_INFO SessionInfo,
  449. IN VIEW_TYPE ViewType
  450. )
  451. /*++
  452. Routine Description:
  453. Acquires one of the SessionInfo View locks
  454. Arguments:
  455. SessionInfo - pointer to SESSION_INFO
  456. ViewType - identifies which list to lock
  457. Return Value:
  458. None.
  459. --*/
  460. {
  461. LPSERIALIZED_LIST list;
  462. INET_ASSERT(SessionInfo != NULL);
  463. INET_ASSERT((ViewType == ViewTypeFile) || (ViewType == ViewTypeFind));
  464. list = (ViewType == ViewTypeFile)
  465. ? &SessionInfo->FileList
  466. : &SessionInfo->FindList
  467. ;
  468. LockSerializedList(list);
  469. }
  470. VOID
  471. ReleaseViewLock(
  472. IN LPSESSION_INFO SessionInfo,
  473. IN VIEW_TYPE ViewType
  474. )
  475. /*++
  476. Routine Description:
  477. Releases the SessionInfo View lock
  478. Arguments:
  479. SessionInfo - pointer to SESSION_INFO
  480. ViewType - identifies which list to lock
  481. Return Value:
  482. None.
  483. --*/
  484. {
  485. LPSERIALIZED_LIST list;
  486. INET_ASSERT(SessionInfo != NULL);
  487. INET_ASSERT((ViewType == ViewTypeFile) || (ViewType == ViewTypeFind));
  488. list = (ViewType == ViewTypeFile)
  489. ? &SessionInfo->FileList
  490. : &SessionInfo->FindList
  491. ;
  492. UnlockSerializedList(list);
  493. }
  494. DWORD
  495. GopherTransaction(
  496. IN LPVIEW_INFO ViewInfo
  497. )
  498. /*++
  499. Routine Description:
  500. Performs an 'atomic' gopher operation. Connects to a server (if it isn't
  501. already connected (in the future?)), sends a request and receives the
  502. entire response message. The connection is terminated
  503. Arguments:
  504. ViewInfo - pointer to VIEW_INFO describing gopher server to talk to,
  505. request and buffer for response
  506. Return Value:
  507. DWORD
  508. Success - ERROR_SUCCESS
  509. Failure - Winsock error
  510. --*/
  511. {
  512. DWORD error;
  513. INET_ASSERT(ViewInfo != NULL);
  514. error = GopherConnect(ViewInfo);
  515. if (error == ERROR_SUCCESS) {
  516. error = GopherSendRequest(ViewInfo);
  517. if (error == ERROR_SUCCESS) {
  518. DWORD bytesReceived;
  519. //
  520. // receive the first part of the response. We don't care about the
  521. // number of bytes received at this point
  522. //
  523. // If the response is completed and the connection is not persistent
  524. // or an error occurs, the connection will be closed
  525. //
  526. ViewInfo->BufferInfo->Flags |= BI_FIRST_RECEIVE;
  527. error = GopherReceiveResponse(ViewInfo, &bytesReceived);
  528. }
  529. }
  530. return error;
  531. }
  532. DWORD
  533. IsServerGopherPlus(
  534. IN LPSESSION_INFO SessionInfo,
  535. OUT LPBOOL Answer
  536. )
  537. /*++
  538. Routine Description:
  539. Tries to determine whether a gopher server identified by Session is gopher+.
  540. The caller should already have determined that we don't know the type of
  541. gopher server described by Session and should modify the flags based on a
  542. successful return from this function
  543. Arguments:
  544. SessionInfo - pointer to SESSION_INFO describing the (unknown) gopher server
  545. Answer - pointer to place to put the answer
  546. Return Value:
  547. DWORD
  548. Success - ERROR_SUCCESS
  549. Failure - WSA error
  550. --*/
  551. {
  552. /*
  553. DWORD error;
  554. BYTE buffer[GOPHER_PLUS_INFO_TOKEN_LENGTH + 2]; // "+INFO"
  555. // + 1 for possible ':'
  556. // + 1 for ' '
  557. BOOL receiveComplete;
  558. //
  559. // in order to find out the type of gopher server, we send a request for
  560. // gopher+ info of the root directory. We will get back either the gopher+
  561. // information or a gopher0 server will return the directory list (or we
  562. // will get an error). Therefore, if the transaction doesn't result in an
  563. // error, we can say that if the buffer starts with "+INFO" then the
  564. // server is gopher+ else plain gopher
  565. //
  566. error = GopherTransaction(SessionInfo,
  567. GOPHER_PLUS_INFO_REQUEST,
  568. TRUE,
  569. sizeof(buffer),
  570. buffer,
  571. NULL,
  572. &receiveComplete
  573. );
  574. //
  575. // in both gopher+ and gopher server cases, the server should want to
  576. // return more data than we've supplied buffer for (7 bytes!). In the
  577. // case of gopher+, it will be trying to return the +INFO block for
  578. // the directory entry. In the case of gopher, it will be trying to
  579. // return the entire default directory list. Either way, we don't care
  580. // to take the data: "+INFO[:] " being present or not at the start of
  581. // the buffer is good enough for us, so just close the session and
  582. // examine what we have
  583. //
  584. DisconnectFromServer(SessionInfo, );
  585. if (error == ERROR_SUCCESS) {
  586. register DWORD matchLength;
  587. matchLength = IsGopherPlusToken(GOPHER_PLUS_INFO_TOKEN,
  588. GOPHER_PLUS_INFO_TOKEN_LENGTH,
  589. buffer,
  590. sizeof(buffer)
  591. );
  592. *Answer = (BOOL)(matchLength != 0);
  593. IF_DEBUG(SESSION) {
  594. DBGPRINT(DBG_INFO,
  595. "IsServerGopherPlus",
  596. ("Server \"%s\" %s gopher+\n",
  597. SessionInfo->Host,
  598. (matchLength == 0) ? "NOT" : "IS"
  599. ));
  600. }
  601. } else {
  602. IF_DEBUG(SESSION) {
  603. DBGPRINT(DBG_ERROR,
  604. "IsServerGopherPlus",
  605. ("GopherTransaction() returns %d\n",
  606. error
  607. ));
  608. }
  609. }
  610. return error;
  611. */
  612. *Answer = FALSE;
  613. return ERROR_SUCCESS;
  614. }
  615. BOOL
  616. IsGopherPlusSession(
  617. IN LPSESSION_INFO SessionInfo
  618. )
  619. /*++
  620. Routine Description:
  621. Returns TRUE if Session is a session with a gopher+ server
  622. Arguments:
  623. SessionInfo - pointer to SESSION_INFO describing gopher[+] server
  624. Return Value:
  625. BOOL
  626. --*/
  627. {
  628. return (BOOL)SessionInfo->Flags & SI_GOPHER_PLUS;
  629. }
  630. DWORD
  631. SearchSessionsForAttribute(
  632. IN LPSTR Locator,
  633. IN LPSTR Attribute,
  634. IN LPBYTE Buffer,
  635. IN OUT LPDWORD BufferLength
  636. )
  637. /*++
  638. Routine Description:
  639. Searches all VIEW_INFO buffers for a requested Locator and extracts the
  640. attributes if found
  641. Arguments:
  642. Locator - pointer to locator describing item to get attributes for
  643. Attribute - pointer to string describing attribute(s) to get
  644. Buffer - pointer to buffer in which to return attribute strings
  645. BufferLength - IN: length of Buffer in bytes
  646. OUT: length of returned attribute strings in bytes,
  647. excluding any terminating NUL
  648. Return Value:
  649. DWORD
  650. Success - ERROR_SUCCESS
  651. Failure - ERROR_GOPHER_ATTRIBUTE_NOT_FOUND
  652. ERROR_INSUFFICIENT_BUFFER
  653. --*/
  654. {
  655. LPSESSION_INFO session;
  656. BOOL found = FALSE;
  657. DWORD error = ERROR_SUCCESS;
  658. AcquireSessionLock();
  659. /*
  660. for (session = (LPSESSION_INFO)SessionList.Flink;
  661. session != (LPSESSION_INFO)&SessionList.Flink;
  662. session = (LPSESSION_INFO)session->List.Flink) {
  663. LPVIEW_INFO viewInfo;
  664. AcquireFindLock(session);
  665. for (findInfo = (LPVIEW_INFO)session->FindList.Flink;
  666. findInfo != (LPVIEW_INFO)&session->FindList;
  667. findInfo = (LPVIEW_INFO)findInfo->List.Flink) {
  668. ReferenceFind(findInfo);
  669. if (findInfo->Handle) {
  670. found = TRUE;
  671. break; // out of for()
  672. }
  673. }
  674. if (found) {
  675. break; // out of while()
  676. }
  677. ReleaseFindLock(session);
  678. }
  679. if (found) {
  680. error = ERROR_SUCCESS;
  681. } else {
  682. error = ERROR_GOPHER_ATTRIBUTE_NOT_FOUND;
  683. }
  684. */
  685. ReleaseSessionLock();
  686. error = ERROR_GOPHER_ATTRIBUTE_NOT_FOUND;
  687. return error;
  688. }