AMP_Proto_T *amp_new_proto(void) { AMP_Proto_T *proto; AMP_Box_T *box = NULL; _AMP_Callback_Map_p outstanding_requests = NULL; _AMP_Responder_Map_p responders = NULL; if ( (proto = MALLOC(sizeof(struct AMP_Proto))) == NULL) return NULL; proto->state = KEY_LEN_READ; proto->error = 0; if((box = amp_new_box()) == NULL) goto error; proto->last_ask_key = 0; proto->key_len = -1; proto->key_data_fetched = 0; proto->val_len = -1; proto->val_data_fetched = 0; proto->dispatch_box = _amp_process_full_packet; if ((outstanding_requests = _amp_new_callback_map()) == NULL) goto error; if((responders = _amp_new_responder_map()) == NULL) goto error; proto->box = box; proto->outstanding_requests = outstanding_requests; proto->responders = responders; debug_print("New AMP_Proto at 0x%p\n", proto); return proto; error: free(proto); if (box) amp_free_box(box); if (outstanding_requests) _amp_free_callback_map(outstanding_requests); /* NOTE - uncomment this if new structures are allocated below * the line above where `responders' is allocated if (responders) _amp_free_responder_map(responders); */ return NULL; }
int amp_consume_bytes(AMP_Proto_T *proto, unsigned char* buf, int len) { /* Guaranteed to have at least 1 byte in `buf' */ int idx = 0; int bytesConsumed = 0; int parseStatus; if (proto->error) { /* refuse to do any more work if the protocol * parser has previously encounted a fatal error. */ return AMP_PROTO_ERROR; } while (idx < len) { parseStatus = amp_parse_box(proto, proto->box, &bytesConsumed, buf+idx, len-idx); idx += bytesConsumed; if (parseStatus) { /* got a full box */ /* Dispatch it */ proto->error = proto->dispatch_box(proto, proto->box); if (proto->error) return proto->error; /* Start parsing a new AMP box. * The handler function has taken ownership of the box we * just dispatched - so don't free it. */ proto->box = amp_new_box(); } else { /* might be error, or might have parsed partial box */ if (proto->error) return proto->error; /* if no error it should mean that amp_parse_box() * consumed all of the bytes remaining in buf, and * we should fall out of the while-loop now */ } } return 0; }
void amp_reset_proto(AMP_Proto_T *proto) { proto->state = KEY_LEN_READ; proto->key_len = -1; proto->key_data_fetched = 0; proto->val_len = -1; proto->val_data_fetched = 0; /* TODO - more efficient to delete the key/values instead of freeing * and allocating a new box ? */ amp_free_box(proto->box); proto->box = amp_new_box(); proto->error = 0; }
/* * Code to Send AMP message */ void do_sum_call(AMP_Proto_T *proto, Sum_State_T sum_state) { int ret; AMP_Box_T *box = amp_new_box(); amp_put_long_long(box, "a", sum_state->operands[sum_state->idx]); amp_put_long_long(box, "b", sum_state->operands[sum_state->idx+1]); sum_state->idx++; ret = amp_call(proto, "Sum", box, resp_cb, sum_state, &(sum_state->lastAskKey)); if (ret) { fprintf(stderr, "amp_call() failed: %s\n", amp_strerror(ret)); exit(1); } }
amp_error_t _amp_send_unhandled_command_error(AMP_Proto_T *proto, AMP_Request_T *req) { /* Fire off an _error box */ AMP_Box_T *box; unsigned char *buf = NULL; unsigned char *idx; unsigned char *packet = NULL; int packetSize; amp_error_t ret = 0; static char prefix[] = "Unhandled Command: '"; static char suffix[] = "'"; if ((box = amp_new_box()) == NULL) return ENOMEM; /* put _error key */ if ((ret = amp_put_bytes(box, _ERROR, req->ask_key->value, req->ask_key->size)) != 0) goto error; /* put _error_code key */ if ((ret = amp_put_cstring(box, ERROR_CODE, AMP_ERROR_UNHANDLED)) != 0) goto error; /* put _error_description key */ int bufSize = sizeof(prefix) + req->command->size + sizeof(suffix) - 2; if ((buf = MALLOC(bufSize)) == NULL) { ret = ENOMEM; goto error; } idx = buf; /* use sizeof(s)-1 instead of strlen() as cheap optimization */ memcpy(idx, prefix, sizeof(prefix)-1); idx += sizeof(prefix)-1; memcpy(idx, req->command->value, req->command->size); idx += req->command->size; memcpy(idx, suffix, sizeof(suffix)-1); /* TODO - it might be handy to have an amp_put_bytes_no_copy() API * to avoid the copying overhead in cases such as this where the * box can happily take ownership of the malloc'd buffer */ if ((ret = amp_put_bytes(box, ERROR_DESCR, buf, bufSize)) != 0) goto error; /* buf has been copied in to the box now */ if ((ret = amp_serialize_box(box, &packet, &packetSize)) != 0) goto error; /* write handler has taken possession of buffer - don't free */ ret = proto->write(proto, packet, packetSize, proto->write_arg); error: amp_free_box(box); free(buf); return ret; }