/* * 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); } }
/* * Code to Get reply */ void resp_cb(AMP_Proto_T *proto, AMP_Result_T *result, void *callback_arg) { Sum_State_T sum_state = callback_arg; int ret; long long total; switch (result->reason) { case AMP_SUCCESS: /* Decode reply keyword value 'total' */ if ( (ret = amp_get_long_long((result->response)->args, "total", &total)) != 0) { fprintf(stderr, "Couldn't get total key: %s\n", amp_strerror(ret)); exit(1); } amp_free_result(result); if (sum_state->idx == sum_state->max_idx) { printf("Finished sums. Total: %lld\n", total); exit(0); } else { sum_state->operands[sum_state->idx] = total; do_sum_call(proto, sum_state); } break; case AMP_ERROR: fprintf(stderr, "Got AMP error from remote peer.\n"); if ((result->error)->error_code) fprintf(stderr, "Code: %s\n", (result->error)->error_code->value); fprintf(stderr, "Description: %s\n", (result->error)->error_descr->value); amp_free_result(result); exit(1); break; } }
int _amp_process_full_packet(AMP_Proto_T *proto, AMP_Box_T *box) { /* Dispatch the box that has been accumulated by the given AMP_Proto . * * Returns 0 on success or an AMP_* code on failure. * * TODO - do we check for insane boxes that have e.g. * an _answer and an _error key? */ amp_error_t ret = 0; if (amp_num_keys(box) == 0) return AMP_BOX_EMPTY; if (amp_has_key(box, COMMAND)) { debug_print("Received %s box.\n", COMMAND); AMP_Request_T *request; if ( (ret = _amp_new_request_from_box(box, &request)) != 0) return ret; proto->box = NULL; /* forget the box that is now held by the request object */ _AMP_Responder_p responder; if ( (responder = _amp_get_responder(proto->responders, request->command->value)) != NULL) { /* Fire off user-supplied responder */ (responder->func)(proto, request, responder->arg); } else { amp_log("No handler for command: %s", request->command->value); /* send error to remote peer if _ask key present. * (ret == 0 before this point) */ if (request->ask_key != NULL) { ret = _amp_send_unhandled_command_error(proto, request); } /* This free's the box too */ amp_free_request(request); return ret; } } else if (amp_has_key(box, ANSWER)) { debug_print("Received %s box.\n", ANSWER); AMP_Response_T *response; if ( (ret = _amp_new_response_from_box(box, &response)) != 0) return ret; proto->box = NULL; /* forget the box that is now held by the newly created response object */ _AMP_Callback_p cb; if ((cb = _amp_pop_callback(proto->outstanding_requests, response->answer_key)) != NULL) { AMP_Result_T *result; if ( (ret = _amp_new_result_with_response(response, &result)) != 0) { amp_free_response(response); _amp_free_callback(cb); return ret; } (cb->func)(proto, result, cb->arg); _amp_free_callback(cb); } else { amp_log("Got unknown _answer key: %u", response->answer_key); amp_free_response(response); /* free's the box too */ return 0; } } else if (amp_has_key(box, _ERROR)) { debug_print("Received %s box.\n", _ERROR); AMP_Error_T *error; if ( (ret = _amp_new_error_from_box(box, &error)) != 0) return ret; /* _amp_new_error_from_box was successful which means the box has * been free'd - so forget it to avoid a potential double-free() */ proto->box = NULL; _AMP_Callback_p cb; if ((cb = _amp_pop_callback(proto->outstanding_requests, error->answer_key)) != NULL) { AMP_Result_T *result; if ( (ret = _amp_new_result_with_error(error, &result)) != 0) { amp_free_error(error); _amp_free_callback(cb); return ret; } (cb->func)(proto, result, cb->arg); _amp_free_callback(cb); } else { amp_log("Got unknown _error key: %u", error->answer_key); amp_free_error(error); return 0; } } else { amp_log("Invalid protocol data: %s", amp_strerror(AMP_REQ_KEY_MISSING)); return AMP_REQ_KEY_MISSING; } return 0; }
int main(int argc, char *argv[]) { if (argc < 4) usage(); char buf[256]; int ret; char server_hostname[NI_MAXHOST]; int server_port; int client_sock; Sum_State_T sum_state; if ( (sum_state = malloc(sizeof(*sum_state))) == NULL) { fprintf(stderr, "ERROR allocating Sum_State_T: %s\n", strerror(errno)); exit(1); } sum_state->idx = 0; /* first operand begins at argv[2] */ sum_state->max_idx = argc - 3; /* do we have too many operands? */ if (sum_state->max_idx >= MAX_OPERANDS) usage(); /* Convert operand arguments to numbers */ const char *errstr; int i; for (i = 0; i <= sum_state->max_idx; i++) { sum_state->operands[i] = strtonum(argv[i+2], LLONG_MIN, LLONG_MAX, &errstr); if (errstr != NULL) usage(); } /* split IP from port number */ if (parse_host_port(argv[1], server_hostname, NI_MAXHOST, &server_port) != 0) usage(); /* Windows is dumb */ #ifdef WIN32 WSADATA wsaData; if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { fprintf(stderr, "WSAStartup() failed.\n"); exit(1); } #endif fprintf(stderr, "Connecting to server..."); /* Connect to server */ if ((client_sock = connect_tcp(server_hostname, server_port, &errstr)) == -1) { fprintf(stderr, "Failed to connect: %s\n", errstr); return 1; } fprintf(stderr, "Done.\n"); /* Done connecting... set up AMP Protocol */ AMP_Proto_T *proto; if ( (proto = amp_new_proto()) == NULL) { fprintf(stderr, "Couldn't allocate AMP_Proto.\n"); return 1; }; amp_set_write_handler(proto, do_write, &client_sock); /* Set up libamp logging to stderr for any error messages that * it wishes to report */ amp_set_log_handler(amp_stderr_logger); /* Make first call... */ do_sum_call(proto, sum_state); /* Start reading loop */ int bytesRead; while ( (bytesRead = recv(client_sock, buf, sizeof(buf), 0)) >= 0) { if ( (ret = amp_consume_bytes(proto, buf, bytesRead)) != 0) { fprintf(stderr, "ERROR detected by amp_consume_bytes(): %s\n", amp_strerror(ret)); return 1; }; } return 0; }