[go: up one dir, main page]

Menu

[897c37]: / runtime / trans.c  Maximize  Restore  History

Download this file

331 lines (311 with data), 8.8 kB

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
/*
** $Id: trans.c,v 1.2 2008/12/18 04:17:02 dredd Exp $
**
** $Source: /cvsroot/swlpc/swlpc/runtime/trans.c,v $
** $Revision: 1.2 $
** $Date: 2008/12/18 04:17:02 $
** $State: Exp $
**
** Author: Mike McGaughey, 1993-1998
**
** See the file "Copying" distributed with this file.
*/
/*
* Transmission - build, buffering, unbuffering.
* Used by the dg receive stuff (comm1) and send stuff
* (interpret) to put together a buffer denoting a value.
* Can send anything except objects. No passing is added to
* any value (this saves enormous amounts of space).
*
* Warning: assumes 32 bit ints. Used to use network byte order,
* but we found that the mips compiler is extremely good with unsigned,
* etc, conversions, so now we send it raw.
*/
#include "proto.h"
/*
* Dgram packaging routines - these write a value into a (sendable) buffer,
* or read a buffer into a value. If the buffer is too short to write to,
* the send routine returns (-2). When receiving, if the incoming data appears
* to be truncated, it returns (-2) (but the passed value is set to as much
* as was read), and if there is an invalid type (or whatever), it returns (-1).
* Other negative values are returned for truncated or too-large or negative arrays.
*
* Note: they expect values (not values).
*
* Integers, etc, are sent in network byte order. It's hard to know what to
* do with floats (besides pray).
*/
#define Ty_0 0 /* A simple zero value - common */
#define Ty_sInt1 1 /* 1 byte signed int */
#define Ty_sInt2 2 /* 2 byte signed int */
#define Ty_sInt4 3 /* 4 byte signed int */
#define Ty_String 4 /* string, with terminator */
#define Ty_ArrayB 5 /* array; followed by (byte) nelem, then elements */
#define Ty_ArrayS 6 /* array, followed by (short) nelem, then elements */
#define Ty_Real 7 /* 4 byte real */
#define Ty_uInt1 8 /* 1 byte unsigned int (appears to be common) */
#define Ty_Image 9 /* Image; (short) width, (short) height, elements */
union {
unsigned char bytes[32];
signed char sc;
unsigned char uc;
signed short ss;
unsigned short us;
signed int si;
unsigned int ui;
float f;
signed long sl;
unsigned long ul;
} convbuf;
#define SPACELEFT(buff, end, need) (((end) - (buff) - 1) < (need)? 0 : 1)
/*
* Build a transmission buffer. If it's going to run out of space
* when fitting in the last value, always include the tag anyway (if it
* fits) - this fits in better with the possibility of the network
* truncating it.
*/
int buff_write_val(unsigned char * buff, int len, Val *from)
{
unsigned char * obuff = buff;/* length calcs in arrays */
signed long i; /* integer manipulations */
int j; /* counter */
int t; /* num array elts */
int wrlen; /* num bytes to dump */
unsigned char tag; /* tag to dump */
unsigned char *outbytes = &convbuf.bytes[0]; /* where to dump from */
if (!from)
return(0); /* a zero-length transmission */
if (len < 1)
return(-2); /* truncated before tag */
switch(from->type) {
default: /* can't send objects */
return(-1);
#ifdef GRAPHICS
case T_IMAGE: /* (short)width,(short)height,(width*height)elements */
{
short w, h;
Img *img;
img = from->u.img;
w = img->w;
h = img->h;
wrlen = w * h;
outbytes = img->pic;
tag = Ty_Image;
*(buff++) = tag; /* if we got here, the tag fits */
convbuf.us = w;
*(buff++) = convbuf.bytes[0];
*(buff++) = convbuf.bytes[1];
convbuf.us = h;
*(buff++) = convbuf.bytes[0];
*(buff++) = convbuf.bytes[1];
for (j=0; j < wrlen; j++)
*(buff++) = outbytes[j];
return wrlen + 5;
}
#endif
case T_NUMBER: /* 32 bit signed; choose the smallest representation */
i = from->u.number;
if (!i) {
tag = Ty_0;
wrlen = 0;
}
else if (i >= 0 && i < 256) {
tag = Ty_uInt1;
convbuf.uc = i;
wrlen = 1;
}
else if (i >= (-128) && i < 127) {
tag = Ty_sInt1;
convbuf.sc = i;
wrlen = 1;
}
else if (-(1<<15) <= i && i < 1<<15) {
tag = Ty_sInt2;
convbuf.ss = i;
wrlen = 2;
}
else {
tag = Ty_sInt4;
convbuf.si = i;
wrlen = 4;
}
break;
case T_REAL:
tag = Ty_Real;
convbuf.f = from->u.real;
wrlen = sizeof(float);
break;
case T_STRING:
tag = Ty_String;
outbytes = (unsigned char *)(from->u.string->str);
wrlen = 1 + from->u.string->length; /* null byte */
break;
case T_POINTER:
/* read the size */
t = from->u.vec->size;
if (t < 256) {
tag = Ty_ArrayB;
convbuf.uc = t;
wrlen = 1;
}
else {
tag = Ty_ArrayS;
convbuf.us = t;
wrlen = 2;
}
*(buff++) = tag;
if (wrlen + 1 > len)
return(-2);
for (j=0; j<wrlen; j++)
*(buff++) = convbuf.bytes[j];
/* dump the contents. while in here, len is relative to obuff. */
for (j = 0; j < t; j++) {
int did = buff_write_val(buff, len - (buff - obuff), &(from->u.vec->item[j]));
if (did < 0)
return(did);
buff += did;
}
return(buff - obuff);
}
*(buff++) = tag; /* if we got here, the tag fits */
if (len < 1 + wrlen)
return(-2);
for (j=0; j < wrlen; j++)
*(buff++) = outbytes[j];
return wrlen + 1;
}
/*
* The reverse of the above (we hope :).
* Build an value from an incoming buffer. The value
* is assumed initialised (to something that assign_value
* won't complain about).
* Strings are treated specially - if they are truncated,
* we can assume the network did it (or some asshole is sending
* spurious packets). So, if no null byte is found before the
* end of the buffer when processing a string, we place a null at the
* end (thus truncating one extra character). Ugly.
*/
int buff_read_val(unsigned char *buff, int len, Val *to)
{
unsigned char tag;
char * x; /* string copying */
int nread = 1;
int j, t;
Shared * y;
if (len < 1)
return(-2);
tag = *(buff++);
switch(tag) {
default: /* bad type */
return(-1);
case Ty_0:
to->type = T_NUMBER;
to->u.number = 0;
nread = 1;
break;
case Ty_uInt1:
if (len < 2)
return(-2);
to->type = T_NUMBER;
to->u.number = (*buff); /* buff is unsigned char */
nread = 2;
break;
case Ty_sInt1:
if (len < 2)
return(-2);
to->type = T_NUMBER;
convbuf.uc = *buff; /* store, without change */
to->u.number = convbuf.sc; /* but bring back with sign extension */
nread = 2;
break;
case Ty_sInt2:
if (len < 3)
return(-2);
to->type = T_NUMBER;
nread = 3;
convbuf.bytes[0] = *(buff++); /* these numbers need to change if we change orders */
convbuf.bytes[1] = *(buff++);
to->u.number = convbuf.ss; /* back as signed short */
break;
case Ty_sInt4:
if (len < 5)
return(-2);
to->type = T_NUMBER;
nread = 5;
for (j=0; j<4; j++)
convbuf.bytes[j] = *(buff++);
to->u.number = convbuf.si;
break;
case Ty_Real:
nread = 1 + sizeof(float);
if (len < nread)
return(-2);
to->type = T_REAL;
for (j=0; j<sizeof(float); j++)
convbuf.bytes[j] = *(buff++);
to->u.real = convbuf.f;
break;
case Ty_String: /* if we're being sent garbage (or if truncated), there may not be nulls, etc */
if (len < 2) /* need space for a null byte */
return(-2);
x = memchr(buff, 0, len-1); /* 1 byte was already read - tag. Find trailing null */
if (!x)
buff[len - 1] = 0; /* ruthlessly truncate it */
y = string_copy(buff);
to->type = T_STRING;
to->u.string = y;
if (!x) return(-2); /* ran out of space, but assigned it ok */
nread = 2 + y->length; /* tag + null + len */
break;
case Ty_ArrayB:
if (len < 2)
return(-2);
t = (*(buff++)); /* buff is unsigned chars */
nread = 2;
goto arr_read;
case Ty_ArrayS:
if (len < 3)
return(-2);
convbuf.bytes[0] = *(buff++);
convbuf.bytes[1] = *(buff++);
t = convbuf.us;
nread = 3;
arr_read:
if (t < 0)
return(-4);
if (t > MAX_ARRAY_SIZE)
return(-5);
assign_value(to, allocate_array(t));
// wipe(1);
/* we work directly in the assigned value, in case of truncation */
for (j = 0; j < t; j++) {
int did = buff_read_val(buff, len - nread, &(to->u.vec->item[j]));
if (did < 0)
return(did);
if (did < 1) /* end of array matches end of buffer */
break;
nread += did;
buff += did;
}
break;
#ifdef GRAPHICS
case Ty_Image:
{
int w, h, t;
Img * i;
if (len < 4)
return (-2);
convbuf.bytes[0] = *(buff++);
convbuf.bytes[1] = *(buff++);
w = convbuf.us;
convbuf.bytes[0] = *(buff++);
convbuf.bytes[1] = *(buff++);
h = convbuf.us;
i = create_image(w, h);
memcpy(i->pic, buff, len - 4);
to->u.img = i;
}
#endif
}
return nread;
}