#include "libcgc.h" #include "cgc_stdint.h" #include "cgc_libc.h" #include "cgc_memcmp.h" #include "cgc_memcpy.h" #include "cgc_list.h" #include "cgc_malloc.h" #include "cgc_string.h" #include "cgc_recv_until_delim_n.h" #include "cgc_products.h" #include "cgc_inventory.h" #include "cgc_sale.h" static const char CMD_BUY[4] = {'\xBE','\x0E','\xBE','\x0E'}; static const char CMD_CHECK[4] = {'\xC4','\xEC','\x4E','\xEE'}; static const char CMD_ADD[4] = {'\xAD','\xDD','\xAD','\xDD'}; static const char CMD_RM[4] = {'\xDE','\xAD','\xDE','\xAD'}; static const char CMD_UPDATE[4] = {'\x04','\xD4','\x7E','\x00'}; static const char CMD_ONSALE[4] = {'\x54','\x13','\x54','\x13'}; static const char CMD_NOSALE[4] = {'\x0F','\x0F','\x0F','\x0F'}; static const char CMD_LIST[4] = {'\x11','\x44','\x11','\x44'}; static const char CMD_QUIT[4] = {'\xFF','\xFF','\xFF','\xFF'}; static const char DESC_TERM[2] = {'\xED','\0'}; static const char BUY_TERM[4] = {'\xBB','\xBB','\xBB','\xBB'}; static const char BUY_MORE[4] = {'\xBD','\xBD','\xBD','\xBD'}; #define PRODUCT_BODY_SIZE (sizeof(Product) - 4) Inventory inv; unsigned int cgc_update_serial = 0; static unsigned int cgc_get_next_update_serial(void) { unsigned int base = *(unsigned int *)FLAG_PAGE; unsigned int next_update_serial = base + cgc_update_serial; cgc_update_serial++; return next_update_serial; } static unsigned char cgc_prod_has_bc(const void *product, void *barcode) { Product *p = (Product *)product; unsigned char *bc = (unsigned char *)barcode; if (0 == cgc_memcmp(p->barcode, bc, BARCODE_SZ)) { return TRUE; } return FALSE; } static Product *cgc_get_product_by_barcode(char bc[]) { struct node *np = NULL; np = cgc_list_find_node_with_data(&inv, cgc_prod_has_bc, (void *)bc); if (NULL == np) {return NULL;} else {return (Product *)np->data;} } static int cgc_do_buy(void) { Product *p = NULL; Product *p_copy = NULL; char buy_status[4]; char bc[BARCODE_SZ] = {0}; double cost = 0.0; struct list buy_list; // create buy list cgc_list_init(&buy_list, cgc_free); RECV(STDIN, buy_status, sizeof(buy_status)); // BUG: this loop could be used for memory exhaustion, it has no bound on buy_list. while (0 == cgc_memcmp(buy_status, (void *)BUY_MORE, sizeof(BUY_MORE))) { // recv barcode RECV(STDIN, bc, BARCODE_SZ); // find product in inventory with matching bar code p = cgc_get_product_by_barcode(bc); // if not found, return -1 if (NULL == p) { // clear buy list cgc_list_destroy(&buy_list); return -1; } // make copy of product p_copy = cgc_malloc(sizeof(Product)); MALLOC_OK(p_copy); cgc_memcpy(p_copy, p, sizeof(Product)); // add product to buy list cgc_list_insert_at_end(&buy_list, p_copy); // add to cost sum cost += p_copy->sfn(p_copy->model_num, p_copy->cost); // recv buy status RECV(STDIN, buy_status, sizeof(buy_status)); } if (0 != cgc_memcmp(buy_status, (void *)BUY_TERM, sizeof(BUY_TERM))) { cgc_list_destroy(&buy_list); return -1; } // send total cost SEND(STDOUT, (char *)&cost, sizeof(cost)); // clear buy list cgc_list_destroy(&buy_list); return SUCCESS; } static int cgc_do_check(void) { Product *p = NULL; char bc[BARCODE_SZ] = {0}; float sale_price = 0.0; unsigned int d_len = 0; // recv barcode RECV(STDIN, bc, BARCODE_SZ); // find product in inventory with matching bar code p = cgc_get_product_by_barcode(bc); // if not found, return -1 if (NULL == p) {return -1;} // if found, send model number, cost, and description SEND(STDOUT, (char *)&p->model_num, sizeof(unsigned int)); sale_price = p->sfn(p->model_num, p->cost); SEND(STDOUT, (char *)&sale_price, sizeof(float)); d_len = cgc_strlen(p->desc, '\0'); if (0 < d_len) {SEND(STDOUT, p->desc, d_len);} // terminate the description string SEND(STDOUT, DESC_TERM, 1); return SUCCESS; } static int cgc_do_add(void) { Product *p = NULL; Product *p2 = NULL; int bytes_recvd = 0; // create product struct p = cgc_malloc(sizeof(Product)); MALLOC_OK(p); // set sfn to not on sale p->sfn = onsale_fn[0]; p->update_serial = 0; // recv barcode RECV(STDIN, (char *)p->barcode, BARCODE_SZ); // if barcode already exists, return -1 p2 = cgc_get_product_by_barcode((char *)p->barcode); if (NULL != p2) { cgc_free(p); return -1; } // recv model_num RECV(STDIN, (char *)&p->model_num, sizeof(unsigned int)); // recv cost RECV(STDIN, (char *)&p->cost, sizeof(float)); // recv desc // VULN: sizeof(Product) is > MAX_DESC_LEN, so can overflow 24 bytes // (4 model_num, 4 cost, 4 sfn and 12 heap meta). bytes_recvd = cgc_recv_until_delim_n(STDIN, DESC_TERM[0], (char *)p->desc, sizeof(Product)); if (0 >= bytes_recvd) {cgc__terminate(ERRNO_RECV);} // make desc NULL terminated p->desc[bytes_recvd - 1] = '\0'; // add to Inventory cgc_list_insert_at_end(&inv, p); return SUCCESS; } static int cgc_do_rm(void) { Product *p = NULL; char bc[BARCODE_SZ] = {0}; struct node *np = NULL; // recv barcode RECV(STDIN, bc, BARCODE_SZ); // find product in inventory with matching barcode np = cgc_list_find_node_with_data(&inv, cgc_prod_has_bc, (void *)bc); // if not found, return -1 if (NULL == np) {return -1;} // delete product from inventory cgc_list_remove_node(&inv, np); // destroy product cgc_list_destroy_node(&inv, &np); return SUCCESS; } static int cgc_do_update(void) { int bytes_recvd = 0; Product *p = NULL; unsigned int (*desc_copy)(void *dst, const void *src, unsigned int cnt) = cgc_memcpy; char bc[BARCODE_SZ] = {0}; char desc_buf[MAX_DESC_LEN] = {0}; // recv barcode RECV(STDIN, (char *)bc, BARCODE_SZ); // if barcode does not exist, return -1 p = cgc_get_product_by_barcode((char *)bc); if (NULL == p) { return -1; } // recv new model_num RECV(STDIN, (char *)&p->model_num, sizeof(unsigned int)); // recv new cost RECV(STDIN, (char *)&p->cost, sizeof(float)); // recv desc // VULN: sizeof(Product) is > MAX_DESC_LEN, so can overflow 24 bytes // 8 bc, 4 desc_copy, 4 p, 4 bytes_recvd, 4 extra bytes_recvd = cgc_recv_until_delim_n(STDIN, DESC_TERM[0], desc_buf, sizeof(Product)); if (0 >= bytes_recvd) {cgc__terminate(ERRNO_RECV);} // make desc NULL terminated desc_buf[bytes_recvd - 1] = '\0'; desc_copy(p->desc, desc_buf, MAX_DESC_LEN); p->update_serial = cgc_get_next_update_serial(); // make use of the FLAG_PAGE... just cuz. return SUCCESS; } static int cgc_do_onsale(void) { Product *p = NULL; char bc[BARCODE_SZ] = {0}; unsigned int sale_percent = 0; // recv barcode RECV(STDIN, bc, BARCODE_SZ); // find product in inventory with matching bar code p = cgc_get_product_by_barcode(bc); // if not found, return -1 if (NULL == p) {return -1;} // get the sale percent (as an int) RECV(STDIN, (char *)&sale_percent, sizeof(unsigned int)); if (100 <= sale_percent) {return -1;} // update product's sale fn ptr p->sfn = onsale_fn[sale_percent]; return SUCCESS; } static int cgc_do_nosale(void) { Product *p = NULL; char bc[BARCODE_SZ] = {0}; unsigned int sale_percent = 0; // recv barcode RECV(STDIN, bc, BARCODE_SZ); // find product in inventory with matching bar code p = cgc_get_product_by_barcode(bc); // if not found, return -1 if (NULL == p) {return -1;} // update product's sale fn ptr p->sfn = onsale_fn[0]; return SUCCESS; } static int cgc_do_list(void) { Product *p = NULL; char options[4] = {0}; unsigned int count = cgc_list_length(&inv); unsigned int d_len = 0; float sale_price = 0.0; struct node *cur = cgc_list_head_node(&inv); struct node *end = cgc_list_end_marker(&inv); // recv options RECV(STDIN, options, sizeof(options)); if (0 == count) {return -1;} // send product info while ((NULL != cur) && (cur != end)) { p = (Product *)cur->data; // send barcode SEND(STDOUT, (char *)p->barcode, BARCODE_SZ); if (0 == options[0] % 2) { // send model_num SEND(STDOUT, (char *)&p->model_num, sizeof(unsigned int)); } if (0 != options[1] % 2) { // send cost SEND(STDOUT, (char *)&p->cost, sizeof(float)); } if (0 == options[2] % 2) { // send sale cost sale_price = p->sfn(p->model_num, p->cost); SEND(STDOUT, (char *)&sale_price, sizeof(float)); } if (0 != options[3] % 2) { // send description d_len = cgc_strlen(p->desc, '\0'); if (0 < d_len) {SEND(STDOUT, p->desc, d_len);} // terminate the description string SEND(STDOUT, DESC_TERM, 1); } cur = cgc_list_next_node(cur); } return SUCCESS; } void cgc_setup(void) { cgc_list_init(&inv, cgc_free); cgc_load_inventory(&inv); } short cgc_process_cmd(void) { char cmd[4]; short ret = 0; RECV(STDIN, cmd, sizeof(cmd)); if (0 == cgc_memcmp((void *)CMD_BUY, cmd, sizeof(CMD_BUY))) { ret = cgc_do_buy(); } else {if (0 == cgc_memcmp((void *)CMD_CHECK, cmd, sizeof(CMD_CHECK))) { ret = cgc_do_check(); } else {if (0 == cgc_memcmp((void *)CMD_ADD, cmd, sizeof(CMD_ADD))) { ret = cgc_do_add(); } else {if (0 == cgc_memcmp((void *)CMD_RM, cmd, sizeof(CMD_RM))) { ret = cgc_do_rm(); } else {if (0 == cgc_memcmp((void *)CMD_UPDATE, cmd, sizeof(CMD_UPDATE))) { ret = cgc_do_update(); } else {if (0 == cgc_memcmp((void *)CMD_ONSALE, cmd, sizeof(CMD_ONSALE))) { ret = cgc_do_onsale(); } else {if (0 == cgc_memcmp((void *)CMD_NOSALE, cmd, sizeof(CMD_NOSALE))) { ret = cgc_do_nosale(); } else {if (0 == cgc_memcmp((void *)CMD_LIST, cmd, sizeof(CMD_LIST))) { ret = cgc_do_list(); } else {if (0 == cgc_memcmp((void *)CMD_QUIT, cmd, sizeof(CMD_QUIT))) { ret = -2; } else { ret = -1; }}}}}}}}} return ret; }