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