PageRenderTime 64ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/nx-3.5.0/nx-X11/programs/Xserver/os/io.c

#
C | 1347 lines | 987 code | 98 blank | 262 comment | 182 complexity | 55c8ab909d59d13baefd63c22e81c439 MD5 | raw file
Possible License(s): BSD-3-Clause, GPL-2.0, LGPL-2.0
  1. /***********************************************************
  2. Copyright 1987, 1989, 1998 The Open Group
  3. Permission to use, copy, modify, distribute, and sell this software and its
  4. documentation for any purpose is hereby granted without fee, provided that
  5. the above copyright notice appear in all copies and that both that
  6. copyright notice and this permission notice appear in supporting
  7. documentation.
  8. The above copyright notice and this permission notice shall be included in
  9. all copies or substantial portions of the Software.
  10. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  11. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  12. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  13. OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
  14. AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  15. CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  16. Except as contained in this notice, the name of The Open Group shall not be
  17. used in advertising or otherwise to promote the sale, use or other dealings
  18. in this Software without prior written authorization from The Open Group.
  19. Copyright 1987, 1989 by Digital Equipment Corporation, Maynard, Massachusetts.
  20. All Rights Reserved
  21. Permission to use, copy, modify, and distribute this software and its
  22. documentation for any purpose and without fee is hereby granted,
  23. provided that the above copyright notice appear in all copies and that
  24. both that copyright notice and this permission notice appear in
  25. supporting documentation, and that the name of Digital not be
  26. used in advertising or publicity pertaining to distribution of the
  27. software without specific, written prior permission.
  28. DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  29. ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
  30. DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
  31. ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  32. WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  33. ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  34. SOFTWARE.
  35. ******************************************************************/
  36. /* $Xorg: io.c,v 1.6 2001/02/09 02:05:23 xorgcvs Exp $ */
  37. /*****************************************************************
  38. * i/o functions
  39. *
  40. * WriteToClient, ReadRequestFromClient
  41. * InsertFakeRequest, ResetCurrentRequest
  42. *
  43. *****************************************************************/
  44. /* $XFree86: xc/programs/Xserver/os/io.c,v 3.34 2002/05/31 18:46:05 dawes Exp $ */
  45. #ifdef HAVE_DIX_CONFIG_H
  46. #include <dix-config.h>
  47. #endif
  48. #if 0
  49. #define DEBUG_COMMUNICATION
  50. #endif
  51. #ifdef WIN32
  52. #include <X11/Xwinsock.h>
  53. #endif
  54. #include <stdio.h>
  55. #include <X11/Xtrans/Xtrans.h>
  56. #include <X11/Xmd.h>
  57. #include <errno.h>
  58. #if !defined(__UNIXOS2__) && !defined(WIN32)
  59. #ifndef Lynx
  60. #include <sys/uio.h>
  61. #else
  62. #include <uio.h>
  63. #endif
  64. #endif
  65. #include <X11/X.h>
  66. #define NEED_REPLIES
  67. #include <X11/Xproto.h>
  68. #include "os.h"
  69. #include "osdep.h"
  70. #include <X11/Xpoll.h>
  71. #include "opaque.h"
  72. #include "dixstruct.h"
  73. #include "misc.h"
  74. #ifdef LBX
  75. #include "colormapst.h"
  76. #include "propertyst.h"
  77. #include "lbxserve.h"
  78. #endif
  79. CallbackListPtr ReplyCallback;
  80. CallbackListPtr FlushCallback;
  81. /* check for both EAGAIN and EWOULDBLOCK, because some supposedly POSIX
  82. * systems are broken and return EWOULDBLOCK when they should return EAGAIN
  83. */
  84. #ifndef __UNIXOS2__
  85. #ifndef WIN32
  86. #if defined(EAGAIN) && defined(EWOULDBLOCK)
  87. #define ETEST(err) (err == EAGAIN || err == EWOULDBLOCK)
  88. #else
  89. #ifdef EAGAIN
  90. #define ETEST(err) (err == EAGAIN)
  91. #else
  92. #define ETEST(err) (err == EWOULDBLOCK)
  93. #endif
  94. #endif
  95. #else /* WIN32 The socket errorcodes differ from the normal errors*/
  96. #define ETEST(err) (err == EAGAIN || err == WSAEWOULDBLOCK)
  97. #endif
  98. #else /* __UNIXOS2__ Writing to full pipes may return ENOSPC */
  99. #define ETEST(err) (err == EAGAIN || err == EWOULDBLOCK || err == ENOSPC)
  100. #endif
  101. Bool CriticalOutputPending;
  102. int timesThisConnection = 0;
  103. ConnectionInputPtr FreeInputs = (ConnectionInputPtr)NULL;
  104. ConnectionOutputPtr FreeOutputs = (ConnectionOutputPtr)NULL;
  105. OsCommPtr AvailableInput = (OsCommPtr)NULL;
  106. #define get_req_len(req,cli) ((cli)->swapped ? \
  107. lswaps((req)->length) : (req)->length)
  108. #ifdef BIGREQS
  109. #include <X11/extensions/bigreqstr.h>
  110. #define get_big_req_len(req,cli) ((cli)->swapped ? \
  111. lswapl(((xBigReq *)(req))->length) : \
  112. ((xBigReq *)(req))->length)
  113. #endif
  114. #define MAX_TIMES_PER 10
  115. /*
  116. * A lot of the code in this file manipulates a ConnectionInputPtr:
  117. *
  118. * -----------------------------------------------
  119. * |------- bufcnt ------->| | |
  120. * | |- gotnow ->| | |
  121. * | |-------- needed ------>| |
  122. * |-----------+--------- size --------+---------->|
  123. * -----------------------------------------------
  124. * ^ ^
  125. * | |
  126. * buffer bufptr
  127. *
  128. * buffer is a pointer to the start of the buffer.
  129. * bufptr points to the start of the current request.
  130. * bufcnt counts how many bytes are in the buffer.
  131. * size is the size of the buffer in bytes.
  132. *
  133. * In several of the functions, gotnow and needed are local variables
  134. * that do the following:
  135. *
  136. * gotnow is the number of bytes of the request that we're
  137. * trying to read that are currently in the buffer.
  138. * Typically, gotnow = (buffer + bufcnt) - bufptr
  139. *
  140. * needed = the length of the request that we're trying to
  141. * read. Watch out: needed sometimes counts bytes and sometimes
  142. * counts CARD32's.
  143. */
  144. /*****************************************************************
  145. * ReadRequestFromClient
  146. * Returns one request in client->requestBuffer. The request
  147. * length will be in client->req_len. Return status is:
  148. *
  149. * > 0 if successful, specifies length in bytes of the request
  150. * = 0 if entire request is not yet available
  151. * < 0 if client should be terminated
  152. *
  153. * The request returned must be contiguous so that it can be
  154. * cast in the dispatcher to the correct request type. Because requests
  155. * are variable length, ReadRequestFromClient() must look at the first 4
  156. * or 8 bytes of a request to determine the length (the request length is
  157. * in the 3rd and 4th bytes of the request unless it is a Big Request
  158. * (see the Big Request Extension), in which case the 3rd and 4th bytes
  159. * are zero and the following 4 bytes are the request length.
  160. *
  161. * Note: in order to make the server scheduler (WaitForSomething())
  162. * "fair", the ClientsWithInput mask is used. This mask tells which
  163. * clients have FULL requests left in their buffers. Clients with
  164. * partial requests require a read. Basically, client buffers
  165. * are drained before select() is called again. But, we can't keep
  166. * reading from a client that is sending buckets of data (or has
  167. * a partial request) because others clients need to be scheduled.
  168. *****************************************************************/
  169. #define YieldControl() \
  170. { isItTimeToYield = TRUE; \
  171. timesThisConnection = 0; }
  172. #define YieldControlNoInput() \
  173. { YieldControl(); \
  174. FD_CLR(fd, &ClientsWithInput); }
  175. #define YieldControlDeath() \
  176. { timesThisConnection = 0; }
  177. #ifdef hpux_not_tog
  178. #define LBX_NEED_OLD_SYMBOL_FOR_LOADABLES
  179. #endif
  180. #ifdef LBX
  181. #ifdef LBX_NEED_OLD_SYMBOL_FOR_LOADABLES
  182. #undef ReadRequestFromClient
  183. int
  184. ReadRequestFromClient(ClientPtr client)
  185. {
  186. return (*client->readRequest)(client);
  187. }
  188. #endif
  189. int
  190. StandardReadRequestFromClient(ClientPtr client)
  191. #else
  192. int
  193. ReadRequestFromClient(ClientPtr client)
  194. #endif
  195. {
  196. OsCommPtr oc = (OsCommPtr)client->osPrivate;
  197. ConnectionInputPtr oci = oc->input;
  198. int fd = oc->fd;
  199. unsigned int gotnow, needed;
  200. int result;
  201. register xReq *request;
  202. Bool need_header;
  203. #ifdef BIGREQS
  204. Bool move_header;
  205. #endif
  206. /* If an input buffer was empty, either free it if it is too big
  207. * or link it into our list of free input buffers. This means that
  208. * different clients can share the same input buffer (at different
  209. * times). This was done to save memory.
  210. */
  211. if (AvailableInput)
  212. {
  213. if (AvailableInput != oc)
  214. {
  215. register ConnectionInputPtr aci = AvailableInput->input;
  216. if (aci->size > BUFWATERMARK)
  217. {
  218. xfree(aci->buffer);
  219. xfree(aci);
  220. }
  221. else
  222. {
  223. aci->next = FreeInputs;
  224. FreeInputs = aci;
  225. }
  226. AvailableInput->input = (ConnectionInputPtr)NULL;
  227. }
  228. AvailableInput = (OsCommPtr)NULL;
  229. }
  230. /* make sure we have an input buffer */
  231. if (!oci)
  232. {
  233. if ((oci = FreeInputs))
  234. {
  235. FreeInputs = oci->next;
  236. }
  237. else if (!(oci = AllocateInputBuffer()))
  238. {
  239. YieldControlDeath();
  240. return -1;
  241. }
  242. oc->input = oci;
  243. }
  244. /* advance to start of next request */
  245. oci->bufptr += oci->lenLastReq;
  246. need_header = FALSE;
  247. #ifdef BIGREQS
  248. move_header = FALSE;
  249. #endif
  250. gotnow = oci->bufcnt + oci->buffer - oci->bufptr;
  251. if (gotnow < sizeof(xReq))
  252. {
  253. /* We don't have an entire xReq yet. Can't tell how big
  254. * the request will be until we get the whole xReq.
  255. */
  256. needed = sizeof(xReq);
  257. need_header = TRUE;
  258. }
  259. else
  260. {
  261. /* We have a whole xReq. We can tell how big the whole
  262. * request will be unless it is a Big Request.
  263. */
  264. request = (xReq *)oci->bufptr;
  265. needed = get_req_len(request, client);
  266. #ifdef BIGREQS
  267. if (!needed && client->big_requests)
  268. {
  269. /* It's a Big Request. */
  270. move_header = TRUE;
  271. if (gotnow < sizeof(xBigReq))
  272. {
  273. /* Still need more data to tell just how big. */
  274. needed = sizeof(xBigReq) >> 2; /* needed is in CARD32s now */
  275. need_header = TRUE;
  276. }
  277. else
  278. needed = get_big_req_len(request, client);
  279. }
  280. #endif
  281. client->req_len = needed;
  282. needed <<= 2; /* needed is in bytes now */
  283. }
  284. if (gotnow < needed)
  285. {
  286. /* Need to read more data, either so that we can get a
  287. * complete xReq (if need_header is TRUE), a complete
  288. * xBigReq (if move_header is TRUE), or the rest of the
  289. * request (if need_header and move_header are both FALSE).
  290. */
  291. oci->lenLastReq = 0;
  292. if (needed > MAXBUFSIZE)
  293. {
  294. /* request is too big for us to handle */
  295. YieldControlDeath();
  296. return -1;
  297. }
  298. if ((gotnow == 0) ||
  299. ((oci->bufptr - oci->buffer + needed) > oci->size))
  300. {
  301. /* no data, or the request is too big to fit in the buffer */
  302. if ((gotnow > 0) && (oci->bufptr != oci->buffer))
  303. /* save the data we've already read */
  304. memmove(oci->buffer, oci->bufptr, gotnow);
  305. if (needed > oci->size)
  306. {
  307. /* make buffer bigger to accomodate request */
  308. char *ibuf;
  309. ibuf = (char *)xrealloc(oci->buffer, needed);
  310. if (!ibuf)
  311. {
  312. YieldControlDeath();
  313. return -1;
  314. }
  315. oci->size = needed;
  316. oci->buffer = ibuf;
  317. }
  318. oci->bufptr = oci->buffer;
  319. oci->bufcnt = gotnow;
  320. }
  321. /* XXX this is a workaround. This function is sometimes called
  322. * after the trans_conn has been freed. In this case trans_conn
  323. * will be null. Really ought to restructure things so that we
  324. * never get here in those circumstances.
  325. */
  326. if (!oc->trans_conn)
  327. {
  328. /* treat as if an error occured on the read, which is what
  329. * used to happen
  330. */
  331. YieldControlDeath();
  332. return -1;
  333. }
  334. #ifdef LBX
  335. if (oc->proxy && oc->proxy->compHandle)
  336. result = (*oc->proxy->streamOpts.streamCompRead)(fd,
  337. (unsigned char *)oci->buffer + oci->bufcnt,
  338. oci->size - oci->bufcnt);
  339. else
  340. #endif
  341. result = _XSERVTransRead(oc->trans_conn, oci->buffer + oci->bufcnt,
  342. oci->size - oci->bufcnt);
  343. if (result <= 0)
  344. {
  345. if ((result < 0) && ETEST(errno))
  346. {
  347. #if defined(SVR4) && defined(i386) && !defined(sun)
  348. #if defined(LBX) && 0
  349. /*
  350. * For LBX connections, we can get a valid EWOULDBLOCK
  351. * There is probably a better way of distinguishing LBX
  352. * connections, but this works. (DHD)
  353. */
  354. extern int LbxRead();
  355. if (oc->Read == LbxRead)
  356. #else
  357. if (0)
  358. #endif
  359. #endif
  360. {
  361. YieldControlNoInput();
  362. return 0;
  363. }
  364. }
  365. YieldControlDeath();
  366. return -1;
  367. }
  368. oci->bufcnt += result;
  369. gotnow += result;
  370. /* free up some space after huge requests */
  371. if ((oci->size > BUFWATERMARK) &&
  372. (oci->bufcnt < BUFSIZE) && (needed < BUFSIZE))
  373. {
  374. char *ibuf;
  375. ibuf = (char *)xrealloc(oci->buffer, BUFSIZE);
  376. if (ibuf)
  377. {
  378. oci->size = BUFSIZE;
  379. oci->buffer = ibuf;
  380. oci->bufptr = ibuf + oci->bufcnt - gotnow;
  381. }
  382. }
  383. if (need_header && gotnow >= needed)
  384. {
  385. /* We wanted an xReq, now we've gotten it. */
  386. request = (xReq *)oci->bufptr;
  387. needed = get_req_len(request, client);
  388. #ifdef BIGREQS
  389. if (!needed && client->big_requests)
  390. {
  391. move_header = TRUE;
  392. if (gotnow < sizeof(xBigReq))
  393. needed = sizeof(xBigReq) >> 2;
  394. else
  395. needed = get_big_req_len(request, client);
  396. }
  397. #endif
  398. client->req_len = needed;
  399. needed <<= 2;
  400. }
  401. if (gotnow < needed)
  402. {
  403. /* Still don't have enough; punt. */
  404. YieldControlNoInput();
  405. return 0;
  406. }
  407. }
  408. if (needed == 0)
  409. {
  410. #ifdef BIGREQS
  411. if (client->big_requests)
  412. needed = sizeof(xBigReq);
  413. else
  414. #endif
  415. needed = sizeof(xReq);
  416. }
  417. oci->lenLastReq = needed;
  418. /*
  419. * Check to see if client has at least one whole request in the
  420. * buffer beyond the request we're returning to the caller.
  421. * If there is only a partial request, treat like buffer
  422. * is empty so that select() will be called again and other clients
  423. * can get into the queue.
  424. */
  425. gotnow -= needed;
  426. if (gotnow >= sizeof(xReq))
  427. {
  428. request = (xReq *)(oci->bufptr + needed);
  429. if (gotnow >= (result = (get_req_len(request, client) << 2))
  430. #ifdef BIGREQS
  431. && (result ||
  432. (client->big_requests &&
  433. (gotnow >= sizeof(xBigReq) &&
  434. gotnow >= (get_big_req_len(request, client) << 2))))
  435. #endif
  436. )
  437. FD_SET(fd, &ClientsWithInput);
  438. else
  439. {
  440. #ifdef SMART_SCHEDULE
  441. if (!SmartScheduleDisable)
  442. FD_CLR(fd, &ClientsWithInput);
  443. else
  444. #endif
  445. YieldControlNoInput();
  446. }
  447. }
  448. else
  449. {
  450. if (!gotnow)
  451. AvailableInput = oc;
  452. #ifdef SMART_SCHEDULE
  453. if (!SmartScheduleDisable)
  454. FD_CLR(fd, &ClientsWithInput);
  455. else
  456. #endif
  457. YieldControlNoInput();
  458. }
  459. #ifdef SMART_SCHEDULE
  460. if (SmartScheduleDisable)
  461. #endif
  462. if (++timesThisConnection >= MAX_TIMES_PER)
  463. YieldControl();
  464. #ifdef BIGREQS
  465. if (move_header)
  466. {
  467. request = (xReq *)oci->bufptr;
  468. oci->bufptr += (sizeof(xBigReq) - sizeof(xReq));
  469. *(xReq *)oci->bufptr = *request;
  470. oci->lenLastReq -= (sizeof(xBigReq) - sizeof(xReq));
  471. client->req_len -= (sizeof(xBigReq) - sizeof(xReq)) >> 2;
  472. }
  473. #endif
  474. client->requestBuffer = (pointer)oci->bufptr;
  475. #ifdef DEBUG_COMMUNICATION
  476. {
  477. xReq *req = client->requestBuffer;
  478. ErrorF("REQUEST: ClientIDX: %i, type: 0x%x data: 0x%x len: %i\n",
  479. client->index,req->reqType,req->data,req->length);
  480. }
  481. #endif
  482. return needed;
  483. }
  484. /*****************************************************************
  485. * InsertFakeRequest
  486. * Splice a consed up (possibly partial) request in as the next request.
  487. *
  488. **********************/
  489. Bool
  490. InsertFakeRequest(ClientPtr client, char *data, int count)
  491. {
  492. OsCommPtr oc = (OsCommPtr)client->osPrivate;
  493. ConnectionInputPtr oci = oc->input;
  494. int fd = oc->fd;
  495. int gotnow, moveup;
  496. if (AvailableInput)
  497. {
  498. if (AvailableInput != oc)
  499. {
  500. ConnectionInputPtr aci = AvailableInput->input;
  501. if (aci->size > BUFWATERMARK)
  502. {
  503. xfree(aci->buffer);
  504. xfree(aci);
  505. }
  506. else
  507. {
  508. aci->next = FreeInputs;
  509. FreeInputs = aci;
  510. }
  511. AvailableInput->input = (ConnectionInputPtr)NULL;
  512. }
  513. AvailableInput = (OsCommPtr)NULL;
  514. }
  515. if (!oci)
  516. {
  517. if ((oci = FreeInputs))
  518. FreeInputs = oci->next;
  519. else if (!(oci = AllocateInputBuffer()))
  520. return FALSE;
  521. oc->input = oci;
  522. }
  523. oci->bufptr += oci->lenLastReq;
  524. oci->lenLastReq = 0;
  525. gotnow = oci->bufcnt + oci->buffer - oci->bufptr;
  526. if ((gotnow + count) > oci->size)
  527. {
  528. char *ibuf;
  529. ibuf = (char *)xrealloc(oci->buffer, gotnow + count);
  530. if (!ibuf)
  531. return(FALSE);
  532. oci->size = gotnow + count;
  533. oci->buffer = ibuf;
  534. oci->bufptr = ibuf + oci->bufcnt - gotnow;
  535. }
  536. moveup = count - (oci->bufptr - oci->buffer);
  537. if (moveup > 0)
  538. {
  539. if (gotnow > 0)
  540. memmove(oci->bufptr + moveup, oci->bufptr, gotnow);
  541. oci->bufptr += moveup;
  542. oci->bufcnt += moveup;
  543. }
  544. memmove(oci->bufptr - count, data, count);
  545. oci->bufptr -= count;
  546. gotnow += count;
  547. if ((gotnow >= sizeof(xReq)) &&
  548. (gotnow >= (int)(get_req_len((xReq *)oci->bufptr, client) << 2)))
  549. FD_SET(fd, &ClientsWithInput);
  550. else
  551. YieldControlNoInput();
  552. return(TRUE);
  553. }
  554. /*****************************************************************
  555. * ResetRequestFromClient
  556. * Reset to reexecute the current request, and yield.
  557. *
  558. **********************/
  559. void
  560. ResetCurrentRequest(ClientPtr client)
  561. {
  562. OsCommPtr oc = (OsCommPtr)client->osPrivate;
  563. register ConnectionInputPtr oci = oc->input;
  564. int fd = oc->fd;
  565. register xReq *request;
  566. int gotnow, needed;
  567. #ifdef LBX
  568. LbxClientPtr lbxClient = LbxClient(client);
  569. if (lbxClient) {
  570. LbxSetForBlock(lbxClient);
  571. if (!oci) {
  572. AppendFakeRequest(client,
  573. client->requestBuffer, client->req_len << 2);
  574. return;
  575. }
  576. }
  577. #endif
  578. if (AvailableInput == oc)
  579. AvailableInput = (OsCommPtr)NULL;
  580. oci->lenLastReq = 0;
  581. gotnow = oci->bufcnt + oci->buffer - oci->bufptr;
  582. if (gotnow < sizeof(xReq))
  583. {
  584. YieldControlNoInput();
  585. }
  586. else
  587. {
  588. request = (xReq *)oci->bufptr;
  589. needed = get_req_len(request, client);
  590. #ifdef BIGREQS
  591. if (!needed && client->big_requests)
  592. {
  593. oci->bufptr -= sizeof(xBigReq) - sizeof(xReq);
  594. *(xReq *)oci->bufptr = *request;
  595. ((xBigReq *)oci->bufptr)->length = client->req_len;
  596. if (client->swapped)
  597. {
  598. char n;
  599. swapl(&((xBigReq *)oci->bufptr)->length, n);
  600. }
  601. }
  602. #endif
  603. if (gotnow >= (needed << 2))
  604. {
  605. if (FD_ISSET(fd, &AllClients))
  606. {
  607. FD_SET(fd, &ClientsWithInput);
  608. }
  609. else
  610. {
  611. FD_SET(fd, &IgnoredClientsWithInput);
  612. }
  613. YieldControl();
  614. }
  615. else
  616. YieldControlNoInput();
  617. }
  618. }
  619. /*****************************************************************
  620. * PeekNextRequest and SkipRequests were implemented to support DBE
  621. * idioms, but can certainly be used outside of DBE. There are two
  622. * related macros in os.h, ReqLen and CastxReq. See the porting
  623. * layer document for more details.
  624. *
  625. **********************/
  626. /*****************************************************************
  627. * PeekNextRequest
  628. * lets you look ahead at the unexecuted requests in a
  629. * client's request buffer.
  630. *
  631. * Note: this implementation of PeekNextRequest ignores the
  632. * readmore parameter.
  633. *
  634. **********************/
  635. xReqPtr
  636. PeekNextRequest(
  637. xReqPtr req, /* request we're starting from */
  638. ClientPtr client, /* client whose requests we're skipping */
  639. Bool readmore) /* attempt to read more if next request isn't there? */
  640. {
  641. register ConnectionInputPtr oci = ((OsCommPtr)client->osPrivate)->input;
  642. xReqPtr pnextreq;
  643. int needed, gotnow, reqlen;
  644. if (!oci) return NULL;
  645. if (!req)
  646. {
  647. /* caller wants the request after the one currently being executed */
  648. pnextreq = (xReqPtr)
  649. (((CARD32 *)client->requestBuffer) + client->req_len);
  650. }
  651. else
  652. {
  653. /* caller wants the request after the one specified by req */
  654. reqlen = get_req_len(req, client);
  655. #ifdef BIGREQS
  656. if (!reqlen) reqlen = get_big_req_len(req, client);
  657. #endif
  658. pnextreq = (xReqPtr)(((char *)req) + (reqlen << 2));
  659. }
  660. /* see how much of the next request we have available */
  661. gotnow = oci->bufcnt - (((char *)pnextreq) - oci->buffer);
  662. if (gotnow < sizeof(xReq))
  663. return NULL;
  664. needed = get_req_len(pnextreq, client) << 2;
  665. #ifdef BIGREQS
  666. if (!needed)
  667. {
  668. /* it's a big request */
  669. if (gotnow < sizeof(xBigReq))
  670. return NULL;
  671. needed = get_big_req_len(pnextreq, client) << 2;
  672. }
  673. #endif
  674. /* if we have less than we need, return NULL */
  675. return (gotnow < needed) ? NULL : pnextreq;
  676. }
  677. /*****************************************************************
  678. * SkipRequests
  679. * lets you skip over some of the requests in a client's
  680. * request buffer. Presumably the caller has used PeekNextRequest
  681. * to examine the requests being skipped and has performed whatever
  682. * actions they dictate.
  683. *
  684. **********************/
  685. CallbackListPtr SkippedRequestsCallback = NULL;
  686. void
  687. SkipRequests(
  688. xReqPtr req, /* last request being skipped */
  689. ClientPtr client, /* client whose requests we're skipping */
  690. int numskipped) /* how many requests we're skipping */
  691. {
  692. OsCommPtr oc = (OsCommPtr)client->osPrivate;
  693. register ConnectionInputPtr oci = oc->input;
  694. int reqlen;
  695. /* see if anyone wants to snoop the skipped requests */
  696. if (SkippedRequestsCallback)
  697. {
  698. SkippedRequestInfoRec skipinfo;
  699. skipinfo.req = req;
  700. skipinfo.client = client;
  701. skipinfo.numskipped = numskipped;
  702. CallCallbacks(&SkippedRequestsCallback, &skipinfo);
  703. }
  704. /* adjust the sequence number */
  705. client->sequence += numskipped;
  706. /* twiddle the oci to skip over the requests */
  707. reqlen = get_req_len(req, client);
  708. #ifdef BIGREQS
  709. if (!reqlen) reqlen = get_big_req_len(req, client);
  710. #endif
  711. reqlen <<= 2;
  712. oci->bufptr = (char *)req;
  713. oci->lenLastReq = reqlen;
  714. /* see if any requests left in the buffer */
  715. if ( ((char *)req + reqlen) == (oci->buffer + oci->bufcnt) )
  716. {
  717. /* no requests; mark input buffer as available and client
  718. * as having no input
  719. */
  720. int fd = oc->fd;
  721. AvailableInput = oc;
  722. YieldControlNoInput();
  723. }
  724. }
  725. /* lookup table for adding padding bytes to data that is read from
  726. or written to the X socket. */
  727. static int padlength[4] = {0, 3, 2, 1};
  728. /********************
  729. * FlushAllOutput()
  730. * Flush all clients with output. However, if some client still
  731. * has input in the queue (more requests), then don't flush. This
  732. * will prevent the output queue from being flushed every time around
  733. * the round robin queue. Now, some say that it SHOULD be flushed
  734. * every time around, but...
  735. *
  736. **********************/
  737. void
  738. FlushAllOutput(void)
  739. {
  740. register int index, base;
  741. register fd_mask mask; /* raphael */
  742. OsCommPtr oc;
  743. register ClientPtr client;
  744. Bool newoutput = NewOutputPending;
  745. #if defined(WIN32)
  746. fd_set newOutputPending;
  747. #endif
  748. if (FlushCallback)
  749. CallCallbacks(&FlushCallback, NULL);
  750. if (!newoutput)
  751. return;
  752. /*
  753. * It may be that some client still has critical output pending,
  754. * but he is not yet ready to receive it anyway, so we will
  755. * simply wait for the select to tell us when he's ready to receive.
  756. */
  757. CriticalOutputPending = FALSE;
  758. NewOutputPending = FALSE;
  759. #ifndef WIN32
  760. for (base = 0; base < howmany(XFD_SETSIZE, NFDBITS); base++)
  761. {
  762. mask = OutputPending.fds_bits[ base ];
  763. OutputPending.fds_bits[ base ] = 0;
  764. while (mask)
  765. {
  766. index = ffs(mask) - 1;
  767. mask &= ~lowbit(mask);
  768. if ((index = ConnectionTranslation[(base * (sizeof(fd_mask)*8)) + index]) == 0)
  769. continue;
  770. client = clients[index];
  771. if (client->clientGone)
  772. continue;
  773. oc = (OsCommPtr)client->osPrivate;
  774. if (
  775. #ifdef LBX
  776. !oc->proxy &&
  777. #endif
  778. FD_ISSET(oc->fd, &ClientsWithInput))
  779. {
  780. FD_SET(oc->fd, &OutputPending); /* set the bit again */
  781. NewOutputPending = TRUE;
  782. }
  783. else
  784. (void)FlushClient(client, oc, (char *)NULL, 0);
  785. }
  786. }
  787. #else /* WIN32 */
  788. FD_ZERO(&newOutputPending);
  789. for (base = 0; base < XFD_SETCOUNT(&OutputPending); base++)
  790. {
  791. index = XFD_FD(&OutputPending, base);
  792. if ((index = GetConnectionTranslation(index)) == 0)
  793. continue;
  794. client = clients[index];
  795. if (client->clientGone)
  796. continue;
  797. oc = (OsCommPtr)client->osPrivate;
  798. if (
  799. #ifdef LBX
  800. !oc->proxy &&
  801. #endif
  802. FD_ISSET(oc->fd, &ClientsWithInput))
  803. {
  804. FD_SET(oc->fd, &newOutputPending); /* set the bit again */
  805. NewOutputPending = TRUE;
  806. }
  807. else
  808. (void)FlushClient(client, oc, (char *)NULL, 0);
  809. }
  810. XFD_COPYSET(&newOutputPending, &OutputPending);
  811. #endif /* WIN32 */
  812. }
  813. void
  814. FlushIfCriticalOutputPending(void)
  815. {
  816. if (CriticalOutputPending)
  817. FlushAllOutput();
  818. }
  819. void
  820. SetCriticalOutputPending(void)
  821. {
  822. CriticalOutputPending = TRUE;
  823. }
  824. /*****************
  825. * WriteToClient
  826. * Copies buf into ClientPtr.buf if it fits (with padding), else
  827. * flushes ClientPtr.buf and buf to client. As of this writing,
  828. * every use of WriteToClient is cast to void, and the result
  829. * is ignored. Potentially, this could be used by requests
  830. * that are sending several chunks of data and want to break
  831. * out of a loop on error. Thus, we will leave the type of
  832. * this routine as int.
  833. *****************/
  834. int
  835. WriteToClient (ClientPtr who, int count, char *buf)
  836. {
  837. OsCommPtr oc = (OsCommPtr)who->osPrivate;
  838. ConnectionOutputPtr oco = oc->output;
  839. int padBytes;
  840. #ifdef DEBUG_COMMUNICATION
  841. Bool multicount = FALSE;
  842. #endif
  843. if (!count)
  844. return(0);
  845. #ifdef DEBUG_COMMUNICATION
  846. {
  847. char info[128];
  848. xError *err;
  849. xGenericReply *rep;
  850. xEvent *ev;
  851. if (!who->replyBytesRemaining) {
  852. switch(buf[0]) {
  853. case X_Reply:
  854. rep = (xGenericReply*)buf;
  855. if (rep->sequenceNumber == who->sequence) {
  856. snprintf(info,127,"Xreply: type: 0x%x data: 0x%x "
  857. "len: %i seq#: 0x%x", rep->type, rep->data1,
  858. rep->length, rep->sequenceNumber);
  859. multicount = TRUE;
  860. }
  861. break;
  862. case X_Error:
  863. err = (xError*)buf;
  864. snprintf(info,127,"Xerror: Code: 0x%x resID: 0x%x maj: 0x%x "
  865. "min: %x", err->errorCode,err->resourceID,
  866. err->minorCode,err->majorCode);
  867. break;
  868. default:
  869. if ((buf[0] & 0x7f) == KeymapNotify)
  870. snprintf(info,127,"KeymapNotifyEvent: %i",buf[0]);
  871. else {
  872. ev = (xEvent*)buf;
  873. snprintf(info,127,"XEvent: type: 0x%x detail: 0x%x "
  874. "seq#: 0x%x", ev->u.u.type, ev->u.u.detail,
  875. ev->u.u.sequenceNumber);
  876. }
  877. }
  878. ErrorF("REPLY: ClientIDX: %i %s\n",who->index, info);
  879. } else
  880. multicount = TRUE;
  881. }
  882. #endif
  883. if (!oco)
  884. {
  885. if ((oco = FreeOutputs))
  886. {
  887. FreeOutputs = oco->next;
  888. }
  889. else if (!(oco = AllocateOutputBuffer()))
  890. {
  891. if (oc->trans_conn) {
  892. _XSERVTransDisconnect(oc->trans_conn);
  893. _XSERVTransClose(oc->trans_conn);
  894. oc->trans_conn = NULL;
  895. }
  896. MarkClientException(who);
  897. return -1;
  898. }
  899. oc->output = oco;
  900. }
  901. padBytes = padlength[count & 3];
  902. if(ReplyCallback)
  903. {
  904. ReplyInfoRec replyinfo;
  905. replyinfo.client = who;
  906. replyinfo.replyData = buf;
  907. replyinfo.dataLenBytes = count + padBytes;
  908. if (who->replyBytesRemaining)
  909. { /* still sending data of an earlier reply */
  910. who->replyBytesRemaining -= count + padBytes;
  911. replyinfo.startOfReply = FALSE;
  912. replyinfo.bytesRemaining = who->replyBytesRemaining;
  913. CallCallbacks((&ReplyCallback), (pointer)&replyinfo);
  914. }
  915. else if (who->clientState == ClientStateRunning
  916. && buf[0] == X_Reply)
  917. { /* start of new reply */
  918. CARD32 replylen;
  919. unsigned long bytesleft;
  920. char n;
  921. replylen = ((xGenericReply *)buf)->length;
  922. if (who->swapped)
  923. swapl(&replylen, n);
  924. bytesleft = (replylen * 4) + SIZEOF(xReply) - count - padBytes;
  925. replyinfo.startOfReply = TRUE;
  926. replyinfo.bytesRemaining = who->replyBytesRemaining = bytesleft;
  927. CallCallbacks((&ReplyCallback), (pointer)&replyinfo);
  928. }
  929. }
  930. #ifdef DEBUG_COMMUNICATION
  931. else if (multicount) {
  932. if (who->replyBytesRemaining) {
  933. who->replyBytesRemaining -= (count + padBytes);
  934. } else {
  935. CARD32 replylen;
  936. replylen = ((xGenericReply *)buf)->length;
  937. who->replyBytesRemaining =
  938. (replylen * 4) + SIZEOF(xReply) - count - padBytes;
  939. }
  940. }
  941. #endif
  942. if (oco->count + count + padBytes > oco->size)
  943. {
  944. FD_CLR(oc->fd, &OutputPending);
  945. if(!XFD_ANYSET(&OutputPending)) {
  946. CriticalOutputPending = FALSE;
  947. NewOutputPending = FALSE;
  948. }
  949. return FlushClient(who, oc, buf, count);
  950. }
  951. NewOutputPending = TRUE;
  952. FD_SET(oc->fd, &OutputPending);
  953. memmove((char *)oco->buf + oco->count, buf, count);
  954. oco->count += count + padBytes;
  955. return(count);
  956. }
  957. /********************
  958. * FlushClient()
  959. * If the client isn't keeping up with us, then we try to continue
  960. * buffering the data and set the apropriate bit in ClientsWritable
  961. * (which is used by WaitFor in the select). If the connection yields
  962. * a permanent error, or we can't allocate any more space, we then
  963. * close the connection.
  964. *
  965. **********************/
  966. #ifdef LBX
  967. #ifdef LBX_NEED_OLD_SYMBOL_FOR_LOADABLES
  968. #undef FlushClient
  969. int
  970. FlushClient(ClientPtr who, OsCommPtr oc, char *extraBuf, int extraCount)
  971. {
  972. return (*oc->Flush)(who, oc, extraBuf, extraCount);
  973. }
  974. #endif
  975. int
  976. StandardFlushClient(ClientPtr who, OsCommPtr oc,
  977. char *extraBuf, int extraCount)
  978. #else
  979. int
  980. FlushClient(ClientPtr who, OsCommPtr oc, char *extraBuf, int extraCount)
  981. #endif
  982. {
  983. ConnectionOutputPtr oco = oc->output;
  984. int connection = oc->fd;
  985. XtransConnInfo trans_conn = oc->trans_conn;
  986. struct iovec iov[3];
  987. static char padBuffer[3];
  988. long written;
  989. long padsize;
  990. long notWritten;
  991. long todo;
  992. if (!oco)
  993. return 0;
  994. written = 0;
  995. padsize = padlength[extraCount & 3];
  996. notWritten = oco->count + extraCount + padsize;
  997. todo = notWritten;
  998. while (notWritten) {
  999. long before = written; /* amount of whole thing written */
  1000. long remain = todo; /* amount to try this time, <= notWritten */
  1001. int i = 0;
  1002. long len;
  1003. /* You could be very general here and have "in" and "out" iovecs
  1004. * and write a loop without using a macro, but what the heck. This
  1005. * translates to:
  1006. *
  1007. * how much of this piece is new?
  1008. * if more new then we are trying this time, clamp
  1009. * if nothing new
  1010. * then bump down amount already written, for next piece
  1011. * else put new stuff in iovec, will need all of next piece
  1012. *
  1013. * Note that todo had better be at least 1 or else we'll end up
  1014. * writing 0 iovecs.
  1015. */
  1016. #define InsertIOV(pointer, length) \
  1017. len = (length) - before; \
  1018. if (len > remain) \
  1019. len = remain; \
  1020. if (len <= 0) { \
  1021. before = (-len); \
  1022. } else { \
  1023. iov[i].iov_len = len; \
  1024. iov[i].iov_base = (pointer) + before; \
  1025. i++; \
  1026. remain -= len; \
  1027. before = 0; \
  1028. }
  1029. InsertIOV ((char *)oco->buf, oco->count)
  1030. InsertIOV (extraBuf, extraCount)
  1031. InsertIOV (padBuffer, padsize)
  1032. errno = 0;
  1033. if (trans_conn && (len = _XSERVTransWritev(trans_conn, iov, i)) >= 0)
  1034. {
  1035. written += len;
  1036. notWritten -= len;
  1037. todo = notWritten;
  1038. }
  1039. else if (ETEST(errno)
  1040. #ifdef SUNSYSV /* check for another brain-damaged OS bug */
  1041. || (errno == 0)
  1042. #endif
  1043. #ifdef EMSGSIZE /* check for another brain-damaged OS bug */
  1044. || ((errno == EMSGSIZE) && (todo == 1))
  1045. #endif
  1046. )
  1047. {
  1048. /* If we've arrived here, then the client is stuffed to the gills
  1049. and not ready to accept more. Make a note of it and buffer
  1050. the rest. */
  1051. FD_SET(connection, &ClientsWriteBlocked);
  1052. AnyClientsWriteBlocked = TRUE;
  1053. if (written < oco->count)
  1054. {
  1055. if (written > 0)
  1056. {
  1057. oco->count -= written;
  1058. memmove((char *)oco->buf,
  1059. (char *)oco->buf + written,
  1060. oco->count);
  1061. written = 0;
  1062. }
  1063. }
  1064. else
  1065. {
  1066. written -= oco->count;
  1067. oco->count = 0;
  1068. }
  1069. if (notWritten > oco->size)
  1070. {
  1071. unsigned char *obuf;
  1072. obuf = (unsigned char *)xrealloc(oco->buf,
  1073. notWritten + BUFSIZE);
  1074. if (!obuf)
  1075. {
  1076. _XSERVTransDisconnect(oc->trans_conn);
  1077. _XSERVTransClose(oc->trans_conn);
  1078. oc->trans_conn = NULL;
  1079. MarkClientException(who);
  1080. oco->count = 0;
  1081. return(-1);
  1082. }
  1083. oco->size = notWritten + BUFSIZE;
  1084. oco->buf = obuf;
  1085. }
  1086. /* If the amount written extended into the padBuffer, then the
  1087. difference "extraCount - written" may be less than 0 */
  1088. if ((len = extraCount - written) > 0)
  1089. memmove ((char *)oco->buf + oco->count,
  1090. extraBuf + written,
  1091. len);
  1092. oco->count = notWritten; /* this will include the pad */
  1093. /* return only the amount explicitly requested */
  1094. return extraCount;
  1095. }
  1096. #ifdef EMSGSIZE /* check for another brain-damaged OS bug */
  1097. else if (errno == EMSGSIZE)
  1098. {
  1099. todo >>= 1;
  1100. }
  1101. #endif
  1102. else
  1103. {
  1104. if (oc->trans_conn)
  1105. {
  1106. _XSERVTransDisconnect(oc->trans_conn);
  1107. _XSERVTransClose(oc->trans_conn);
  1108. oc->trans_conn = NULL;
  1109. }
  1110. MarkClientException(who);
  1111. oco->count = 0;
  1112. return(-1);
  1113. }
  1114. }
  1115. /* everything was flushed out */
  1116. oco->count = 0;
  1117. /* check to see if this client was write blocked */
  1118. if (AnyClientsWriteBlocked)
  1119. {
  1120. FD_CLR(oc->fd, &ClientsWriteBlocked);
  1121. if (! XFD_ANYSET(&ClientsWriteBlocked))
  1122. AnyClientsWriteBlocked = FALSE;
  1123. }
  1124. if (oco->size > BUFWATERMARK)
  1125. {
  1126. xfree(oco->buf);
  1127. xfree(oco);
  1128. }
  1129. else
  1130. {
  1131. oco->next = FreeOutputs;
  1132. FreeOutputs = oco;
  1133. }
  1134. oc->output = (ConnectionOutputPtr)NULL;
  1135. return extraCount; /* return only the amount explicitly requested */
  1136. }
  1137. ConnectionInputPtr
  1138. AllocateInputBuffer(void)
  1139. {
  1140. ConnectionInputPtr oci;
  1141. oci = (ConnectionInputPtr)xalloc(sizeof(ConnectionInput));
  1142. if (!oci)
  1143. return (ConnectionInputPtr)NULL;
  1144. oci->buffer = (char *)xalloc(BUFSIZE);
  1145. if (!oci->buffer)
  1146. {
  1147. xfree(oci);
  1148. return (ConnectionInputPtr)NULL;
  1149. }
  1150. oci->size = BUFSIZE;
  1151. oci->bufptr = oci->buffer;
  1152. oci->bufcnt = 0;
  1153. oci->lenLastReq = 0;
  1154. return oci;
  1155. }
  1156. ConnectionOutputPtr
  1157. AllocateOutputBuffer(void)
  1158. {
  1159. ConnectionOutputPtr oco;
  1160. oco = (ConnectionOutputPtr)xalloc(sizeof(ConnectionOutput));
  1161. if (!oco)
  1162. return (ConnectionOutputPtr)NULL;
  1163. oco->buf = (unsigned char *) xalloc(BUFSIZE);
  1164. if (!oco->buf)
  1165. {
  1166. xfree(oco);
  1167. return (ConnectionOutputPtr)NULL;
  1168. }
  1169. oco->size = BUFSIZE;
  1170. oco->count = 0;
  1171. #ifdef LBX
  1172. oco->nocompress = FALSE;
  1173. #endif
  1174. return oco;
  1175. }
  1176. void
  1177. FreeOsBuffers(OsCommPtr oc)
  1178. {
  1179. ConnectionInputPtr oci;
  1180. ConnectionOutputPtr oco;
  1181. if (AvailableInput == oc)
  1182. AvailableInput = (OsCommPtr)NULL;
  1183. if ((oci = oc->input))
  1184. {
  1185. if (FreeInputs)
  1186. {
  1187. xfree(oci->buffer);
  1188. xfree(oci);
  1189. }
  1190. else
  1191. {
  1192. FreeInputs = oci;
  1193. oci->next = (ConnectionInputPtr)NULL;
  1194. oci->bufptr = oci->buffer;
  1195. oci->bufcnt = 0;
  1196. oci->lenLastReq = 0;
  1197. }
  1198. }
  1199. if ((oco = oc->output))
  1200. {
  1201. if (FreeOutputs)
  1202. {
  1203. xfree(oco->buf);
  1204. xfree(oco);
  1205. }
  1206. else
  1207. {
  1208. FreeOutputs = oco;
  1209. oco->next = (ConnectionOutputPtr)NULL;
  1210. oco->count = 0;
  1211. }
  1212. }
  1213. #ifdef LBX
  1214. if ((oci = oc->largereq)) {
  1215. xfree(oci->buffer);
  1216. xfree(oci);
  1217. }
  1218. #endif
  1219. }
  1220. void
  1221. ResetOsBuffers(void)
  1222. {
  1223. ConnectionInputPtr oci;
  1224. ConnectionOutputPtr oco;
  1225. while ((oci = FreeInputs))
  1226. {
  1227. FreeInputs = oci->next;
  1228. xfree(oci->buffer);
  1229. xfree(oci);
  1230. }
  1231. while ((oco = FreeOutputs))
  1232. {
  1233. FreeOutputs = oco->next;
  1234. xfree(oco->buf);
  1235. xfree(oco);
  1236. }
  1237. }