/*
This file is part of GNUnet.
(C) 2001, 2002, 2006, 2008, 2009, 2012 Christian Grothoff (and other contributing authors)
GNUnet 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; either version 2, 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
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNUnet; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
*/
/**
* @file util/client.c
* @brief code for access to services
* @author Christian Grothoff
*
* Generic TCP code for reliable, record-oriented TCP
* connections between clients and service providers.
*/
#include "platform.h"
#include "gnunet_protocols.h"
#include "gnunet_util_lib.h"
/**
* How often do we re-try tranmsitting requests before giving up?
* Note that if we succeeded transmitting a request but failed to read
* a response, we do NOT re-try.
*/
#define MAX_ATTEMPTS 50
#define LOG(kind,...) GNUNET_log_from (kind, "util",__VA_ARGS__)
/**
* Handle for a transmission request.
*/
struct GNUNET_CLIENT_TransmitHandle
{
/**
* Connection state.
*/
struct GNUNET_CLIENT_Connection *client;
/**
* Function to call to get the data for transmission.
*/
GNUNET_CONNECTION_TransmitReadyNotify notify;
/**
* Closure for notify.
*/
void *notify_cls;
/**
* Handle to the transmission with the underlying
* connection.
*/
struct GNUNET_CONNECTION_TransmitHandle *th;
/**
* If we are re-trying and are delaying to do so,
* handle to the scheduled task managing the delay.
*/
GNUNET_SCHEDULER_TaskIdentifier reconnect_task;
/**
* Timeout for the operation overall.
*/
struct GNUNET_TIME_Absolute timeout;
/**
* Number of bytes requested.
*/
size_t size;
/**
* Are we allowed to re-try to connect without telling
* the user (of this API) about the connection troubles?
*/
int auto_retry;
/**
* Number of attempts left for transmitting the request. We may
* fail the first time (say because the service is not yet up), in
* which case (if auto_retry is set) we wait a bit and re-try
* (timeout permitting).
*/
unsigned int attempts_left;
};
/**
* Context for processing
* "GNUNET_CLIENT_transmit_and_get_response" requests.
*/
struct TransmitGetResponseContext
{
/**
* Client handle.
*/
struct GNUNET_CLIENT_Connection *client;
/**
* Message to transmit; do not free, allocated
* right after this struct.
*/
const struct GNUNET_MessageHeader *hdr;
/**
* Timeout to use.
*/
struct GNUNET_TIME_Absolute timeout;
/**
* Function to call when done.
*/
GNUNET_CLIENT_MessageHandler rn;
/**
* Closure for "rn".
*/
void *rn_cls;
};
/**
* Struct to refer to a GNUnet TCP connection.
* This is more than just a socket because if the server
* drops the connection, the client automatically tries
* to reconnect (and for that needs connection information).
*/
struct GNUNET_CLIENT_Connection
{
/**
* The connection handle, NULL if not live
*/
struct GNUNET_CONNECTION_Handle *connection;
/**
* Our configuration.
*/
const struct GNUNET_CONFIGURATION_Handle *cfg;
/**
* Name of the service we interact with.
*/
char *service_name;
/**
* Context of a transmit_and_get_response operation, NULL
* if no such operation is pending.
*/
struct TransmitGetResponseContext *tag;
/**
* Handler for current receiver task.
*/
GNUNET_CLIENT_MessageHandler receiver_handler;
/**
* Closure for receiver_handler.
*/
void *receiver_handler_cls;
/**
* Handle for a pending transmission request, NULL if there is
* none pending.
*/
struct GNUNET_CLIENT_TransmitHandle *th;
/**
* Handler for service test completion (NULL unless in service_test)
*/
GNUNET_SCHEDULER_Task test_cb;
/**
* Deadline for calling 'test_cb'.
*/
struct GNUNET_TIME_Absolute test_deadline;
/**
* If we are re-trying and are delaying to do so,
* handle to the scheduled task managing the delay.
*/
GNUNET_SCHEDULER_TaskIdentifier receive_task;
/**
* Closure for test_cb (NULL unless in service_test)
*/
void *test_cb_cls;
/**
* Buffer for received message.
*/
char *received_buf;
/**
* Timeout for receiving a response (absolute time).
*/
struct GNUNET_TIME_Absolute receive_timeout;
/**
* Current value for our incremental back-off (for
* connect re-tries).
*/
struct GNUNET_TIME_Relative back_off;
/**
* Number of bytes in received_buf that are valid.
*/
size_t received_pos;
/**
* Size of received_buf.
*/
unsigned int received_size;
/**
* Do we have a complete response in received_buf?
*/
int msg_complete;
/**
* Are we currently busy doing re