]> git.tdb.fi Git - gldbg.git/blob - source/packet.c
Use a centralized packet framework
[gldbg.git] / source / packet.c
1 /* $Id$
2
3 This file is part of gldbg
4 Copyright © 2010  Mikko Rasa, Mikkosoft Productions
5 Distributed under the GPL
6 */
7
8 #include <stdlib.h>
9 #include <string.h>
10 #include <sys/uio.h>
11 #include "packet.h"
12 #include "tmpalloc.h"
13
14 struct GlOutPacket
15 {
16         char *ptr;
17         unsigned length;
18         struct iovec *vec;
19 };
20
21 struct GlInPacket
22 {
23         const char *ptr;
24         unsigned length;
25         unsigned chunk;
26 };
27
28 typedef struct GlOutPacket GlOutPacket;
29 typedef struct GlInPacket GlInPacket;
30
31 struct GlPacket
32 {
33         union
34         {
35                 GlOutPacket out;
36                 GlInPacket in;
37         };
38 };
39
40 // XXX Should make this stuff truly re-entrant
41 static char *out_buffer = 0;
42 static struct iovec *iovecs = 0;
43 static GlPacket packet;
44 /*static char *in_buffer = 0;
45 static unsigned in_length;*/
46
47 static void next_vec(GlPacket *pkt)
48 {
49         GlOutPacket *out = &pkt->out;
50
51         if(out->ptr!=out->vec->iov_base)
52         {
53                 out->vec->iov_len = out->ptr-(char *)out->vec->iov_base;
54                 out->length += out->vec->iov_len;
55                 ++out->vec;
56                 out->vec->iov_base = out->ptr;
57         }
58 }
59
60 static void reset(GlPacket *pkt)
61 {
62         GlOutPacket *out = &pkt->out;
63
64         out->ptr = out_buffer;
65         out->vec = iovecs;
66         out->vec->iov_base = out->ptr;
67         out->length = 0;
68 }
69
70 GlPacket *packet_begin(unsigned short func)
71 {
72         GlPacket *pkt;
73
74         if(!out_buffer)
75                 out_buffer = (char *)malloc(1024);
76         if(!iovecs)
77                 iovecs = (struct iovec *)malloc(16*sizeof(struct iovec));
78
79         pkt = &packet;
80         reset(pkt);
81
82         packet_write_int(pkt, 0);
83         packet_write_short(pkt, func);
84
85         return pkt;
86 }
87
88 void packet_send_partial(GlPacket *pkt, int fd)
89 {
90         GlOutPacket *out = &pkt->out;
91
92         out->length |= 0x80000000;
93         packet_send(pkt, fd);
94
95         reset(pkt);
96
97         packet_write_int(pkt, 0);
98 }
99
100 void packet_send(GlPacket *pkt, int fd)
101 {
102         GlOutPacket *out = &pkt->out;
103         struct iovec *v;
104
105         next_vec(pkt);
106         out->ptr = out_buffer;
107         packet_write_int(pkt, out->length);
108
109         for(v=iovecs; v!=out->vec; )
110         {
111                 int ret;
112
113                 ret = writev(fd, v, out->vec-v);
114                 if(ret<0)
115                         return;
116
117                 while(v!=out->vec && (unsigned)ret>=v->iov_len)
118                 {
119                         ret -= v->iov_len;
120                         ++v;
121                 }
122
123                 if(v!=out->vec)
124                 {
125                         v->iov_base += ret;
126                         v->iov_len -= ret;
127                 }
128         }
129 }
130
131 static void write_raw(GlPacket *pkt, const char *ptr, unsigned size, int byteswap)
132 {
133         GlOutPacket *out = &pkt->out;
134         unsigned i;
135
136 #if __BYTE_ORDER == __LITTLE_ENDIAN
137         if(byteswap)
138         {
139                 ptr += size;
140                 for(i=0; i<size; ++i)
141                         *out->ptr++ = *--ptr;
142         }
143         else
144 #endif
145         {
146                 for(i=0; i<size; ++i)
147                         *out->ptr++ = *ptr++;
148         }
149 }
150
151 void packet_write_char(GlPacket *pkt, char v)
152 {
153         GlOutPacket *out = &pkt->out;
154         *out->ptr++ = v;
155 }
156
157 void packet_write_short(GlPacket *pkt, short v)
158 {
159         write_raw(pkt, (char *)&v, sizeof(short), 1);
160 }
161
162 void packet_write_int(GlPacket *pkt, int v)
163 {
164         write_raw(pkt, (char *)&v, sizeof(int), 1);
165 }
166
167 void packet_write_long(GlPacket *pkt, long v)
168 {
169         write_raw(pkt, (char *)&v, sizeof(long), 1);
170 }
171
172 void packet_write_long_long(GlPacket *pkt, long long v)
173 {
174         write_raw(pkt, (char *)&v, sizeof(long long), 1);
175 }
176
177 void packet_write_float(GlPacket *pkt, float v)
178 {
179         write_raw(pkt, (char *)&v, sizeof(float), 1);
180 }
181
182 void packet_write_double(GlPacket *pkt, double v)
183 {
184         write_raw(pkt, (char *)&v, sizeof(double), 1);
185 }
186
187 void packet_write_pointer(GlPacket *pkt, const void *p)
188 {
189         write_raw(pkt, (char *)&p, sizeof(void *), 1);
190 }
191
192 void packet_write_data(GlPacket *pkt, const void *data, unsigned size)
193 {
194         if(data)
195         {
196                 GlOutPacket *out = &pkt->out;
197
198                 packet_write_int(pkt, size);
199                 next_vec(pkt);
200                 out->vec->iov_base = (void *)data;
201                 out->vec->iov_len = size;
202                 out->length += size;
203                 ++out->vec;
204                 out->vec->iov_base = out->ptr;
205         }
206         else
207                 packet_write_int(pkt, 0);
208 }
209
210 void packet_write_string(GlPacket *pkt, const char *s)
211 {
212         packet_write_data(pkt, s, strlen(s)+1);
213 }
214
215 void packet_write_string_array(GlPacket *pkt, const char **sa, unsigned size)
216 {
217         unsigned i;
218         size /= sizeof(const char *);
219         packet_write_int(pkt, size);
220         for(i=0; i<size; ++i)
221                 packet_write_string(pkt, sa[i]);
222 }
223
224 GlPacket *packet_receive_str(const char *data, unsigned *len)
225 {
226         const char *end = data+*len;
227         GlPacket *pkt;
228         GlInPacket *in;
229
230         if(*len<sizeof(int)+sizeof(short))
231                 return 0;
232
233         pkt = &packet;
234         in = &pkt->in;
235         in->ptr = data;
236         in->chunk = *len;
237
238         packet_read_int(pkt, (int *)&in->chunk);
239
240         if(in->chunk&0x80000000)
241         {
242                 in->chunk &= 0x7FFFFFFF;
243                 in->length = in->chunk;
244
245                 while(1)
246                 {
247                         if(end<in->ptr+in->length+sizeof(int))
248                                 return NULL;
249
250                         GlPacket p;
251                         p.in.ptr = in->ptr+in->length;
252                         p.in.chunk = p.in.length = end-p.in.ptr;
253
254                         unsigned chunk;
255                         packet_read_int(&p, (int *)&chunk);
256
257                         in->length += chunk&0x7FFFFFFF;
258                         if(!(chunk&0x80000000))
259                                 break;
260                 }
261         }
262         else
263                 in->length = in->chunk;
264
265         if(end<in->ptr+in->length)
266                 return NULL;
267
268         *len = in->ptr+in->length-data;
269
270         return pkt;
271 }
272
273 static void next_chunk(GlPacket *pkt)
274 {
275         GlInPacket *in = &pkt->in;
276
277         if(in->length==0)
278                 return;
279
280         in->chunk = in->length;
281         packet_read_int(pkt, (int *)&in->chunk);
282         in->chunk &= 0x7FFFFFFF;
283 }
284
285 static void read_raw(GlPacket *pkt, char *ptr, unsigned size, int byteswap)
286 {
287         GlInPacket *in = &pkt->in;
288
289         if(in->chunk==0)
290                 next_chunk(pkt);
291
292         if(in->chunk>=size)
293         {
294                 unsigned i;
295
296 #if __BYTE_ORDER == __LITTLE_ENDIAN
297                 if(byteswap)
298                 {
299                         ptr += size;
300                         for(i=0; i<size; ++i)
301                                 *--ptr = *in->ptr++;
302                 }
303                 else
304 #endif
305                 {
306                         for(i=0; i<size; ++i)
307                                 *ptr++ = *in->ptr++;
308                 }
309
310                 in->length -= size;
311                 in->chunk -= size;
312         }
313         else
314         {
315                 memset(ptr, 0, size);
316                 in->length -= in->chunk;
317                 in->chunk = 0;
318         }
319 }
320
321 void packet_read_char(GlPacket *pkt, char *v)
322 {
323         read_raw(pkt, v, 1, 0);
324 }
325
326 void packet_read_short(GlPacket *pkt, short *v)
327 {
328         read_raw(pkt, (char *)v, sizeof(short), 1);
329 }
330
331 void packet_read_int(GlPacket *pkt, int *v)
332 {
333         read_raw(pkt, (char *)v, sizeof(int), 1);
334 }
335
336 void packet_read_long(GlPacket *pkt, long *v)
337 {
338         read_raw(pkt, (char *)v, sizeof(long), 1);
339 }
340
341 void packet_read_long_long(GlPacket *pkt, long long *v)
342 {
343         read_raw(pkt, (char *)v, sizeof(long long), 1);
344 }
345
346 void packet_read_float(GlPacket *pkt, float *v)
347 {
348         read_raw(pkt, (char *)v, sizeof(float), 1);
349 }
350
351 void packet_read_double(GlPacket *pkt, double *v)
352 {
353         read_raw(pkt, (char *)v, sizeof(double), 1);
354 }
355
356 void packet_read_pointer(GlPacket *pkt, pointer *v)
357 {
358         read_raw(pkt, (char *)v, sizeof(pointer), 1);
359 }
360
361 void packet_read_data(GlPacket *pkt, pointer *v)
362 {
363         GlInPacket *in = &pkt->in;
364         int vlen;
365
366         packet_read_int(pkt, &vlen);
367         if(vlen)
368                 *v = in->ptr;
369         else
370                 *v = NULL;
371         in->ptr += vlen;
372         in->chunk -= vlen;
373         in->length -= vlen;
374 }
375
376 void packet_read_string(GlPacket *pkt, string *v)
377 {
378         packet_read_data(pkt, (pointer *)v);
379 }
380
381 void packet_read_string_array(GlPacket *pkt, string **v)
382 {
383         int count;
384         int i;
385         packet_read_int(pkt, &count);
386         *v = (string *)tmpalloc(count*sizeof(string));
387         for(i=0; i<count; ++i)
388                 packet_read_string(pkt, *v+i);
389 }