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