/* // 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 = pabort_id; } else if (flags & VEIL_P_CLOSE) { list[1].type = SYMBOL; list[1].u.symbol = pclose_id; } else if (flags & VEIL_P_OPEN) { list[1].type = SYMBOL; list[1].u.symbol = 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); }