/*
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 */