/* This file is part of GNUnet Copyright (C) 2015, 2016 GNUnet e.V. GNUnet is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. GNUnet 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . SPDX-License-Identifier: AGPL3.0-or-later */ /** * @file curl/curl_reschedule.c * @brief API for event loop integration with GNUnet SCHEDULER. * @author Christian Grothoff */ #include "platform.h" #include #include "gnunet_curl_lib.h" #include "gnunet_util_lib.h" extern void * GNUNET_CURL_download_get_result_(struct GNUNET_CURL_DownloadBuffer *db, CURL *eh, long *response_code); /** * Closure for #GNUNET_CURL_gnunet_scheduler_reschedule(). */ struct GNUNET_CURL_RescheduleContext { /** * Just the task. */ struct GNUNET_SCHEDULER_Task *task; /** * Context we manage. */ struct GNUNET_CURL_Context *ctx; /** * Parser of the raw response. */ GNUNET_CURL_RawParser parser; /** * Deallocate the response object. */ GNUNET_CURL_ResponseCleaner cleaner; }; /** * Initialize reschedule context; with custom response parser * * @param ctx context to manage * @return closure for #GNUNET_CURL_gnunet_scheduler_reschedule(). */ struct GNUNET_CURL_RescheduleContext * GNUNET_CURL_gnunet_rc_create_with_parser(struct GNUNET_CURL_Context *ctx, GNUNET_CURL_RawParser rp, GNUNET_CURL_ResponseCleaner rc) { struct GNUNET_CURL_RescheduleContext *rctx; rctx = GNUNET_new(struct GNUNET_CURL_RescheduleContext); rctx->ctx = ctx; rctx->parser = rp; rctx->cleaner = rc; return rctx; } /** * Just a wrapper to avoid casting of function pointers. * * @param response the (JSON) response to clean. */ static void clean_result(void *response) { json_decref(response); } /** * Initialize reschedule context. * * @param ctx context to manage * @return closure for #GNUNET_CURL_gnunet_scheduler_reschedule(). */ struct GNUNET_CURL_RescheduleContext * GNUNET_CURL_gnunet_rc_create(struct GNUNET_CURL_Context *ctx) { struct GNUNET_CURL_RescheduleContext *rc; rc = GNUNET_new(struct GNUNET_CURL_RescheduleContext); rc->ctx = ctx; rc->parser = &GNUNET_CURL_download_get_result_; rc->cleaner = &clean_result; return rc; } /** * Destroy reschedule context. * * @param rc context to destroy */ void GNUNET_CURL_gnunet_rc_destroy(struct GNUNET_CURL_RescheduleContext *rc) { if (NULL != rc->task) GNUNET_SCHEDULER_cancel(rc->task); GNUNET_free(rc); } /** * Task that runs the context's event loop with the GNUnet scheduler. * * @param cls a `struct GNUNET_CURL_RescheduleContext *` */ static void context_task(void *cls) { struct GNUNET_CURL_RescheduleContext *rc = cls; long timeout; int max_fd; fd_set read_fd_set; fd_set write_fd_set; fd_set except_fd_set; struct GNUNET_NETWORK_FDSet *rs; struct GNUNET_NETWORK_FDSet *ws; struct GNUNET_TIME_Relative delay; rc->task = NULL; GNUNET_CURL_perform2(rc->ctx, rc->parser, rc->cleaner); max_fd = -1; timeout = -1; FD_ZERO(&read_fd_set); FD_ZERO(&write_fd_set); FD_ZERO(&except_fd_set); GNUNET_CURL_get_select_info(rc->ctx, &read_fd_set, &write_fd_set, &except_fd_set, &max_fd, &timeout); if (timeout >= 0) delay = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, timeout); else delay = GNUNET_TIME_UNIT_FOREVER_REL; rs = GNUNET_NETWORK_fdset_create(); GNUNET_NETWORK_fdset_copy_native(rs, &read_fd_set, max_fd + 1); ws = GNUNET_NETWORK_fdset_create(); GNUNET_NETWORK_fdset_copy_native(ws, &write_fd_set, max_fd + 1); if (NULL == rc->task) rc->task = GNUNET_SCHEDULER_add_select(GNUNET_SCHEDULER_PRIORITY_DEFAULT, delay, rs, ws, &context_task, rc); GNUNET_NETWORK_fdset_destroy(rs); GNUNET_NETWORK_fdset_destroy(ws); } /** * Implementation of the #GNUNET_CURL_RescheduleCallback for GNUnet's * scheduler. Will run the CURL context using GNUnet's scheduler. * Note that you MUST immediately destroy the reschedule context after * calling #GNUNET_CURL_fini(). * * @param cls must point to a `struct GNUNET_CURL_RescheduleContext *` * (pointer to a pointer!) */ void GNUNET_CURL_gnunet_scheduler_reschedule(void *cls) { struct GNUNET_CURL_RescheduleContext *rc = *(void **)cls; if (NULL != rc->task) GNUNET_SCHEDULER_cancel(rc->task); rc->task = GNUNET_SCHEDULER_add_now(&context_task, rc); } /* end of curl_reschedule.c */