diff --git a/test/aaip_0_2.c b/test/aaip_0_2.c index 1df3c58d..7b66a9d3 100644 --- a/test/aaip_0_2.c +++ b/test/aaip_0_2.c @@ -2,7 +2,7 @@ /* Arbitrary Attribute Interchange Protocol , AAIP version 0.2 - Demonstration program for encoding and decoding EA and ACL. + Demonstration implementation of encoding and decoding EA and ACL. See test/aaip_0_2.h http://libburnia-project.org/wiki/AAIP @@ -184,6 +184,12 @@ static int aaip_encode_pair(char *name, size_t attr_length, char *attr, /* Not less than 2 * 2048 */ #define Aaip_buffer_sizE 4096 +/* Enough for one full component record and three empty ones which might get + added in case of unclean end of attribute list. +*/ +#define Aaip_buffer_reservE (257 + 3 * 2) + + struct aaip_state { /* AA field status */ @@ -195,8 +201,9 @@ struct aaip_state { /* Buffer for component records */ int recs_invalid; /* number of components to skip */ - unsigned char recs[Aaip_buffer_sizE]; + unsigned char recs[Aaip_buffer_sizE + Aaip_buffer_reservE]; size_t recs_fill; + unsigned char *recs_start; int rec_head_missing; /* number of bytes needed to complete rec header */ int rec_missing; /* number of bytes needed to complete current rec */ int rec_ends; @@ -207,6 +214,7 @@ struct aaip_state { /* Counter and meaning for completed components */ unsigned int num_components; + size_t end_of_components; /* start index of eventual incomplete component */ int first_is_name; /* Last return value of aaip_decode_pair() */ @@ -233,8 +241,9 @@ int aaip_init(struct aaip_state *aaip, char aa_name[2], int flag) aaip->aa_missing= 0; aaip->recs_invalid= 0; - memset(aaip->recs, 0, Aaip_buffer_sizE); + memset(aaip->recs, 0, Aaip_buffer_sizE + Aaip_buffer_reservE); aaip->recs_fill= 0; + aaip->recs_start= aaip->recs; aaip->rec_head_missing= 2; aaip->rec_missing= 0; aaip->rec_ends= 0; @@ -243,33 +252,217 @@ int aaip_init(struct aaip_state *aaip, char aa_name[2], int flag) aaip->ready_bytes= 0; aaip->num_components= 0; + aaip->end_of_components= 0; aaip->first_is_name= 1; - aaip->pair_status= 1; + aaip->pair_status= 2; aaip->pairs_skipped= 0; return(1); } +/* +*/ +#define Aaip_with_ring_buffeR yes + +#ifdef Aaip_with_ring_buffeR + +/* Compute the one or two byte intervals in the ring buffer which form a + given byte interval in the virtual shift fifo. + @param idx The byte start index in the virtual shift fifo. + @param todo Number of bytes to cover + @param start_pt Will return the start address of the first interval + @param at_start_pt Will return the size of the first interval + @param at_recs Will return the size of the second interval which + always starts at aaip->recs + @param flag Bitfield for control purposes + @return 1= next start_pt is *start_pt + *at_start_pt + 2= next start_pt is aaip->recs + *at_recs +*/ +static int aaip_ring_adr(struct aaip_state *aaip, size_t idx, size_t todo, + unsigned char **start_pt, size_t *at_start_pt, + size_t *at_recs, int flag) +{ + size_t ahead; + + ahead= Aaip_buffer_sizE + Aaip_buffer_reservE + - (aaip->recs_start - aaip->recs); + if(idx < ahead) + *start_pt= (aaip->recs_start + idx); + else + *start_pt= aaip->recs + (idx - ahead); + ahead= Aaip_buffer_sizE + Aaip_buffer_reservE - (*start_pt - aaip->recs); + if(todo >= ahead) { + *at_start_pt= ahead; + *at_recs= todo - ahead; + return(2); + } + *at_start_pt= todo; + *at_recs= 0; + return(1); +} + + +/* + @param flag Bitfield for control purposes + bit0= count as ready_bytes +*/ +static int aaip_push_to_recs(struct aaip_state *aaip, unsigned char *data, + size_t todo, int flag) +{ + unsigned char *start_pt; + size_t at_start_pt, at_recs; + + aaip_ring_adr(aaip, aaip->recs_fill, todo, + &start_pt, &at_start_pt, &at_recs, 0); + if(at_start_pt > 0) + memcpy(start_pt, data, at_start_pt); + if(at_recs > 0) + memcpy(aaip->recs, data + at_start_pt, at_recs); + aaip->recs_fill+= todo; + if(flag & 1) + aaip->ready_bytes+= todo; + return(1); +} + + +static int aaip_read_from_recs(struct aaip_state *aaip, size_t idx, + unsigned char *data, size_t num_data, int flag) +{ + unsigned char *start_pt; + size_t at_start_pt, at_recs; + + aaip_ring_adr(aaip, idx, num_data, + &start_pt, &at_start_pt, &at_recs, 0); + if(at_start_pt > 0) + memcpy(data, start_pt, at_start_pt); + if(at_recs > 0) + memcpy(data + at_start_pt, aaip->recs, at_recs); + return(1); +} + + +static int aaip_set_buffer_byte(struct aaip_state *aaip, size_t idx, + unsigned char data, int flag) +{ + unsigned char *start_pt; + size_t at_start_pt, at_recs; + + aaip_ring_adr(aaip, idx, 1, + &start_pt, &at_start_pt, &at_recs, 0); + *start_pt= data; + return(1); +} + + +static int aaip_get_buffer_byte(struct aaip_state *aaip, size_t idx, int flag) +{ + unsigned char *start_pt; + size_t at_start_pt, at_recs; + + aaip_ring_adr(aaip, idx, 1, + &start_pt, &at_start_pt, &at_recs, 0); + return((int) *start_pt); +} + + +static int aaip_shift_recs(struct aaip_state *aaip, size_t todo, int flag) +{ + int ret; + unsigned char *start_pt; + size_t at_start_pt, at_recs; + + if(todo < aaip->recs_fill) { + ret= aaip_ring_adr(aaip, 0, todo, &start_pt, &at_start_pt, &at_recs, 0); + if(ret == 1) + aaip->recs_start= start_pt + todo; + else + aaip->recs_start= aaip->recs + at_recs; + } else { + aaip->recs_start= aaip->recs; + } + aaip->recs_fill-= todo; + if(aaip->end_of_components >= todo) + aaip->end_of_components-= todo; + else + aaip->end_of_components= 0; + return(1); +} + + +#else /* Aaip_with_ring_buffeR */ + + +/* + @param flag Bitfield for control purposes + bit0= count as ready_bytes +*/ +static int aaip_push_to_recs(struct aaip_state *aaip, unsigned char *data, + size_t todo, int flag) +{ + memcpy(aaip->recs + aaip->recs_fill, data, todo); + aaip->recs_fill+= todo; + if(flag & 1) + aaip->ready_bytes+= todo; + return(1); +} + + +static int aaip_read_from_recs(struct aaip_state *aaip, size_t idx, + unsigned char *data, size_t num_data, int flag) +{ + memcpy(data, aaip->recs + idx, num_data); + return(1); +} + + +static int aaip_set_buffer_byte(struct aaip_state *aaip, size_t idx, + unsigned char data, int flag) +{ + aaip->recs[idx]= data; + return(1); +} + + +static int aaip_get_buffer_byte(struct aaip_state *aaip, size_t idx, int flag) +{ + return((int) aaip->recs[idx]); +} + + +static int aaip_shift_recs(struct aaip_state *aaip, size_t todo, int flag) +{ + if(todo < aaip->recs_fill) + memmove(aaip->recs, aaip->recs + todo, aaip->recs_fill - todo); + aaip->recs_fill-= todo; + + if(aaip->end_of_components >= todo) + aaip->end_of_components-= todo; + else + aaip->end_of_components= 0; + return(1); +} + + +#endif /* ! Aaip_with_ring_buffeR */ + static int aaip_consume_rec_head(struct aaip_state *aaip, unsigned char **data, size_t *num_data, int flag) { - size_t todo, i; + size_t todo; todo= *num_data; if(todo > aaip->aa_missing) todo= aaip->aa_missing; if(todo >= aaip->rec_head_missing) todo= aaip->rec_head_missing; - if(!aaip->recs_invalid) { - memcpy(aaip->recs + aaip->recs_fill, *data + i, todo); - aaip->recs_fill+= todo; - } + if(!aaip->recs_invalid) + aaip_push_to_recs(aaip, *data, todo, 0); aaip->rec_head_missing-= todo; if(aaip->rec_head_missing == 0) { - aaip->rec_missing= aaip->recs[aaip->recs_fill - 1]; - aaip->rec_ends= !(aaip->recs[aaip->recs_fill - 2] & 1); + aaip->rec_missing= aaip_get_buffer_byte(aaip, aaip->recs_fill - 1, 0); + aaip->rec_ends= !(aaip_get_buffer_byte(aaip, aaip->recs_fill - 2, 0) & 1); } aaip->aa_missing-= todo; (*num_data)-= todo; @@ -281,18 +474,15 @@ static int aaip_consume_rec_head(struct aaip_state *aaip, static int aaip_consume_rec_data(struct aaip_state *aaip, unsigned char **data, size_t *num_data, int flag) { - size_t todo, i; + size_t todo; todo= *num_data; if(todo > aaip->aa_missing) todo= aaip->aa_missing; if(todo > aaip->rec_missing) todo= aaip->rec_missing; - if(!aaip->recs_invalid) { - memcpy(aaip->recs + aaip->recs_fill, *data + i, todo); - aaip->recs_fill+= todo; - aaip->ready_bytes+= todo; - } + if(!aaip->recs_invalid) + aaip_push_to_recs(aaip, *data, todo, 1); aaip->rec_missing-= todo; aaip->aa_missing-= todo; (*num_data)-= todo; @@ -303,8 +493,10 @@ static int aaip_consume_rec_data(struct aaip_state *aaip, aaip->recs_invalid--; } else { aaip->num_recs++; - if(aaip->rec_ends) + if(aaip->rec_ends) { aaip->num_components++; + aaip->end_of_components= aaip->recs_fill; + } } aaip->rec_head_missing= 2; } @@ -315,21 +507,21 @@ static int aaip_consume_rec_data(struct aaip_state *aaip, static int aaip_consume_aa_head(struct aaip_state *aaip, unsigned char **data, size_t *num_data, int flag) { - size_t todo, i; + size_t todo; + unsigned char aa_head[5]; todo= *num_data; if(todo >= aaip->aa_head_missing) todo= aaip->aa_head_missing; - for(i= 0; i < todo; i++) - aaip->recs[aaip->recs_fill++]= (*data)[i]; + aaip_push_to_recs(aaip, *data, todo, 0); aaip->aa_head_missing-= todo; if(aaip->aa_head_missing == 0) { - if(aaip->recs[aaip->recs_fill - 5] != aaip->aa_name[0] || - aaip->recs[aaip->recs_fill - 4] != aaip->aa_name[1] || - aaip->recs[aaip->recs_fill - 2] != 1) + aaip_read_from_recs(aaip, aaip->recs_fill - 5, aa_head, 5, 0); + if(aa_head[0] != aaip->aa_name[0] || aa_head[1] != aaip->aa_name[1] || + aa_head[3] != 1) return(-1); - aaip->aa_missing= aaip->recs[aaip->recs_fill - 3]; - aaip->aa_ends= !(aaip->recs[aaip->recs_fill - 1] & 1); + aaip->aa_missing= aa_head[2]; + aaip->aa_ends= !(aa_head[4] & 1); aaip->recs_fill-= 5; /* AA heads do not get delivered */ if(aaip->aa_missing >= 5) aaip->aa_missing-= 5; @@ -345,6 +537,9 @@ static int aaip_consume_aa_head(struct aaip_state *aaip, static int aaip_consume_aa_data(struct aaip_state *aaip, unsigned char **data, size_t *num_data, int flag) { + size_t i; + static unsigned char zero_char[2]= {0, 0}; + while(*num_data > 0 && aaip->aa_missing > 0) { if(aaip->rec_head_missing > 0) { aaip_consume_rec_head(aaip, data, num_data, 0); @@ -355,9 +550,42 @@ static int aaip_consume_aa_data(struct aaip_state *aaip, } if(aaip->aa_missing <= 0) { if(aaip->aa_ends) { - - /* >>> Check for incomplete component or pair, discard it */; - + /* Check for incomplete pair and eventually make emergency closure */ + if(aaip->rec_head_missing != 2) { /* incomplete record detected */ + if(aaip->rec_head_missing) { + /* fake 0 length record */ + aaip_set_buffer_byte(aaip, aaip->recs_fill - 1, (unsigned char) 0, 0); + aaip_push_to_recs(aaip, zero_char, 1, 0); + } else { + /* fill in missing btes */ + for(i= 0; i < aaip->rec_missing; i++) + aaip_push_to_recs(aaip, zero_char, 1, 1); + } + aaip->rec_head_missing= 2; + aaip->rec_missing= 0; + aaip->num_recs++; + if(aaip->rec_ends) { + aaip->num_components++; + aaip->end_of_components= aaip->recs_fill; + } + } + if(aaip->end_of_components != aaip->recs_fill && + aaip->end_of_components != 0) { + /* incomplete component detected */ + /* add empty end record */ + aaip_push_to_recs(aaip, zero_char, 2, 0); + aaip->num_recs++; + aaip->num_components++; + aaip->end_of_components= aaip->recs_fill; + } + if(!(aaip->first_is_name ^ (aaip->num_components % 2))) { + /* value component is missing */ + /* add dummy component */ + aaip_push_to_recs(aaip, zero_char, 2, 0); + aaip->num_recs++; + aaip->num_components++; + aaip->end_of_components= aaip->recs_fill; + } aaip->aa_ends= 2; } else aaip->aa_head_missing= 5; @@ -397,7 +625,7 @@ int aaip_submit_data(struct aaip_state *aaip, if(aaip->recs_fill + num_data > Aaip_buffer_sizE) return(0); - while(aaip->aa_missing == 0 && num_data > 0) { + while(num_data > 0) { if(aaip->aa_head_missing > 0) { ret= aaip_consume_aa_head(aaip, &data, &num_data, 0); if(ret < 0) { @@ -408,6 +636,8 @@ int aaip_submit_data(struct aaip_state *aaip, goto ex; } aaip_consume_aa_data(aaip, &data, &num_data, 0); + if(aaip->aa_missing) + break; } ex:; *ready_bytes= aaip->ready_bytes; @@ -445,7 +675,7 @@ int aaip_fetch_data(struct aaip_state *aaip, char *result, size_t result_size, size_t *num_result, int flag) { - int ret= -1, complete= 0; + int ret= -1, complete= 0, payload; unsigned int i, num_bytes= 0, h; if(aaip->num_recs == 0) @@ -454,24 +684,24 @@ int aaip_fetch_data(struct aaip_state *aaip, /* Copy data until end of buffer or end of component */ h= 0; for(i= 0; i < aaip->num_recs && !complete; i++) { + payload= aaip_get_buffer_byte(aaip, h + 1, 0); if(!(flag & 1)) { - if(num_bytes + aaip->recs[h + 1] > result_size) + if(num_bytes + payload > result_size) return(-2); - memcpy(result + num_bytes, aaip->recs + h + 2, aaip->recs[h + 1]); - *num_result= num_bytes + aaip->recs[h + 1]; + aaip_read_from_recs(aaip, h + 2, (unsigned char *) (result + num_bytes), + payload, 0); + *num_result= num_bytes + payload; } - num_bytes+= aaip->recs[h + 1]; - if(!(aaip->recs[h] & 1)) + num_bytes+= payload; + if(!(aaip_get_buffer_byte(aaip, h, 0) & 1)) complete= 1; - h+= aaip->recs[h + 1] + 2; + h+= payload + 2; } - aaip->num_recs-= i; aaip->ready_bytes-= num_bytes; + aaip->num_recs-= i; /* Shift buffer */ - if(h < aaip->recs_fill) - memmove(aaip->recs, aaip->recs + h, aaip->recs_fill - h); - aaip->recs_fill-= h; + aaip_shift_recs(aaip, h, 0); /* Compute reply */ ret= 2 * !aaip->first_is_name; @@ -500,12 +730,12 @@ int aaip_skip_component(struct aaip_state *aaip, int flag) { int to_skip= 1; - if(aaip->recs_invalid) { - aaip->recs_invalid+= 1 + (flag & 1); - return(1); - } if(aaip->first_is_name && !(flag & 1)) to_skip= 2; + if(aaip->recs_invalid) { + aaip->recs_invalid+= to_skip; + return(1); + } if(aaip->num_components) { /* null-fetch */ diff --git a/test/aaip_0_2.h b/test/aaip_0_2.h index 2e1647bc..5eee54a5 100644 --- a/test/aaip_0_2.h +++ b/test/aaip_0_2.h @@ -168,6 +168,7 @@ int aaip_skip_component(struct aaip_state *aaip, int flag); 3 name and value are valid, pairs pending, fetch with num_data == 0 4 name and value are valid, no more data expected 5 name and value are not valid, no more data expected + */ int aaip_decode_pair(struct aaip_state *aaip, unsigned char *data, size_t num_data, size_t *consumed, diff --git a/test/aaip_0_2_test.c b/test/aaip_0_2_test.c index 92875f16..b89e08d4 100644 --- a/test/aaip_0_2_test.c +++ b/test/aaip_0_2_test.c @@ -26,6 +26,8 @@ #include "aaip_0_2.h" +#define Aaip_test_name_sizE 1024 +#define Aaip_test_value_sizE 1024 int main(int argc, char **argv) { @@ -37,11 +39,9 @@ int main(int argc, char **argv) struct aaip_state *aaip; size_t consumed= 0; - char name[1025]; - size_t name_size= 4; + char name[Aaip_test_name_sizE + 1]; size_t name_fill; - char value[1025]; - size_t value_size= 1024; + char value[Aaip_test_value_sizE + 1]; size_t value_fill; size_t todo; int submit_data, is_done; @@ -126,8 +126,8 @@ int main(int argc, char **argv) } else todo= 0; ret= aaip_decode_pair(aaip, rpt, todo, &consumed, - name, name_size, &name_fill, - value, value_size, &value_fill, 0); + name, Aaip_test_name_sizE, &name_fill, + value, Aaip_test_value_sizE, &value_fill, 0); skipped= aaip_get_pairs_skipped(aaip, 0); if(skipped > was_skipped) { printf("- skipped %d pair%s -\n\n", skipped - was_skipped,