1706f2543Smrg/*********************************************************** 2706f2543Smrg 3706f2543SmrgCopyright 1987, 1989, 1998 The Open Group 4706f2543Smrg 5706f2543SmrgPermission to use, copy, modify, distribute, and sell this software and its 6706f2543Smrgdocumentation for any purpose is hereby granted without fee, provided that 7706f2543Smrgthe above copyright notice appear in all copies and that both that 8706f2543Smrgcopyright notice and this permission notice appear in supporting 9706f2543Smrgdocumentation. 10706f2543Smrg 11706f2543SmrgThe above copyright notice and this permission notice shall be included in 12706f2543Smrgall copies or substantial portions of the Software. 13706f2543Smrg 14706f2543SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15706f2543SmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16706f2543SmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17706f2543SmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 18706f2543SmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19706f2543SmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20706f2543Smrg 21706f2543SmrgExcept as contained in this notice, the name of The Open Group shall not be 22706f2543Smrgused in advertising or otherwise to promote the sale, use or other dealings 23706f2543Smrgin this Software without prior written authorization from The Open Group. 24706f2543Smrg 25706f2543Smrg 26706f2543SmrgCopyright 1987, 1989 by Digital Equipment Corporation, Maynard, Massachusetts. 27706f2543Smrg 28706f2543Smrg All Rights Reserved 29706f2543Smrg 30706f2543SmrgPermission to use, copy, modify, and distribute this software and its 31706f2543Smrgdocumentation for any purpose and without fee is hereby granted, 32706f2543Smrgprovided that the above copyright notice appear in all copies and that 33706f2543Smrgboth that copyright notice and this permission notice appear in 34706f2543Smrgsupporting documentation, and that the name of Digital not be 35706f2543Smrgused in advertising or publicity pertaining to distribution of the 36706f2543Smrgsoftware without specific, written prior permission. 37706f2543Smrg 38706f2543SmrgDIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 39706f2543SmrgALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 40706f2543SmrgDIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 41706f2543SmrgANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 42706f2543SmrgWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 43706f2543SmrgARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 44706f2543SmrgSOFTWARE. 45706f2543Smrg 46706f2543Smrg 47706f2543Smrg******************************************************************/ 48706f2543Smrg/***************************************************************** 49706f2543Smrg * i/o functions 50706f2543Smrg * 51706f2543Smrg * WriteToClient, ReadRequestFromClient 52706f2543Smrg * InsertFakeRequest, ResetCurrentRequest 53706f2543Smrg * 54706f2543Smrg *****************************************************************/ 55706f2543Smrg 56706f2543Smrg#include <X11/Xpoll.h> 57706f2543Smrg 58706f2543Smrg#ifdef HAVE_DIX_CONFIG_H 59706f2543Smrg#include <dix-config.h> 60706f2543Smrg#endif 61706f2543Smrg 62706f2543Smrg#undef DEBUG_COMMUNICATION 63706f2543Smrg 64706f2543Smrg#ifdef WIN32 65706f2543Smrg#include <X11/Xwinsock.h> 66706f2543Smrg#endif 67706f2543Smrg#include <stdio.h> 68706f2543Smrg#define XSERV_t 69706f2543Smrg#define TRANS_SERVER 70706f2543Smrg#define TRANS_REOPEN 71706f2543Smrg#include <X11/Xtrans/Xtrans.h> 72706f2543Smrg#include <X11/Xmd.h> 73706f2543Smrg#include <errno.h> 74706f2543Smrg#if !defined(WIN32) 75706f2543Smrg#include <sys/uio.h> 76706f2543Smrg#endif 77706f2543Smrg#include <X11/X.h> 78706f2543Smrg#include <X11/Xproto.h> 79706f2543Smrg#include "os.h" 80706f2543Smrg#include "osdep.h" 81706f2543Smrg#include "opaque.h" 82706f2543Smrg#include "dixstruct.h" 83706f2543Smrg#include "misc.h" 84706f2543Smrg 85706f2543SmrgCallbackListPtr ReplyCallback; 86706f2543SmrgCallbackListPtr FlushCallback; 87706f2543Smrg 88706f2543Smrgstatic ConnectionInputPtr AllocateInputBuffer(void); 89706f2543Smrgstatic ConnectionOutputPtr AllocateOutputBuffer(void); 90706f2543Smrg 91706f2543Smrg/* check for both EAGAIN and EWOULDBLOCK, because some supposedly POSIX 92706f2543Smrg * systems are broken and return EWOULDBLOCK when they should return EAGAIN 93706f2543Smrg */ 94706f2543Smrg#ifndef WIN32 95706f2543Smrg#define ETEST(err) (err == EAGAIN || err == EWOULDBLOCK) 96706f2543Smrg#else /* WIN32 The socket errorcodes differ from the normal errors*/ 97706f2543Smrg#define ETEST(err) (err == EAGAIN || err == WSAEWOULDBLOCK) 98706f2543Smrg#endif 99706f2543Smrg 100706f2543Smrgstatic Bool CriticalOutputPending; 101706f2543Smrgstatic int timesThisConnection = 0; 102706f2543Smrgstatic ConnectionInputPtr FreeInputs = (ConnectionInputPtr)NULL; 103706f2543Smrgstatic ConnectionOutputPtr FreeOutputs = (ConnectionOutputPtr)NULL; 104706f2543Smrgstatic OsCommPtr AvailableInput = (OsCommPtr)NULL; 105706f2543Smrg 106706f2543Smrg#define get_req_len(req,cli) ((cli)->swapped ? \ 107706f2543Smrg lswaps((req)->length) : (req)->length) 108706f2543Smrg 109706f2543Smrg#include <X11/extensions/bigreqsproto.h> 110706f2543Smrg 111706f2543Smrg#define get_big_req_len(req,cli) ((cli)->swapped ? \ 112706f2543Smrg lswapl(((xBigReq *)(req))->length) : \ 113706f2543Smrg ((xBigReq *)(req))->length) 114706f2543Smrg 115706f2543Smrg#define MAX_TIMES_PER 10 116706f2543Smrg 117706f2543Smrg/* 118706f2543Smrg * A lot of the code in this file manipulates a ConnectionInputPtr: 119706f2543Smrg * 120706f2543Smrg * ----------------------------------------------- 121706f2543Smrg * |------- bufcnt ------->| | | 122706f2543Smrg * | |- gotnow ->| | | 123706f2543Smrg * | |-------- needed ------>| | 124706f2543Smrg * |-----------+--------- size --------+---------->| 125706f2543Smrg * ----------------------------------------------- 126706f2543Smrg * ^ ^ 127706f2543Smrg * | | 128706f2543Smrg * buffer bufptr 129706f2543Smrg * 130706f2543Smrg * buffer is a pointer to the start of the buffer. 131706f2543Smrg * bufptr points to the start of the current request. 132706f2543Smrg * bufcnt counts how many bytes are in the buffer. 133706f2543Smrg * size is the size of the buffer in bytes. 134706f2543Smrg * 135706f2543Smrg * In several of the functions, gotnow and needed are local variables 136706f2543Smrg * that do the following: 137706f2543Smrg * 138706f2543Smrg * gotnow is the number of bytes of the request that we're 139706f2543Smrg * trying to read that are currently in the buffer. 140706f2543Smrg * Typically, gotnow = (buffer + bufcnt) - bufptr 141706f2543Smrg * 142706f2543Smrg * needed = the length of the request that we're trying to 143706f2543Smrg * read. Watch out: needed sometimes counts bytes and sometimes 144706f2543Smrg * counts CARD32's. 145706f2543Smrg */ 146706f2543Smrg 147706f2543Smrg 148706f2543Smrg/***************************************************************** 149706f2543Smrg * ReadRequestFromClient 150706f2543Smrg * Returns one request in client->requestBuffer. The request 151706f2543Smrg * length will be in client->req_len. Return status is: 152706f2543Smrg * 153706f2543Smrg * > 0 if successful, specifies length in bytes of the request 154706f2543Smrg * = 0 if entire request is not yet available 155706f2543Smrg * < 0 if client should be terminated 156706f2543Smrg * 157706f2543Smrg * The request returned must be contiguous so that it can be 158706f2543Smrg * cast in the dispatcher to the correct request type. Because requests 159706f2543Smrg * are variable length, ReadRequestFromClient() must look at the first 4 160706f2543Smrg * or 8 bytes of a request to determine the length (the request length is 161706f2543Smrg * in the 3rd and 4th bytes of the request unless it is a Big Request 162706f2543Smrg * (see the Big Request Extension), in which case the 3rd and 4th bytes 163706f2543Smrg * are zero and the following 4 bytes are the request length. 164706f2543Smrg * 165706f2543Smrg * Note: in order to make the server scheduler (WaitForSomething()) 166706f2543Smrg * "fair", the ClientsWithInput mask is used. This mask tells which 167706f2543Smrg * clients have FULL requests left in their buffers. Clients with 168706f2543Smrg * partial requests require a read. Basically, client buffers 169706f2543Smrg * are drained before select() is called again. But, we can't keep 170706f2543Smrg * reading from a client that is sending buckets of data (or has 171706f2543Smrg * a partial request) because others clients need to be scheduled. 172706f2543Smrg *****************************************************************/ 173706f2543Smrg 174706f2543Smrgstatic void 175706f2543SmrgYieldControl(void) 176706f2543Smrg{ 177706f2543Smrg isItTimeToYield = TRUE; 178706f2543Smrg timesThisConnection = 0; 179706f2543Smrg} 180706f2543Smrg 181706f2543Smrgstatic void 182706f2543SmrgYieldControlNoInput(int fd) 183706f2543Smrg{ 184706f2543Smrg YieldControl(); 185706f2543Smrg FD_CLR(fd, &ClientsWithInput); 186706f2543Smrg} 187706f2543Smrg 188706f2543Smrgstatic void 189706f2543SmrgYieldControlDeath(void) 190706f2543Smrg{ 191706f2543Smrg timesThisConnection = 0; 192706f2543Smrg} 193706f2543Smrg 194706f2543Smrgint 195706f2543SmrgReadRequestFromClient(ClientPtr client) 196706f2543Smrg{ 197706f2543Smrg OsCommPtr oc = (OsCommPtr)client->osPrivate; 198706f2543Smrg ConnectionInputPtr oci = oc->input; 199706f2543Smrg int fd = oc->fd; 200706f2543Smrg unsigned int gotnow, needed; 201706f2543Smrg int result; 202706f2543Smrg register xReq *request; 203706f2543Smrg Bool need_header; 204706f2543Smrg Bool move_header; 205706f2543Smrg 206706f2543Smrg /* If an input buffer was empty, either free it if it is too big 207706f2543Smrg * or link it into our list of free input buffers. This means that 208706f2543Smrg * different clients can share the same input buffer (at different 209706f2543Smrg * times). This was done to save memory. 210706f2543Smrg */ 211706f2543Smrg 212706f2543Smrg if (AvailableInput) 213706f2543Smrg { 214706f2543Smrg if (AvailableInput != oc) 215706f2543Smrg { 216706f2543Smrg register ConnectionInputPtr aci = AvailableInput->input; 217706f2543Smrg if (aci->size > BUFWATERMARK) 218706f2543Smrg { 219706f2543Smrg free(aci->buffer); 220706f2543Smrg free(aci); 221706f2543Smrg } 222706f2543Smrg else 223706f2543Smrg { 224706f2543Smrg aci->next = FreeInputs; 225706f2543Smrg FreeInputs = aci; 226706f2543Smrg } 227706f2543Smrg AvailableInput->input = (ConnectionInputPtr)NULL; 228706f2543Smrg } 229706f2543Smrg AvailableInput = (OsCommPtr)NULL; 230706f2543Smrg } 231706f2543Smrg 232706f2543Smrg /* make sure we have an input buffer */ 233706f2543Smrg 234706f2543Smrg if (!oci) 235706f2543Smrg { 236706f2543Smrg if ((oci = FreeInputs)) 237706f2543Smrg { 238706f2543Smrg FreeInputs = oci->next; 239706f2543Smrg } 240706f2543Smrg else if (!(oci = AllocateInputBuffer())) 241706f2543Smrg { 242706f2543Smrg YieldControlDeath(); 243706f2543Smrg return -1; 244706f2543Smrg } 245706f2543Smrg oc->input = oci; 246706f2543Smrg } 247706f2543Smrg 248706f2543Smrg /* advance to start of next request */ 249706f2543Smrg 250706f2543Smrg oci->bufptr += oci->lenLastReq; 251706f2543Smrg 252706f2543Smrg need_header = FALSE; 253706f2543Smrg move_header = FALSE; 254706f2543Smrg gotnow = oci->bufcnt + oci->buffer - oci->bufptr; 255706f2543Smrg 256706f2543Smrg if (oci->ignoreBytes > 0) { 257706f2543Smrg if (oci->ignoreBytes > oci->size) 258706f2543Smrg needed = oci->size; 259706f2543Smrg else 260706f2543Smrg needed = oci->ignoreBytes; 261706f2543Smrg } 262706f2543Smrg else if (gotnow < sizeof(xReq)) 263706f2543Smrg { 264706f2543Smrg /* We don't have an entire xReq yet. Can't tell how big 265706f2543Smrg * the request will be until we get the whole xReq. 266706f2543Smrg */ 267706f2543Smrg needed = sizeof(xReq); 268706f2543Smrg need_header = TRUE; 269706f2543Smrg } 270706f2543Smrg else 271706f2543Smrg { 272706f2543Smrg /* We have a whole xReq. We can tell how big the whole 273706f2543Smrg * request will be unless it is a Big Request. 274706f2543Smrg */ 275706f2543Smrg request = (xReq *)oci->bufptr; 276706f2543Smrg needed = get_req_len(request, client); 277706f2543Smrg if (!needed && client->big_requests) 278706f2543Smrg { 279706f2543Smrg /* It's a Big Request. */ 280706f2543Smrg move_header = TRUE; 281706f2543Smrg if (gotnow < sizeof(xBigReq)) 282706f2543Smrg { 283706f2543Smrg /* Still need more data to tell just how big. */ 284706f2543Smrg needed = bytes_to_int32(sizeof(xBigReq)); /* needed is in CARD32s now */ 285706f2543Smrg need_header = TRUE; 286706f2543Smrg } 287706f2543Smrg else 288706f2543Smrg needed = get_big_req_len(request, client); 289706f2543Smrg } 290706f2543Smrg client->req_len = needed; 291706f2543Smrg needed <<= 2; /* needed is in bytes now */ 292706f2543Smrg } 293706f2543Smrg if (gotnow < needed) 294706f2543Smrg { 295706f2543Smrg /* Need to read more data, either so that we can get a 296706f2543Smrg * complete xReq (if need_header is TRUE), a complete 297706f2543Smrg * xBigReq (if move_header is TRUE), or the rest of the 298706f2543Smrg * request (if need_header and move_header are both FALSE). 299706f2543Smrg */ 300706f2543Smrg 301706f2543Smrg oci->lenLastReq = 0; 302706f2543Smrg if (needed > maxBigRequestSize << 2) 303706f2543Smrg { 304706f2543Smrg /* request is too big for us to handle */ 305706f2543Smrg /* 306706f2543Smrg * Mark the rest of it as needing to be ignored, and then return 307706f2543Smrg * the full size. Dispatch() will turn it into a BadLength error. 308706f2543Smrg */ 309706f2543Smrg oci->ignoreBytes = needed - gotnow; 310706f2543Smrg oci->lenLastReq = gotnow; 311706f2543Smrg return needed; 312706f2543Smrg } 313706f2543Smrg if ((gotnow == 0) || 314706f2543Smrg ((oci->bufptr - oci->buffer + needed) > oci->size)) 315706f2543Smrg { 316706f2543Smrg /* no data, or the request is too big to fit in the buffer */ 317706f2543Smrg 318706f2543Smrg if ((gotnow > 0) && (oci->bufptr != oci->buffer)) 319706f2543Smrg /* save the data we've already read */ 320706f2543Smrg memmove(oci->buffer, oci->bufptr, gotnow); 321706f2543Smrg if (needed > oci->size) 322706f2543Smrg { 323706f2543Smrg /* make buffer bigger to accomodate request */ 324706f2543Smrg char *ibuf; 325706f2543Smrg 326706f2543Smrg ibuf = (char *)realloc(oci->buffer, needed); 327706f2543Smrg if (!ibuf) 328706f2543Smrg { 329706f2543Smrg YieldControlDeath(); 330706f2543Smrg return -1; 331706f2543Smrg } 332706f2543Smrg oci->size = needed; 333706f2543Smrg oci->buffer = ibuf; 334706f2543Smrg } 335706f2543Smrg oci->bufptr = oci->buffer; 336706f2543Smrg oci->bufcnt = gotnow; 337706f2543Smrg } 338706f2543Smrg /* XXX this is a workaround. This function is sometimes called 339706f2543Smrg * after the trans_conn has been freed. In this case trans_conn 340706f2543Smrg * will be null. Really ought to restructure things so that we 341706f2543Smrg * never get here in those circumstances. 342706f2543Smrg */ 343706f2543Smrg if (!oc->trans_conn) 344706f2543Smrg { 345706f2543Smrg /* treat as if an error occured on the read, which is what 346706f2543Smrg * used to happen 347706f2543Smrg */ 348706f2543Smrg YieldControlDeath(); 349706f2543Smrg return -1; 350706f2543Smrg } 351706f2543Smrg result = _XSERVTransRead(oc->trans_conn, oci->buffer + oci->bufcnt, 352706f2543Smrg oci->size - oci->bufcnt); 353706f2543Smrg if (result <= 0) 354706f2543Smrg { 355706f2543Smrg if ((result < 0) && ETEST(errno)) 356706f2543Smrg { 357706f2543Smrg#if defined(SVR4) && defined(__i386__) && !defined(sun) 358706f2543Smrg if (0) 359706f2543Smrg#endif 360706f2543Smrg { 361706f2543Smrg YieldControlNoInput(fd); 362706f2543Smrg return 0; 363706f2543Smrg } 364706f2543Smrg } 365706f2543Smrg YieldControlDeath(); 366706f2543Smrg return -1; 367706f2543Smrg } 368706f2543Smrg oci->bufcnt += result; 369706f2543Smrg gotnow += result; 370706f2543Smrg /* free up some space after huge requests */ 371706f2543Smrg if ((oci->size > BUFWATERMARK) && 372706f2543Smrg (oci->bufcnt < BUFSIZE) && (needed < BUFSIZE)) 373706f2543Smrg { 374706f2543Smrg char *ibuf; 375706f2543Smrg 376706f2543Smrg ibuf = (char *)realloc(oci->buffer, BUFSIZE); 377706f2543Smrg if (ibuf) 378706f2543Smrg { 379706f2543Smrg oci->size = BUFSIZE; 380706f2543Smrg oci->buffer = ibuf; 381706f2543Smrg oci->bufptr = ibuf + oci->bufcnt - gotnow; 382706f2543Smrg } 383706f2543Smrg } 384706f2543Smrg if (need_header && gotnow >= needed) 385706f2543Smrg { 386706f2543Smrg /* We wanted an xReq, now we've gotten it. */ 387706f2543Smrg request = (xReq *)oci->bufptr; 388706f2543Smrg needed = get_req_len(request, client); 389706f2543Smrg if (!needed && client->big_requests) 390706f2543Smrg { 391706f2543Smrg move_header = TRUE; 392706f2543Smrg if (gotnow < sizeof(xBigReq)) 393706f2543Smrg needed = bytes_to_int32(sizeof(xBigReq)); 394706f2543Smrg else 395706f2543Smrg needed = get_big_req_len(request, client); 396706f2543Smrg } 397706f2543Smrg client->req_len = needed; 398706f2543Smrg needed <<= 2; 399706f2543Smrg } 400706f2543Smrg if (gotnow < needed) 401706f2543Smrg { 402706f2543Smrg /* Still don't have enough; punt. */ 403706f2543Smrg YieldControlNoInput(fd); 404706f2543Smrg return 0; 405706f2543Smrg } 406706f2543Smrg } 407706f2543Smrg if (needed == 0) 408706f2543Smrg { 409706f2543Smrg if (client->big_requests) 410706f2543Smrg needed = sizeof(xBigReq); 411706f2543Smrg else 412706f2543Smrg needed = sizeof(xReq); 413706f2543Smrg } 414706f2543Smrg 415706f2543Smrg /* If there are bytes to ignore, ignore them now. */ 416706f2543Smrg 417706f2543Smrg if (oci->ignoreBytes > 0) { 418706f2543Smrg assert(needed == oci->ignoreBytes || needed == oci->size); 419706f2543Smrg /* 420706f2543Smrg * The _XSERVTransRead call above may return more or fewer bytes than we 421706f2543Smrg * want to ignore. Ignore the smaller of the two sizes. 422706f2543Smrg */ 423706f2543Smrg if (gotnow < needed) { 424706f2543Smrg oci->ignoreBytes -= gotnow; 425706f2543Smrg oci->bufptr += gotnow; 426706f2543Smrg gotnow = 0; 427706f2543Smrg } else { 428706f2543Smrg oci->ignoreBytes -= needed; 429706f2543Smrg oci->bufptr += needed; 430706f2543Smrg gotnow -= needed; 431706f2543Smrg } 432706f2543Smrg needed = 0; 433706f2543Smrg } 434706f2543Smrg 435706f2543Smrg oci->lenLastReq = needed; 436706f2543Smrg 437706f2543Smrg /* 438706f2543Smrg * Check to see if client has at least one whole request in the 439706f2543Smrg * buffer beyond the request we're returning to the caller. 440706f2543Smrg * If there is only a partial request, treat like buffer 441706f2543Smrg * is empty so that select() will be called again and other clients 442706f2543Smrg * can get into the queue. 443706f2543Smrg */ 444706f2543Smrg 445706f2543Smrg gotnow -= needed; 446706f2543Smrg if (gotnow >= sizeof(xReq)) 447706f2543Smrg { 448706f2543Smrg request = (xReq *)(oci->bufptr + needed); 449706f2543Smrg if (gotnow >= (result = (get_req_len(request, client) << 2)) 450706f2543Smrg && (result || 451706f2543Smrg (client->big_requests && 452706f2543Smrg (gotnow >= sizeof(xBigReq) && 453706f2543Smrg gotnow >= (get_big_req_len(request, client) << 2)))) 454706f2543Smrg ) 455706f2543Smrg FD_SET(fd, &ClientsWithInput); 456706f2543Smrg else 457706f2543Smrg { 458706f2543Smrg if (!SmartScheduleDisable) 459706f2543Smrg FD_CLR(fd, &ClientsWithInput); 460706f2543Smrg else 461706f2543Smrg YieldControlNoInput(fd); 462706f2543Smrg } 463706f2543Smrg } 464706f2543Smrg else 465706f2543Smrg { 466706f2543Smrg if (!gotnow) 467706f2543Smrg AvailableInput = oc; 468706f2543Smrg if (!SmartScheduleDisable) 469706f2543Smrg FD_CLR(fd, &ClientsWithInput); 470706f2543Smrg else 471706f2543Smrg YieldControlNoInput(fd); 472706f2543Smrg } 473706f2543Smrg if (SmartScheduleDisable) 474706f2543Smrg if (++timesThisConnection >= MAX_TIMES_PER) 475706f2543Smrg YieldControl(); 476706f2543Smrg if (move_header) 477706f2543Smrg { 478706f2543Smrg request = (xReq *)oci->bufptr; 479706f2543Smrg oci->bufptr += (sizeof(xBigReq) - sizeof(xReq)); 480706f2543Smrg *(xReq *)oci->bufptr = *request; 481706f2543Smrg oci->lenLastReq -= (sizeof(xBigReq) - sizeof(xReq)); 482706f2543Smrg client->req_len -= bytes_to_int32(sizeof(xBigReq) - sizeof(xReq)); 483706f2543Smrg } 484706f2543Smrg client->requestBuffer = (pointer)oci->bufptr; 485706f2543Smrg#ifdef DEBUG_COMMUNICATION 486706f2543Smrg { 487706f2543Smrg xReq *req = client->requestBuffer; 488706f2543Smrg ErrorF("REQUEST: ClientIDX: %i, type: 0x%x data: 0x%x len: %i\n", 489706f2543Smrg client->index,req->reqType,req->data,req->length); 490706f2543Smrg } 491706f2543Smrg#endif 492706f2543Smrg return needed; 493706f2543Smrg} 494706f2543Smrg 495706f2543Smrg/***************************************************************** 496706f2543Smrg * InsertFakeRequest 497706f2543Smrg * Splice a consed up (possibly partial) request in as the next request. 498706f2543Smrg * 499706f2543Smrg **********************/ 500706f2543Smrg 501706f2543SmrgBool 502706f2543SmrgInsertFakeRequest(ClientPtr client, char *data, int count) 503706f2543Smrg{ 504706f2543Smrg OsCommPtr oc = (OsCommPtr)client->osPrivate; 505706f2543Smrg ConnectionInputPtr oci = oc->input; 506706f2543Smrg int fd = oc->fd; 507706f2543Smrg int gotnow, moveup; 508706f2543Smrg 509706f2543Smrg if (AvailableInput) 510706f2543Smrg { 511706f2543Smrg if (AvailableInput != oc) 512706f2543Smrg { 513706f2543Smrg ConnectionInputPtr aci = AvailableInput->input; 514706f2543Smrg if (aci->size > BUFWATERMARK) 515706f2543Smrg { 516706f2543Smrg free(aci->buffer); 517706f2543Smrg free(aci); 518706f2543Smrg } 519706f2543Smrg else 520706f2543Smrg { 521706f2543Smrg aci->next = FreeInputs; 522706f2543Smrg FreeInputs = aci; 523706f2543Smrg } 524706f2543Smrg AvailableInput->input = (ConnectionInputPtr)NULL; 525706f2543Smrg } 526706f2543Smrg AvailableInput = (OsCommPtr)NULL; 527706f2543Smrg } 528706f2543Smrg if (!oci) 529706f2543Smrg { 530706f2543Smrg if ((oci = FreeInputs)) 531706f2543Smrg FreeInputs = oci->next; 532706f2543Smrg else if (!(oci = AllocateInputBuffer())) 533706f2543Smrg return FALSE; 534706f2543Smrg oc->input = oci; 535706f2543Smrg } 536706f2543Smrg oci->bufptr += oci->lenLastReq; 537706f2543Smrg oci->lenLastReq = 0; 538706f2543Smrg gotnow = oci->bufcnt + oci->buffer - oci->bufptr; 539706f2543Smrg if ((gotnow + count) > oci->size) 540706f2543Smrg { 541706f2543Smrg char *ibuf; 542706f2543Smrg 543706f2543Smrg ibuf = (char *)realloc(oci->buffer, gotnow + count); 544706f2543Smrg if (!ibuf) 545706f2543Smrg return FALSE; 546706f2543Smrg oci->size = gotnow + count; 547706f2543Smrg oci->buffer = ibuf; 548706f2543Smrg oci->bufptr = ibuf + oci->bufcnt - gotnow; 549706f2543Smrg } 550706f2543Smrg moveup = count - (oci->bufptr - oci->buffer); 551706f2543Smrg if (moveup > 0) 552706f2543Smrg { 553706f2543Smrg if (gotnow > 0) 554706f2543Smrg memmove(oci->bufptr + moveup, oci->bufptr, gotnow); 555706f2543Smrg oci->bufptr += moveup; 556706f2543Smrg oci->bufcnt += moveup; 557706f2543Smrg } 558706f2543Smrg memmove(oci->bufptr - count, data, count); 559706f2543Smrg oci->bufptr -= count; 560706f2543Smrg gotnow += count; 561706f2543Smrg if ((gotnow >= sizeof(xReq)) && 562706f2543Smrg (gotnow >= (int)(get_req_len((xReq *)oci->bufptr, client) << 2))) 563706f2543Smrg FD_SET(fd, &ClientsWithInput); 564706f2543Smrg else 565706f2543Smrg YieldControlNoInput(fd); 566706f2543Smrg return TRUE; 567706f2543Smrg} 568706f2543Smrg 569706f2543Smrg/***************************************************************** 570706f2543Smrg * ResetRequestFromClient 571706f2543Smrg * Reset to reexecute the current request, and yield. 572706f2543Smrg * 573706f2543Smrg **********************/ 574706f2543Smrg 575706f2543Smrgvoid 576706f2543SmrgResetCurrentRequest(ClientPtr client) 577706f2543Smrg{ 578706f2543Smrg OsCommPtr oc = (OsCommPtr)client->osPrivate; 579706f2543Smrg register ConnectionInputPtr oci = oc->input; 580706f2543Smrg int fd = oc->fd; 581706f2543Smrg register xReq *request; 582706f2543Smrg int gotnow, needed; 583706f2543Smrg if (AvailableInput == oc) 584706f2543Smrg AvailableInput = (OsCommPtr)NULL; 585706f2543Smrg oci->lenLastReq = 0; 586706f2543Smrg gotnow = oci->bufcnt + oci->buffer - oci->bufptr; 587706f2543Smrg if (gotnow < sizeof(xReq)) 588706f2543Smrg { 589706f2543Smrg YieldControlNoInput(fd); 590706f2543Smrg } 591706f2543Smrg else 592706f2543Smrg { 593706f2543Smrg request = (xReq *)oci->bufptr; 594706f2543Smrg needed = get_req_len(request, client); 595706f2543Smrg if (!needed && client->big_requests) 596706f2543Smrg { 597706f2543Smrg oci->bufptr -= sizeof(xBigReq) - sizeof(xReq); 598706f2543Smrg *(xReq *)oci->bufptr = *request; 599706f2543Smrg ((xBigReq *)oci->bufptr)->length = client->req_len; 600706f2543Smrg if (client->swapped) 601706f2543Smrg { 602706f2543Smrg char n; 603706f2543Smrg swapl(&((xBigReq *)oci->bufptr)->length, n); 604706f2543Smrg } 605706f2543Smrg } 606706f2543Smrg if (gotnow >= (needed << 2)) 607706f2543Smrg { 608706f2543Smrg if (FD_ISSET(fd, &AllClients)) 609706f2543Smrg { 610706f2543Smrg FD_SET(fd, &ClientsWithInput); 611706f2543Smrg } 612706f2543Smrg else 613706f2543Smrg { 614706f2543Smrg FD_SET(fd, &IgnoredClientsWithInput); 615706f2543Smrg } 616706f2543Smrg YieldControl(); 617706f2543Smrg } 618706f2543Smrg else 619706f2543Smrg YieldControlNoInput(fd); 620706f2543Smrg } 621706f2543Smrg} 622706f2543Smrg 623706f2543Smrgstatic const int padlength[4] = {0, 3, 2, 1}; 624706f2543Smrg 625706f2543Smrg /******************** 626706f2543Smrg * FlushAllOutput() 627706f2543Smrg * Flush all clients with output. However, if some client still 628706f2543Smrg * has input in the queue (more requests), then don't flush. This 629706f2543Smrg * will prevent the output queue from being flushed every time around 630706f2543Smrg * the round robin queue. Now, some say that it SHOULD be flushed 631706f2543Smrg * every time around, but... 632706f2543Smrg * 633706f2543Smrg **********************/ 634706f2543Smrg 635706f2543Smrgvoid 636706f2543SmrgFlushAllOutput(void) 637706f2543Smrg{ 638706f2543Smrg register int index, base; 639706f2543Smrg register fd_mask mask; /* raphael */ 640706f2543Smrg OsCommPtr oc; 641706f2543Smrg register ClientPtr client; 642706f2543Smrg Bool newoutput = NewOutputPending; 643706f2543Smrg#if defined(WIN32) 644706f2543Smrg fd_set newOutputPending; 645706f2543Smrg#endif 646706f2543Smrg 647706f2543Smrg if (FlushCallback) 648706f2543Smrg CallCallbacks(&FlushCallback, NULL); 649706f2543Smrg 650706f2543Smrg if (!newoutput) 651706f2543Smrg return; 652706f2543Smrg 653706f2543Smrg /* 654706f2543Smrg * It may be that some client still has critical output pending, 655706f2543Smrg * but he is not yet ready to receive it anyway, so we will 656706f2543Smrg * simply wait for the select to tell us when he's ready to receive. 657706f2543Smrg */ 658706f2543Smrg CriticalOutputPending = FALSE; 659706f2543Smrg NewOutputPending = FALSE; 660706f2543Smrg 661706f2543Smrg#ifndef WIN32 662706f2543Smrg for (base = 0; base < howmany(XFD_SETSIZE, NFDBITS); base++) 663706f2543Smrg { 664706f2543Smrg mask = OutputPending.fds_bits[ base ]; 665706f2543Smrg OutputPending.fds_bits[ base ] = 0; 666706f2543Smrg while (mask) 667706f2543Smrg { 668706f2543Smrg index = ffs(mask) - 1; 669706f2543Smrg mask &= ~lowbit(mask); 670706f2543Smrg if ((index = ConnectionTranslation[(base * (sizeof(fd_mask)*8)) + index]) == 0) 671706f2543Smrg continue; 672706f2543Smrg client = clients[index]; 673706f2543Smrg if (client->clientGone) 674706f2543Smrg continue; 675706f2543Smrg oc = (OsCommPtr)client->osPrivate; 676706f2543Smrg if (FD_ISSET(oc->fd, &ClientsWithInput)) 677706f2543Smrg { 678706f2543Smrg FD_SET(oc->fd, &OutputPending); /* set the bit again */ 679706f2543Smrg NewOutputPending = TRUE; 680706f2543Smrg } 681706f2543Smrg else 682706f2543Smrg (void)FlushClient(client, oc, (char *)NULL, 0); 683706f2543Smrg } 684706f2543Smrg } 685706f2543Smrg#else /* WIN32 */ 686706f2543Smrg FD_ZERO(&newOutputPending); 687706f2543Smrg for (base = 0; base < XFD_SETCOUNT(&OutputPending); base++) 688706f2543Smrg { 689706f2543Smrg index = XFD_FD(&OutputPending, base); 690706f2543Smrg if ((index = GetConnectionTranslation(index)) == 0) 691706f2543Smrg continue; 692706f2543Smrg client = clients[index]; 693706f2543Smrg if (client->clientGone) 694706f2543Smrg continue; 695706f2543Smrg oc = (OsCommPtr)client->osPrivate; 696706f2543Smrg if (FD_ISSET(oc->fd, &ClientsWithInput)) 697706f2543Smrg { 698706f2543Smrg FD_SET(oc->fd, &newOutputPending); /* set the bit again */ 699706f2543Smrg NewOutputPending = TRUE; 700706f2543Smrg } 701706f2543Smrg else 702706f2543Smrg (void)FlushClient(client, oc, (char *)NULL, 0); 703706f2543Smrg } 704706f2543Smrg XFD_COPYSET(&newOutputPending, &OutputPending); 705706f2543Smrg#endif /* WIN32 */ 706706f2543Smrg} 707706f2543Smrg 708706f2543Smrgvoid 709706f2543SmrgFlushIfCriticalOutputPending(void) 710706f2543Smrg{ 711706f2543Smrg if (CriticalOutputPending) 712706f2543Smrg FlushAllOutput(); 713706f2543Smrg} 714706f2543Smrg 715706f2543Smrgvoid 716706f2543SmrgSetCriticalOutputPending(void) 717706f2543Smrg{ 718706f2543Smrg CriticalOutputPending = TRUE; 719706f2543Smrg} 720706f2543Smrg 721706f2543Smrg/***************** 722706f2543Smrg * WriteToClient 723706f2543Smrg * Copies buf into ClientPtr.buf if it fits (with padding), else 724706f2543Smrg * flushes ClientPtr.buf and buf to client. As of this writing, 725706f2543Smrg * every use of WriteToClient is cast to void, and the result 726706f2543Smrg * is ignored. Potentially, this could be used by requests 727706f2543Smrg * that are sending several chunks of data and want to break 728706f2543Smrg * out of a loop on error. Thus, we will leave the type of 729706f2543Smrg * this routine as int. 730706f2543Smrg *****************/ 731706f2543Smrg 732706f2543Smrgint 733706f2543SmrgWriteToClient (ClientPtr who, int count, const void *__buf) 734706f2543Smrg{ 735706f2543Smrg OsCommPtr oc; 736706f2543Smrg ConnectionOutputPtr oco; 737706f2543Smrg int padBytes; 738706f2543Smrg const char *buf = __buf; 739706f2543Smrg#ifdef DEBUG_COMMUNICATION 740706f2543Smrg Bool multicount = FALSE; 741706f2543Smrg#endif 742706f2543Smrg if (!count || !who || who == serverClient || who->clientGone) 743706f2543Smrg return 0; 744706f2543Smrg oc = who->osPrivate; 745706f2543Smrg oco = oc->output; 746706f2543Smrg#ifdef DEBUG_COMMUNICATION 747706f2543Smrg { 748706f2543Smrg char info[128]; 749706f2543Smrg xError *err; 750706f2543Smrg xGenericReply *rep; 751706f2543Smrg xEvent *ev; 752706f2543Smrg 753706f2543Smrg if (!who->replyBytesRemaining) { 754706f2543Smrg switch(buf[0]) { 755706f2543Smrg case X_Reply: 756706f2543Smrg rep = (xGenericReply*)buf; 757706f2543Smrg if (rep->sequenceNumber == who->sequence) { 758706f2543Smrg snprintf(info,127,"Xreply: type: 0x%x data: 0x%x " 759706f2543Smrg "len: %i seq#: 0x%x", rep->type, rep->data1, 760706f2543Smrg rep->length, rep->sequenceNumber); 761706f2543Smrg multicount = TRUE; 762706f2543Smrg } 763706f2543Smrg break; 764706f2543Smrg case X_Error: 765706f2543Smrg err = (xError*)buf; 766706f2543Smrg snprintf(info,127,"Xerror: Code: 0x%x resID: 0x%x maj: 0x%x " 767706f2543Smrg "min: %x", err->errorCode,err->resourceID, 768706f2543Smrg err->minorCode,err->majorCode); 769706f2543Smrg break; 770706f2543Smrg default: 771706f2543Smrg if ((buf[0] & 0x7f) == KeymapNotify) 772706f2543Smrg snprintf(info,127,"KeymapNotifyEvent: %i",buf[0]); 773706f2543Smrg else { 774706f2543Smrg ev = (xEvent*)buf; 775706f2543Smrg snprintf(info,127,"XEvent: type: 0x%x detail: 0x%x " 776706f2543Smrg "seq#: 0x%x", ev->u.u.type, ev->u.u.detail, 777706f2543Smrg ev->u.u.sequenceNumber); 778706f2543Smrg } 779706f2543Smrg } 780706f2543Smrg ErrorF("REPLY: ClientIDX: %i %s\n",who->index, info); 781706f2543Smrg } else 782706f2543Smrg multicount = TRUE; 783706f2543Smrg } 784706f2543Smrg#endif 785706f2543Smrg 786706f2543Smrg if (!oco) 787706f2543Smrg { 788706f2543Smrg if ((oco = FreeOutputs)) 789706f2543Smrg { 790706f2543Smrg FreeOutputs = oco->next; 791706f2543Smrg } 792706f2543Smrg else if (!(oco = AllocateOutputBuffer())) 793706f2543Smrg { 794706f2543Smrg if (oc->trans_conn) { 795706f2543Smrg _XSERVTransDisconnect(oc->trans_conn); 796706f2543Smrg _XSERVTransClose(oc->trans_conn); 797706f2543Smrg oc->trans_conn = NULL; 798706f2543Smrg } 799706f2543Smrg MarkClientException(who); 800706f2543Smrg return -1; 801706f2543Smrg } 802706f2543Smrg oc->output = oco; 803706f2543Smrg } 804706f2543Smrg 805706f2543Smrg padBytes = padlength[count & 3]; 806706f2543Smrg 807706f2543Smrg if(ReplyCallback) 808706f2543Smrg { 809706f2543Smrg ReplyInfoRec replyinfo; 810706f2543Smrg 811706f2543Smrg replyinfo.client = who; 812706f2543Smrg replyinfo.replyData = buf; 813706f2543Smrg replyinfo.dataLenBytes = count + padBytes; 814706f2543Smrg if (who->replyBytesRemaining) 815706f2543Smrg { /* still sending data of an earlier reply */ 816706f2543Smrg who->replyBytesRemaining -= count + padBytes; 817706f2543Smrg replyinfo.startOfReply = FALSE; 818706f2543Smrg replyinfo.bytesRemaining = who->replyBytesRemaining; 819706f2543Smrg CallCallbacks((&ReplyCallback), (pointer)&replyinfo); 820706f2543Smrg } 821706f2543Smrg else if (who->clientState == ClientStateRunning 822706f2543Smrg && buf[0] == X_Reply) 823706f2543Smrg { /* start of new reply */ 824706f2543Smrg CARD32 replylen; 825706f2543Smrg unsigned long bytesleft; 826706f2543Smrg char n; 827706f2543Smrg 828706f2543Smrg replylen = ((xGenericReply *)buf)->length; 829706f2543Smrg if (who->swapped) 830706f2543Smrg swapl(&replylen, n); 831706f2543Smrg bytesleft = (replylen * 4) + SIZEOF(xReply) - count - padBytes; 832706f2543Smrg replyinfo.startOfReply = TRUE; 833706f2543Smrg replyinfo.bytesRemaining = who->replyBytesRemaining = bytesleft; 834706f2543Smrg CallCallbacks((&ReplyCallback), (pointer)&replyinfo); 835706f2543Smrg } 836706f2543Smrg } 837706f2543Smrg#ifdef DEBUG_COMMUNICATION 838706f2543Smrg else if (multicount) { 839706f2543Smrg if (who->replyBytesRemaining) { 840706f2543Smrg who->replyBytesRemaining -= (count + padBytes); 841706f2543Smrg } else { 842706f2543Smrg CARD32 replylen; 843706f2543Smrg replylen = ((xGenericReply *)buf)->length; 844706f2543Smrg who->replyBytesRemaining = 845706f2543Smrg (replylen * 4) + SIZEOF(xReply) - count - padBytes; 846706f2543Smrg } 847706f2543Smrg } 848706f2543Smrg#endif 849706f2543Smrg if (oco->count + count + padBytes > oco->size) 850706f2543Smrg { 851706f2543Smrg FD_CLR(oc->fd, &OutputPending); 852706f2543Smrg if(!XFD_ANYSET(&OutputPending)) { 853706f2543Smrg CriticalOutputPending = FALSE; 854706f2543Smrg NewOutputPending = FALSE; 855706f2543Smrg } 856706f2543Smrg 857706f2543Smrg if (FlushCallback) 858706f2543Smrg CallCallbacks(&FlushCallback, NULL); 859706f2543Smrg 860706f2543Smrg return FlushClient(who, oc, buf, count); 861706f2543Smrg } 862706f2543Smrg 863706f2543Smrg NewOutputPending = TRUE; 864706f2543Smrg FD_SET(oc->fd, &OutputPending); 865706f2543Smrg memmove((char *)oco->buf + oco->count, buf, count); 866706f2543Smrg oco->count += count + padBytes; 867706f2543Smrg return count; 868706f2543Smrg} 869706f2543Smrg 870706f2543Smrg /******************** 871706f2543Smrg * FlushClient() 872706f2543Smrg * If the client isn't keeping up with us, then we try to continue 873706f2543Smrg * buffering the data and set the apropriate bit in ClientsWritable 874706f2543Smrg * (which is used by WaitFor in the select). If the connection yields 875706f2543Smrg * a permanent error, or we can't allocate any more space, we then 876706f2543Smrg * close the connection. 877706f2543Smrg * 878706f2543Smrg **********************/ 879706f2543Smrg 880706f2543Smrgint 881706f2543SmrgFlushClient(ClientPtr who, OsCommPtr oc, const void *__extraBuf, int extraCount) 882706f2543Smrg{ 883706f2543Smrg ConnectionOutputPtr oco = oc->output; 884706f2543Smrg int connection = oc->fd; 885706f2543Smrg XtransConnInfo trans_conn = oc->trans_conn; 886706f2543Smrg struct iovec iov[3]; 887706f2543Smrg static char padBuffer[3]; 888706f2543Smrg const char *extraBuf = __extraBuf; 889706f2543Smrg long written; 890706f2543Smrg long padsize; 891706f2543Smrg long notWritten; 892706f2543Smrg long todo; 893706f2543Smrg 894706f2543Smrg if (!oco) 895706f2543Smrg return 0; 896706f2543Smrg written = 0; 897706f2543Smrg padsize = padlength[extraCount & 3]; 898706f2543Smrg notWritten = oco->count + extraCount + padsize; 899706f2543Smrg todo = notWritten; 900706f2543Smrg while (notWritten) { 901706f2543Smrg long before = written; /* amount of whole thing written */ 902706f2543Smrg long remain = todo; /* amount to try this time, <= notWritten */ 903706f2543Smrg int i = 0; 904706f2543Smrg long len; 905706f2543Smrg 906706f2543Smrg /* You could be very general here and have "in" and "out" iovecs 907706f2543Smrg * and write a loop without using a macro, but what the heck. This 908706f2543Smrg * translates to: 909706f2543Smrg * 910706f2543Smrg * how much of this piece is new? 911706f2543Smrg * if more new then we are trying this time, clamp 912706f2543Smrg * if nothing new 913706f2543Smrg * then bump down amount already written, for next piece 914706f2543Smrg * else put new stuff in iovec, will need all of next piece 915706f2543Smrg * 916706f2543Smrg * Note that todo had better be at least 1 or else we'll end up 917706f2543Smrg * writing 0 iovecs. 918706f2543Smrg */ 919706f2543Smrg#define InsertIOV(pointer, length) \ 920706f2543Smrg len = (length) - before; \ 921706f2543Smrg if (len > remain) \ 922706f2543Smrg len = remain; \ 923706f2543Smrg if (len <= 0) { \ 924706f2543Smrg before = (-len); \ 925706f2543Smrg } else { \ 926706f2543Smrg iov[i].iov_len = len; \ 927706f2543Smrg iov[i].iov_base = (pointer) + before; \ 928706f2543Smrg i++; \ 929706f2543Smrg remain -= len; \ 930706f2543Smrg before = 0; \ 931706f2543Smrg } 932706f2543Smrg 933706f2543Smrg InsertIOV ((char *)oco->buf, oco->count) 934706f2543Smrg InsertIOV ((char *)extraBuf, extraCount) 935706f2543Smrg InsertIOV (padBuffer, padsize) 936706f2543Smrg 937706f2543Smrg errno = 0; 938706f2543Smrg if (trans_conn && (len = _XSERVTransWritev(trans_conn, iov, i)) >= 0) 939706f2543Smrg { 940706f2543Smrg written += len; 941706f2543Smrg notWritten -= len; 942706f2543Smrg todo = notWritten; 943706f2543Smrg } 944706f2543Smrg else if (ETEST(errno) 945706f2543Smrg#ifdef SUNSYSV /* check for another brain-damaged OS bug */ 946706f2543Smrg || (errno == 0) 947706f2543Smrg#endif 948706f2543Smrg#ifdef EMSGSIZE /* check for another brain-damaged OS bug */ 949706f2543Smrg || ((errno == EMSGSIZE) && (todo == 1)) 950706f2543Smrg#endif 951706f2543Smrg ) 952706f2543Smrg { 953706f2543Smrg /* If we've arrived here, then the client is stuffed to the gills 954706f2543Smrg and not ready to accept more. Make a note of it and buffer 955706f2543Smrg the rest. */ 956706f2543Smrg FD_SET(connection, &ClientsWriteBlocked); 957706f2543Smrg AnyClientsWriteBlocked = TRUE; 958706f2543Smrg 959706f2543Smrg if (written < oco->count) 960706f2543Smrg { 961706f2543Smrg if (written > 0) 962706f2543Smrg { 963706f2543Smrg oco->count -= written; 964706f2543Smrg memmove((char *)oco->buf, 965706f2543Smrg (char *)oco->buf + written, 966706f2543Smrg oco->count); 967706f2543Smrg written = 0; 968706f2543Smrg } 969706f2543Smrg } 970706f2543Smrg else 971706f2543Smrg { 972706f2543Smrg written -= oco->count; 973706f2543Smrg oco->count = 0; 974706f2543Smrg } 975706f2543Smrg 976706f2543Smrg if (notWritten > oco->size) 977706f2543Smrg { 978706f2543Smrg unsigned char *obuf; 979706f2543Smrg 980706f2543Smrg obuf = (unsigned char *)realloc(oco->buf, 981706f2543Smrg notWritten + BUFSIZE); 982706f2543Smrg if (!obuf) 983706f2543Smrg { 984706f2543Smrg _XSERVTransDisconnect(oc->trans_conn); 985706f2543Smrg _XSERVTransClose(oc->trans_conn); 986706f2543Smrg oc->trans_conn = NULL; 987706f2543Smrg MarkClientException(who); 988706f2543Smrg oco->count = 0; 989706f2543Smrg return -1; 990706f2543Smrg } 991706f2543Smrg oco->size = notWritten + BUFSIZE; 992706f2543Smrg oco->buf = obuf; 993706f2543Smrg } 994706f2543Smrg 995706f2543Smrg /* If the amount written extended into the padBuffer, then the 996706f2543Smrg difference "extraCount - written" may be less than 0 */ 997706f2543Smrg if ((len = extraCount - written) > 0) 998706f2543Smrg memmove ((char *)oco->buf + oco->count, 999706f2543Smrg extraBuf + written, 1000706f2543Smrg len); 1001706f2543Smrg 1002706f2543Smrg oco->count = notWritten; /* this will include the pad */ 1003706f2543Smrg /* return only the amount explicitly requested */ 1004706f2543Smrg return extraCount; 1005706f2543Smrg } 1006706f2543Smrg#ifdef EMSGSIZE /* check for another brain-damaged OS bug */ 1007706f2543Smrg else if (errno == EMSGSIZE) 1008706f2543Smrg { 1009706f2543Smrg todo >>= 1; 1010706f2543Smrg } 1011706f2543Smrg#endif 1012706f2543Smrg else 1013706f2543Smrg { 1014706f2543Smrg if (oc->trans_conn) 1015706f2543Smrg { 1016706f2543Smrg _XSERVTransDisconnect(oc->trans_conn); 1017706f2543Smrg _XSERVTransClose(oc->trans_conn); 1018706f2543Smrg oc->trans_conn = NULL; 1019706f2543Smrg } 1020706f2543Smrg MarkClientException(who); 1021706f2543Smrg oco->count = 0; 1022706f2543Smrg return -1; 1023706f2543Smrg } 1024706f2543Smrg } 1025706f2543Smrg 1026706f2543Smrg /* everything was flushed out */ 1027706f2543Smrg oco->count = 0; 1028706f2543Smrg /* check to see if this client was write blocked */ 1029706f2543Smrg if (AnyClientsWriteBlocked) 1030706f2543Smrg { 1031706f2543Smrg FD_CLR(oc->fd, &ClientsWriteBlocked); 1032706f2543Smrg if (! XFD_ANYSET(&ClientsWriteBlocked)) 1033706f2543Smrg AnyClientsWriteBlocked = FALSE; 1034706f2543Smrg } 1035706f2543Smrg if (oco->size > BUFWATERMARK) 1036706f2543Smrg { 1037706f2543Smrg free(oco->buf); 1038706f2543Smrg free(oco); 1039706f2543Smrg } 1040706f2543Smrg else 1041706f2543Smrg { 1042706f2543Smrg oco->next = FreeOutputs; 1043706f2543Smrg FreeOutputs = oco; 1044706f2543Smrg } 1045706f2543Smrg oc->output = (ConnectionOutputPtr)NULL; 1046706f2543Smrg return extraCount; /* return only the amount explicitly requested */ 1047706f2543Smrg} 1048706f2543Smrg 1049706f2543Smrgstatic ConnectionInputPtr 1050706f2543SmrgAllocateInputBuffer(void) 1051706f2543Smrg{ 1052706f2543Smrg ConnectionInputPtr oci; 1053706f2543Smrg 1054706f2543Smrg oci = malloc(sizeof(ConnectionInput)); 1055706f2543Smrg if (!oci) 1056706f2543Smrg return NULL; 1057706f2543Smrg oci->buffer = malloc(BUFSIZE); 1058706f2543Smrg if (!oci->buffer) 1059706f2543Smrg { 1060706f2543Smrg free(oci); 1061706f2543Smrg return NULL; 1062706f2543Smrg } 1063706f2543Smrg oci->size = BUFSIZE; 1064706f2543Smrg oci->bufptr = oci->buffer; 1065706f2543Smrg oci->bufcnt = 0; 1066706f2543Smrg oci->lenLastReq = 0; 1067706f2543Smrg oci->ignoreBytes = 0; 1068706f2543Smrg return oci; 1069706f2543Smrg} 1070706f2543Smrg 1071706f2543Smrgstatic ConnectionOutputPtr 1072706f2543SmrgAllocateOutputBuffer(void) 1073706f2543Smrg{ 1074706f2543Smrg ConnectionOutputPtr oco; 1075706f2543Smrg 1076706f2543Smrg oco = malloc(sizeof(ConnectionOutput)); 1077706f2543Smrg if (!oco) 1078706f2543Smrg return NULL; 1079706f2543Smrg oco->buf = calloc(1, BUFSIZE); 1080706f2543Smrg if (!oco->buf) 1081706f2543Smrg { 1082706f2543Smrg free(oco); 1083706f2543Smrg return NULL; 1084706f2543Smrg } 1085706f2543Smrg oco->size = BUFSIZE; 1086706f2543Smrg oco->count = 0; 1087706f2543Smrg return oco; 1088706f2543Smrg} 1089706f2543Smrg 1090706f2543Smrgvoid 1091706f2543SmrgFreeOsBuffers(OsCommPtr oc) 1092706f2543Smrg{ 1093706f2543Smrg ConnectionInputPtr oci; 1094706f2543Smrg ConnectionOutputPtr oco; 1095706f2543Smrg 1096706f2543Smrg if (AvailableInput == oc) 1097706f2543Smrg AvailableInput = (OsCommPtr)NULL; 1098706f2543Smrg if ((oci = oc->input)) 1099706f2543Smrg { 1100706f2543Smrg if (FreeInputs) 1101706f2543Smrg { 1102706f2543Smrg free(oci->buffer); 1103706f2543Smrg free(oci); 1104706f2543Smrg } 1105706f2543Smrg else 1106706f2543Smrg { 1107706f2543Smrg FreeInputs = oci; 1108706f2543Smrg oci->next = (ConnectionInputPtr)NULL; 1109706f2543Smrg oci->bufptr = oci->buffer; 1110706f2543Smrg oci->bufcnt = 0; 1111706f2543Smrg oci->lenLastReq = 0; 1112706f2543Smrg } 1113706f2543Smrg } 1114706f2543Smrg if ((oco = oc->output)) 1115706f2543Smrg { 1116706f2543Smrg if (FreeOutputs) 1117706f2543Smrg { 1118706f2543Smrg free(oco->buf); 1119706f2543Smrg free(oco); 1120706f2543Smrg } 1121706f2543Smrg else 1122706f2543Smrg { 1123706f2543Smrg FreeOutputs = oco; 1124706f2543Smrg oco->next = (ConnectionOutputPtr)NULL; 1125706f2543Smrg oco->count = 0; 1126706f2543Smrg } 1127706f2543Smrg } 1128706f2543Smrg} 1129706f2543Smrg 1130706f2543Smrgvoid 1131706f2543SmrgResetOsBuffers(void) 1132706f2543Smrg{ 1133706f2543Smrg ConnectionInputPtr oci; 1134706f2543Smrg ConnectionOutputPtr oco; 1135706f2543Smrg 1136706f2543Smrg while ((oci = FreeInputs)) 1137706f2543Smrg { 1138706f2543Smrg FreeInputs = oci->next; 1139706f2543Smrg free(oci->buffer); 1140706f2543Smrg free(oci); 1141706f2543Smrg } 1142706f2543Smrg while ((oco = FreeOutputs)) 1143706f2543Smrg { 1144706f2543Smrg FreeOutputs = oco->next; 1145706f2543Smrg free(oco->buf); 1146706f2543Smrg free(oco); 1147706f2543Smrg } 1148706f2543Smrg} 1149