diff --git a/include/mastodont_fetch.h b/include/mastodont_fetch.h index 544b64b..a7da90e 100644 --- a/include/mastodont_fetch.h +++ b/include/mastodont_fetch.h @@ -19,20 +19,42 @@ #include #include -struct mstdnt_fetch_results +/** Used to store the response from CURL */ +struct mstdnt_fetch_data { char* response; size_t size; + + // Callback from user + mstdnt_request_cb_t callback; + void* callback_args; +}; + +enum mstdnt_fetch_await +{ + MSTDNT_AWAIT_ALL, + MSTDNT_AWAIT_ONCE, }; size_t mstdnt_curl_write_callback(char* ptr, size_t _size, size_t nmemb, void* _content); -void mstdnt_fetch_results_cleanup(struct mstdnt_fetch_results* res); -int mstdnt_fetch_curl(mastodont_t* mstdnt, - CURL* curl, - struct mstdnt_args* args, - char* url, - struct mstdnt_fetch_results* results, - CURLoption request_t, - char* request_t_custom); +void mstdnt_fetch_data_cleanup(struct mstdnt_fetch_data* res); + +/** + * @brief Attempts to fetch, async or blocking. + * + * @param mstdnt Mastodont struct + * @param curl curl API + * @param args Mastodont General args passed + * @param url URL of request + * @param results Results from response + */ +int mstdnt_fetch_curl_async(mastodont_t* mstdnt, + CURL* curl, + struct mstdnt_args* args, + mstdnt_request_cb_t cb_request, + void* cb_args, + char* url, + CURLoption request_t, + char* request_t_custom); #endif /* MASTODONT_FETCH_H */ diff --git a/include/mastodont_request.h b/include/mastodont_request.h index 177df0d..ae51d37 100644 --- a/include/mastodont_request.h +++ b/include/mastodont_request.h @@ -34,10 +34,19 @@ struct mstdnt_request_args int (*callback)(cJSON*, void*); }; +/** + * Sends a mastoAPI request to an HTTP server. + * + * @param data Mastodont struct + * @param m_args Mastodont general args pointer + * @param cb_request Callback pointer associated with this request + * @param cb_args Args passed into cb_request + * @param args Propagated arguments to request to the server + */ int mstdnt_request(mastodont_t* data, - struct mstdnt_args* m_args, -mstdnt_request_cb_t cb_request, -void* cb_args, - struct mstdnt_request_args* args); + struct mstdnt_args* m_args, + mstdnt_request_cb_t cb_request, + void* cb_args, + struct mstdnt_request_args* args); #endif /* MASTODONT_REQUEST_H */ diff --git a/include/mastodont_types.h b/include/mastodont_types.h index 2b88169..b0d5782 100644 --- a/include/mastodont_types.h +++ b/include/mastodont_types.h @@ -23,13 +23,13 @@ #define MSTDNT_URLSIZE 2048 #define MSTDNT_URISIZE 512 typedef int8_t mstdnt_bool; +// Don't be fooled! #define MSTDNT_TRUE 2 #define MSTDNT_FALSE 1 #define MSTDNT_BOOL_UNSET 0 typedef void (*mstdnt_request_cb_t)(void* data, void* args); -// It's more logical to not sanitize than to sanitize data #define MSTDNT_FLAG_NO_URI_SANITIZE (1<<0) #define MSTDNT_FLAG_SSL_UNVERIFIED (1<<1) #define MSTDNT_FLAG_ISSET(flags, flag) (((flags) & (flag)) == (flag)) diff --git a/src/account.c b/src/account.c index 6924a65..fabb643 100644 --- a/src/account.c +++ b/src/account.c @@ -89,7 +89,7 @@ void* cb_args, mstdnt_accounts_json_callback, }; - return mstdnt_request(data, m_args, &req_args); + return mstdnt_request(data, m_args, &req_args, ); } int mstdnt_get_followers(mastodont_t* data, diff --git a/src/fetch.c b/src/fetch.c index da2fc10..342cc72 100644 --- a/src/fetch.c +++ b/src/fetch.c @@ -23,7 +23,7 @@ size_t mstdnt_curl_write_callback(char* ptr, size_t _size, size_t nmemb, void* _content) { size_t size = nmemb * _size; /* Mostly pointless, but portable */ - struct mstdnt_fetch_results* res = _content; /* Cast */ + struct mstdnt_fetch_data* res = _content; /* Cast */ char* data; if ((data = mstdnt_realloc(res->response, res->size + size + 1)) == NULL) @@ -40,36 +40,33 @@ size_t mstdnt_curl_write_callback(char* ptr, size_t _size, size_t nmemb, void* _ return size; } -void mstdnt_fetch_results_cleanup(struct mstdnt_fetch_results* res) +void mstdnt_fetch_data_cleanup(struct mstdnt_fetch_data* res) { mstdnt_free(res->response); } #define TOKEN_STR_SIZE 512 -int mstdnt_fetch_curl(mastodont_t* mstdnt, - CURL* curl, - struct mstdnt_args* m_args, -mstdnt_request_cb_t cb_request, -void* cb_args, - char* _url, - struct mstdnt_fetch_results* results, - CURLoption request_t, - char* request_t_custom) +int mstdnt_fetch_curl_async(mastodont_t* mstdnt, + CURL* curl, + struct mstdnt_args* m_args, + mstdnt_request_cb_t cb_request, + void* cb_args, + char* _url, + CURLoption request_t, + char* request_t_custom) { #define is_custom request_t_custom && request_t == CURLOPT_CUSTOMREQUEST + struct mstdnt_fetch_data* results = NULL; CURLMcode res = 3; - int status = 0; - CURLMsg* msg; - int running = 1; char token[TOKEN_STR_SIZE] = { 0 }; struct curl_slist* list = NULL; - /* Setup URL */ + // Setup URL char url[MSTDNT_URLSIZE] = { 0 }; strncpy(url, m_args->url, MSTDNT_URLSIZE-1); strncat(url, _url, MSTDNT_URLSIZE-1); - /* Setup token */ + // Setup token if (m_args->token) { snprintf(token, TOKEN_STR_SIZE, "Authorization: Bearer %s", @@ -78,81 +75,74 @@ void* cb_args, curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list); } - /* Set options */ + // Setup data to pass into results + results = calloc(1, sizeof(struct mstdnt_fetch_data)); + results.callback = cb_request; + results.callback_args = cb_args; + + // Set options curl_easy_setopt(curl, CURLOPT_URL, url); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, mstdnt_curl_write_callback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, results); + /* Copy into private pointer value + * A little stupid, but we can let CURL hold our values for us. + * Curl won't let us get the WRITEDATA opt pointer back sadly, so this has to be done */ + curl_easy_setopt(curl, CURLOPT_PRIVATE, results); /* Should we verify the peer's SSL cert? */ curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, !MSTDNT_T_FLAG_ISSET(m_args, MSTDNT_FLAG_SSL_UNVERIFIED)); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, !MSTDNT_T_FLAG_ISSET(m_args, MSTDNT_FLAG_SSL_UNVERIFIED)); - /* PUT, POST, GET, Custom */ - /* Mimes are expected to be set beforehand manually */ + // PUT, POST, GET, Custom + // Mimes are expected to be set beforehand manually if (is_custom) curl_easy_setopt(curl, request_t, request_t_custom); else if (request_t != CURLOPT_MIMEPOST) curl_easy_setopt(curl, request_t, 1); - // Add curl handle to multi, then run and block -#ifndef THREAD_UNSAFE - static pthread_mutex_t multi_mutex = PTHREAD_MUTEX_INITIALIZER; -#endif - -#ifndef THREAD_UNSAFE - pthread_mutex_lock(&multi_mutex); -#endif + // Add curl handle to multi, then run curl_multi_add_handle(mstdnt->curl, curl); -#ifndef THREAD_UNSAFE - pthread_mutex_unlock(&multi_mutex); -#endif + + res = curl_multi_perform(mstdnt->curl, &running); - int msgs_left; - while (running) + + + + if (list) curl_slist_free_all(list); + return res; +} + +int mstdnt_await(enum mstdnt_fetch_await opt) +{ + CURLMsg* msg; + int msgs_left = 1; + struct mstdnt_fetch_data* data; + + // TODO + //curl_easy_getinfo(curl, CURLINFO_PRIVATE, &data); + + do { -#ifndef THREAD_UNSAFE - pthread_mutex_lock(&multi_mutex); -#endif - res = curl_multi_perform(mstdnt->curl, &running); -#ifndef THREAD_UNSAFE - pthread_mutex_unlock(&multi_mutex); -#endif - - if (running) - res = curl_multi_poll(mstdnt->curl, NULL, 0, 1000, NULL); + res = curl_multi_poll(mstdnt->curl, NULL, 0, 1000, NULL); // Check if our socket is done -#ifndef THREAD_UNSAEF - pthread_mutex_lock(&multi_mutex); -#endif while ((msg = curl_multi_info_read(mstdnt->curl, &msgs_left))) { if (msg->msg == CURLMSG_DONE && msg->easy_handle == curl) { status = msg->data.result; -#ifndef THREAD_UNSAFE - pthread_mutex_unlock(&multi_mutex); -#endif goto out; } } -#ifndef THREAD_UNSAFE - pthread_mutex_unlock(&multi_mutex); -#endif if (res) break; } - -out: -#ifndef THREAD_UNSAFE - pthread_mutex_lock(&multi_mutex); -#endif - // Looks like we're done here - curl_multi_remove_handle(mstdnt->curl, curl); - #ifndef THREAD_UNSAFE - pthread_mutex_unlock(&multi_mutex); -#endif - - if (list) curl_slist_free_all(list); - return status; + while (opt == MSTDNT_AWAIT_ALL && msgs_left); + + //mstdnt_fetch_data_cleanup(&results); + // Note: the fetch removed the handle from our multi handle + out: + /* // Looks like we're done here */ + /* curl_multi_remove_handle(mstdnt->curl, curl); */ + //curl_easy_cleanup(curl); } diff --git a/src/request.c b/src/request.c index 06553e9..afb17b4 100644 --- a/src/request.c +++ b/src/request.c @@ -72,18 +72,16 @@ static void mime_params_post(curl_mime* mime, } int mstdnt_request(mastodont_t* data, - struct mstdnt_args* m_args, -mstdnt_request_cb_t cb_request, -void* cb_args, - struct mstdnt_request_args* args) + struct mstdnt_args* m_args, + mstdnt_request_cb_t cb_request, + void* cb_args, + struct mstdnt_request_args* args) { int res = 0, curlerror = 0; struct mstdnt_storage* storage = args->storage; - struct mstdnt_fetch_results results = { 0 }; cJSON* root; curl_mime* mime = NULL; char* post; - // TODO debug me char* url_query = args->params_query ? _mstdnt_query_string(data, m_args, args->url, args->params_query, args->params_query_len) : args->url; @@ -116,14 +114,17 @@ void* cb_args, else if (args->request_type == CURLOPT_POST) curl_easy_setopt(curl, CURLOPT_POSTFIELDS, ""); - curlerror = mstdnt_fetch_curl(data, - curl, - m_args, - url_query, - &results, - args->request_type, - args->request_type_custom); + curlerror = mstdnt_fetch_curl_async( + data, + curl, + m_args, + cb_request, + cb_args, + url_query, + args->request_type, + args->request_type_custom); + // Mime already used, free it early if (mime) curl_mime_free(mime); if (curlerror != CURLE_OK) @@ -134,6 +135,7 @@ void* cb_args, } // Create json structure +#if 0 if (_mstdnt_json_init(&root, &results, storage)) { res = 1; @@ -148,14 +150,14 @@ void* cb_args, } else res = 1; +#endif cleanup_res: - mstdnt_fetch_results_cleanup(&results); + cleanup: - // Note: the fetch removed the handle from our multi handle - curl_easy_cleanup(curl); + if (args->params_post && args->request_type == CURLOPT_POST) + mstdnt_free(post); - if (args->params_post && args->request_type == CURLOPT_POST) mstdnt_free(post); /* Only free if params_query set */ if (args->params_query) mstdnt_free(url_query); return res;