/*
// Full copyright information is available in the file ../doc/CREDITS
//
// VEIL packets buffer manipulation module
//
// look at http://www.cold.org/VEIL/ for more information.
//
*/
#define NATIVE_MODULE "$buffer"
#define VEIL_C
#include "veil.h"
module_t veil_module = {YES, init_veil, YES, uninit_veil};
#define VEIL_P_PUSH 1
#define VEIL_P_ABORT 2
#define VEIL_P_CLOSE 4
#define VEIL_P_OPEN 8
#define VEIL_P_UNDF1 16
#define VEIL_P_UNDF2 32
#define VEIL_P_UNDF3 64
#define VEIL_P_UNDF4 128
/*
// 1 byte bitfield flags
// 2 bytes channel id
// 2 bytes length
*/
#define HEADER_SIZE 5
void init_veil(Int argc, char ** argv) {
pabort_id = ident_get("abort");
pclose_id = ident_get("close");
popen_id = ident_get("open");
}
void uninit_veil(void) {
ident_discard(pabort_id);
ident_discard(pclose_id);
ident_discard(popen_id);
}
/*
// -------------------------------------------------------------------
// In ColdC we represent a VEIL packet as:
//
// [1|0, 'abort|'close|'open|0, id, `[]]
//
// The first argument represents the push bit, and the end of a message.
// id is an integer.
*/
/*
// -------------------------------------------------------------------
// internal function for buffer -> VEIL packet
*/
cList * buf_to_veil_packets(cBuf * buf) {
Int flags,
channel,
length,
blen;
cBuf * databuf,
* incomplete;
cData d,
* list;
cList * output,
* packet;
unsigned char * cbuf;
output = list_new(0);
blen = buf->len;
cbuf = buf->s;
forever {
/* 5 bytes will give us the header, we check length again after
that, because the header gives us the data length */
if (blen < HEADER_SIZE)
break;
/* grab the bit flags */
flags = (Int) cbuf[0];
/* get the Channel ID and data length */
channel = (Int) (((int) cbuf[1] * 256) + ((int) cbuf[2]));
length = (Int) (((int) cbuf[3] * 256) + ((int) cbuf[4]));
if (length > (blen - HEADER_SIZE))
break;
/* copy the data segment of the packet to the databuf */
databuf = buffer_new(length);
cbuf += HEADER_SIZE;
MEMCPY(databuf->s, cbuf, length);
cbuf += (length);
blen -= (length + HEADER_SIZE);
/* create the packet list, add it to the output list */
packet = list_new(4);
list = list_empty_spaces(packet, 4);
list[0].type = INTEGER;
list[0].u.val = (flags & VEIL_P_PUSH) ? 1 : 0;
/* give abort precedence */
if (flags & VEIL_P_ABORT) {
list[1].type = SYMBOL;
list[1].u.symbol = ident_dup(pabort_id);
} else if (flags & VEIL_P_CLOSE) {
list[1].type = SYMBOL;
list[1].u.symbol = ident_dup(pclose_id);
} else if (flags & VEIL_P_OPEN) {
list[1].type = SYMBOL;
list[1].u.symbol = ident_dup(popen_id);
} else {
list[1].type = INTEGER;
list[1].u.val = 0;
}
list[2].type = INTEGER;
list[2].u.val = channel;
list[3].type = BUFFER;
list[3].u.buffer = buffer_dup(databuf);
/* add it to the list */
d.type = LIST;
d.u.list = packet;
output = list_add(output, &d);
buffer_discard(databuf);
list_discard(packet);
}
/* add the incomplete buffer to the end */
incomplete = buffer_new(blen);
if (blen > 0)
MEMMOVE(incomplete->s, cbuf, blen);
d.type = BUFFER;
d.u.buffer = incomplete;
output = list_add(output, &d);
buffer_discard(incomplete);
return output;
}
/*
// -------------------------------------------------------------------
// Convert from a buffer to the standard 'VEIL packet' format
*/
NATIVE_METHOD(to_veil_pkts) {
cBuf * buf;
cList * packets;
INIT_1_OR_2_ARGS(BUFFER, BUFFER);
if (argc == 1) {
buf = buffer_dup(_BUF(ARG1));
} else {
/* if they sent us a second argument, concatenate it on the end */
buf = buffer_append(buffer_dup(_BUF(ARG1)), _BUF(ARG2));
}
packets = buf_to_veil_packets(buf);
buffer_discard(buf);
CLEAN_RETURN_LIST(packets);
}
/*
// -------------------------------------------------------------------
// Convert to a buffer from the standard 'VEIL packet' format
//
// in leiu of speed, we do not do COMPLETE checking on every argument
// sent to the packet, just make sure you do it right
*/
NATIVE_METHOD(from_veil_pkts) {
cData * d,
* pa;
cBuf * out,
* header;
cList * p,
* packets;
Int len;
INIT_1_ARG(LIST);
header = buffer_new(HEADER_SIZE);
out = buffer_new(0);
packets = LIST1;
for (d = list_first(packets); d; d = list_next(packets, d)) {
if (d->type != LIST)
THROW((type_id, "Packets submitted in an invalid format"));
p = d->u.list;
pa = list_first(p);
if (!pa || pa->type != INTEGER)
THROW((type_id, "Packet submitted in an invalid format"));
header->s[0] = (unsigned char) 0;
if (pa->u.val)
header->s[0] |= VEIL_P_PUSH;
pa = list_next(p, pa);
if (!pa)
THROW((type_id, "Not enough elements in the packet!"));
if (pa->type == SYMBOL) {
if (pa->u.symbol == pabort_id)
header->s[0] |= VEIL_P_ABORT;
else if (pa->u.symbol == pclose_id)
header->s[0] |= VEIL_P_CLOSE;
else if (pa->u.symbol == popen_id)
header->s[0] |= VEIL_P_OPEN;
}
pa = list_next(p, pa);
if (!pa || pa->type != INTEGER)
THROW((type_id, "Packet submitted in an invalid format"));
header->s[1] = (unsigned char) pa->u.val/256;
header->s[2] = (unsigned char) pa->u.val%256;
pa = list_next(p, pa);
if (!pa || pa->type != BUFFER)
THROW((type_id, "Packet submitted in an invalid format"));
header->s[3] = (unsigned char) pa->u.buffer->len/256;
header->s[4] = (unsigned char) pa->u.buffer->len%256;
len = out->len + header->len + pa->u.buffer->len - 2;
out = (cBuf *) erealloc(out, sizeof(cBuf) + len);
MEMCPY(out->s + out->len, header->s, header->len);
out->len += header->len;
MEMCPY(out->s + out->len, pa->u.buffer->s, pa->u.buffer->len);
out->len += pa->u.buffer->len;
}
CLEAN_RETURN_BUFFER(out);
}