]> git.tdb.fi Git - gldbg.git/blobdiff - source/packet.c
Use a centralized packet framework
[gldbg.git] / source / packet.c
diff --git a/source/packet.c b/source/packet.c
new file mode 100644 (file)
index 0000000..465f118
--- /dev/null
@@ -0,0 +1,389 @@
+/* $Id$
+
+This file is part of gldbg
+Copyright © 2010  Mikko Rasa, Mikkosoft Productions
+Distributed under the GPL
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/uio.h>
+#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; i<size; ++i)
+                       *out->ptr++ = *--ptr;
+       }
+       else
+#endif
+       {
+               for(i=0; i<size; ++i)
+                       *out->ptr++ = *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; i<size; ++i)
+               packet_write_string(pkt, sa[i]);
+}
+
+GlPacket *packet_receive_str(const char *data, unsigned *len)
+{
+       const char *end = data+*len;
+       GlPacket *pkt;
+       GlInPacket *in;
+
+       if(*len<sizeof(int)+sizeof(short))
+               return 0;
+
+       pkt = &packet;
+       in = &pkt->in;
+       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(end<in->ptr+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(end<in->ptr+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; i<size; ++i)
+                               *--ptr = *in->ptr++;
+               }
+               else
+#endif
+               {
+                       for(i=0; i<size; ++i)
+                               *ptr++ = *in->ptr++;
+               }
+
+               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<count; ++i)
+               packet_read_string(pkt, *v+i);
+}