Add support for MIT-SHM AttachFd request

This passes a file descriptor from the client to the server, which is
then mmap'd

Signed-off-by: Keith Packard <keithp@keithp.com>
Reviewed-by: Adam Jackson <ajax@redhat.com>
This commit is contained in:
Keith Packard 2013-01-17 13:46:55 -08:00
parent 9fd35daa31
commit fdec793cdc
4 changed files with 167 additions and 3 deletions

View File

@ -53,6 +53,7 @@ in this Software without prior written authorization from The Open Group.
#include "xace.h" #include "xace.h"
#include <X11/extensions/shmproto.h> #include <X11/extensions/shmproto.h>
#include <X11/Xfuncproto.h> #include <X11/Xfuncproto.h>
#include <sys/mman.h>
#include "protocol-versions.h" #include "protocol-versions.h"
/* Needed for Solaris cross-zone shared memory extension */ /* Needed for Solaris cross-zone shared memory extension */
@ -382,8 +383,10 @@ ProcShmAttach(ClientPtr client)
client->errorValue = stuff->readOnly; client->errorValue = stuff->readOnly;
return BadValue; return BadValue;
} }
for (shmdesc = Shmsegs; for (shmdesc = Shmsegs; shmdesc; shmdesc = shmdesc->next) {
shmdesc && (shmdesc->shmid != stuff->shmid); shmdesc = shmdesc->next); if (!shmdesc->is_fd && shmdesc->shmid == stuff->shmid)
break;
}
if (shmdesc) { if (shmdesc) {
if (!stuff->readOnly && !shmdesc->writable) if (!stuff->readOnly && !shmdesc->writable)
return BadAccess; return BadAccess;
@ -393,6 +396,7 @@ ProcShmAttach(ClientPtr client)
shmdesc = malloc(sizeof(ShmDescRec)); shmdesc = malloc(sizeof(ShmDescRec));
if (!shmdesc) if (!shmdesc)
return BadAlloc; return BadAlloc;
shmdesc->is_fd = FALSE;
shmdesc->addr = shmat(stuff->shmid, 0, shmdesc->addr = shmat(stuff->shmid, 0,
stuff->readOnly ? SHM_RDONLY : 0); stuff->readOnly ? SHM_RDONLY : 0);
if ((shmdesc->addr == ((char *) -1)) || SHMSTAT(stuff->shmid, &buf)) { if ((shmdesc->addr == ((char *) -1)) || SHMSTAT(stuff->shmid, &buf)) {
@ -431,6 +435,9 @@ ShmDetachSegment(pointer value, /* must conform to DeleteType */
if (--shmdesc->refcnt) if (--shmdesc->refcnt)
return TRUE; return TRUE;
if (shmdesc->is_fd)
munmap(shmdesc->addr, shmdesc->size);
else
shmdt(shmdesc->addr); shmdt(shmdesc->addr);
for (prev = &Shmsegs; *prev != shmdesc; prev = &(*prev)->next); for (prev = &Shmsegs; *prev != shmdesc; prev = &(*prev)->next);
*prev = shmdesc->next; *prev = shmdesc->next;
@ -1087,6 +1094,122 @@ ProcShmCreatePixmap(ClientPtr client)
return BadAlloc; return BadAlloc;
} }
static int
ProcShmAttachFd(ClientPtr client)
{
int fd;
ShmDescPtr shmdesc;
REQUEST(xShmAttachFdReq);
struct stat statb;
SetReqFds(client, 1);
REQUEST_SIZE_MATCH(xShmAttachFdReq);
LEGAL_NEW_RESOURCE(stuff->shmseg, client);
if ((stuff->readOnly != xTrue) && (stuff->readOnly != xFalse)) {
client->errorValue = stuff->readOnly;
return BadValue;
}
fd = ReadFdFromClient(client);
if (fd < 0)
return BadMatch;
if (fstat(fd, &statb) < 0 || statb.st_size == 0) {
close(fd);
return BadMatch;
}
shmdesc = malloc(sizeof(ShmDescRec));
if (!shmdesc) {
close(fd);
return BadAlloc;
}
shmdesc->is_fd = TRUE;
shmdesc->addr = mmap(NULL, statb.st_size,
stuff->readOnly ? PROT_READ : PROT_READ|PROT_WRITE,
MAP_SHARED,
fd, 0);
close(fd);
if ((shmdesc->addr == ((char *) -1))) {
free(shmdesc);
return BadAccess;
}
shmdesc->refcnt = 1;
shmdesc->writable = !stuff->readOnly;
shmdesc->size = statb.st_size;
shmdesc->next = Shmsegs;
Shmsegs = shmdesc;
if (!AddResource(stuff->shmseg, ShmSegType, (pointer) shmdesc))
return BadAlloc;
return Success;
}
static int
ProcShmCreateSegment(ClientPtr client)
{
int fd;
ShmDescPtr shmdesc;
REQUEST(xShmCreateSegmentReq);
xShmCreateSegmentReply rep = {
.type = X_Reply,
.nfd = 1,
.sequenceNumber = client->sequence,
.length = 0,
};
char template[] = "/tmp/shm-XXXXXX";
REQUEST_SIZE_MATCH(xShmCreateSegmentReq);
if ((stuff->readOnly != xTrue) && (stuff->readOnly != xFalse)) {
client->errorValue = stuff->readOnly;
return BadValue;
}
fd = mkstemp(template);
if (fd < 0)
return BadAlloc;
unlink(template);
if (ftruncate(fd, stuff->size) < 0) {
close(fd);
return BadAlloc;
}
shmdesc = malloc(sizeof(ShmDescRec));
if (!shmdesc) {
close(fd);
return BadAlloc;
}
shmdesc->is_fd = TRUE;
shmdesc->addr = mmap(NULL, stuff->size,
stuff->readOnly ? PROT_READ : PROT_READ|PROT_WRITE,
MAP_SHARED,
fd, 0);
if ((shmdesc->addr == ((char *) -1))) {
close(fd);
free(shmdesc);
return BadAccess;
}
shmdesc->refcnt = 1;
shmdesc->writable = !stuff->readOnly;
shmdesc->size = stuff->size;
shmdesc->next = Shmsegs;
Shmsegs = shmdesc;
if (!AddResource(stuff->shmseg, ShmSegType, (pointer) shmdesc)) {
close(fd);
return BadAlloc;
}
if (WriteFdToClient(client, fd, TRUE) < 0) {
FreeResource(stuff->shmseg, RT_NONE);
close(fd);
return BadAlloc;
}
WriteToClient(client, sizeof (xShmCreateSegmentReply), &rep);
return Success;
}
static int static int
ProcShmDispatch(ClientPtr client) ProcShmDispatch(ClientPtr client)
{ {
@ -1116,6 +1239,10 @@ ProcShmDispatch(ClientPtr client)
return ProcPanoramiXShmCreatePixmap(client); return ProcPanoramiXShmCreatePixmap(client);
#endif #endif
return ProcShmCreatePixmap(client); return ProcShmCreatePixmap(client);
case X_ShmAttachFd:
return ProcShmAttachFd(client);
case X_ShmCreateSegment:
return ProcShmCreateSegment(client);
default: default:
return BadRequest; return BadRequest;
} }
@ -1216,6 +1343,28 @@ SProcShmCreatePixmap(ClientPtr client)
return ProcShmCreatePixmap(client); return ProcShmCreatePixmap(client);
} }
static int
SProcShmAttachFd(ClientPtr client)
{
REQUEST(xShmAttachFdReq);
SetReqFds(client, 1);
swaps(&stuff->length);
REQUEST_SIZE_MATCH(xShmAttachFdReq);
swapl(&stuff->shmseg);
return ProcShmAttachFd(client);
}
static int
SProcShmCreateSegment(ClientPtr client)
{
REQUEST(xShmCreateSegmentReq);
swaps(&stuff->length);
REQUEST_SIZE_MATCH(xShmCreateSegmentReq);
swapl(&stuff->shmseg);
swapl(&stuff->size);
return ProcShmCreateSegment(client);
}
static int static int
SProcShmDispatch(ClientPtr client) SProcShmDispatch(ClientPtr client)
{ {
@ -1233,6 +1382,10 @@ SProcShmDispatch(ClientPtr client)
return SProcShmGetImage(client); return SProcShmGetImage(client);
case X_ShmCreatePixmap: case X_ShmCreatePixmap:
return SProcShmCreatePixmap(client); return SProcShmCreatePixmap(client);
case X_ShmAttachFd:
return SProcShmAttachFd(client);
case X_ShmCreateSegment:
return SProcShmCreateSegment(client);
default: default:
return BadRequest; return BadRequest;
} }

View File

@ -61,6 +61,7 @@ typedef struct _ShmDesc {
int shmid; int shmid;
int refcnt; int refcnt;
char *addr; char *addr;
Bool is_fd;
Bool writable; Bool writable;
unsigned long size; unsigned long size;
} ShmDescRec, *ShmDescPtr; } ShmDescRec, *ShmDescPtr;

View File

@ -100,6 +100,8 @@ extern _X_EXPORT int ReadRequestFromClient(ClientPtr /*client */ );
extern _X_EXPORT int ReadFdFromClient(ClientPtr client); extern _X_EXPORT int ReadFdFromClient(ClientPtr client);
extern _X_EXPORT int WriteFdToClient(ClientPtr client, int fd, Bool do_close);
extern _X_EXPORT Bool InsertFakeRequest(ClientPtr /*client */ , extern _X_EXPORT Bool InsertFakeRequest(ClientPtr /*client */ ,
char * /*data */ , char * /*data */ ,
int /*count */ ); int /*count */ );

View File

@ -506,6 +506,14 @@ ReadFdFromClient(ClientPtr client)
return fd; return fd;
} }
int
WriteFdToClient(ClientPtr client, int fd, Bool do_close)
{
OsCommPtr oc = (OsCommPtr) client->osPrivate;
return _XSERVTransSendFd(oc->trans_conn, fd, do_close);
}
/***************************************************************** /*****************************************************************
* InsertFakeRequest * InsertFakeRequest
* Splice a consed up (possibly partial) request in as the next request. * Splice a consed up (possibly partial) request in as the next request.