556 lines
14 KiB
C
556 lines
14 KiB
C
/* $XFree86: xc/programs/Xserver/os/lbxio.c,v 3.17 2002/05/31 18:46:06 dawes Exp $ */
|
|
/*
|
|
|
|
Copyright 1996, 1998 The Open Group
|
|
|
|
Permission to use, copy, modify, distribute, and sell this software and its
|
|
documentation for any purpose is hereby granted without fee, provided that
|
|
the above copyright notice appear in all copies and that both that
|
|
copyright notice and this permission notice appear in supporting
|
|
documentation.
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
|
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
Except as contained in this notice, the name of The Open Group shall not be
|
|
used in advertising or otherwise to promote the sale, use or other dealings
|
|
in this Software without prior written authorization from The Open Group.
|
|
|
|
*/
|
|
/***********************************************************
|
|
Copyright 1987, 1989 by Digital Equipment Corporation, Maynard, Massachusetts,
|
|
and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
|
|
|
|
All Rights Reserved
|
|
|
|
Permission to use, copy, modify, and distribute this software and its
|
|
documentation for any purpose and without fee is hereby granted,
|
|
provided that the above copyright notice appear in all copies and that
|
|
both that copyright notice and this permission notice appear in
|
|
supporting documentation, and that the names of Digital or MIT not be
|
|
used in advertising or publicity pertaining to distribution of the
|
|
software without specific, written prior permission.
|
|
|
|
DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
|
|
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
|
|
DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
|
|
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
|
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
|
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
|
SOFTWARE.
|
|
|
|
******************************************************************/
|
|
/* $Xorg: lbxio.c,v 1.4 2001/02/09 02:05:23 xorgcvs Exp $ */
|
|
|
|
#ifdef HAVE_DIX_CONFIG_H
|
|
#include <dix-config.h>
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
#include <X11/Xtrans/Xtrans.h>
|
|
#include <X11/Xmd.h>
|
|
#include <errno.h>
|
|
#ifndef Lynx
|
|
#include <sys/param.h>
|
|
#ifndef __UNIXOS2__
|
|
#include <sys/uio.h>
|
|
#endif
|
|
#else
|
|
#include <uio.h>
|
|
#endif
|
|
#include <X11/X.h>
|
|
#include <X11/Xproto.h>
|
|
#include "os.h"
|
|
#include <X11/Xpoll.h>
|
|
#include "osdep.h"
|
|
#include "opaque.h"
|
|
#include "dixstruct.h"
|
|
#include "misc.h"
|
|
#include "colormapst.h"
|
|
#include "propertyst.h"
|
|
#include "lbxserve.h"
|
|
|
|
/* check for both EAGAIN and EWOULDBLOCK, because some supposedly POSIX
|
|
* systems are broken and return EWOULDBLOCK when they should return EAGAIN
|
|
*/
|
|
#if defined(EAGAIN) && defined(EWOULDBLOCK)
|
|
#define ETEST(err) (err == EAGAIN || err == EWOULDBLOCK)
|
|
#else
|
|
#ifdef EAGAIN
|
|
#define ETEST(err) (err == EAGAIN)
|
|
#else
|
|
#define ETEST(err) (err == EWOULDBLOCK)
|
|
#endif
|
|
#endif
|
|
|
|
#define get_req_len(req,cli) ((cli)->swapped ? \
|
|
lswaps((req)->length) : (req)->length)
|
|
|
|
#define YieldControl() \
|
|
{ isItTimeToYield = TRUE; \
|
|
timesThisConnection = 0; }
|
|
#define YieldControlNoInput() \
|
|
{ YieldControl(); \
|
|
FD_CLR(fd, &ClientsWithInput); }
|
|
|
|
void
|
|
SwitchClientInput (ClientPtr client, Bool pending)
|
|
{
|
|
OsCommPtr oc = (OsCommPtr)client->osPrivate;
|
|
|
|
#ifndef WIN32
|
|
ConnectionTranslation[oc->fd] = client->index;
|
|
#else
|
|
SetConnectionTranslation(oc->fd, client->index);
|
|
#endif
|
|
if (pending)
|
|
FD_SET(oc->fd, &ClientsWithInput);
|
|
else
|
|
YieldControl();
|
|
}
|
|
|
|
void
|
|
LbxPrimeInput(ClientPtr client, LbxProxyPtr proxy)
|
|
{
|
|
OsCommPtr oc = (OsCommPtr)client->osPrivate;
|
|
ConnectionInputPtr oci = oc->input;
|
|
|
|
if (oci && proxy->compHandle) {
|
|
char *extra = oci->bufptr + oci->lenLastReq;
|
|
int left = oci->bufcnt + oci->buffer - extra;
|
|
|
|
(*proxy->streamOpts.streamCompStuffInput)(oc->fd,
|
|
(unsigned char *)extra,
|
|
left);
|
|
oci->bufcnt -= left;
|
|
AvailableInput = oc;
|
|
}
|
|
}
|
|
|
|
void
|
|
AvailableClientInput (ClientPtr client)
|
|
{
|
|
OsCommPtr oc = (OsCommPtr)client->osPrivate;
|
|
|
|
if (FD_ISSET(oc->fd, &AllSockets))
|
|
FD_SET(oc->fd, &ClientsWithInput);
|
|
}
|
|
|
|
/*****************************************************************
|
|
* AppendFakeRequest
|
|
* Append a (possibly partial) request in as the last request.
|
|
*
|
|
**********************/
|
|
|
|
Bool
|
|
AppendFakeRequest (ClientPtr client, char *data, int count)
|
|
{
|
|
OsCommPtr oc = (OsCommPtr)client->osPrivate;
|
|
ConnectionInputPtr oci = oc->input;
|
|
int fd = oc->fd;
|
|
int gotnow;
|
|
|
|
if (!oci)
|
|
{
|
|
if ((oci = FreeInputs))
|
|
FreeInputs = oci->next;
|
|
else if (!(oci = AllocateInputBuffer()))
|
|
return FALSE;
|
|
oc->input = oci;
|
|
} else if (AvailableInput == oc)
|
|
AvailableInput = (OsCommPtr)NULL;
|
|
/* do not free AvailableInput here, it could be proxy's */
|
|
oci->bufptr += oci->lenLastReq;
|
|
oci->lenLastReq = 0;
|
|
gotnow = oci->bufcnt + oci->buffer - oci->bufptr;
|
|
if ((gotnow + count) > oci->size)
|
|
{
|
|
char *ibuf;
|
|
|
|
ibuf = (char *)xrealloc(oci->buffer, gotnow + count);
|
|
if (!ibuf)
|
|
return(FALSE);
|
|
oci->size = gotnow + count;
|
|
oci->buffer = ibuf;
|
|
oci->bufptr = ibuf + oci->bufcnt - gotnow;
|
|
}
|
|
if (oci->bufcnt + count > oci->size) {
|
|
memmove(oci->buffer, oci->bufptr, gotnow);
|
|
oci->bufcnt = gotnow;
|
|
oci->bufptr = oci->buffer;
|
|
}
|
|
memmove(oci->bufptr + gotnow, data, count);
|
|
oci->bufcnt += count;
|
|
gotnow += count;
|
|
if ((gotnow >= sizeof(xReq)) &&
|
|
(gotnow >= (int)(get_req_len((xReq *)oci->bufptr, client) << 2)))
|
|
FD_SET(fd, &ClientsWithInput);
|
|
else
|
|
YieldControlNoInput();
|
|
return(TRUE);
|
|
}
|
|
|
|
static int
|
|
LbxWrite(XtransConnInfo trans_conn, LbxProxyPtr proxy,
|
|
char *buf, int len)
|
|
{
|
|
struct iovec iov;
|
|
int n;
|
|
int notWritten;
|
|
|
|
notWritten = len;
|
|
iov.iov_base = buf;
|
|
iov.iov_len = len;
|
|
while (notWritten) {
|
|
errno = 0;
|
|
if (proxy->compHandle)
|
|
n = (*proxy->streamOpts.streamCompWriteV)(proxy->fd, &iov, 1);
|
|
else
|
|
n = _XSERVTransWritev(trans_conn, &iov, 1);
|
|
if (n >= 0) {
|
|
iov.iov_base = (char *)iov.iov_base + n;
|
|
notWritten -= n;
|
|
iov.iov_len = notWritten;
|
|
}
|
|
else if (ETEST(errno)
|
|
#ifdef SUNSYSV /* check for another brain-damaged OS bug */
|
|
|| (errno == 0)
|
|
#endif
|
|
#ifdef EMSGSIZE /* check for another brain-damaged OS bug */
|
|
|| ((errno == EMSGSIZE) && (iov.iov_len == 1))
|
|
#endif
|
|
)
|
|
break;
|
|
#ifdef EMSGSIZE /* check for another brain-damaged OS bug */
|
|
else if (errno == EMSGSIZE)
|
|
iov.iov_len >>= 1;
|
|
#endif
|
|
else
|
|
return -1;
|
|
}
|
|
return len - notWritten;
|
|
}
|
|
|
|
static Bool
|
|
LbxAppendOutput(LbxProxyPtr proxy, ClientPtr client, ConnectionOutputPtr oco)
|
|
{
|
|
ConnectionOutputPtr noco = proxy->olast;
|
|
LbxClientPtr lbxClient = LbxClient(client);
|
|
|
|
if (!lbxClient) {
|
|
xfree(oco->buf);
|
|
xfree(oco);
|
|
return TRUE;
|
|
}
|
|
if (noco)
|
|
LbxReencodeOutput(client,
|
|
(char *)noco->buf, &noco->count,
|
|
(char *)oco->buf, &oco->count);
|
|
else
|
|
LbxReencodeOutput(client,
|
|
(char *)NULL, (int *)NULL,
|
|
(char *)oco->buf, &oco->count);
|
|
if (!oco->count) {
|
|
if (oco->size > BUFWATERMARK)
|
|
{
|
|
xfree(oco->buf);
|
|
xfree(oco);
|
|
}
|
|
else
|
|
{
|
|
oco->next = FreeOutputs;
|
|
FreeOutputs = oco;
|
|
}
|
|
return TRUE;
|
|
}
|
|
if ((lbxClient->id != proxy->cur_send_id) && proxy->lbxClients[0]) {
|
|
xLbxSwitchEvent *ev;
|
|
int n;
|
|
|
|
if (!noco || (noco->size - noco->count) < sz_xLbxSwitchEvent) {
|
|
if ((noco = FreeOutputs))
|
|
FreeOutputs = noco->next;
|
|
else
|
|
noco = AllocateOutputBuffer();
|
|
if (!noco) {
|
|
MarkClientException(client);
|
|
return FALSE;
|
|
}
|
|
noco->next = NULL;
|
|
if (proxy->olast)
|
|
proxy->olast->next = noco;
|
|
else
|
|
proxy->ofirst = noco;
|
|
proxy->olast = noco;
|
|
}
|
|
ev = (xLbxSwitchEvent *) (noco->buf + noco->count);
|
|
noco->count += sz_xLbxSwitchEvent;
|
|
proxy->cur_send_id = lbxClient->id;
|
|
ev->type = LbxEventCode;
|
|
ev->lbxType = LbxSwitchEvent;
|
|
ev->pad = 0;
|
|
ev->client = proxy->cur_send_id;
|
|
if (LbxProxyClient(proxy)->swapped) {
|
|
swapl(&ev->client, n);
|
|
}
|
|
}
|
|
oco->next = NULL;
|
|
if (proxy->olast)
|
|
proxy->olast->next = oco;
|
|
else
|
|
proxy->ofirst = oco;
|
|
proxy->olast = oco;
|
|
return TRUE;
|
|
}
|
|
|
|
static int
|
|
LbxClientOutput(ClientPtr client, OsCommPtr oc,
|
|
char *extraBuf, int extraCount, Bool nocompress)
|
|
{
|
|
ConnectionOutputPtr oco;
|
|
int len;
|
|
|
|
if ((oco = oc->output)) {
|
|
oc->output = NULL;
|
|
if (!LbxAppendOutput(oc->proxy, client, oco))
|
|
return -1;
|
|
}
|
|
|
|
if (extraCount) {
|
|
NewOutputPending = TRUE;
|
|
FD_SET(oc->fd, &OutputPending);
|
|
len = (extraCount + 3) & ~3;
|
|
if ((oco = FreeOutputs) && (oco->size >= len))
|
|
FreeOutputs = oco->next;
|
|
else {
|
|
oco = (ConnectionOutputPtr)xalloc(sizeof(ConnectionOutput));
|
|
if (!oco) {
|
|
MarkClientException(client);
|
|
return -1;
|
|
}
|
|
oco->size = len;
|
|
if (oco->size < BUFSIZE)
|
|
oco->size = BUFSIZE;
|
|
oco->buf = (unsigned char *) xalloc(oco->size);
|
|
if (!oco->buf) {
|
|
xfree(oco);
|
|
MarkClientException(client);
|
|
return -1;
|
|
}
|
|
}
|
|
oco->count = len;
|
|
oco->nocompress = nocompress;
|
|
memmove((char *)oco->buf, extraBuf, extraCount);
|
|
if (!nocompress && oco->count < oco->size)
|
|
oc->output = oco;
|
|
else if (!LbxAppendOutput(oc->proxy, client, oco))
|
|
return -1;
|
|
}
|
|
return extraCount;
|
|
}
|
|
|
|
void
|
|
LbxForceOutput(LbxProxyPtr proxy)
|
|
{
|
|
int i;
|
|
LbxClientPtr lbxClient;
|
|
OsCommPtr coc;
|
|
ConnectionOutputPtr oco;
|
|
|
|
for (i = proxy->maxIndex; i >= 0; i--) { /* proxy must be last */
|
|
lbxClient = proxy->lbxClients[i];
|
|
if (!lbxClient)
|
|
continue;
|
|
coc = (OsCommPtr)lbxClient->client->osPrivate;
|
|
if ((oco = coc->output)) {
|
|
coc->output = NULL;
|
|
LbxAppendOutput(proxy, lbxClient->client, oco);
|
|
}
|
|
}
|
|
}
|
|
|
|
int
|
|
LbxFlushClient(ClientPtr who, OsCommPtr oc,
|
|
char *extraBuf, int extraCount)
|
|
{
|
|
LbxProxyPtr proxy;
|
|
ConnectionOutputPtr oco;
|
|
int n;
|
|
XtransConnInfo trans_conn = NULL;
|
|
|
|
if (extraBuf)
|
|
return LbxClientOutput(who, oc, extraBuf, extraCount, FALSE);
|
|
proxy = oc->proxy;
|
|
if (!proxy->lbxClients[0])
|
|
return 0;
|
|
LbxForceOutput(proxy);
|
|
if (!proxy->compHandle)
|
|
trans_conn = ((OsCommPtr)LbxProxyClient(proxy)->osPrivate)->trans_conn;
|
|
while ((oco = proxy->ofirst)) {
|
|
/* XXX bundle up into writev someday */
|
|
if (proxy->compHandle) {
|
|
if (oco->nocompress)
|
|
(*proxy->streamOpts.streamCompOff)(proxy->fd);
|
|
n = LbxWrite(NULL, proxy, (char *)oco->buf, oco->count);
|
|
if (oco->nocompress)
|
|
(*proxy->streamOpts.streamCompOn)(proxy->fd);
|
|
} else
|
|
n = LbxWrite(trans_conn, proxy, (char *)oco->buf, oco->count);
|
|
if (n < 0) {
|
|
ClientPtr pclient = LbxProxyClient(proxy);
|
|
if (proxy->compHandle)
|
|
trans_conn = ((OsCommPtr)pclient->osPrivate)->trans_conn;
|
|
_XSERVTransDisconnect(trans_conn);
|
|
_XSERVTransClose(trans_conn);
|
|
((OsCommPtr)pclient->osPrivate)->trans_conn = NULL;
|
|
MarkClientException(pclient);
|
|
return 0;
|
|
} else if (n == oco->count) {
|
|
proxy->ofirst = oco->next;
|
|
if (!proxy->ofirst)
|
|
proxy->olast = NULL;
|
|
if (oco->size > BUFWATERMARK)
|
|
{
|
|
xfree(oco->buf);
|
|
xfree(oco);
|
|
}
|
|
else
|
|
{
|
|
oco->next = FreeOutputs;
|
|
oco->count = 0;
|
|
FreeOutputs = oco;
|
|
}
|
|
} else {
|
|
if (n) {
|
|
oco->count -= n;
|
|
memmove((char *)oco->buf, (char *)oco->buf + n, oco->count);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
if ((proxy->compHandle &&
|
|
(*proxy->streamOpts.streamCompFlush)(proxy->fd)) ||
|
|
proxy->ofirst) {
|
|
FD_SET(proxy->fd, &ClientsWriteBlocked);
|
|
AnyClientsWriteBlocked = TRUE;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
UncompressedWriteToClient (ClientPtr who, int count, char *buf)
|
|
{
|
|
return LbxClientOutput(who, (OsCommPtr)who->osPrivate, buf, count, TRUE);
|
|
}
|
|
|
|
void
|
|
LbxFreeOsBuffers(LbxProxyPtr proxy)
|
|
{
|
|
ConnectionOutputPtr oco;
|
|
|
|
while ((oco = proxy->ofirst)) {
|
|
proxy->ofirst = oco->next;
|
|
xfree(oco->buf);
|
|
xfree(oco);
|
|
}
|
|
}
|
|
|
|
Bool
|
|
AllocateLargeReqBuffer(ClientPtr client, int size)
|
|
{
|
|
OsCommPtr oc = (OsCommPtr)client->osPrivate;
|
|
ConnectionInputPtr oci;
|
|
|
|
if (!(oci = oc->largereq)) {
|
|
if ((oci = FreeInputs))
|
|
FreeInputs = oci->next;
|
|
else {
|
|
oci = (ConnectionInputPtr)xalloc(sizeof(ConnectionInput));
|
|
if (!oci)
|
|
return FALSE;
|
|
oci->buffer = NULL;
|
|
oci->size = 0;
|
|
}
|
|
}
|
|
if (oci->size < size) {
|
|
char *ibuf;
|
|
|
|
oci->size = size;
|
|
if (size < BUFSIZE)
|
|
oci->size = BUFSIZE;
|
|
if (!(ibuf = (char *)xrealloc(oci->buffer, oci->size)))
|
|
{
|
|
xfree(oci->buffer);
|
|
xfree(oci);
|
|
oc->largereq = NULL;
|
|
return FALSE;
|
|
}
|
|
oci->buffer = ibuf;
|
|
}
|
|
oci->bufptr = oci->buffer;
|
|
oci->bufcnt = 0;
|
|
oci->lenLastReq = size;
|
|
oc->largereq = oci;
|
|
return TRUE;
|
|
}
|
|
|
|
Bool
|
|
AddToLargeReqBuffer(ClientPtr client, char *data, int size)
|
|
{
|
|
OsCommPtr oc = (OsCommPtr)client->osPrivate;
|
|
ConnectionInputPtr oci = oc->largereq;
|
|
|
|
if (!oci || (oci->bufcnt + size > oci->lenLastReq))
|
|
return FALSE;
|
|
memcpy(oci->buffer + oci->bufcnt, data, size);
|
|
oci->bufcnt += size;
|
|
return TRUE;
|
|
}
|
|
|
|
static OsCommRec lbxAvailableInput;
|
|
|
|
int
|
|
PrepareLargeReqBuffer(ClientPtr client)
|
|
{
|
|
OsCommPtr oc = (OsCommPtr)client->osPrivate;
|
|
ConnectionInputPtr oci = oc->largereq;
|
|
|
|
if (!oci)
|
|
return client->req_len << 2;
|
|
oc->largereq = NULL;
|
|
if (oci->bufcnt != oci->lenLastReq) {
|
|
xfree(oci->buffer);
|
|
xfree(oci);
|
|
return client->req_len << 2;
|
|
}
|
|
client->requestBuffer = oci->buffer;
|
|
client->req_len = oci->lenLastReq >> 2;
|
|
oci->bufcnt = 0;
|
|
oci->lenLastReq = 0;
|
|
if (AvailableInput)
|
|
{
|
|
ConnectionInputPtr aci = AvailableInput->input;
|
|
if (aci->size > BUFWATERMARK)
|
|
{
|
|
xfree(aci->buffer);
|
|
xfree(aci);
|
|
}
|
|
else
|
|
{
|
|
aci->next = FreeInputs;
|
|
FreeInputs = aci;
|
|
}
|
|
AvailableInput->input = (ConnectionInputPtr)NULL;
|
|
}
|
|
lbxAvailableInput.input = oci;
|
|
AvailableInput = &lbxAvailableInput;
|
|
return client->req_len << 2;
|
|
}
|