108 lines
1.8 KiB
C
108 lines
1.8 KiB
C
#include <u.h>
|
|
#include <libc.h>
|
|
#include <draw.h>
|
|
#include <event.h>
|
|
#include "plumb.h"
|
|
|
|
typedef struct EQueue EQueue;
|
|
|
|
struct EQueue
|
|
{
|
|
int id;
|
|
char *buf;
|
|
int nbuf;
|
|
EQueue *next;
|
|
};
|
|
|
|
static EQueue *equeue;
|
|
static Lock eqlock;
|
|
|
|
static
|
|
int
|
|
partial(int id, Event *e, uchar *b, int n)
|
|
{
|
|
EQueue *eq, *p;
|
|
int nmore;
|
|
|
|
lock(&eqlock);
|
|
for(eq = equeue; eq != nil; eq = eq->next)
|
|
if(eq->id == id)
|
|
break;
|
|
unlock(&eqlock);
|
|
if(eq == nil)
|
|
return 0;
|
|
/* partial message exists for this id */
|
|
eq->buf = realloc(eq->buf, eq->nbuf+n);
|
|
if(eq->buf == nil)
|
|
drawerror(display, "eplumb: cannot allocate buffer");
|
|
memmove(eq->buf+eq->nbuf, b, n);
|
|
eq->nbuf += n;
|
|
e->v = plumbunpackpartial((char*)eq->buf, eq->nbuf, &nmore);
|
|
if(nmore == 0){ /* no more to read in this message */
|
|
lock(&eqlock);
|
|
if(eq == equeue)
|
|
equeue = eq->next;
|
|
else{
|
|
for(p = equeue; p!=nil && p->next!=eq; p = p->next)
|
|
;
|
|
if(p == nil)
|
|
drawerror(display, "eplumb: bad event queue");
|
|
p->next = eq->next;
|
|
}
|
|
unlock(&eqlock);
|
|
free(eq->buf);
|
|
free(eq);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static
|
|
void
|
|
addpartial(int id, char *b, int n)
|
|
{
|
|
EQueue *eq;
|
|
|
|
eq = malloc(sizeof(EQueue));
|
|
if(eq == nil)
|
|
return;
|
|
eq->id = id;
|
|
eq->nbuf = n;
|
|
eq->buf = malloc(n);
|
|
if(eq->buf == nil){
|
|
free(eq);
|
|
return;
|
|
}
|
|
memmove(eq->buf, b, n);
|
|
lock(&eqlock);
|
|
eq->next = equeue;
|
|
equeue = eq;
|
|
unlock(&eqlock);
|
|
}
|
|
|
|
static
|
|
int
|
|
plumbevent(int id, Event *e, uchar *b, int n)
|
|
{
|
|
int nmore;
|
|
|
|
if(partial(id, e, b, n) == 0){
|
|
/* no partial message already waiting for this id */
|
|
e->v = plumbunpackpartial((char*)b, n, &nmore);
|
|
if(nmore > 0) /* incomplete message */
|
|
addpartial(id, (char*)b, n);
|
|
}
|
|
if(e->v == nil)
|
|
return 0;
|
|
return id;
|
|
}
|
|
|
|
int
|
|
eplumb(int key, char *port)
|
|
{
|
|
int fd;
|
|
|
|
fd = plumbopen(port, OREAD|OCEXEC);
|
|
if(fd < 0)
|
|
return -1;
|
|
return estartfn(key, fd, 8192, plumbevent);
|
|
}
|