diff options
Diffstat (limited to 'src/util.c')
-rw-r--r-- | src/util.c | 164 |
1 files changed, 107 insertions, 57 deletions
@@ -1,5 +1,5 @@ /* This file is part of Eclat. - Copyright (C) 2012-2015 Sergey Poznyakoff. + Copyright (C) 2012-2018 Sergey Poznyakoff. Eclat is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -213,79 +213,130 @@ describe_request_update(eclat_command_env_t *env, int argc, char **argv, void describe_request_create(eclat_command_env_t *env, int argc, char **argv, - const char *uparm) + const char *uparm) { describe_request_update(env, argc, argv, uparm, 1, NULL); } - + +unsigned long max_retry_sleep = 600; +unsigned long max_retry_time = 1800; + int -eclat_send_request(CURL *curl, struct ec2_request *req) +eclat_send_request(struct ec2_request *orig, struct grecs_node **ret_tree) { char *url; CURLcode res; - int rc = 0; + int ret = 0; struct curl_slist *headers = NULL; + struct eclat_io *io; + time_t endtime; + unsigned long tts, t; - /* Prepare the request */ - if (req->flags & EC2_RF_POST) { - eclat_request_finalize(req); - curl_easy_setopt(curl, CURLOPT_POST, 1); - curl_easy_setopt(curl, CURLOPT_POSTFIELDS, req->postdata); - curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, - strlen(req->postdata)); + io = eclat_io_init(0); + if (!io) { + err("cannot initialize IO structure"); + return -1; } - eclat_request_sign(req, secret_key, signature_version); - url = eclat_request_to_url(req); - curl_easy_setopt(curl, CURLOPT_URL, url); - debug(ECLAT_DEBCAT_MAIN, 1, ("using URL: %s", url)); - free(url); - if (req->headers) { - struct grecs_list_entry *ep; - struct grecs_txtacc *acc; - int rc; - - acc = grecs_txtacc_create(); - - for (ep = req->headers->head; ep; ep = ep->next) { - struct ec2_param *p = ep->data; - char *str; - - grecs_txtacc_grow_string(acc, p->name); - grecs_txtacc_grow_char(acc, ':'); - grecs_txtacc_grow_string(acc, p->value); - grecs_txtacc_grow_char(acc, 0); - str = grecs_txtacc_finish(acc, 0); - debug(ECLAT_DEBCAT_MAIN, 1, ("HDR: %s", str)); - headers = curl_slist_append(headers, str); - grecs_txtacc_free_string(acc, str); + endtime = time(NULL) + max_retry_time; + tts = 1; + do { + struct grecs_node *node; + /* Prepare the request */ + struct ec2_request *req = eclat_request_dup(orig); + if (req->flags & EC2_RF_POST) { + eclat_request_finalize(orig); + curl_easy_setopt(io->curl, CURLOPT_POST, 1); + curl_easy_setopt(io->curl, CURLOPT_POSTFIELDS, + req->postdata); + curl_easy_setopt(io->curl, CURLOPT_POSTFIELDSIZE, + strlen(req->postdata)); } + eclat_request_sign(req, secret_key, signature_version); + url = eclat_request_to_url(req); + curl_easy_setopt(io->curl, CURLOPT_URL, url); + debug(ECLAT_DEBCAT_MAIN, 1, ("using URL: %s", url)); + free(url); + if (req->headers) { + struct grecs_list_entry *ep; + struct grecs_txtacc *acc; + int rc; + + acc = grecs_txtacc_create(); + + for (ep = req->headers->head; ep; ep = ep->next) { + struct ec2_param *p = ep->data; + char *str; + + grecs_txtacc_grow_string(acc, p->name); + grecs_txtacc_grow_char(acc, ':'); + grecs_txtacc_grow_string(acc, p->value); + grecs_txtacc_grow_char(acc, 0); + str = grecs_txtacc_finish(acc, 0); + debug(ECLAT_DEBCAT_MAIN, 1, ("HDR: %s", str)); + + headers = curl_slist_append(headers, str); + grecs_txtacc_free_string(acc, str); + } - rc = curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); - grecs_txtacc_free(acc); + rc = curl_easy_setopt(io->curl, CURLOPT_HTTPHEADER, + headers); + grecs_txtacc_free(acc); - if (rc) - die(EX_SOFTWARE, - "failed to add headers: %s", - curl_easy_strerror(rc)); - } + if (rc) + die(EX_SOFTWARE, + "failed to add headers: %s", + curl_easy_strerror(rc)); + } - if (req->flags & EC2_RF_POST) - debug(ECLAT_DEBCAT_MAIN, 1, ("DATA: %s", req->postdata)); + if (req->flags & EC2_RF_POST) + debug(ECLAT_DEBCAT_MAIN, 1, + ("DATA: %s", req->postdata)); - if (dry_run_mode) - debug(ECLAT_DEBCAT_MAIN, 1, ("not sending request")); - else { - res = curl_easy_perform(curl); + if (dry_run_mode) + debug(ECLAT_DEBCAT_MAIN, 1, ("not sending request")); + else { + res = curl_easy_perform(io->curl); + if (res == CURLE_OK) { + *ret_tree = eclat_io_finish(io); + } else { + err("CURL: %s", curl_easy_strerror(res)); + ret = 1; + } + } + + curl_slist_free_all(headers); + eclat_request_free(req); + + if (ret) + break; - if (res != CURLE_OK) { - err("CURL: %s", curl_easy_strerror(res)); - rc = 1; + node = grecs_find_node(*ret_tree, + ".Response.Errors.Error.Code"); + if (!node) + break; + if (node->type != grecs_node_stmt + || node->v.value->type == GRECS_TYPE_STRING) { + err("unexpectedly formatted error code"); + break; } - } - eclat_request_free(req); - curl_slist_free_all(headers); - return rc; + + if (strcmp(node->v.value->v.string, + "Client.RequestLimitExceeded")) + break; + + t = random() % tts; + sleep(t); + if (tts < max_retry_sleep) { + tts <<= 1; + if (tts == 0 || tts > max_retry_sleep) + tts = max_retry_sleep; + } + } while (time(NULL) < endtime); + + eclat_io_free(io); + + return ret; } int @@ -429,7 +480,6 @@ char *instance_store_credentials_path = "meta-data/iam/security-credentials"; static CURL * get_curl(struct grecs_txtacc *acc) { - CURLcode res; CURL *curl = instance_store_curl_new(acc); eclat_set_curl_trace(curl, debug_level(ECLAT_DEBCAT_CURL)); |