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