Source code of Windows XP (NT5)
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.

1136 lines
38 KiB

  1. /*************************************************************************
  2. * Microsoft Windows NT *
  3. * *
  4. * Copyright(c) Microsoft Corp., 1994 *
  5. * *
  6. * Revision History: *
  7. * *
  8. * Jan. 23,94 Koti Created *
  9. * *
  10. * Description: *
  11. * *
  12. * This file contains the functions that actually get the LPD service *
  13. * running, and also all the functions that deal with socket interface *
  14. * *
  15. *************************************************************************/
  16. #include "lpd.h"
  17. typedef struct _FAMILY {
  18. int family;
  19. int socklen;
  20. HANDLE hAcceptThread;
  21. SOCKET sListener; // the socket that listens for ever
  22. int iErrcode;
  23. } FAMILY;
  24. FAMILY family[] = {
  25. { AF_INET, sizeof(SOCKADDR_IN), NULL },
  26. { AF_INET6, sizeof(SOCKADDR_IN6), NULL },
  27. };
  28. #define NUM_FAMILIES (sizeof(family) / sizeof(FAMILY))
  29. DWORD
  30. StartLPDFamily(int famidx)
  31. {
  32. SOCKADDR_STORAGE saiSs;
  33. INT iErrcode;
  34. BOOL fExclsv;
  35. SERVENT *pserv;
  36. DWORD dwNewThreadId;
  37. DWORD dwErrcode;
  38. // Create the socket (which will be the listening socket)
  39. family[famidx].sListener = socket( family[famidx].family, SOCK_STREAM, 0 );
  40. if ( family[famidx].sListener == INVALID_SOCKET )
  41. {
  42. iErrcode = WSAGetLastError();
  43. LPD_DEBUG( "socket() failed\n" );
  44. return( (DWORD)iErrcode );
  45. }
  46. //
  47. // set this port to be "Exclusive" so that no other app can grab it
  48. //
  49. fExclsv = TRUE;
  50. if (setsockopt( family[famidx].sListener,
  51. SOL_SOCKET,
  52. SO_EXCLUSIVEADDRUSE,
  53. (CHAR *)&fExclsv,
  54. sizeof(fExclsv) ) != 0)
  55. {
  56. LPD_DEBUG( "setsockopt SO_EXCLUSIVEADDRUSE failed\n");
  57. }
  58. // bind the socket to the LPD port
  59. memset(&saiSs, 0, sizeof(saiSs));
  60. pserv = getservbyname( "printer", "tcp" );
  61. if ( pserv == NULL )
  62. {
  63. SS_PORT(&saiSs) = htons( LPD_PORT );
  64. }
  65. else
  66. {
  67. SS_PORT(&saiSs) = pserv->s_port;
  68. }
  69. saiSs.ss_family = (short)family[famidx].family;
  70. iErrcode = bind( family[famidx].sListener, (LPSOCKADDR)&saiSs, sizeof(saiSs) );
  71. if ( iErrcode == SOCKET_ERROR )
  72. {
  73. iErrcode = WSAGetLastError();
  74. LPD_DEBUG( "bind() failed\n" );
  75. closesocket(family[famidx].sListener);
  76. family[famidx].sListener = INVALID_SOCKET;
  77. return( (DWORD)iErrcode );
  78. }
  79. // put the socket to listen,
  80. // backlog should be 50 not 5, MohsinA, 07-May-97.
  81. iErrcode = listen( family[famidx].sListener, 50 );
  82. if ( iErrcode == SOCKET_ERROR )
  83. {
  84. iErrcode = WSAGetLastError();
  85. LPD_DEBUG( "listen() failed\n" );
  86. closesocket(family[famidx].sListener);
  87. family[famidx].sListener = INVALID_SOCKET;
  88. return( (DWORD)iErrcode );
  89. }
  90. // Create the thread that keeps looping on accept
  91. family[famidx].hAcceptThread = CreateThread( NULL, 0, LoopOnAccept,
  92. IntToPtr(famidx), 0, &dwNewThreadId );
  93. if ( family[famidx].hAcceptThread == (HANDLE)NULL )
  94. {
  95. dwErrcode = GetLastError();
  96. LPD_DEBUG( "StartLPD:CreateThread() failed\n" );
  97. closesocket(family[famidx].sListener);
  98. family[famidx].sListener = INVALID_SOCKET;
  99. return( dwErrcode );
  100. }
  101. return( 0 );
  102. }
  103. /*****************************************************************************
  104. * *
  105. * StartLPD(): *
  106. * This function does everything that's needed to accept an incoming call *
  107. * (create a socket, listen, create a thread that loops on accept) *
  108. * *
  109. * Returns: *
  110. * NO_ERROR if everything went ok *
  111. * Error code (returned by the operation that failed) otherwise *
  112. * *
  113. * Parameters: *
  114. * dwArgc (IN): number of arguments passed in *
  115. * lpszArgv (IN): arguments to this function (array of null-terminated *
  116. * strings). First arg is the name of the service and the *
  117. * remaining are the ones passed by the calling process. *
  118. * (e.g. net start lpd /p:xyz) *
  119. * *
  120. * History: *
  121. * Jan.23, 94 Koti Created *
  122. * *
  123. *****************************************************************************/
  124. DWORD StartLPD( DWORD dwArgc, LPTSTR *lpszArgv )
  125. {
  126. INT iErrcode, i;
  127. HANDLE hNewThread;
  128. WSADATA wsaData;
  129. // for now, we ignore dwArgc and lpszArgv. Plan is to support
  130. // command line (and/or registry configurable) parameters to the
  131. // "net start lpd" command. At that time, we need to use them.
  132. // initialize winsock dll
  133. iErrcode = WSAStartup( MAKEWORD(WINSOCK_VER_MAJOR, WINSOCK_VER_MINOR),
  134. &wsaData );
  135. if (iErrcode != 0)
  136. {
  137. LPD_DEBUG( "WSAStarup() failed\n" );
  138. return( (DWORD)iErrcode );
  139. }
  140. // initialize families and only fail if ALL of them fail.
  141. for (i=0; i<NUM_FAMILIES; i++) {
  142. family[i].iErrcode = StartLPDFamily(i);
  143. }
  144. if ((family[0].iErrcode != 0) && (family[1].iErrcode != 0)) {
  145. return( family[0].iErrcode );
  146. }
  147. // everything went fine: the LPD service is now running!
  148. return( NO_ERROR );
  149. } // end StartLPD()
  150. void
  151. StopLPDFamily(INT iFamIdx)
  152. {
  153. DWORD dwResult;
  154. if (family[iFamIdx].sListener == INVALID_SOCKET) {
  155. // Not started
  156. return;
  157. }
  158. SureCloseSocket( family[iFamIdx].sListener );
  159. //
  160. // accept() can take some time to return after the accept socket has
  161. // been closed. wait for the accept thread to exit before continuing.
  162. // This will prevent an access violation in the case where WSACleanup
  163. // is called before accept() returns.
  164. //
  165. LPD_DEBUG( "Waiting for the accept thread to exit\n" );
  166. dwResult = WaitForSingleObject( family[iFamIdx].hAcceptThread, INFINITE );
  167. LPD_ASSERT( WAIT_OBJECT_0 == dwResult );
  168. CloseHandle( family[iFamIdx].hAcceptThread );
  169. }
  170. /*****************************************************************************
  171. * *
  172. * StopLPD(): *
  173. * This function stops the LPD service by closing the listener socket *
  174. * (so that new connections are not accepted), and by allowing all the *
  175. * active threads to finish their job and terminate on their own. *
  176. * *
  177. * Returns: *
  178. * None *
  179. * *
  180. * Parameters: *
  181. * None *
  182. * *
  183. * History: *
  184. * Jan.23, 94 Koti Created *
  185. * *
  186. *****************************************************************************/
  187. VOID StopLPD( VOID )
  188. {
  189. BOOL fClientsConnected=FALSE;
  190. INT i;
  191. DBG_TRACEIN( "StopLPD" );
  192. //
  193. // first of all, set the flag! This is the *only* place where we
  194. // change the value, so need not worry about guarding it.
  195. // This flag will cause all worker threads to exit.
  196. //
  197. fShuttingDownGLB = TRUE;
  198. //
  199. // stop accepting new connections,
  200. // This will wake the accept(), and LoopOnAccept will exit.
  201. //
  202. for (i=0; i<NUM_FAMILIES; i++) {
  203. StopLPDFamily(i);
  204. }
  205. EnterCriticalSection( &csConnSemGLB );
  206. {
  207. if( Common.AliveThreads > 0 ){
  208. fClientsConnected = TRUE;
  209. }
  210. }
  211. LeaveCriticalSection( &csConnSemGLB );
  212. // wait here until the last thread to leave sets the event
  213. if ( fClientsConnected )
  214. {
  215. LPD_DEBUG( "Waiting for last worker thread to exit\n" );
  216. WaitForSingleObject( hEventLastThreadGLB, INFINITE );
  217. LPD_DEBUG( "Waiting for last worker thread done.\n" );
  218. }
  219. WSACleanup();
  220. DBG_TRACEOUT( "StopLPD" );;
  221. return;
  222. } // end StopLPD()
  223. /*****************************************************************************
  224. * *
  225. * LoopOnAccept(): *
  226. * This function is executed by the new thread that's created in StartLPD *
  227. * When a new connection request arrives, this function accepts it and *
  228. * creates a new thread which goes off and processes that connection. *
  229. * *
  230. * Returns: *
  231. * NO_ERROR (always) *
  232. * *
  233. * Parameters: *
  234. * lpArgv (IN): address family index *
  235. * *
  236. * History: *
  237. * Jan.23, 94 Koti Created *
  238. * *
  239. *****************************************************************************/
  240. DWORD LoopOnAccept( LPVOID lpArgv )
  241. {
  242. INT iFamIdx = (INT)(INT_PTR)lpArgv;
  243. SOCKET sNewConn;
  244. SOCKADDR_STORAGE saAddr;
  245. INT cbAddr;
  246. INT iErrcode;
  247. PSOCKCONN pscConn = NULL;
  248. PSOCKCONN pConnToFree = NULL;
  249. PSOCKCONN pPrevConn = NULL;
  250. BOOLEAN fLinkedIn=FALSE;
  251. HANDLE hNewThread;
  252. DWORD dwNewThreadId;
  253. DWORD dwErrcode;
  254. int MoreThread;
  255. COMMON_LPD local_common;
  256. int QueueTooLong;
  257. DBG_TRACEIN( "LoopOnAccept " );
  258. cbAddr = sizeof( saAddr );
  259. // loop forever, trying to accept new calls
  260. while( TRUE )
  261. {
  262. LPD_DEBUG( "Calling accept.\n");
  263. MoreThread = 0;
  264. hNewThread = NULL;
  265. sNewConn = accept( family[iFamIdx].sListener, (LPSOCKADDR)&saAddr, &cbAddr );
  266. if ( sNewConn == INVALID_SOCKET )
  267. {
  268. iErrcode = WSAGetLastError();
  269. LOGIT(("LoopOnAccept(): accept failed err=%d\n", iErrcode ));
  270. if ( iErrcode == WSAEINTR )
  271. {
  272. //
  273. // sListener closed, it's shutdown time:
  274. // exit loop (& thread!)
  275. //
  276. break;
  277. }
  278. else
  279. {
  280. // some error: ignore; go back & wait! (didn't connect anyway)
  281. LOGIT(("LoopOnAccept(): bad accept err=%d\n", iErrcode ));
  282. continue;
  283. }
  284. }else{ // it's a good connection
  285. // Allocate a PSOCKCONN structure for this connection
  286. pscConn = (PSOCKCONN)LocalAlloc( LMEM_FIXED, sizeof(SOCKCONN) );
  287. // Create a new thread to deal with this connection
  288. if ( pscConn != NULL )
  289. {
  290. memset( (PCHAR)pscConn, 0, sizeof( SOCKCONN ) );
  291. InitializeListHead( &pscConn->CFile_List );
  292. InitializeListHead( &pscConn->DFile_List );
  293. pscConn->sSock = sNewConn;
  294. pscConn->fLogGenericEvent = TRUE;
  295. pscConn->dwThread = 0; // GetCurrentThreadId();
  296. pscConn->hPrinter = (HANDLE)INVALID_HANDLE_VALUE;
  297. #ifdef PROFILING
  298. pscConn->time_queued = time(NULL);
  299. #endif
  300. EnterCriticalSection( &csConnSemGLB );
  301. {
  302. Common.TotalAccepts++;
  303. //
  304. // scConnHeadGLB is the head and not used for jobs.
  305. // Insertheadlist pscConn, WorkerThread will pull
  306. // it out and process it.
  307. //
  308. if ((Common.QueueLength >= Common.AliveThreads) &&
  309. (Common.AliveThreads < (int) dwMaxUsersGLB ))
  310. {
  311. MoreThread = (int)TRUE;
  312. }
  313. if( Common.QueueLength < (int) MaxQueueLength ){
  314. QueueTooLong = 0;
  315. pscConn->pNext = scConnHeadGLB.pNext;
  316. scConnHeadGLB.pNext = pscConn;
  317. fLinkedIn = TRUE;
  318. // = Doubly linked now, MohsinA, 28-May-97.
  319. // pscConn->pPrev = &scConnHeadGLB;
  320. // pscConn->pNext->pPrev = pscConn;
  321. Common.QueueLength++;
  322. }else{
  323. QueueTooLong = 1;
  324. MoreThread = 0;
  325. fLinkedIn = FALSE;
  326. }
  327. assert( Common.QueueLength > 0 );
  328. assert( Common.AliveThreads >= 0 );
  329. assert( Common.TotalAccepts > 0 );
  330. }
  331. LeaveCriticalSection( &csConnSemGLB );
  332. if( MoreThread ){
  333. hNewThread = CreateThread( NULL,
  334. 0,
  335. WorkerThread,
  336. NULL, // was pscConn
  337. 0,
  338. &dwNewThreadId );
  339. if( hNewThread == NULL ){
  340. LPD_DEBUG( "LoopOnAccept: CreateThread failed\n" );
  341. }
  342. }else{
  343. hNewThread = NULL;
  344. LOGIT(("LoopOnAccept: no new thread, dwMaxUsersGLB=%d.\n",
  345. dwMaxUsersGLB ));
  346. }
  347. }
  348. else
  349. {
  350. LPD_DEBUG( "LoopOnAccept: LocalAlloc(pscConn) failed\n" );
  351. }
  352. // Update the global information.
  353. EnterCriticalSection( &csConnSemGLB );
  354. {
  355. if( MoreThread && hNewThread )
  356. Common.AliveThreads++;
  357. if( Common.MaxThreads < Common.AliveThreads )
  358. Common.MaxThreads = Common.AliveThreads;
  359. if( (pscConn == NULL)
  360. || (MoreThread && ! hNewThread)
  361. || QueueTooLong
  362. ){
  363. Common.TotalErrors++;
  364. }
  365. local_common = Common; // struct copy, for readonly.
  366. }
  367. LeaveCriticalSection( &csConnSemGLB );
  368. //
  369. // Something went wrong? close the new connection, do cleanup.
  370. // Q. What if CreateThread fails? does another thread
  371. // picks up this job automatically?
  372. // A. Yes, another thread will process it.
  373. // We shouldn't even expect it to be at the head
  374. // of the queue since we left the CS above.
  375. //
  376. if( (pscConn == NULL)
  377. || (MoreThread && !hNewThread )
  378. || QueueTooLong
  379. ){
  380. dwErrcode = GetLastError();
  381. pConnToFree = NULL;
  382. if (!fLinkedIn)
  383. {
  384. pConnToFree = pscConn;
  385. }
  386. //
  387. // we had already linked it in: try to find it first
  388. //
  389. else
  390. {
  391. EnterCriticalSection( &csConnSemGLB );
  392. // if there is no other thread alive and if we hit an error
  393. if( pscConn && ( Common.AliveThreads == 0 ) )
  394. {
  395. pPrevConn = &scConnHeadGLB;
  396. pConnToFree = scConnHeadGLB.pNext;
  397. while (pConnToFree)
  398. {
  399. if (pConnToFree == pscConn)
  400. {
  401. pPrevConn->pNext = pConnToFree->pNext;
  402. break;
  403. }
  404. pPrevConn = pConnToFree;
  405. pConnToFree = pConnToFree->pNext;
  406. }
  407. }
  408. LeaveCriticalSection( &csConnSemGLB );
  409. }
  410. if (pConnToFree)
  411. {
  412. LocalFree( pConnToFree );
  413. pscConn = NULL;
  414. SureCloseSocket( sNewConn );
  415. }
  416. LpdReportEvent( LPDLOG_OUT_OF_RESOURCES, 0, NULL, 0 );
  417. }else{
  418. #ifdef PROFILING
  419. LOGIT(("PROFILING: LoopOnAccept:\n"
  420. " QueueLength=%d, MaxQueueLength=%d,\n"
  421. " AliveThreads=%d, TotalAccepts=%d, TotalErrors=%d\n"
  422. ,
  423. local_common.QueueLength, MaxQueueLength,
  424. local_common.AliveThreads,
  425. local_common.TotalAccepts,
  426. local_common.TotalErrors ));
  427. #endif
  428. }
  429. if( hNewThread ){
  430. CloseHandle( hNewThread );
  431. }
  432. }
  433. } // while( TRUE )
  434. // ====================================================================
  435. // we reach here only when shutdown is happening. The thread exits here.
  436. DBG_TRACEOUT( "LoopOnAccept exit." );
  437. return NO_ERROR;
  438. } // end LoopOnAccept()
  439. /*****************************************************************************
  440. * *
  441. * SureCloseSocket(): *
  442. * This function closes a given socket. It first attempts a graceful *
  443. * close. If that fails for some reason, then it does a "hard" close *
  444. * *
  445. * Returns: *
  446. * Nothing *
  447. * *
  448. * Parameters: *
  449. * sSockToClose (IN): socket descriptor of the socket to close *
  450. * *
  451. * History: *
  452. * Jan.23, 94 Koti Created *
  453. * *
  454. *****************************************************************************/
  455. VOID SureCloseSocket( SOCKET sSockToClose )
  456. {
  457. LINGER lLinger;
  458. if (sSockToClose == INVALID_SOCKET)
  459. {
  460. LPD_DEBUG( "SureCloseSocket: bad socket\n" );
  461. return;
  462. }
  463. // try to do a graceful close
  464. if ( closesocket(sSockToClose) == 0 )
  465. {
  466. return;
  467. }
  468. //for some reason, we couldn't close the socket: do a "hard" close now
  469. LPD_DEBUG( "SureCloseSocket: graceful close did not work; doing hard close\n" );
  470. lLinger.l_onoff = 1; // non-zero integer to say SO_LINGER
  471. lLinger.l_linger = 0; // timeout=0 seconds to say "hard" close
  472. // don't bother to check return code: can't do much anyway!
  473. setsockopt( sSockToClose, SOL_SOCKET, SO_LINGER,
  474. (CHAR *)&lLinger, sizeof(lLinger) );
  475. closesocket( sSockToClose );
  476. } // end SureCloseSocket()
  477. /*****************************************************************************
  478. * *
  479. * ReplyToClient(): *
  480. * This function sends an ACK or a NAK to the LPR client *
  481. * *
  482. * Returns: *
  483. * NO_ERROR if reply sent *
  484. * Errorcode if something didn't go well *
  485. * *
  486. * Parameters: *
  487. * pscConn (IN): PSOCKCONN structure for this connection *
  488. * wResponse (IN): what needs to be sent - ACK or NAK *
  489. * *
  490. * History: *
  491. * Jan.24, 94 Koti Created *
  492. * *
  493. *****************************************************************************/
  494. DWORD ReplyToClient( PSOCKCONN pscConn, WORD wResponse )
  495. {
  496. // we will always send only one byte in this function!
  497. CHAR szSndBuf[2];
  498. INT iErrcode;
  499. szSndBuf[0] = (CHAR)wResponse; // ACK or NAK
  500. iErrcode = send( pscConn->sSock, szSndBuf, 1, 0 );
  501. if ( iErrcode == 1 )
  502. {
  503. return( NO_ERROR );
  504. }
  505. if ( iErrcode == SOCKET_ERROR )
  506. {
  507. LPD_DEBUG( "send() failed in ReplyToClient()\n" );
  508. }
  509. return( iErrcode );
  510. } // end ReplyToClient()
  511. /*****************************************************************************
  512. * *
  513. * GetCmdFromClient(): *
  514. * This function reads a command sent by the LPR client (keeps reading *
  515. * until it finds '\n' (LF) in the stream, since every command ends with *
  516. * a LF). It allocates memory for the command. *
  517. * *
  518. * Returns: *
  519. * NO_ERROR if everything went ok *
  520. * Errorcode if something goes wrong (e.g. connection goes away etc.) *
  521. * *
  522. * Parameters: *
  523. * pscConn (IN-OUT): PSOCKCONN structure for this connection *
  524. * *
  525. * History: *
  526. * Jan.24, 94 Koti Created *
  527. * *
  528. *****************************************************************************/
  529. DWORD GetCmdFromClient( PSOCKCONN pscConn )
  530. {
  531. INT cbBytesRead;
  532. INT cbBytesReadSoFar;
  533. INT cbBytesToRead;
  534. INT cbCmdLen;
  535. INT i;
  536. BOOL fCompleteCmd=FALSE;
  537. CHAR szCmdBuf[500];
  538. PCHAR pchAllocedBuf=NULL;
  539. PCHAR pchOrgAllocedBuf=NULL;
  540. SOCKET sDestSock;
  541. DWORD dwErrcode = SOCKET_ERROR;
  542. int rdready;
  543. struct fd_set rdsocks;
  544. struct timeval timeo = { dwRecvTimeout, 0 };
  545. cbCmdLen = 0;
  546. cbBytesReadSoFar = 0;
  547. sDestSock = pscConn->sSock;
  548. // allocate a 1 byte buffer, so that we can use reallocate in a loop
  549. pchAllocedBuf = (PCHAR)LocalAlloc( LMEM_FIXED, 1 );
  550. if ( pchAllocedBuf == NULL )
  551. {
  552. LPD_DEBUG( "First LocalAlloc failed in GetCmdFromClient()\n" );
  553. goto GetCmdFromClient_BAIL;
  554. }
  555. // Keep reading in a loop until we receive one complete command
  556. // (with rfc1179, we shouldn't get more bytes than one command,
  557. // though less than one command is possible)
  558. //
  559. // What if the client never sends nor closes? we never Timeout?
  560. // We loose a worker thread - MohsinA, 01-May-97.
  561. //
  562. do {
  563. FD_ZERO(&rdsocks);
  564. FD_SET(sDestSock, &rdsocks);
  565. rdready = select( 1, &rdsocks, 0, 0, &timeo);
  566. if( rdready == 0 )
  567. {
  568. LOGIT(("GetCmdFromClient: select timeout.\n"));
  569. goto GetCmdFromClient_BAIL;
  570. }else if( rdready == SOCKET_ERROR ){
  571. LOGIT(("GetCmdFromClient: select error %d.\n", GetLastError()));
  572. goto GetCmdFromClient_BAIL;
  573. }
  574. cbBytesRead = recv( sDestSock, szCmdBuf, sizeof(szCmdBuf), 0 );
  575. if ( cbBytesRead < 0 )
  576. {
  577. goto GetCmdFromClient_BAIL;
  578. }
  579. else if( cbBytesRead == 0 )
  580. {
  581. if ( pchAllocedBuf != NULL )
  582. {
  583. LocalFree( pchAllocedBuf );
  584. }
  585. return CONNECTION_CLOSED;
  586. }
  587. cbBytesToRead = cbBytesRead;
  588. // see if we have received one complete command
  589. for( i=0; i<cbBytesRead; i++)
  590. {
  591. if ( szCmdBuf[i] == LF )
  592. {
  593. fCompleteCmd = TRUE;
  594. cbCmdLen = (i+1) + (cbBytesReadSoFar);
  595. cbBytesToRead = (i+1);
  596. break;
  597. }
  598. }
  599. // our needs are now bigger: reallocate memory
  600. pchOrgAllocedBuf = pchAllocedBuf;
  601. // alloc 1 more for NULL byte
  602. pchAllocedBuf = (PCHAR)LocalReAlloc( pchAllocedBuf,
  603. cbBytesToRead+cbBytesReadSoFar + 1,
  604. LMEM_MOVEABLE );
  605. if ( pchAllocedBuf == NULL )
  606. {
  607. LPD_DEBUG( "Second LocalAlloc failed in GetCmdFromClient()\n" );
  608. LocalFree( pchOrgAllocedBuf );
  609. pchOrgAllocedBuf = NULL;
  610. goto GetCmdFromClient_BAIL;
  611. }
  612. // now copy those bytes into our buffer
  613. strncpy( (pchAllocedBuf+cbBytesReadSoFar), szCmdBuf, cbBytesToRead );
  614. cbBytesReadSoFar += cbBytesRead;
  615. // if some bad implementation of LPR fails to follow spec and
  616. // never puts LF, then we don't want to be stuck here forever!
  617. if ( cbBytesReadSoFar > LPD_MAX_COMMAND_LEN )
  618. {
  619. LPD_DEBUG( "GetCmdFromClient(): command len exceeds our max\n" );
  620. goto GetCmdFromClient_BAIL;
  621. }
  622. } while( (!fCompleteCmd) || (cbBytesReadSoFar < cbCmdLen) );
  623. pchAllocedBuf[cbCmdLen] = '\0';
  624. pscConn->pchCommand = pchAllocedBuf;
  625. pscConn->cbCommandLen = cbCmdLen;
  626. return( NO_ERROR );
  627. //
  628. // if we reach here, something went wrong: return NULL and
  629. // the caller will understand!
  630. //
  631. GetCmdFromClient_BAIL:
  632. LOGIT(("GetCmdFromClient: failed, err=%d\n", GetLastError() ));
  633. if ( pchAllocedBuf != NULL )
  634. {
  635. LocalFree( pchAllocedBuf );
  636. }
  637. return dwErrcode;
  638. }
  639. /*****************************************************************************
  640. * *
  641. * ReadData(): *
  642. * This function reads the specified number of bytes into the given *
  643. * buffer from the given socket. This function blocks until all the *
  644. * required data is available (or error occurs). *
  645. * *
  646. * Returns: *
  647. * NO_ERROR if everything went ok *
  648. * Errorcode if something goes wrong (e.g. connection goes away etc.) *
  649. * *
  650. * Parameters: *
  651. * sDestSock (IN): socket from which to read or receive data *
  652. * pchBuf (OUT): buffer into which to store the data *
  653. * cbBytesToRead (IN): how many bytes to read *
  654. * *
  655. * History: *
  656. * Jan.24, 94 Koti Created *
  657. * *
  658. *****************************************************************************/
  659. DWORD ReadData( SOCKET sDestSock, PCHAR pchBuf, DWORD cbBytesToRead )
  660. {
  661. DWORD cbBytesExpctd;
  662. DWORD cbBytesRead;
  663. int rdready;
  664. struct fd_set rdsocks;
  665. struct timeval timeo = { dwRecvTimeout, 0 };
  666. cbBytesExpctd = cbBytesToRead;
  667. do{
  668. FD_ZERO(&rdsocks);
  669. FD_SET(sDestSock, &rdsocks);
  670. rdready = select( 1, &rdsocks, 0, 0, &timeo);
  671. if( rdready == 0 ){
  672. LOGIT(("ReadData: select timeout.\n"));
  673. goto ReadData_Bail;
  674. }else if( rdready == SOCKET_ERROR ){
  675. LOGIT(("ReadData: select error %d.\n", GetLastError()));
  676. goto ReadData_Bail;
  677. }
  678. cbBytesRead = recv( sDestSock, pchBuf, cbBytesExpctd, 0 );
  679. if ( (cbBytesRead == SOCKET_ERROR) || (cbBytesRead == 0) )
  680. {
  681. goto ReadData_Bail;
  682. }
  683. cbBytesExpctd -= cbBytesRead;
  684. pchBuf += cbBytesRead;
  685. } while( cbBytesExpctd != 0 );
  686. return( NO_ERROR );
  687. ReadData_Bail:
  688. LOGIT(("ReadData: failed %d\n", GetLastError() ));
  689. return LPDERR_NORESPONSE;
  690. } // end ReadData()
  691. // ========================================================================
  692. // We sleep while file is downloaded from the socket.
  693. // Performance fix, MohsinA, 23-Apr-97.
  694. //
  695. DWORD ReadDataEx( SOCKET sDestSock, PCHAR pchBuf, DWORD cbBytesToRead )
  696. {
  697. BOOL ok;
  698. DWORD err;
  699. DWORD BytesRead = 0;
  700. OVERLAPPED ol = { 0,0,0,0,0 };
  701. while( cbBytesToRead ){
  702. ok = ReadFile( (HANDLE) sDestSock,
  703. pchBuf,
  704. cbBytesToRead,
  705. &BytesRead,
  706. &ol );
  707. if( ok ){
  708. cbBytesToRead -= BytesRead;
  709. pchBuf += BytesRead;
  710. continue;
  711. }
  712. // Else ReadFile is pending?
  713. err = GetLastError();
  714. switch( err ){
  715. case ERROR_IO_PENDING :
  716. ok = GetOverlappedResult( (HANDLE) sDestSock,
  717. &ol,
  718. &BytesRead,
  719. TRUE );
  720. if( ! ok ){
  721. err = GetLastError();
  722. LOGIT(("lpd:ReadDataEx:GetOverlappedResult failed %d.\n",
  723. err ));
  724. return LPDERR_NORESPONSE;
  725. }
  726. break;
  727. case ERROR_HANDLE_EOF :
  728. return NO_ERROR;
  729. default:
  730. LOGIT(("lpd:ReadDataEx:ReadFileEx failed %d.\n", err ));
  731. return LPDERR_NORESPONSE;
  732. }
  733. } // while.
  734. return( NO_ERROR );
  735. }
  736. /*****************************************************************************
  737. * *
  738. * SendData(): *
  739. * This function attempts to send the specified number of bytes over the *
  740. * given socket. The function blocks until send() returns. *
  741. * *
  742. * Returns: *
  743. * NO_ERROR if everything went ok *
  744. * Errorcode if data couldn't be sent (e.g. connection goes away etc.) *
  745. * *
  746. * Parameters: *
  747. * sDestSock (IN): socket over which to send data *
  748. * pchBuf (IN): buffer containing data *
  749. * cbBytesToSend (IN): how many bytes to send *
  750. * *
  751. * History: *
  752. * Jan.24, 94 Koti Created *
  753. * *
  754. *****************************************************************************/
  755. DWORD SendData( SOCKET sDestSock, PCHAR pchBuf, DWORD cbBytesToSend )
  756. {
  757. INT iErrcode;
  758. iErrcode = send( sDestSock, pchBuf, cbBytesToSend, 0 );
  759. if ( iErrcode == SOCKET_ERROR )
  760. {
  761. LPD_DEBUG( "send() failed in SendData()\n" );
  762. }
  763. return( (DWORD)iErrcode );
  764. } // end SendData()
  765. /*****************************************************************************
  766. * *
  767. * GetClientInfo(); *
  768. * This function retrieves info about the client (for now, only the IP *
  769. * address). This info is used during logging. *
  770. * *
  771. * Returns: *
  772. * Nothing *
  773. * Parameters: *
  774. * pscConn (IN-OUT): PSOCKCONN structure for this connection *
  775. * *
  776. * History: *
  777. * Jan.24, 94 Koti Created *
  778. * *
  779. *****************************************************************************/
  780. VOID GetClientInfo( PSOCKCONN pscConn )
  781. {
  782. INT iErrcode;
  783. INT iLen, iLen2;
  784. SOCKADDR_STORAGE saName;
  785. iLen = sizeof(saName);
  786. iErrcode = getpeername( pscConn->sSock, (SOCKADDR *)&saName, &iLen );
  787. if ( iErrcode == 0 )
  788. {
  789. iLen2 = sizeof(pscConn->szIPAddr);
  790. SS_PORT(&saName) = 0;
  791. iErrcode = WSAAddressToString((SOCKADDR*)&saName, iLen, NULL,
  792. pscConn->szIPAddr, &iLen2);
  793. }
  794. if (iErrcode == SOCKET_ERROR)
  795. {
  796. LPD_DEBUG( "GetClientInfo(): couldn't retrieve ip address!\n" );
  797. strcpy( pscConn->szIPAddr, GETSTRING( LPD_ERMSG_NO_IPADDR) );
  798. return;
  799. }
  800. LOGTIME;
  801. LOGIT(("GetClientInfo: %s:%d\n",
  802. pscConn->szIPAddr,
  803. htons(SS_PORT(&saName)) ));
  804. } // end GetClientInfo()
  805. /*****************************************************************************
  806. * *
  807. * GetServerInfo(); *
  808. * This function retrieves info about the Server (for now, only the IP *
  809. * address). This info is used during logging. *
  810. * *
  811. * Returns: *
  812. * Nothing *
  813. * Parameters: *
  814. * pscConn (IN-OUT): PSOCKCONN structure for this connection *
  815. * *
  816. * History: From Albert Ting, Printer Group, 4-Mar-97. *
  817. * MohsinA. *
  818. *****************************************************************************/
  819. VOID GetServerInfo( PSOCKCONN pscConn )
  820. {
  821. INT iErrcode;
  822. INT iLen, iLen2;
  823. SOCKADDR_STORAGE saName;
  824. iLen = sizeof(saName);
  825. iErrcode = getsockname( pscConn->sSock, (SOCKADDR *)&saName, &iLen );
  826. if ( iErrcode == 0 ){
  827. iLen2 = sizeof(pscConn->szServerIPAddr);
  828. SS_PORT(&saName) = 0;
  829. iErrcode = WSAAddressToString((SOCKADDR*)&saName, iLen, NULL,
  830. pscConn->szServerIPAddr, &iLen2);
  831. }
  832. if (iErrcode == SOCKET_ERROR){
  833. LPD_DEBUG( "GetServerInfo(): couldn't retrieve ip address!\n" );
  834. strcpy( pscConn->szServerIPAddr, GETSTRING( LPD_ERMSG_NO_IPADDR) );
  835. return;
  836. }
  837. } // end GetServerInfo()