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.

770 lines
20 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name :
  4. conn.cxx
  5. Abstract:
  6. This module defines the functions for base class of connections
  7. for Internet Services ( class CLIENT_CONNECTION)
  8. Author:
  9. Rohan Phillips ( Rohanp ) 11-Dec-1995
  10. Project:
  11. Gibraltar Services Common Code
  12. Functions Exported:
  13. CLIENT_CONNECTION::Initialize()
  14. CLIENT_CONNECTION::Cleanup()
  15. CLIENT_CONNECTION::~CLIENT_CONNECTION()
  16. BOOL CLIENT_CONNECTION::ProcessClient( IN DWORD cbWritten,
  17. IN DWORD dwCompletionStatus,
  18. IN BOOL fIOCompletion)
  19. VOID CLIENT_CONNECTION::DisconnectClient( IN DWORD ErrorReponse)
  20. BOOL CLIENT_CONNECTION::StartupSession( VOID)
  21. BOOL CLIENT_CONNECTION::ReceiveRequest(
  22. OUT LPBOOL pfFullRequestRecd)
  23. BOOL CLIENT_CONNECTION::ReadFile( OUT LPVOID pvBuffer,
  24. IN DWORD dwSize)
  25. BOOL CLIENT_CONNECTION::WriteFile( IN LPVOID pvBuffer,
  26. IN DWORD dwSize)
  27. BOOL CLIENT_CONNECTION::TransmitFile( IN HANDLE hFile,
  28. IN DWORD cbToSend)
  29. BOOL CLIENT_CONNECTION::PostCompletionStatus( IN DWORD dwBytes )
  30. Revision History:
  31. Revision History:
  32. Richard Kamicar ( rkamicar ) 31-Dec-1995
  33. Moved to common directory, filled in more
  34. --*/
  35. /************************************************************
  36. * Include Headers
  37. ************************************************************/
  38. #define INCL_INETSRV_INCS
  39. #include "smtpinc.h"
  40. #include "conn.hxx"
  41. /************************************************************
  42. * Functions
  43. ************************************************************/
  44. /*++
  45. ICLIENT_CONNECTION::Initialize()
  46. Constructor for ICLIENT_CONNECTION object.
  47. Initializes the fields of the client connection.
  48. Arguments:
  49. sClient socket for communicating with client
  50. psockAddrRemote pointer to address of the remote client
  51. ( the value should be copied).
  52. psockAddrLocal pointer to address for the local card through
  53. which the client came in.
  54. pAtqContext pointer to ATQ Context used for AcceptEx'ed conn.
  55. pvInitialRequest pointer to void buffer containing the initial request
  56. cbInitialData count of bytes of data read initially.
  57. Note:
  58. TO keep the number of connected users <= Max connections specified.
  59. Make sure to add this object to global list of connections,
  60. after creating it.
  61. If there is a failure to add to global list, delete this object.
  62. --*/
  63. CLIENT_CONNECTION::Initialize(
  64. IN SOCKET sClient,
  65. IN const SOCKADDR_IN * psockAddrRemote,
  66. IN const SOCKADDR_IN * psockAddrLocal /* Default = NULL */,
  67. IN PATQ_CONTEXT pAtqContext /* Default = NULL */,
  68. IN PVOID pvInitialRequest/* Default = NULL */,
  69. IN DWORD cbInitialData /* Default = 0 */
  70. )
  71. {
  72. DWORD dwError = NO_ERROR;
  73. m_sClient = ( sClient);
  74. m_pAtqContext = pAtqContext;
  75. m_cbReceived = 0;
  76. m_pvInitial = pvInitialRequest;
  77. m_cbInitial = cbInitialData;
  78. m_Destroy = FALSE;
  79. _ASSERT( psockAddrRemote != NULL);
  80. m_saClient = *psockAddrRemote;
  81. // Obtain the socket addresses for the socket
  82. m_pchRemoteHostName[0] =
  83. m_pchLocalHostName[0] =
  84. m_pchLocalPortName[0] = '\0';
  85. // InetNtoa() wants just 16 byte buffer.
  86. _ASSERT( 16 <= MAX_HOST_NAME_LEN);
  87. dwError = InetNtoa( psockAddrRemote->sin_addr, m_pchRemoteHostName);
  88. _ASSERT( dwError == NO_ERROR); // since we had given sufficient buffer
  89. if ( psockAddrLocal != NULL)
  90. {
  91. dwError = InetNtoa( psockAddrLocal->sin_addr, m_pchLocalHostName);
  92. _itoa( ntohs(psockAddrLocal->sin_port), m_pchLocalPortName, 10);
  93. } else
  94. {
  95. SOCKADDR_IN sockAddr;
  96. int cbAddr = sizeof( sockAddr);
  97. if ( getsockname( sClient,
  98. (struct sockaddr *) &sockAddr,
  99. &cbAddr ))
  100. {
  101. dwError = InetNtoa( sockAddr.sin_addr, m_pchLocalHostName );
  102. _itoa( ntohs(sockAddr.sin_port), m_pchLocalPortName, 10);
  103. }
  104. }
  105. // DBG_ASSERT( dwError == NO_ERROR); // since we had given sufficient buffer
  106. #if 0
  107. DBG_CODE(
  108. if ( dwError != NO_ERROR) {
  109. DBGPRINTF( ( DBG_CONTEXT,
  110. "Obtaining Local Host Name Failed. Error = %u\n",
  111. dwError)
  112. );
  113. SetLastError( dwError);
  114. }
  115. );
  116. DEBUG_IF( CLIENT, {
  117. DBGPRINTF( ( DBG_CONTEXT,
  118. " Constructed ICLIENT_CONNECTION object ( %08x)."
  119. " Socket (%d), Host (%s).\n",
  120. this,
  121. sClient,
  122. QueryClientHostName()
  123. ));
  124. });
  125. #endif
  126. return ( TRUE);
  127. }
  128. /*++
  129. ICLIENT_CONNECTION::Cleanup()
  130. Destructor function for client connection object.
  131. Checks and frees the AtqContext.
  132. Note:
  133. If enlisted in the global list of connections,
  134. ensure that this object is freed from that list before deletion.
  135. --*/
  136. VOID CLIENT_CONNECTION::Cleanup( VOID)
  137. {
  138. PATQ_CONTEXT pAtqContext;
  139. if(m_DoCleanup)
  140. {
  141. //release the context from Atq
  142. pAtqContext = (PATQ_CONTEXT)InterlockedExchangePointer( (PVOID *)&m_pAtqContext, NULL);
  143. if ( pAtqContext != NULL )
  144. {
  145. AtqFreeContext( pAtqContext, TRUE );
  146. }
  147. }
  148. } // ICLIENT_CONNECTION::Cleanup()
  149. /*++
  150. Description:
  151. Checks to see if we have received the complete request from the client.
  152. ( A complete request is a line of text terminated by <cr><lf> )
  153. if a CRLF is found, it returns a pointer into the buffer were the CR
  154. starts, else it returns NULL. If this routine finds a CR without a
  155. LF it will return NULL
  156. Arguments:
  157. InputBuffer pointer to character buffer containing received data.
  158. cbRecvd count of bytes of data received
  159. Returns:
  160. a pointer to the CR if CRLF is found
  161. NULL if CRLF is not found.
  162. --*/
  163. // VIRTUAL
  164. char * CLIENT_CONNECTION::IsLineComplete(IN OUT const char * InputBuffer, IN DWORD cbRecvd)
  165. {
  166. register DWORD Loop = 0;
  167. _ASSERT(InputBuffer != NULL);
  168. //we need at least 2 bytes to find a
  169. //CRLF pair
  170. if( ((int) cbRecvd) < 2)
  171. return NULL;
  172. //we are going to start at the 2nd byte
  173. //looking for the LF, then look backwards
  174. //for the CR
  175. Loop = 1;
  176. while (Loop < cbRecvd)
  177. {
  178. if(InputBuffer[Loop] == LF)
  179. {
  180. if(InputBuffer[Loop - 1] == CR)
  181. return (char *) &InputBuffer[Loop - 1];
  182. else
  183. {
  184. //skip 2 bytes since we saw a LF
  185. //without a CR.
  186. Loop += 2;
  187. }
  188. }
  189. else if(InputBuffer[Loop] == CR)
  190. {
  191. //we saw a CR, so increment out
  192. //loop variable by one so that
  193. //we can catch the LF on the next
  194. //go around
  195. Loop += 1;
  196. }
  197. else
  198. {
  199. //This character is neither a CR
  200. //or a LF, so we can increment by
  201. //2
  202. Loop += 2;
  203. }
  204. }
  205. //didn't find a CRLF pair
  206. return NULL;
  207. }
  208. /*++
  209. Description:
  210. VIRTUAL Method that MUST be defined by the derived class
  211. Main function for this class. Processes the connection based
  212. on current state of the connection.
  213. It may invoke or be invoked by ATQ functions.
  214. Arguments:
  215. cbWritten count of bytes written
  216. dwCompletionStatus Error Code for last IO operation
  217. fIOCompletion TRUE if this was an IO completion
  218. Returns:
  219. TRUE when processing is incomplete.
  220. FALSE when the connection is completely processed and this
  221. object may be deleted.
  222. --*/
  223. // VIRTUAL
  224. BOOL CLIENT_CONNECTION::ProcessClient( IN DWORD cbWritten, IN DWORD dwCompletionStatus, IN OUT OVERLAPPED * lpo)
  225. {
  226. return ( TRUE);
  227. } // CLIENT_CONNECTION::ProcessClient()
  228. /*++
  229. Reads contents using ATQ into the given buffer.
  230. ( thin wrapper for ATQ call and managing references)
  231. Arguments:
  232. pvBuffer pointer to buffer where to read in the contents
  233. cbSize size of the buffer
  234. Returns:
  235. TRUE on success and FALSE on a failure.
  236. --*/
  237. // VIRTUAL
  238. BOOL CLIENT_CONNECTION::ReadFile(
  239. IN LPVOID pBuffer,
  240. IN DWORD cbSize /* = MAX_READ_BUFF_SIZE */
  241. )
  242. {
  243. _ASSERT(pBuffer != NULL);
  244. _ASSERT(cbSize > 0);
  245. if(INVALID_SOCKET == m_sClient)
  246. return FALSE;
  247. ZeroMemory(&m_Overlapped, sizeof(OVERLAPPED));
  248. return AtqReadFile(m_pAtqContext, // Atq context
  249. pBuffer, // Buffer
  250. cbSize, // BytesToRead
  251. &m_Overlapped) ;
  252. }
  253. /*++
  254. Writes contents from given buffer using ATQ.
  255. ( thin wrapper for ATQ call and managing references)
  256. Arguments:
  257. pvBuffer pointer to buffer containing contents for write
  258. cbSize size of the buffer
  259. Returns:
  260. TRUE on success and FALSE on a failure.
  261. --*/
  262. // VIRTUAL
  263. BOOL CLIENT_CONNECTION::WriteFile( IN LPVOID pBuffer, IN DWORD cbSize )
  264. {
  265. BOOL fReturn = TRUE;
  266. int BytesAlreadySent = 0;
  267. DWORD BytesSent;
  268. DWORD dwError = NO_ERROR;
  269. DWORD cTimesBlocked = 0;
  270. DWORD dwSleepTime = 1000;
  271. _ASSERT(pBuffer != NULL);
  272. for (BytesSent = 0; BytesSent < cbSize; BytesSent += BytesAlreadySent)
  273. {
  274. BytesAlreadySent = send(m_sClient,
  275. (const char FAR *) pBuffer + BytesSent,
  276. (int) (cbSize - BytesSent),
  277. 0);
  278. if (BytesAlreadySent == SOCKET_ERROR)
  279. {
  280. //The above send will fail with WSAEWOULDBLOCK when
  281. //the TCP buffer is full... this can easily happen for blob
  282. //protocol sinks. The correct thing to do is rely on memory
  283. //instead of TCP buffers to store pending sends, but the
  284. //low impact work-around is to sleep after we would block
  285. dwError = GetLastError();
  286. if ((WSAEWOULDBLOCK == dwError) && (cTimesBlocked < 500))
  287. {
  288. SetLastError(NO_ERROR);
  289. cTimesBlocked++;
  290. BytesAlreadySent = 0;
  291. Sleep(dwSleepTime);
  292. dwSleepTime += dwSleepTime;
  293. continue;
  294. }
  295. fReturn = FALSE;
  296. break;
  297. }
  298. }
  299. return fReturn;
  300. }
  301. BOOL CLIENT_CONNECTION::WriteSocket( IN SOCKET Sock, IN LPVOID pBuffer, IN DWORD cbSize )
  302. {
  303. BOOL fReturn = TRUE;
  304. int BytesAlreadySent = 0;
  305. DWORD BytesSent;
  306. _ASSERT(pBuffer != NULL);
  307. for (BytesSent = 0; BytesSent < cbSize; BytesSent += BytesAlreadySent)
  308. {
  309. BytesAlreadySent = send(Sock,
  310. (const char FAR *) pBuffer + BytesSent,
  311. (int) (cbSize - BytesSent),
  312. 0);
  313. if (BytesAlreadySent == SOCKET_ERROR)
  314. {
  315. fReturn = FALSE;
  316. break;
  317. }
  318. }
  319. return fReturn;
  320. }
  321. /*++
  322. Writes contents from given buffer using ATQ.
  323. (thin wrapper for ATQ call and managing references)
  324. Arguments:
  325. Pov pointer to OVERLAPPED structure describing the write
  326. Returns:
  327. TRUE on success and FALSE on a failure.
  328. --*/
  329. // VIRTUAL
  330. BOOL CLIENT_CONNECTION::WriteFile(
  331. IN LPVOID lpvBuffer,
  332. IN DWORD cbSize,
  333. IN OVERLAPPED *lpo)
  334. {
  335. BOOL fReturn = TRUE;
  336. _ASSERT(lpo != NULL);
  337. _ASSERT(lpvBuffer != NULL);
  338. _ASSERT(cbSize != 0);
  339. fReturn = AtqWriteFile(m_pAtqContext, lpvBuffer, cbSize, lpo);
  340. return fReturn;
  341. }
  342. /*++
  343. Transmits contents of the file ( of specified size)
  344. using the ATQ and client socket.
  345. ( thin wrapper for ATQ call and managing references)
  346. Arguments:
  347. hFile handle for file to be transmitted
  348. liSize large integer containing the size of file
  349. lpTransmitBuffers
  350. buffers containing the head and tail buffers that
  351. need to be transmitted along with the file.
  352. Returns:
  353. TRUE on success and FALSE on a failure.
  354. --*/
  355. BOOL CLIENT_CONNECTION::TransmitFile(
  356. IN HANDLE hFile,
  357. IN LARGE_INTEGER &liSize,
  358. IN LPTRANSMIT_FILE_BUFFERS lpTransmitBuffers
  359. )
  360. {
  361. _ASSERT(hFile != INVALID_HANDLE_VALUE);
  362. _ASSERT(liSize.QuadPart > 0);
  363. return AtqTransmitFile(
  364. m_pAtqContext, // Atq context
  365. hFile, // file data comes from
  366. (DWORD) liSize.LowPart, // Bytes To Send
  367. lpTransmitBuffers, // header/tail buffers
  368. 0 // Flags
  369. );
  370. }
  371. //+------------------------------------------------------------
  372. //
  373. // Function: CLIENT_CONNECTION::PostCompletionStatus
  374. //
  375. // Synopsis: Wrapper around atq for posting completion status
  376. //
  377. // Arguments:
  378. // dwBytes: The number of bytes to indicate in the completion status
  379. //
  380. // Returns:
  381. // TRUE: Success
  382. // FALSE: Failure
  383. //
  384. // History:
  385. // jstamerj 1998/11/03 20:16:17: Created.
  386. //
  387. //-------------------------------------------------------------
  388. BOOL CLIENT_CONNECTION::PostCompletionStatus(
  389. IN DWORD dwBytes)
  390. {
  391. return AtqPostCompletionStatus(
  392. m_pAtqContext,
  393. dwBytes);
  394. }
  395. /*++
  396. Starts up a session for new client.
  397. Adds the client socket to the ATQ completion port and gets an ATQ context.
  398. Then prepares receive buffer and starts off a receive request from client.
  399. ( Also moves the client connection to CcsGettingRequest state)
  400. Parameters:
  401. pvInitial pointer to void buffer containing the initial data
  402. cbWritten count of bytes in the buffer
  403. Returns:
  404. TRUE on success and FALSE if there is any error.
  405. --*/
  406. // VIRTUAL
  407. BOOL CLIENT_CONNECTION::StartSession( void)
  408. {
  409. return TRUE;
  410. }
  411. /*++
  412. Receive full Request from the client.
  413. If the entire request is received,
  414. *pfFullRequestRecvd will be set to TRUE and
  415. the request will be parsed.
  416. Arguments:
  417. cbWritten count of bytes written in last IO operation.
  418. pfFullRequestRecvd pointer to boolean, which on successful return
  419. indicates if the full request was received.
  420. Returns:
  421. TRUE on success and
  422. FALSE if there is any error ( to abort this connection).
  423. --*/
  424. BOOL CLIENT_CONNECTION::ReceiveRequest(IN DWORD cbWritten, OUT LPBOOL pfFullRequestRecvd)
  425. {
  426. return ( TRUE);
  427. }
  428. /*++
  429. Description:
  430. Initiates a disconnect operation for current connection.
  431. If already shutdown, this function returns doing nothing.
  432. Optionally if there is any error message to be sent, they may be sent
  433. Arguments:
  434. dwErrorCode
  435. error code for server errors if any ( Win 32 error code)
  436. If dwErrorCode != NO_ERROR, then there is a system level error code.
  437. by the REQUEST object. But the disconnection occurs immediately; Hence
  438. the REQUEST object should send synchronous error messages.
  439. Returns:
  440. None
  441. --*/
  442. VOID CLIENT_CONNECTION::DisconnectClient(IN DWORD dwErrorCode)
  443. {
  444. SOCKET hSocket;
  445. hSocket = (SOCKET)InterlockedExchangePointer( (PVOID *)&m_sClient, (PVOID) INVALID_SOCKET );
  446. if ( hSocket != INVALID_SOCKET )
  447. {
  448. if ( QueryAtqContext() != NULL )
  449. {
  450. AtqCloseSocket(QueryAtqContext() , (dwErrorCode == NO_ERROR));
  451. }
  452. else
  453. {
  454. ShutAndCloseSocket( m_sClient );
  455. }
  456. }
  457. }
  458. /*++
  459. Description:
  460. returns the client user name
  461. VIRTUAL function so apps can override its return value
  462. Arguments:
  463. void
  464. Returns:
  465. returns ptr to user name
  466. --*/
  467. LPCTSTR CLIENT_CONNECTION::QueryClientUserName( VOID )
  468. {
  469. return m_pchLocalHostName;
  470. }
  471. //
  472. // Private Functions
  473. //
  474. # if DBG
  475. // VIRTUAL
  476. VOID CLIENT_CONNECTION::Print( VOID) const
  477. {
  478. return;
  479. } // ICLIENT_CONNECTION::Print()
  480. # endif // DBG
  481. /*++
  482. Description:
  483. Performs a hard close on the socket using shutdown before close.
  484. Arguments:
  485. sock socket to be closed
  486. Returns:
  487. 0 if no errors or
  488. socket specific error code
  489. --*/
  490. INT ShutAndCloseSocket( IN SOCKET sock)
  491. {
  492. INT serr = 0;
  493. //
  494. // Shut the socket. ( Assumes this to be a TCP socket.)
  495. // Prevent future sends from occuring. hence 2nd param is "1"
  496. //
  497. if( sock != INVALID_SOCKET )
  498. {
  499. if ( shutdown( sock, 1) == SOCKET_ERROR)
  500. serr = WSAGetLastError();
  501. closesocket( sock);
  502. }
  503. return ( serr);
  504. } // ShutAndCloseSocket()
  505. /*++
  506. This function canonicalizes the path, taking into account the current
  507. user's current directory value.
  508. Arguments:
  509. pszDest string that will on return contain the complete
  510. canonicalized path. This buffer will be of size
  511. specified in *lpdwSize.
  512. lpdwSize Contains the size of the buffer pszDest on entry.
  513. On return contains the number of bytes written
  514. into the buffer or number of bytes required.
  515. pszSearchPath pointer to string containing the path to be converted.
  516. IF NULL, use the current directory only
  517. Returns:
  518. Win32 Error Code - NO_ERROR on success
  519. MuraliK 24-Apr-1995 Created.
  520. --*/
  521. BOOL
  522. ResolveVirtualRoot(
  523. OUT CHAR * pszDest,
  524. IN OUT LPDWORD lpdwSize,
  525. IN OUT CHAR * pszSearchPath,
  526. OUT HANDLE * phToken /* = NULL */
  527. )
  528. {
  529. TraceFunctEnter("ResolveVirtualRoot");
  530. _ASSERT(pszDest != NULL);
  531. _ASSERT(lpdwSize != NULL);
  532. _ASSERT(pszSearchPath != NULL);
  533. //
  534. // Now we have the complete symbolic path to the target file.
  535. // Translate it into the absolute path
  536. //
  537. #if 0
  538. if (!TsLookupVirtualRoot(g_pTsvcInfo->GetTsvcCache(), // TSvcCache
  539. pszSearchPath, // pszRoot
  540. pszDest, // pszDirectory
  541. lpdwSize, // lpcbSize
  542. NULL, // lpdwAccessMask
  543. NULL, // pcchDirRoot
  544. NULL, // pcchVroot
  545. phToken, // phImpersonationToken
  546. NULL, // pszAddress
  547. NULL // lpdwFileSystem
  548. ))
  549. {
  550. ErrorTrace(NULL, "TsLookupVirtualRoot failed looking for %s: %d", pszSearchPath, GetLastError());
  551. TraceFunctLeave();
  552. return FALSE;
  553. }
  554. #endif
  555. TraceFunctLeave();
  556. return TRUE;
  557. }
  558. /************************ End of File ***********************/