X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Fpacket.c;fp=source%2Fpacket.c;h=465f11868ccdb1197577273b804f13b1e7b1da61;hb=fab9ed5163a8f4ef5314bc67e48d1690d1126649;hp=0000000000000000000000000000000000000000;hpb=0205804a10fe3beb01ed0135fde052d13b045570;p=gldbg.git diff --git a/source/packet.c b/source/packet.c new file mode 100644 index 0000000..465f118 --- /dev/null +++ b/source/packet.c @@ -0,0 +1,389 @@ +/* $Id$ + +This file is part of gldbg +Copyright © 2010 Mikko Rasa, Mikkosoft Productions +Distributed under the GPL +*/ + +#include +#include +#include +#include "packet.h" +#include "tmpalloc.h" + +struct GlOutPacket +{ + char *ptr; + unsigned length; + struct iovec *vec; +}; + +struct GlInPacket +{ + const char *ptr; + unsigned length; + unsigned chunk; +}; + +typedef struct GlOutPacket GlOutPacket; +typedef struct GlInPacket GlInPacket; + +struct GlPacket +{ + union + { + GlOutPacket out; + GlInPacket in; + }; +}; + +// XXX Should make this stuff truly re-entrant +static char *out_buffer = 0; +static struct iovec *iovecs = 0; +static GlPacket packet; +/*static char *in_buffer = 0; +static unsigned in_length;*/ + +static void next_vec(GlPacket *pkt) +{ + GlOutPacket *out = &pkt->out; + + if(out->ptr!=out->vec->iov_base) + { + out->vec->iov_len = out->ptr-(char *)out->vec->iov_base; + out->length += out->vec->iov_len; + ++out->vec; + out->vec->iov_base = out->ptr; + } +} + +static void reset(GlPacket *pkt) +{ + GlOutPacket *out = &pkt->out; + + out->ptr = out_buffer; + out->vec = iovecs; + out->vec->iov_base = out->ptr; + out->length = 0; +} + +GlPacket *packet_begin(unsigned short func) +{ + GlPacket *pkt; + + if(!out_buffer) + out_buffer = (char *)malloc(1024); + if(!iovecs) + iovecs = (struct iovec *)malloc(16*sizeof(struct iovec)); + + pkt = &packet; + reset(pkt); + + packet_write_int(pkt, 0); + packet_write_short(pkt, func); + + return pkt; +} + +void packet_send_partial(GlPacket *pkt, int fd) +{ + GlOutPacket *out = &pkt->out; + + out->length |= 0x80000000; + packet_send(pkt, fd); + + reset(pkt); + + packet_write_int(pkt, 0); +} + +void packet_send(GlPacket *pkt, int fd) +{ + GlOutPacket *out = &pkt->out; + struct iovec *v; + + next_vec(pkt); + out->ptr = out_buffer; + packet_write_int(pkt, out->length); + + for(v=iovecs; v!=out->vec; ) + { + int ret; + + ret = writev(fd, v, out->vec-v); + if(ret<0) + return; + + while(v!=out->vec && (unsigned)ret>=v->iov_len) + { + ret -= v->iov_len; + ++v; + } + + if(v!=out->vec) + { + v->iov_base += ret; + v->iov_len -= ret; + } + } +} + +static void write_raw(GlPacket *pkt, const char *ptr, unsigned size, int byteswap) +{ + GlOutPacket *out = &pkt->out; + unsigned i; + +#if __BYTE_ORDER == __LITTLE_ENDIAN + if(byteswap) + { + ptr += size; + for(i=0; iptr++ = *--ptr; + } + else +#endif + { + for(i=0; iptr++ = *ptr++; + } +} + +void packet_write_char(GlPacket *pkt, char v) +{ + GlOutPacket *out = &pkt->out; + *out->ptr++ = v; +} + +void packet_write_short(GlPacket *pkt, short v) +{ + write_raw(pkt, (char *)&v, sizeof(short), 1); +} + +void packet_write_int(GlPacket *pkt, int v) +{ + write_raw(pkt, (char *)&v, sizeof(int), 1); +} + +void packet_write_long(GlPacket *pkt, long v) +{ + write_raw(pkt, (char *)&v, sizeof(long), 1); +} + +void packet_write_long_long(GlPacket *pkt, long long v) +{ + write_raw(pkt, (char *)&v, sizeof(long long), 1); +} + +void packet_write_float(GlPacket *pkt, float v) +{ + write_raw(pkt, (char *)&v, sizeof(float), 1); +} + +void packet_write_double(GlPacket *pkt, double v) +{ + write_raw(pkt, (char *)&v, sizeof(double), 1); +} + +void packet_write_pointer(GlPacket *pkt, const void *p) +{ + write_raw(pkt, (char *)&p, sizeof(void *), 1); +} + +void packet_write_data(GlPacket *pkt, const void *data, unsigned size) +{ + if(data) + { + GlOutPacket *out = &pkt->out; + + packet_write_int(pkt, size); + next_vec(pkt); + out->vec->iov_base = (void *)data; + out->vec->iov_len = size; + out->length += size; + ++out->vec; + out->vec->iov_base = out->ptr; + } + else + packet_write_int(pkt, 0); +} + +void packet_write_string(GlPacket *pkt, const char *s) +{ + packet_write_data(pkt, s, strlen(s)+1); +} + +void packet_write_string_array(GlPacket *pkt, const char **sa, unsigned size) +{ + unsigned i; + size /= sizeof(const char *); + packet_write_int(pkt, size); + for(i=0; iin; + in->ptr = data; + in->chunk = *len; + + packet_read_int(pkt, (int *)&in->chunk); + + if(in->chunk&0x80000000) + { + in->chunk &= 0x7FFFFFFF; + in->length = in->chunk; + + while(1) + { + if(endptr+in->length+sizeof(int)) + return NULL; + + GlPacket p; + p.in.ptr = in->ptr+in->length; + p.in.chunk = p.in.length = end-p.in.ptr; + + unsigned chunk; + packet_read_int(&p, (int *)&chunk); + + in->length += chunk&0x7FFFFFFF; + if(!(chunk&0x80000000)) + break; + } + } + else + in->length = in->chunk; + + if(endptr+in->length) + return NULL; + + *len = in->ptr+in->length-data; + + return pkt; +} + +static void next_chunk(GlPacket *pkt) +{ + GlInPacket *in = &pkt->in; + + if(in->length==0) + return; + + in->chunk = in->length; + packet_read_int(pkt, (int *)&in->chunk); + in->chunk &= 0x7FFFFFFF; +} + +static void read_raw(GlPacket *pkt, char *ptr, unsigned size, int byteswap) +{ + GlInPacket *in = &pkt->in; + + if(in->chunk==0) + next_chunk(pkt); + + if(in->chunk>=size) + { + unsigned i; + +#if __BYTE_ORDER == __LITTLE_ENDIAN + if(byteswap) + { + ptr += size; + for(i=0; iptr++; + } + else +#endif + { + for(i=0; iptr++; + } + + in->length -= size; + in->chunk -= size; + } + else + { + memset(ptr, 0, size); + in->length -= in->chunk; + in->chunk = 0; + } +} + +void packet_read_char(GlPacket *pkt, char *v) +{ + read_raw(pkt, v, 1, 0); +} + +void packet_read_short(GlPacket *pkt, short *v) +{ + read_raw(pkt, (char *)v, sizeof(short), 1); +} + +void packet_read_int(GlPacket *pkt, int *v) +{ + read_raw(pkt, (char *)v, sizeof(int), 1); +} + +void packet_read_long(GlPacket *pkt, long *v) +{ + read_raw(pkt, (char *)v, sizeof(long), 1); +} + +void packet_read_long_long(GlPacket *pkt, long long *v) +{ + read_raw(pkt, (char *)v, sizeof(long long), 1); +} + +void packet_read_float(GlPacket *pkt, float *v) +{ + read_raw(pkt, (char *)v, sizeof(float), 1); +} + +void packet_read_double(GlPacket *pkt, double *v) +{ + read_raw(pkt, (char *)v, sizeof(double), 1); +} + +void packet_read_pointer(GlPacket *pkt, pointer *v) +{ + read_raw(pkt, (char *)v, sizeof(pointer), 1); +} + +void packet_read_data(GlPacket *pkt, pointer *v) +{ + GlInPacket *in = &pkt->in; + int vlen; + + packet_read_int(pkt, &vlen); + if(vlen) + *v = in->ptr; + else + *v = NULL; + in->ptr += vlen; + in->chunk -= vlen; + in->length -= vlen; +} + +void packet_read_string(GlPacket *pkt, string *v) +{ + packet_read_data(pkt, (pointer *)v); +} + +void packet_read_string_array(GlPacket *pkt, string **v) +{ + int count; + int i; + packet_read_int(pkt, &count); + *v = (string *)tmpalloc(count*sizeof(string)); + for(i=0; i