| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191 |
- #include "unpack.h"
- #include "hevent.h"
- #include "herr.h"
- #include "hlog.h"
- #include "hmath.h"
- int hio_unpack(hio_t* io, void* buf, int readbytes) {
- unpack_setting_t* setting = io->unpack_setting;
- switch(setting->mode) {
- case UNPACK_BY_FIXED_LENGTH:
- return hio_unpack_by_fixed_length(io, buf, readbytes);
- case UNPACK_BY_DELIMITER:
- return hio_unpack_by_delimiter(io, buf, readbytes);
- case UNPACK_BY_LENGTH_FIELD:
- return hio_unpack_by_length_field(io, buf, readbytes);
- default:
- hio_read_cb(io, buf, readbytes);
- return readbytes;
- }
- }
- int hio_unpack_by_fixed_length(hio_t* io, void* buf, int readbytes) {
- const unsigned char* sp = (const unsigned char*)io->readbuf.base + io->readbuf.head;
- const unsigned char* ep = (const unsigned char*)buf + readbytes;
- unpack_setting_t* setting = io->unpack_setting;
- int fixed_length = setting->fixed_length;
- assert(io->readbuf.len >= fixed_length);
- const unsigned char* p = sp;
- int remain = ep - p;
- int handled = 0;
- while (remain >= fixed_length) {
- hio_read_cb(io, (void*)p, fixed_length);
- handled += fixed_length;
- p += fixed_length;
- remain -= fixed_length;
- }
- io->readbuf.head = 0;
- io->readbuf.tail = remain;
- if (remain) {
- // [p, p+remain] => [base, base+remain]
- if (p != (unsigned char*)io->readbuf.base) {
- memmove(io->readbuf.base, p, remain);
- }
- }
- return handled;
- }
- int hio_unpack_by_delimiter(hio_t* io, void* buf, int readbytes) {
- const unsigned char* sp = (const unsigned char*)io->readbuf.base + io->readbuf.head;
- const unsigned char* ep = (const unsigned char*)buf + readbytes;
- unpack_setting_t* setting = io->unpack_setting;
- unsigned char* delimiter = setting->delimiter;
- int delimiter_bytes = setting->delimiter_bytes;
- const unsigned char* p = (const unsigned char*)buf - delimiter_bytes + 1;
- if (p < sp) p = sp;
- int remain = ep - p;
- int handled = 0;
- int i = 0;
- while (remain >= delimiter_bytes) {
- for (i = 0; i < delimiter_bytes; ++i) {
- if (p[i] != delimiter[i]) {
- goto not_match;
- }
- }
- match:
- p += delimiter_bytes;
- remain -= delimiter_bytes;
- hio_read_cb(io, (void*)sp, p - sp);
- handled += p - sp;
- sp = p;
- continue;
- not_match:
- ++p;
- --remain;
- }
- remain = ep - sp;
- io->readbuf.head = 0;
- io->readbuf.tail = remain;
- if (remain) {
- // [sp, sp+remain] => [base, base+remain]
- if (sp != (unsigned char*)io->readbuf.base) {
- memmove(io->readbuf.base, sp, remain);
- }
- if (io->readbuf.tail == io->readbuf.len) {
- if (io->readbuf.len >= setting->package_max_length) {
- hloge("recv package over %d bytes!", (int)setting->package_max_length);
- io->error = ERR_OVER_LIMIT;
- hio_close(io);
- return -1;
- }
- int newsize = MIN(io->readbuf.len * 2, setting->package_max_length);
- hio_alloc_readbuf(io, newsize);
- }
- }
- return handled;
- }
- int hio_unpack_by_length_field(hio_t* io, void* buf, int readbytes) {
- const unsigned char* sp = (const unsigned char*)io->readbuf.base + io->readbuf.head;
- const unsigned char* ep = (const unsigned char*)buf + readbytes;
- unpack_setting_t* setting = io->unpack_setting;
- const unsigned char* p = sp;
- int remain = ep - p;
- int handled = 0;
- unsigned int head_len = setting->body_offset;
- unsigned int body_len = 0;
- unsigned int package_len = head_len;
- const unsigned char* lp = NULL;
- while (remain >= setting->body_offset) {
- body_len = 0;
- lp = p + setting->length_field_offset;
- if (setting->length_field_coding == BIG_ENDIAN) {
- for (int i = 0; i < setting->length_field_bytes; ++i) {
- body_len = (body_len << 8) | (unsigned int)*lp++;
- }
- }
- else if (setting->length_field_coding == LITTLE_ENDIAN) {
- for (int i = 0; i < setting->length_field_bytes; ++i) {
- body_len |= ((unsigned int)*lp++) << (i * 8);
- }
- }
- else if (setting->length_field_coding == ENCODE_BY_VARINT) {
- int varint_bytes = ep - lp;
- body_len = varint_decode(lp, &varint_bytes);
- if (varint_bytes == 0) break;
- if (varint_bytes == -1) {
- hloge("varint is too big!");
- io->error = ERR_OVER_LIMIT;
- hio_close(io);
- return -1;
- }
- head_len = setting->body_offset + varint_bytes - setting->length_field_bytes;
- }
- else if (setting->length_field_coding == ENCODE_BY_ASN1) {
- int varint_bytes = ep - lp;
- body_len = asn1_decode(lp, &varint_bytes);
- if (varint_bytes == 0) break;
- if (varint_bytes == -1) {
- hloge("varint is too big!");
- io->error = ERR_OVER_LIMIT;
- hio_close(io);
- return -1;
- }
- head_len = setting->body_offset + varint_bytes - setting->length_field_bytes;
- } else {
- hloge("Unknown length_field_coding!");
- io->error = ERR_INVALID_PARAM;
- hio_close(io);
- return -1;
- }
- package_len = head_len + body_len + setting->length_adjustment;
- if (remain >= package_len) {
- hio_read_cb(io, (void*)p, package_len);
- handled += package_len;
- p += package_len;
- remain -= package_len;
- } else {
- break;
- }
- }
- io->readbuf.head = 0;
- io->readbuf.tail = remain;
- if (remain) {
- // [p, p+remain] => [base, base+remain]
- if (p != (unsigned char*)io->readbuf.base) {
- memmove(io->readbuf.base, p, remain);
- }
- if (package_len > io->readbuf.len) {
- if (package_len > setting->package_max_length) {
- hloge("package length over %d bytes!", (int)setting->package_max_length);
- io->error = ERR_OVER_LIMIT;
- hio_close(io);
- return -1;
- }
- int newsize = LIMIT(package_len, io->readbuf.len * 2, setting->package_max_length);
- hio_alloc_readbuf(io, newsize);
- }
- }
- return handled;
- }
|