X-Git-Url: http://git.vrable.net/?a=blobdiff_plain;f=libs3-1.4%2Fsrc%2Frequest_context.c;fp=libs3-1.4%2Fsrc%2Frequest_context.c;h=ae48e55d8af0dab3a1817068eafdda0ac34aa43c;hb=1d62668cef91cf8f93f078ff47b4f99dec0f1669;hp=0000000000000000000000000000000000000000;hpb=45a4f324927f8fe3b7e689dd0c9a28716d0d1e93;p=bluesky.git diff --git a/libs3-1.4/src/request_context.c b/libs3-1.4/src/request_context.c new file mode 100644 index 0000000..ae48e55 --- /dev/null +++ b/libs3-1.4/src/request_context.c @@ -0,0 +1,190 @@ +/** ************************************************************************** + * request_context.c + * + * Copyright 2008 Bryan Ischo + * + * This file is part of libs3. + * + * libs3 is free software: you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation, version 3 of the License. + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of this library and its programs with the + * OpenSSL library, and distribute linked combinations including the two. + * + * libs3 is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License version 3 + * along with libs3, in a file named COPYING. If not, see + * . + * + ************************************************************************** **/ + +#include +#include +#include +#include "request.h" +#include "request_context.h" + + +S3Status S3_create_request_context(S3RequestContext **requestContextReturn) +{ + *requestContextReturn = + (S3RequestContext *) malloc(sizeof(S3RequestContext)); + + if (!*requestContextReturn) { + return S3StatusOutOfMemory; + } + + if (!((*requestContextReturn)->curlm = curl_multi_init())) { + free(*requestContextReturn); + return S3StatusOutOfMemory; + } + + (*requestContextReturn)->requests = 0; + + return S3StatusOK; +} + + +void S3_destroy_request_context(S3RequestContext *requestContext) +{ + curl_multi_cleanup(requestContext->curlm); + + // For each request in the context, call back its done method with + // 'interrupted' status + Request *r = requestContext->requests, *rFirst = r; + + if (r) do { + r->status = S3StatusInterrupted; + Request *rNext = r->next; + request_finish(r); + r = rNext; + } while (r != rFirst); + + free(requestContext); +} + + +S3Status S3_runall_request_context(S3RequestContext *requestContext) +{ + int requestsRemaining; + do { + fd_set readfds, writefds, exceptfds; + FD_ZERO(&readfds); + FD_ZERO(&writefds); + FD_ZERO(&exceptfds); + int maxfd; + S3Status status = S3_get_request_context_fdsets + (requestContext, &readfds, &writefds, &exceptfds, &maxfd); + if (status != S3StatusOK) { + return status; + } + // curl will return -1 if it hasn't even created any fds yet because + // none of the connections have started yet. In this case, don't + // do the select at all, because it will wait forever; instead, just + // skip it and go straight to running the underlying CURL handles + if (maxfd != -1) { + int64_t timeout = S3_get_request_context_timeout(requestContext); + struct timeval tv = { timeout / 1000, (timeout % 1000) * 1000 }; + select(maxfd + 1, &readfds, &writefds, &exceptfds, + (timeout == -1) ? 0 : &tv); + } + status = S3_runonce_request_context(requestContext, + &requestsRemaining); + if (status != S3StatusOK) { + return status; + } + } while (requestsRemaining); + + return S3StatusOK; +} + + +S3Status S3_runonce_request_context(S3RequestContext *requestContext, + int *requestsRemainingReturn) +{ + CURLMcode status; + + do { + status = curl_multi_perform(requestContext->curlm, + requestsRemainingReturn); + + switch (status) { + case CURLM_OK: + case CURLM_CALL_MULTI_PERFORM: + break; + case CURLM_OUT_OF_MEMORY: + return S3StatusOutOfMemory; + default: + return S3StatusInternalError; + } + + CURLMsg *msg; + int junk; + while ((msg = curl_multi_info_read(requestContext->curlm, &junk))) { + if (msg->msg != CURLMSG_DONE) { + return S3StatusInternalError; + } + Request *request; + if (curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, + (char **) (char *) &request) != CURLE_OK) { + return S3StatusInternalError; + } + // Remove the request from the list of requests + if (request->prev == request->next) { + // It was the only one on the list + requestContext->requests = 0; + } + else { + // It doesn't matter what the order of them are, so just in + // case request was at the head of the list, put the one after + // request to the head of the list + requestContext->requests = request->next; + request->prev->next = request->next; + request->next->prev = request->prev; + } + if ((msg->data.result != CURLE_OK) && + (request->status == S3StatusOK)) { + request->status = request_curl_code_to_status + (msg->data.result); + } + if (curl_multi_remove_handle(requestContext->curlm, + msg->easy_handle) != CURLM_OK) { + return S3StatusInternalError; + } + // Finish the request, ensuring that all callbacks have been made, + // and also releases the request + request_finish(request); + // Now, since a callback was made, there may be new requests + // queued up to be performed immediately, so do so + status = CURLM_CALL_MULTI_PERFORM; + } + } while (status == CURLM_CALL_MULTI_PERFORM); + + return S3StatusOK; +} + +S3Status S3_get_request_context_fdsets(S3RequestContext *requestContext, + fd_set *readFdSet, fd_set *writeFdSet, + fd_set *exceptFdSet, int *maxFd) +{ + return ((curl_multi_fdset(requestContext->curlm, readFdSet, writeFdSet, + exceptFdSet, maxFd) == CURLM_OK) ? + S3StatusOK : S3StatusInternalError); +} + +int64_t S3_get_request_context_timeout(S3RequestContext *requestContext) +{ + long timeout; + + if (curl_multi_timeout(requestContext->curlm, &timeout) != CURLM_OK) { + timeout = 0; + } + + return timeout; +}