gnunet

Main GNUnet Logic
Log | Files | Refs | Submodules | README | LICENSE

commit 99779b455ce3bf9c53dd411575766bf298a3a5f3
parent 8c702327dae9e504e0f6e1678884d9327321f44a
Author: Christian Grothoff <christian@grothoff.org>
Date:   Tue, 14 Dec 2021 15:59:07 +0100

introducing GNUNET_TIME_Timestamp

Diffstat:
Msrc/curl/curl.c | 196++-----------------------------------------------------------------------------
Msrc/include/gnunet_getopt_lib.h | 18++++++++++++++++++
Msrc/include/gnunet_json_lib.h | 38+++++++++++++++++++-------------------
Msrc/include/gnunet_pq_lib.h | 53++++++++++++++++++++++++++++++++++++++++++++++++++++-
Msrc/include/gnunet_sq_lib.h | 10+++++-----
Msrc/include/gnunet_strings_lib.h | 19+++++++++++++++++--
Msrc/include/gnunet_time_lib.h | 220++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
Msrc/json/json_generator.c | 86+++++++++++++++++++++++++------------------------------------------------------
Msrc/json/json_helper.c | 124++++++++++++++++++++++++++++++++++++++-----------------------------------------
Msrc/json/json_pack.c | 16++++++++--------
Msrc/json/test_json.c | 70++++++++++++++++++++++++++++++++++++++++++----------------------------
Msrc/pq/pq_query_helper.c | 107+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------
Msrc/pq/pq_result_helper.c | 142+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/util/Makefile.am | 2+-
Msrc/util/getopt_helpers.c | 249++++++++++++++++++++++++++-----------------------------------------------------
Msrc/util/strings.c | 22++++++++++++++++------
Msrc/util/time.c | 218+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------
17 files changed, 979 insertions(+), 611 deletions(-)

diff --git a/src/curl/curl.c b/src/curl/curl.c @@ -201,14 +201,6 @@ struct GNUNET_CURL_Context }; -/** - * Force use of the provided username and password - * for client authentication for all operations performed - * with @a ctx. - * - * @param ctx context to set authentication data for - * @param userpass string with "$USERNAME:$PASSWORD" - */ void GNUNET_CURL_set_userpass (struct GNUNET_CURL_Context *ctx, const char *userpass) @@ -219,21 +211,6 @@ GNUNET_CURL_set_userpass (struct GNUNET_CURL_Context *ctx, } -/** - * Force use of the provided TLS client certificate - * for client authentication for all operations performed - * with @a ctx. - * - * Note that if the provided information is incorrect, - * the earliest operation that could fail is - * #GNUNET_CURL_job_add() or #GNUNET_CURL_job_add2()! - * - * @param ctx context to set authentication data for - * @param certtype type of the certificate - * @param certfile file with the certificate - * @param keyfile file with the private key - * @param keypass passphrase to decrypt @a keyfile (or NULL) - */ void GNUNET_CURL_set_tlscert (struct GNUNET_CURL_Context *ctx, const char *certtype, @@ -256,14 +233,6 @@ GNUNET_CURL_set_tlscert (struct GNUNET_CURL_Context *ctx, } -/** - * Initialise this library. This function should be called before using any of - * the following functions. - * - * @param cb function to call when rescheduling is required - * @param cb_cls closure for @a cb - * @return library context - */ struct GNUNET_CURL_Context * GNUNET_CURL_init (GNUNET_CURL_RescheduleCallback cb, void *cb_cls) @@ -299,12 +268,6 @@ GNUNET_CURL_init (GNUNET_CURL_RescheduleCallback cb, } -/** - * Enable sending the async scope ID as a header. - * - * @param ctx the context to enable this for - * @param header_name name of the header to send. - */ void GNUNET_CURL_enable_async_scope_header (struct GNUNET_CURL_Context *ctx, const char *header_name) @@ -313,15 +276,6 @@ GNUNET_CURL_enable_async_scope_header (struct GNUNET_CURL_Context *ctx, } -/** - * Return #GNUNET_YES if given a valid scope ID and - * #GNUNET_NO otherwise. See #setup_job_headers, - * logic related to - * #GNUNET_CURL_enable_async_scope_header() for the - * code that generates such a @a scope_id. - * - * @returns #GNUNET_YES iff given a valid scope ID - */ int GNUNET_CURL_is_valid_scope_id (const char *scope_id) { @@ -447,7 +401,9 @@ setup_job (CURL *eh, struct GNUNET_CURL_Job *job; if (CURLE_OK != - curl_easy_setopt (eh, CURLOPT_HTTPHEADER, all_headers)) + curl_easy_setopt (eh, + CURLOPT_HTTPHEADER, + all_headers)) { GNUNET_break (0); curl_slist_free_all (all_headers); @@ -491,12 +447,6 @@ setup_job (CURL *eh, } -/** - * Add @a extra_headers to the HTTP headers for @a job. - * - * @param[in,out] job the job to modify - * @param extra_headers headers to append - */ void GNUNET_CURL_extend_headers (struct GNUNET_CURL_Job *job, const struct curl_slist *extra_headers) @@ -515,21 +465,6 @@ GNUNET_CURL_extend_headers (struct GNUNET_CURL_Job *job, } -/** - * Schedule a CURL request to be executed and call the given @a jcc - * upon its completion. Note that the context will make use of the - * CURLOPT_PRIVATE facility of the CURL @a eh. Used to download - * resources that are NOT in JSON. The raw body will be returned. - * - * @param ctx context to execute the job in - * @param eh curl easy handle for the request, will - * be executed AND cleaned up - * @param job_headers extra headers to add for this request - * @param max_reply_size largest acceptable response body - * @param jcc callback to invoke upon completion - * @param jcc_cls closure for @a jcc - * @return NULL on error (in this case, @eh is still released!) - */ struct GNUNET_CURL_Job * GNUNET_CURL_job_add_raw (struct GNUNET_CURL_Context *ctx, CURL *eh, @@ -554,25 +489,6 @@ GNUNET_CURL_job_add_raw (struct GNUNET_CURL_Context *ctx, } -/** - * Schedule a CURL request to be executed and call the given @a jcc - * upon its completion. Note that the context will make use of the - * CURLOPT_PRIVATE facility of the CURL @a eh. - * - * This function modifies the CURL handle to add the - * "Content-Type: application/json" header if @a add_json is set. - * - * @param ctx context to execute the job in - * @param eh curl easy handle for the request, will be executed AND - * cleaned up. NOTE: the handle should _never_ have gotten - * any headers list, as that would then be overridden by - * @a jcc. Therefore, always pass custom headers as the - * @a job_headers parameter. - * @param job_headers extra headers to add for this request - * @param jcc callback to invoke upon completion - * @param jcc_cls closure for @a jcc - * @return NULL on error (in this case, @eh is still released!) - */ struct GNUNET_CURL_Job * GNUNET_CURL_job_add2 (struct GNUNET_CURL_Context *ctx, CURL *eh, @@ -624,21 +540,6 @@ GNUNET_CURL_job_add2 (struct GNUNET_CURL_Context *ctx, } -/** - * Schedule a CURL request to be executed and call the given @a jcc - * upon its completion. Note that the context will make use of the - * CURLOPT_PRIVATE facility of the CURL @a eh. - * - * This function modifies the CURL handle to add the - * "Content-Type: application/json" header. - * - * @param ctx context to execute the job in - * @param eh curl easy handle for the request, will - * be executed AND cleaned up - * @param jcc callback to invoke upon completion - * @param jcc_cls closure for @a jcc - * @return NULL on error (in this case, @eh is still released!) - */ struct GNUNET_CURL_Job * GNUNET_CURL_job_add_with_ct_json (struct GNUNET_CURL_Context *ctx, CURL *eh, @@ -661,18 +562,6 @@ GNUNET_CURL_job_add_with_ct_json (struct GNUNET_CURL_Context *ctx, } -/** - * Schedule a CURL request to be executed and call the given @a jcc - * upon its completion. Note that the context will make use of the - * CURLOPT_PRIVATE facility of the CURL @a eh. - * - * @param ctx context to execute the job in - * @param eh curl easy handle for the request, will - * be executed AND cleaned up - * @param jcc callback to invoke upon completion - * @param jcc_cls closure for @a jcc - * @return NULL on error (in this case, @eh is still released!) - */ struct GNUNET_CURL_Job * GNUNET_CURL_job_add (struct GNUNET_CURL_Context *ctx, CURL *eh, @@ -687,12 +576,6 @@ GNUNET_CURL_job_add (struct GNUNET_CURL_Context *ctx, } -/** - * Cancel a job. Must only be called before the job completion - * callback is called for the respective job. - * - * @param job job to cancel - */ void GNUNET_CURL_job_cancel (struct GNUNET_CURL_Job *job) { @@ -746,24 +629,6 @@ is_json (const char *ct) } -/** - * Obtain information about the final result about the - * HTTP download. If the download was successful, parses - * the JSON in the @a db and returns it. Also returns - * the HTTP @a response_code. If the download failed, - * the return value is NULL. The response code is set - * in any case, on download errors to zero. - * - * Calling this function also cleans up @a db. - * - * @param db download buffer - * @param eh CURL handle (to get the response code) - * @param[out] response_code set to the HTTP response code - * (or zero if we aborted the download, for example - * because the response was too big, or if - * the JSON we received was malformed). - * @return NULL if downloading a JSON reply failed. - */ void * GNUNET_CURL_download_get_result_ (struct GNUNET_CURL_DownloadBuffer *db, CURL *eh, @@ -838,13 +703,6 @@ GNUNET_CURL_download_get_result_ (struct GNUNET_CURL_DownloadBuffer *db, } -/** - * Add custom request header. - * - * @param ctx cURL context. - * @param header header string; will be given to the context AS IS. - * @return #GNUNET_OK if no errors occurred, #GNUNET_SYSERR otherwise. - */ enum GNUNET_GenericReturnValue GNUNET_CURL_append_header (struct GNUNET_CURL_Context *ctx, const char *header) @@ -858,14 +716,6 @@ GNUNET_CURL_append_header (struct GNUNET_CURL_Context *ctx, } -/** - * Run the main event loop for the HTTP interaction. - * - * @param ctx the library context - * @param rp parses the raw response returned from - * the Web server. - * @param rc cleans/frees the response - */ void GNUNET_CURL_perform2 (struct GNUNET_CURL_Context *ctx, GNUNET_CURL_RawParser rp, @@ -920,11 +770,6 @@ GNUNET_CURL_perform2 (struct GNUNET_CURL_Context *ctx, } -/** - * Run the main event loop for the HTTP interaction. - * - * @param ctx the library context - */ void GNUNET_CURL_perform (struct GNUNET_CURL_Context *ctx) { @@ -934,34 +779,6 @@ GNUNET_CURL_perform (struct GNUNET_CURL_Context *ctx) } -/** - * Obtain the information for a select() call to wait until - * #GNUNET_CURL_perform() is ready again. Note that calling - * any other GNUNET_CURL-API may also imply that the library - * is again ready for #GNUNET_CURL_perform(). - * - * Basically, a client should use this API to prepare for select(), - * then block on select(), then call #GNUNET_CURL_perform() and then - * start again until the work with the context is done. - * - * This function will NOT zero out the sets and assumes that @a max_fd - * and @a timeout are already set to minimal applicable values. It is - * safe to give this API FD-sets and @a max_fd and @a timeout that are - * already initialized to some other descriptors that need to go into - * the select() call. - * - * @param ctx context to get the event loop information for - * @param read_fd_set will be set for any pending read operations - * @param write_fd_set will be set for any pending write operations - * @param except_fd_set is here because curl_multi_fdset() has this argument - * @param max_fd set to the highest FD included in any set; - * if the existing sets have no FDs in it, the initial - * value should be "-1". (Note that `max_fd + 1` will need - * to be passed to select().) - * @param timeout set to the timeout in milliseconds (!); -1 means - * no timeout (NULL, blocking forever is OK), 0 means to - * proceed immediately with #GNUNET_CURL_perform(). - */ void GNUNET_CURL_get_select_info (struct GNUNET_CURL_Context *ctx, fd_set *read_fd_set, @@ -995,13 +812,6 @@ GNUNET_CURL_get_select_info (struct GNUNET_CURL_Context *ctx, } -/** - * Cleanup library initialisation resources. This function should be called - * after using this library to cleanup the resources occupied during library's - * initialisation. - * - * @param ctx the library context - */ void GNUNET_CURL_fini (struct GNUNET_CURL_Context *ctx) { diff --git a/src/include/gnunet_getopt_lib.h b/src/include/gnunet_getopt_lib.h @@ -378,6 +378,24 @@ GNUNET_GETOPT_option_absolute_time (char shortName, /** + * Allow user to specify a `struct GNUNET_TIME_Timestamp` + * (using human-readable "fancy" time). + * + * @param shortName short name of the option + * @param name long name of the option + * @param argumentHelp help text for the option argument + * @param description long help text for the option + * @param[out] val set to the time specified at the command line + */ +struct GNUNET_GETOPT_CommandLineOption +GNUNET_GETOPT_option_timestamp (char shortName, + const char *name, + const char *argumentHelp, + const char *description, + struct GNUNET_TIME_Timestamp *val); + + +/** * Increment @a val each time the option flag is given by one. * * @param shortName short name of the option diff --git a/src/include/gnunet_json_lib.h b/src/include/gnunet_json_lib.h @@ -304,25 +304,25 @@ GNUNET_JSON_spec_boolean (const char *name, /* ************ GNUnet-specific parser specifications ******************* */ /** - * Absolute time. + * Timestamp. * * @param name name of the JSON field * @param[out] at where to store the absolute time found under @a name */ struct GNUNET_JSON_Specification -GNUNET_JSON_spec_absolute_time (const char *name, - struct GNUNET_TIME_Absolute *at); +GNUNET_JSON_spec_timestamp (const char *name, + struct GNUNET_TIME_Timestamp *t); /** - * Absolute time in network byte order. + * Timestamp in network byte order. * * @param name name of the JSON field - * @param[out] at where to store the absolute time found under @a name + * @param[out] tn where to store the absolute time found under @a name */ struct GNUNET_JSON_Specification -GNUNET_JSON_spec_absolute_time_nbo (const char *name, - struct GNUNET_TIME_AbsoluteNBO *at); +GNUNET_JSON_spec_timestamp_nbo (const char *name, + struct GNUNET_TIME_TimestampNBO *tn); /** @@ -385,23 +385,23 @@ GNUNET_JSON_from_data (const void *data, size_t size); /** - * Convert absolute timestamp to a json string. + * Convert timestamp to a json string. * * @param stamp the time stamp * @return a json string with the timestamp in @a stamp */ json_t * -GNUNET_JSON_from_time_abs (struct GNUNET_TIME_Absolute stamp); +GNUNET_JSON_from_timestamp (struct GNUNET_TIME_Timestamp stamp); /** - * Convert absolute timestamp to a json string. + * Convert timestamp to a json string. * * @param stamp the time stamp * @return a json string with the timestamp in @a stamp */ json_t * -GNUNET_JSON_from_time_abs_nbo (struct GNUNET_TIME_AbsoluteNBO stamp); +GNUNET_JSON_from_timestamp_nbo (struct GNUNET_TIME_TimestampNBO stamp); /** @@ -747,30 +747,30 @@ GNUNET_JSON_pack_data_varsize (const char *name, /** * Generate packer instruction for a JSON field of type - * absolute time. + * timestamp. * * @param name name of the field to add to the object - * @param at absolute time to pack, a value of 0 is only + * @param at timestamp pack, a value of 0 is only * allowed with #GNUNET_JSON_pack_allow_null()! * @return json pack specification */ struct GNUNET_JSON_PackSpec -GNUNET_JSON_pack_time_abs (const char *name, - struct GNUNET_TIME_Absolute at); +GNUNET_JSON_pack_timestamp (const char *name, + struct GNUNET_TIME_Timestamp at); /** * Generate packer instruction for a JSON field of type - * absolute time in network byte order. + * timestamp in network byte order. * * @param name name of the field to add to the object - * @param at absolute time to pack, a value of 0 is only + * @param at timestamp to pack, a value of 0 is only * allowed with #GNUNET_JSON_pack_allow_null()! * @return json pack specification */ struct GNUNET_JSON_PackSpec -GNUNET_JSON_pack_time_abs_nbo (const char *name, - struct GNUNET_TIME_AbsoluteNBO at); +GNUNET_JSON_pack_timestamp_nbo (const char *name, + struct GNUNET_TIME_TimestampNBO at); /** diff --git a/src/include/gnunet_pq_lib.h b/src/include/gnunet_pq_lib.h @@ -96,7 +96,11 @@ struct GNUNET_PQ_QueryParam */ #define GNUNET_PQ_query_param_end \ { \ - NULL, NULL, NULL, 0, 0 \ + .conv = NULL, \ + .conv_cls = NULL, \ + .data = NULL, \ + .size = 0, \ + .num_params = 0 \ } @@ -200,6 +204,17 @@ GNUNET_PQ_query_param_absolute_time (const struct GNUNET_TIME_Absolute *x); /** + * Generate query parameter for a timestamp. + * The database must store a 64-bit integer. + * + * @param x pointer to the query parameter to pass + * @return query parameter to use + */ +struct GNUNET_PQ_QueryParam +GNUNET_PQ_query_param_timestamp (const struct GNUNET_TIME_Timestamp *x); + + +/** * Generate query parameter for an absolute time value. * The database must store a 64-bit integer. * @@ -212,6 +227,18 @@ GNUNET_PQ_query_param_absolute_time_nbo ( /** + * Generate query parameter for a timestamp in NBO. + * The database must store a 64-bit integer. + * + * @param x pointer to the query parameter to pass + * @return query parameter to use + */ +struct GNUNET_PQ_QueryParam +GNUNET_PQ_query_param_timestamp_nbo ( + const struct GNUNET_TIME_TimestampNBO *t); + + +/** * Generate query parameter for an uint16_t in host byte order. * * @param x pointer to the query parameter to pass @@ -472,6 +499,18 @@ GNUNET_PQ_result_spec_absolute_time (const char *name, /** + * Timestamp expected. + * + * @param name name of the field in the table + * @param[out] t where to store the result + * @return array entry for the result specification to use + */ +struct GNUNET_PQ_ResultSpec +GNUNET_PQ_result_spec_timestamp (const char *name, + struct GNUNET_TIME_Timestamp *t); + + +/** * Relative time expected. * * @param name name of the field in the table @@ -496,6 +535,18 @@ GNUNET_PQ_result_spec_absolute_time_nbo (const char *name, /** + * Timestamp expected. + * + * @param name name of the field in the table + * @param[out] tn where to store the result + * @return array entry for the result specification to use + */ +struct GNUNET_PQ_ResultSpec +GNUNET_PQ_result_spec_timestamp_nbo (const char *name, + struct GNUNET_TIME_TimestampNBO *tn); + + +/** * uint16_t expected. * * @param name name of the field in the table diff --git a/src/include/gnunet_sq_lib.h b/src/include/gnunet_sq_lib.h @@ -40,7 +40,7 @@ * so immediately suitable for passing to `sqlite3_bind`-functions. * @return #GNUNET_SYSERR on error, #GNUNET_OK on success */ -typedef int +typedef enum GNUNET_GenericReturnValue (*GNUNET_SQ_QueryConverter)(void *cls, const void *data, size_t data_len, @@ -156,8 +156,8 @@ GNUNET_SQ_query_param_absolute_time (const struct GNUNET_TIME_Absolute *x); * @param x pointer to the query parameter to pass */ struct GNUNET_SQ_QueryParam -GNUNET_SQ_query_param_absolute_time_nbo (const struct - GNUNET_TIME_AbsoluteNBO *x); +GNUNET_SQ_query_param_absolute_time_nbo ( + const struct GNUNET_TIME_AbsoluteNBO *x); /** @@ -222,7 +222,7 @@ GNUNET_SQ_reset (sqlite3 *dbh, * #GNUNET_YES if all results could be extracted * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL) */ -typedef int +typedef enum GNUNET_GenericReturnValue (*GNUNET_SQ_ResultConverter)(void *cls, sqlite3_stmt *result, unsigned int column, @@ -436,7 +436,7 @@ GNUNET_SQ_result_spec_uint64 (uint64_t *u64); * #GNUNET_OK if all results could be extracted * #GNUNET_SYSERR if a result was invalid (non-existing field) */ -int +enum GNUNET_GenericReturnValue GNUNET_SQ_extract_result (sqlite3_stmt *result, struct GNUNET_SQ_ResultSpec *rs); diff --git a/src/include/gnunet_strings_lib.h b/src/include/gnunet_strings_lib.h @@ -76,7 +76,7 @@ GNUNET_STRINGS_fancy_size_to_bytes (const char *fancy_size, * @param rtime set to the relative time * @return #GNUNET_OK on success, #GNUNET_SYSERR on error */ -int +enum GNUNET_GenericReturnValue GNUNET_STRINGS_fancy_time_to_relative (const char *fancy_time, struct GNUNET_TIME_Relative *rtime); @@ -91,12 +91,27 @@ GNUNET_STRINGS_fancy_time_to_relative (const char *fancy_time, * @param atime set to the absolute time * @return #GNUNET_OK on success, #GNUNET_SYSERR on error */ -int +enum GNUNET_GenericReturnValue GNUNET_STRINGS_fancy_time_to_absolute (const char *fancy_time, struct GNUNET_TIME_Absolute *atime); /** + * @ingroup time + * Convert a given fancy human-readable time to our internal + * representation. The human-readable time is expected to be + * in local time, whereas the returned value will be in UTC. + * + * @param fancy_time human readable string (e.g. %Y-%m-%d %H:%M:%S) + * @param atime set to the absolute time + * @return #GNUNET_OK on success, #GNUNET_SYSERR on error + */ +enum GNUNET_GenericReturnValue +GNUNET_STRINGS_fancy_time_to_timestamp (const char *fancy_time, + struct GNUNET_TIME_Timestamp *atime); + + +/** * Convert a given filesize into a fancy human-readable format. * * @param size number of bytes diff --git a/src/include/gnunet_time_lib.h b/src/include/gnunet_time_lib.h @@ -54,6 +54,17 @@ struct GNUNET_TIME_Absolute }; /** + * Rounded time for timestamps used by GNUnet, in seconds. + */ +struct GNUNET_TIME_Timestamp +{ + /** + * The actual value. Must be round number in seconds. + */ + struct GNUNET_TIME_Absolute abs_time; +}; + +/** * Time for relative time used by GNUnet, in microseconds. * Always positive, so we can only refer to future time. */ @@ -89,17 +100,34 @@ struct GNUNET_TIME_AbsoluteNBO */ uint64_t abs_value_us__ GNUNET_PACKED; }; + +/** + * Time for timestamps used by GNUnet, in seconds and in network byte order. + */ +struct GNUNET_TIME_TimestampNBO +{ + /** + * The actual value. Must be round number in seconds. + */ + struct GNUNET_TIME_AbsoluteNBO abs_time_nbo; +}; + GNUNET_NETWORK_STRUCT_END /** * Relative time zero. */ -#define GNUNET_TIME_UNIT_ZERO GNUNET_TIME_relative_get_zero_ () +#define GNUNET_TIME_UNIT_ZERO ((struct GNUNET_TIME_Relative){0}) /** * Absolute time zero. */ -#define GNUNET_TIME_UNIT_ZERO_ABS GNUNET_TIME_absolute_get_zero_ () +#define GNUNET_TIME_UNIT_ZERO_ABS ((struct GNUNET_TIME_Absolute){0}) + +/** + * Timestamp of zero. + */ +#define GNUNET_TIME_UNIT_ZERO_TS ((struct GNUNET_TIME_Timestamp){{0}}) /** * One microsecond, our basic time unit. @@ -154,13 +182,22 @@ GNUNET_NETWORK_STRUCT_END * Constant used to specify "forever". This constant * will be treated specially in all time operations. */ -#define GNUNET_TIME_UNIT_FOREVER_REL GNUNET_TIME_relative_get_forever_ () +#define GNUNET_TIME_UNIT_FOREVER_REL \ + ((struct GNUNET_TIME_Relative){UINT64_MAX}) /** * Constant used to specify "forever". This constant * will be treated specially in all time operations. */ -#define GNUNET_TIME_UNIT_FOREVER_ABS GNUNET_TIME_absolute_get_forever_ () +#define GNUNET_TIME_UNIT_FOREVER_ABS \ + ((struct GNUNET_TIME_Absolute){UINT64_MAX}) + +/** + * Constant used to specify "forever". This constant + * will be treated specially in all time operations. + */ +#define GNUNET_TIME_UNIT_FOREVER_TS \ + ((struct GNUNET_TIME_Timestamp){{UINT64_MAX}}) /** @@ -183,6 +220,47 @@ GNUNET_NETWORK_STRUCT_END /** + * Convert @a ts to human-readable timestamp. + * Note that the returned value will be overwritten if this function + * is called again. + * + * @param ts the timestamp to convert + * @return statically allocated string, will change on the next call + */ +const char * +GNUNET_TIME_timestamp2s (struct GNUNET_TIME_Timestamp ts); + + +/** + * @ingroup time + * Like `asctime`, except for GNUnet time. Converts a GNUnet internal + * absolute time (which is in UTC) to a string in local time. + * Note that the returned value will be overwritten if this function + * is called again. + * + * @param t the absolute time to convert + * @return timestamp in human-readable form in local time + */ +const char * +GNUNET_TIME_absolute2s (struct GNUNET_TIME_Absolute ts); + + +/** + * @ingroup time + * Give relative time in human-readable fancy format. + * This is one of the very few calls in the entire API that is + * NOT reentrant! + * + * @param delta time in milli seconds + * @param do_round are we allowed to round a bit? + * @return string in human-readable form + */ +const char * +GNUNET_TIME_relative2s (struct GNUNET_TIME_Relative delta, + bool do_round); + + +/** * Randomized exponential back-off, starting at 1 ms * and going up by a factor of 2+r, where 0 <= r <= 0.5, up * to a maximum of the given threshold. @@ -192,8 +270,8 @@ GNUNET_NETWORK_STRUCT_END * @return the next backoff time */ struct GNUNET_TIME_Relative -GNUNET_TIME_randomized_backoff (struct GNUNET_TIME_Relative rt, struct - GNUNET_TIME_Relative threshold); +GNUNET_TIME_randomized_backoff (struct GNUNET_TIME_Relative rt, + struct GNUNET_TIME_Relative threshold); /** @@ -290,27 +368,69 @@ GNUNET_TIME_relative_to_absolute (struct GNUNET_TIME_Relative rel); /** - * Round a time value so that it is suitable for transmission - * via JSON encodings. + * Convert relative time to a timestamp in the + * future. + * + * @param rel relative time to convert + * @return timestamp that is "rel" in the future, or FOREVER if rel==FOREVER (or if we would overflow) + */ +struct GNUNET_TIME_Timestamp +GNUNET_TIME_relative_to_timestamp (struct GNUNET_TIME_Relative rel); + + +/** + * Round an absolute time to a timestamp. * * @param at time to round - * @return #GNUNET_OK if time was already rounded, #GNUNET_NO if - * it was just now rounded + * @return the result */ -int -GNUNET_TIME_round_abs (struct GNUNET_TIME_Absolute *at); +struct GNUNET_TIME_Timestamp +GNUNET_TIME_absolute_to_timestamp (struct GNUNET_TIME_Absolute at); /** - * Round a time value so that it is suitable for transmission - * via JSON encodings. + * Get timestamp representing the current time. * - * @param rt time to round - * @return #GNUNET_OK if time was already rounded, #GNUNET_NO if - * it was just now rounded + * @return current time, rounded down to seconds */ -int -GNUNET_TIME_round_rel (struct GNUNET_TIME_Relative *rt); +struct GNUNET_TIME_Timestamp +GNUNET_TIME_timestamp_get (void); + + +/** + * Compare two absolute times. + * + * @param t1 first time + * @param op compare operator + * @param t2 second time + * @return true if @a t1 @a op @a t2 + */ +#define GNUNET_TIME_absolute_cmp(t1,op,t2) \ + (((void) (1 op 2), (t1).abs_value_us op (t2).abs_value_us)) + + +/** + * Compare two timestamps + * + * @param t1 first timestamp + * @param op compare operator + * @param t2 second timestamp + * @return true if @a t1 @a op @a t2 + */ +#define GNUNET_TIME_timestamp_cmp(t1,op,t2) \ + GNUNET_TIME_absolute_cmp ((t1).abs_time,op,(t2).abs_time) + + +/** + * Compare two relative times. + * + * @param t1 first time + * @param op compare operator + * @param t2 second time + * @return true if @a t1 @a op @a t2 + */ +#define GNUNET_TIME_relative_cmp(t1,op,t2) \ + ((void) (1 op 2), (t1).rel_value_us op (t2).rel_value_us) /** @@ -362,6 +482,30 @@ GNUNET_TIME_absolute_max (struct GNUNET_TIME_Absolute t1, /** + * Return the maximum of two timestamps. + * + * @param t1 first timestamp + * @param t2 other timestamp + * @return timestamp that is smaller + */ +struct GNUNET_TIME_Timestamp +GNUNET_TIME_timestamp_max (struct GNUNET_TIME_Timestamp t1, + struct GNUNET_TIME_Timestamp t2); + + +/** + * Return the minimum of two timestamps. + * + * @param t1 first timestamp + * @param t2 other timestamp + * @return timestamp that is smaller + */ +struct GNUNET_TIME_Timestamp +GNUNET_TIME_timestamp_min (struct GNUNET_TIME_Timestamp t1, + struct GNUNET_TIME_Timestamp t2); + + +/** * Given a timestamp in the future, how much time * remains until then? * @@ -530,6 +674,16 @@ GNUNET_TIME_absolute_hton (struct GNUNET_TIME_Absolute a); /** + * Convert timestamp to network byte order. + * + * @param t time to convert + * @return converted time value + */ +struct GNUNET_TIME_TimestampNBO +GNUNET_TIME_timestamp_hton (struct GNUNET_TIME_Timestamp t); + + +/** * Convert milliseconds after the UNIX epoch to absolute time. * * @param ms_after_epoch millisecond timestamp to convert @@ -558,6 +712,15 @@ GNUNET_TIME_absolute_is_past (struct GNUNET_TIME_Absolute abs); /** + * Test if @a abs is truly zero. + * + * @return true if it is. + */ +bool +GNUNET_TIME_absolute_is_zero (struct GNUNET_TIME_Absolute abs); + + +/** * Test if @a abs is truly in the future (excluding now). * * @return true if it is. @@ -595,6 +758,15 @@ GNUNET_TIME_absolute_from_s (uint64_t s_after_epoch); /** + * Convert seconds after the UNIX epoch to timestamp. + * + * @param s_after_epoch seconds after epoch to convert + * @return converted time value + */struct GNUNET_TIME_Timestamp +GNUNET_TIME_timestamp_from_s (uint64_t s_after_epoch); + + +/** * Convert absolute time from network byte order. * * @param a time to convert @@ -605,6 +777,16 @@ GNUNET_TIME_absolute_ntoh (struct GNUNET_TIME_AbsoluteNBO a); /** + * Convert timestamp from network byte order. + * + * @param tn time to convert + * @return converted time value + */ +struct GNUNET_TIME_Timestamp +GNUNET_TIME_timestamp_ntoh (struct GNUNET_TIME_TimestampNBO tn); + + +/** * Set the timestamp offset for this instance. * * @param offset the offset to skew the locale time by diff --git a/src/json/json_generator.c b/src/json/json_generator.c @@ -27,14 +27,6 @@ #include "gnunet_json_lib.h" -/** - * Convert binary data to a JSON string - * with the base32crockford encoding. - * - * @param data binary data - * @param size size of @a data in bytes - * @return json string that encodes @a data - */ json_t * GNUNET_JSON_from_data (const void *data, size_t size) @@ -57,31 +49,22 @@ GNUNET_JSON_from_data (const void *data, } -/** - * Convert absolute timestamp to a json string. - * - * @param stamp the time stamp - * @return a json string with the timestamp in @a stamp - */ json_t * -GNUNET_JSON_from_time_abs (struct GNUNET_TIME_Absolute stamp) +GNUNET_JSON_from_timestamp (struct GNUNET_TIME_Timestamp stamp) { json_t *j; - GNUNET_assert (GNUNET_OK == - GNUNET_TIME_round_abs (&stamp)); - j = json_object (); if (NULL == j) { GNUNET_break (0); return NULL; } - if (stamp.abs_value_us == GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us) + if (GNUNET_TIME_absolute_is_never (stamp.abs_time)) { if (0 != json_object_set_new (j, - "t_ms", + "t_s", json_string ("never"))) { GNUNET_break (0); @@ -90,11 +73,17 @@ GNUNET_JSON_from_time_abs (struct GNUNET_TIME_Absolute stamp) } return j; } + GNUNET_assert ( + 0 == + (stamp.abs_time.abs_value_us + % GNUNET_TIME_UNIT_SECONDS.rel_value_us)); if (0 != - json_object_set_new (j, - "t_ms", - json_integer ((json_int_t) (stamp.abs_value_us - / 1000LL)))) + json_object_set_new ( + j, + "t_s", + json_integer ( + (json_int_t) (stamp.abs_time.abs_value_us + / GNUNET_TIME_UNIT_SECONDS.rel_value_us)))) { GNUNET_break (0); json_decref (j); @@ -104,44 +93,29 @@ GNUNET_JSON_from_time_abs (struct GNUNET_TIME_Absolute stamp) } -/** - * Convert absolute timestamp to a json string. - * - * @param stamp the time stamp - * @return a json string with the timestamp in @a stamp - */ json_t * -GNUNET_JSON_from_time_abs_nbo (struct GNUNET_TIME_AbsoluteNBO stamp) +GNUNET_JSON_from_timestamp_nbo (struct GNUNET_TIME_TimestampNBO stamp) { - return GNUNET_JSON_from_time_abs (GNUNET_TIME_absolute_ntoh (stamp)); + return GNUNET_JSON_from_timestamp (GNUNET_TIME_timestamp_ntoh (stamp)); } -/** - * Convert relative timestamp to a json string. - * - * @param stamp the time stamp - * @return a json string with the timestamp in @a stamp - */ json_t * GNUNET_JSON_from_time_rel (struct GNUNET_TIME_Relative stamp) { json_t *j; - GNUNET_assert (GNUNET_OK == - GNUNET_TIME_round_rel (&stamp)); - j = json_object (); if (NULL == j) { GNUNET_break (0); return NULL; } - if (stamp.rel_value_us == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us) + if (GNUNET_TIME_relative_is_forever (stamp)) { if (0 != json_object_set_new (j, - "d_ms", + "d_us", json_string ("forever"))) { GNUNET_break (0); @@ -150,11 +124,17 @@ GNUNET_JSON_from_time_rel (struct GNUNET_TIME_Relative stamp) } return j; } + if (stamp.rel_value_us >= (1LLU << 53)) + { + /* value is larger than allowed */ + GNUNET_break (0); + return NULL; + } if (0 != - json_object_set_new (j, - "d_ms", - json_integer ((json_int_t) (stamp.rel_value_us - / 1000LL)))) + json_object_set_new ( + j, + "d_us", + json_integer ((json_int_t) stamp.rel_value_us))) { GNUNET_break (0); json_decref (j); @@ -164,12 +144,6 @@ GNUNET_JSON_from_time_rel (struct GNUNET_TIME_Relative stamp) } -/** - * Convert RSA public key to JSON. - * - * @param pk public key to convert - * @return corresponding JSON encoding - */ json_t * GNUNET_JSON_from_rsa_public_key (const struct GNUNET_CRYPTO_RsaPublicKey *pk) { @@ -186,12 +160,6 @@ GNUNET_JSON_from_rsa_public_key (const struct GNUNET_CRYPTO_RsaPublicKey *pk) } -/** - * Convert RSA signature to JSON. - * - * @param sig signature to convert - * @return corresponding JSON encoding - */ json_t * GNUNET_JSON_from_rsa_signature (const struct GNUNET_CRYPTO_RsaSignature *sig) { diff --git a/src/json/json_helper.c b/src/json/json_helper.c @@ -49,7 +49,7 @@ GNUNET_JSON_spec_end () * @param[out] spec where to write the data * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error */ -static int +static enum GNUNET_GenericReturnValue parse_fixed_data (void *cls, json_t *root, struct GNUNET_JSON_Specification *spec) @@ -579,20 +579,20 @@ GNUNET_JSON_spec_int64 (const char *name, /* ************ GNUnet-specific parser specifications ******************* */ /** - * Parse given JSON object to absolute time. + * Parse given JSON object to a timestamp. * * @param cls closure, NULL * @param root the json object representing data * @param[out] spec where to write the data * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error */ -static int -parse_abs_time (void *cls, - json_t *root, - struct GNUNET_JSON_Specification *spec) +static enum GNUNET_GenericReturnValue +parse_timestamp (void *cls, + json_t *root, + struct GNUNET_JSON_Specification *spec) { - struct GNUNET_TIME_Absolute *abs = spec->ptr; - json_t *json_t_ms; + struct GNUNET_TIME_Timestamp *ts = spec->ptr; + json_t *json_t_s; unsigned long long int tval; if (! json_is_object (root)) @@ -600,14 +600,16 @@ parse_abs_time (void *cls, GNUNET_break_op (0); return GNUNET_SYSERR; } - json_t_ms = json_object_get (root, "t_ms"); - if (json_is_integer (json_t_ms)) + json_t_s = json_object_get (root, + "t_s"); + if (json_is_integer (json_t_s)) { - tval = json_integer_value (json_t_ms); - /* Time is in milliseconds in JSON, but in microseconds in GNUNET_TIME_Absolute */ - abs->abs_value_us = tval * GNUNET_TIME_UNIT_MILLISECONDS.rel_value_us; - if ((abs->abs_value_us) - / GNUNET_TIME_UNIT_MILLISECONDS.rel_value_us + tval = json_integer_value (json_t_s); + /* Time is in seconds in JSON, but in microseconds in GNUNET_TIME_Absolute */ + ts->abs_time.abs_value_us + = tval * GNUNET_TIME_UNIT_SECONDS.rel_value_us; + if (ts->abs_time.abs_value_us + / GNUNET_TIME_UNIT_SECONDS.rel_value_us != tval) { /* Integer overflow */ @@ -616,14 +618,15 @@ parse_abs_time (void *cls, } return GNUNET_OK; } - if (json_is_string (json_t_ms)) + if (json_is_string (json_t_s)) { const char *val; - val = json_string_value (json_t_ms); - if ((0 == strcasecmp (val, "never"))) + val = json_string_value (json_t_s); + if ((0 == strcasecmp (val, + "never"))) { - *abs = GNUNET_TIME_UNIT_FOREVER_ABS; + ts->abs_time = GNUNET_TIME_UNIT_FOREVER_ABS; return GNUNET_OK; } GNUNET_break_op (0); @@ -635,17 +638,14 @@ parse_abs_time (void *cls, struct GNUNET_JSON_Specification -GNUNET_JSON_spec_absolute_time (const char *name, - struct GNUNET_TIME_Absolute *at) +GNUNET_JSON_spec_timestamp (const char *name, + struct GNUNET_TIME_Timestamp *t) { struct GNUNET_JSON_Specification ret = { - .parser = &parse_abs_time, - .cleaner = NULL, - .cls = NULL, + .parser = &parse_timestamp, .field = name, - .ptr = at, - .ptr_size = sizeof(struct GNUNET_TIME_Absolute), - .size_ptr = NULL + .ptr = t, + .ptr_size = sizeof(struct GNUNET_TIME_Timestamp) }; return ret; @@ -660,40 +660,37 @@ GNUNET_JSON_spec_absolute_time (const char *name, * @param[out] spec where to write the data * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error */ -static int -parse_abs_time_nbo (void *cls, - json_t *root, - struct GNUNET_JSON_Specification *spec) +static enum GNUNET_GenericReturnValue +parse_timestamp_nbo (void *cls, + json_t *root, + struct GNUNET_JSON_Specification *spec) { - struct GNUNET_TIME_AbsoluteNBO *abs = spec->ptr; - struct GNUNET_TIME_Absolute a; + struct GNUNET_TIME_TimestampNBO *ts = spec->ptr; + struct GNUNET_TIME_Timestamp a; struct GNUNET_JSON_Specification ispec; ispec = *spec; - ispec.parser = &parse_abs_time; + ispec.parser = &parse_timestamp; ispec.ptr = &a; if (GNUNET_OK != - parse_abs_time (NULL, - root, - &ispec)) + parse_timestamp (NULL, + root, + &ispec)) return GNUNET_SYSERR; - *abs = GNUNET_TIME_absolute_hton (a); + *ts = GNUNET_TIME_timestamp_hton (a); return GNUNET_OK; } struct GNUNET_JSON_Specification -GNUNET_JSON_spec_absolute_time_nbo (const char *name, - struct GNUNET_TIME_AbsoluteNBO *at) +GNUNET_JSON_spec_timestamp_nbo (const char *name, + struct GNUNET_TIME_TimestampNBO *at) { struct GNUNET_JSON_Specification ret = { - .parser = &parse_abs_time_nbo, - .cleaner = NULL, - .cls = NULL, + .parser = &parse_timestamp_nbo, .field = name, .ptr = at, - .ptr_size = sizeof(struct GNUNET_TIME_AbsoluteNBO), - .size_ptr = NULL + .ptr_size = sizeof(struct GNUNET_TIME_TimestampNBO) }; return ret; @@ -708,13 +705,13 @@ GNUNET_JSON_spec_absolute_time_nbo (const char *name, * @param[out] spec where to write the data * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error */ -static int +static enum GNUNET_GenericReturnValue parse_rel_time (void *cls, json_t *root, struct GNUNET_JSON_Specification *spec) { struct GNUNET_TIME_Relative *rel = spec->ptr; - json_t *json_d_ms; + json_t *json_d_us; unsigned long long int tval; if (! json_is_object (root)) @@ -722,25 +719,27 @@ parse_rel_time (void *cls, GNUNET_break_op (0); return GNUNET_SYSERR; } - json_d_ms = json_object_get (root, "d_ms"); - if (json_is_integer (json_d_ms)) + json_d_us = json_object_get (root, + "d_us"); + if (json_is_integer (json_d_us)) { - tval = json_integer_value (json_d_ms); - /* Time is in milliseconds in JSON, but in microseconds in GNUNET_TIME_Absolute */ - rel->rel_value_us = tval * 1000LL; - if ((rel->rel_value_us) / 1000LL != tval) + tval = json_integer_value (json_d_us); + if (tval >= (1LLU << 53)) { - /* Integer overflow */ + /* value is larger than allowed */ GNUNET_break_op (0); return GNUNET_SYSERR; } + rel->rel_value_us = tval; return GNUNET_OK; } - if (json_is_string (json_d_ms)) + if (json_is_string (json_d_us)) { const char *val; - val = json_string_value (json_d_ms); - if ((0 == strcasecmp (val, "forever"))) + + val = json_string_value (json_d_us); + if ((0 == strcasecmp (val, + "forever"))) { *rel = GNUNET_TIME_UNIT_FOREVER_REL; return GNUNET_OK; @@ -759,12 +758,9 @@ GNUNET_JSON_spec_relative_time (const char *name, { struct GNUNET_JSON_Specification ret = { .parser = &parse_rel_time, - .cleaner = NULL, - .cls = NULL, .field = name, .ptr = rt, - .ptr_size = sizeof(struct GNUNET_TIME_Relative), - .size_ptr = NULL + .ptr_size = sizeof(struct GNUNET_TIME_Relative) }; return ret; @@ -779,7 +775,7 @@ GNUNET_JSON_spec_relative_time (const char *name, * @param[out] spec where to write the data * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error */ -static int +static enum GNUNET_GenericReturnValue parse_rsa_public_key (void *cls, json_t *root, struct GNUNET_JSON_Specification *spec) @@ -864,7 +860,7 @@ GNUNET_JSON_spec_rsa_public_key (const char *name, * @param[out] spec where to write the data * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error */ -static int +static enum GNUNET_GenericReturnValue parse_rsa_signature (void *cls, json_t *root, struct GNUNET_JSON_Specification *spec) @@ -952,7 +948,7 @@ GNUNET_JSON_spec_rsa_signature (const char *name, * @param[out] spec where to write the data * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error */ -static int +static enum GNUNET_GenericReturnValue parse_boolean (void *cls, json_t *root, struct GNUNET_JSON_Specification *spec) diff --git a/src/json/json_pack.c b/src/json/json_pack.c @@ -245,16 +245,16 @@ GNUNET_JSON_pack_data_varsize (const char *name, struct GNUNET_JSON_PackSpec -GNUNET_JSON_pack_time_abs (const char *name, - struct GNUNET_TIME_Absolute at) +GNUNET_JSON_pack_timestamp (const char *name, + struct GNUNET_TIME_Timestamp t) { struct GNUNET_JSON_PackSpec ps = { .field_name = name }; - if (0 != at.abs_value_us) + if (! GNUNET_TIME_absolute_is_zero (t.abs_time)) { - ps.object = GNUNET_JSON_from_time_abs (at); + ps.object = GNUNET_JSON_from_timestamp (t); GNUNET_assert (NULL != ps.object); } else @@ -266,11 +266,11 @@ GNUNET_JSON_pack_time_abs (const char *name, struct GNUNET_JSON_PackSpec -GNUNET_JSON_pack_time_abs_nbo (const char *name, - struct GNUNET_TIME_AbsoluteNBO at) +GNUNET_JSON_pack_timestamp_nbo (const char *name, + struct GNUNET_TIME_TimestampNBO at) { - return GNUNET_JSON_pack_time_abs (name, - GNUNET_TIME_absolute_ntoh (at)); + return GNUNET_JSON_pack_timestamp (name, + GNUNET_TIME_timestamp_ntoh (at)); } diff --git a/src/json/test_json.c b/src/json/test_json.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet - (C) 2015, 2016 GNUnet e.V. + (C) 2015, 2016, 2021 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 @@ -34,33 +34,45 @@ * @return 0 on success */ static int -test_abs_time () +test_timestamp (void) { json_t *j; struct GNUNET_TIME_Absolute a1; - struct GNUNET_TIME_Absolute a2; - struct GNUNET_JSON_Specification s1[] = { GNUNET_JSON_spec_absolute_time ( - NULL, - &a2), - GNUNET_JSON_spec_end () }; - struct GNUNET_JSON_Specification s2[] = { GNUNET_JSON_spec_absolute_time ( - NULL, - &a2), - GNUNET_JSON_spec_end () }; + struct GNUNET_TIME_Timestamp t1; + struct GNUNET_TIME_Timestamp t2; + struct GNUNET_JSON_Specification s1[] = { + GNUNET_JSON_spec_timestamp (NULL, + &t2), + GNUNET_JSON_spec_end () + }; + struct GNUNET_JSON_Specification s2[] = { + GNUNET_JSON_spec_timestamp (NULL, + &t2), + GNUNET_JSON_spec_end () + }; a1 = GNUNET_TIME_absolute_get (); - GNUNET_TIME_round_abs (&a1); - j = GNUNET_JSON_from_time_abs (a1); + GNUNET_TIME_absolute_to_timestamp (a1, + &t1); + j = GNUNET_JSON_from_timestamp (t1); GNUNET_assert (NULL != j); - GNUNET_assert (GNUNET_OK == GNUNET_JSON_parse (j, s1, NULL, NULL)); - GNUNET_assert (a1.abs_value_us == a2.abs_value_us); + GNUNET_assert (GNUNET_OK == + GNUNET_JSON_parse (j, + s1, + NULL, + NULL)); + GNUNET_assert (GNUNET_TIME_timestamp_cmp (t1, ==, t2)); json_decref (j); a1 = GNUNET_TIME_UNIT_FOREVER_ABS; - j = GNUNET_JSON_from_time_abs (a1); + j = GNUNET_JSON_from_timestamp (t1); GNUNET_assert (NULL != j); - GNUNET_assert (GNUNET_OK == GNUNET_JSON_parse (j, s2, NULL, NULL)); - GNUNET_assert (a1.abs_value_us == a2.abs_value_us); + GNUNET_assert (GNUNET_OK == + GNUNET_JSON_parse (j, + s2, + NULL, + NULL)); + GNUNET_assert (GNUNET_TIME_timestamp_cmp (t1, ==, t2)); json_decref (j); return 0; } @@ -72,19 +84,21 @@ test_abs_time () * @return 0 on success */ static int -test_rel_time () +test_rel_time (void) { json_t *j; struct GNUNET_TIME_Relative r1; struct GNUNET_TIME_Relative r2; - struct GNUNET_JSON_Specification s1[] = { GNUNET_JSON_spec_relative_time ( - NULL, - &r2), - GNUNET_JSON_spec_end () }; - struct GNUNET_JSON_Specification s2[] = { GNUNET_JSON_spec_relative_time ( - NULL, - &r2), - GNUNET_JSON_spec_end () }; + struct GNUNET_JSON_Specification s1[] = { + GNUNET_JSON_spec_relative_time (NULL, + &r2), + GNUNET_JSON_spec_end () + }; + struct GNUNET_JSON_Specification s2[] = { + GNUNET_JSON_spec_relative_time (NULL, + &r2), + GNUNET_JSON_spec_end () + }; r1 = GNUNET_TIME_UNIT_SECONDS; j = GNUNET_JSON_from_time_rel (r1); @@ -211,7 +225,7 @@ int main (int argc, const char *const argv[]) { GNUNET_log_setup ("test-json", "WARNING", NULL); - if (0 != test_abs_time ()) + if (0 != test_timestamp ()) return 1; if (0 != test_rel_time ()) return 1; diff --git a/src/pq/pq_query_helper.c b/src/pq/pq_query_helper.c @@ -70,7 +70,8 @@ struct GNUNET_PQ_QueryParam GNUNET_PQ_query_param_null (void) { struct GNUNET_PQ_QueryParam res = { - &qconv_null, NULL, NULL, 0, 1 + .conv = &qconv_null, + .num_params = 1 }; return res; @@ -192,7 +193,10 @@ struct GNUNET_PQ_QueryParam GNUNET_PQ_query_param_uint16 (const uint16_t *x) { struct GNUNET_PQ_QueryParam res = { - &qconv_uint16, NULL, x, sizeof(*x), 1 + .conv = &qconv_uint16, + .data = x, + .size = sizeof(*x), + .num_params = 1 }; return res; @@ -246,7 +250,10 @@ struct GNUNET_PQ_QueryParam GNUNET_PQ_query_param_uint32 (const uint32_t *x) { struct GNUNET_PQ_QueryParam res = { - &qconv_uint32, NULL, x, sizeof(*x), 1 + .conv = &qconv_uint32, + .data = x, + .size = sizeof(*x), + .num_params = 1 }; return res; @@ -300,7 +307,10 @@ struct GNUNET_PQ_QueryParam GNUNET_PQ_query_param_uint64 (const uint64_t *x) { struct GNUNET_PQ_QueryParam res = { - &qconv_uint64, NULL, x, sizeof(*x), 1 + .conv = &qconv_uint64, + .data = x, + .size = sizeof(*x), + .num_params = 1 }; return res; @@ -350,11 +360,13 @@ qconv_rsa_public_key (void *cls, struct GNUNET_PQ_QueryParam -GNUNET_PQ_query_param_rsa_public_key (const struct - GNUNET_CRYPTO_RsaPublicKey *x) +GNUNET_PQ_query_param_rsa_public_key ( + const struct GNUNET_CRYPTO_RsaPublicKey *x) { struct GNUNET_PQ_QueryParam res = { - &qconv_rsa_public_key, NULL, (x), 0, 1 + .conv = &qconv_rsa_public_key, + .data = x, + .num_params = 1 }; return res; @@ -407,7 +419,9 @@ struct GNUNET_PQ_QueryParam GNUNET_PQ_query_param_rsa_signature (const struct GNUNET_CRYPTO_RsaSignature *x) { struct GNUNET_PQ_QueryParam res = { - &qconv_rsa_signature, NULL, (x), 0, 1 + .conv = &qconv_rsa_signature, + .data = x, + .num_params = 1 }; return res; @@ -463,7 +477,10 @@ struct GNUNET_PQ_QueryParam GNUNET_PQ_query_param_relative_time (const struct GNUNET_TIME_Relative *x) { struct GNUNET_PQ_QueryParam res = { - &qconv_rel_time, NULL, x, sizeof(*x), 1 + .conv = &qconv_rel_time, + .data = x, + .size = sizeof(*x), + .num_params = 1 }; return res; @@ -519,7 +536,10 @@ struct GNUNET_PQ_QueryParam GNUNET_PQ_query_param_absolute_time (const struct GNUNET_TIME_Absolute *x) { struct GNUNET_PQ_QueryParam res = { - &qconv_abs_time, NULL, x, sizeof(*x), 1 + .conv = &qconv_abs_time, + .data = x, + .size = sizeof(*x), + .num_params = 1 }; return res; @@ -534,4 +554,71 @@ GNUNET_PQ_query_param_absolute_time_nbo ( } +/** + * Function called to convert input argument into SQL parameters. + * + * @param cls closure + * @param data pointer to input argument + * @param data_len number of bytes in @a data (if applicable) + * @param[out] param_values SQL data to set + * @param[out] param_lengths SQL length data to set + * @param[out] param_formats SQL format data to set + * @param param_length number of entries available in the @a param_values, @a param_lengths and @a param_formats arrays + * @param[out] scratch buffer for dynamic allocations (to be done via #GNUNET_malloc() + * @param scratch_length number of entries left in @a scratch + * @return -1 on error, number of offsets used in @a scratch otherwise + */ +static int +qconv_timestamp (void *cls, + const void *data, + size_t data_len, + void *param_values[], + int param_lengths[], + int param_formats[], + unsigned int param_length, + void *scratch[], + unsigned int scratch_length) +{ + const struct GNUNET_TIME_Timestamp *u = data; + struct GNUNET_TIME_Absolute abs; + uint64_t *u_nbo; + + GNUNET_break (NULL == cls); + if (1 != param_length) + return -1; + abs = u->abs_time; + if (abs.abs_value_us > INT64_MAX) + abs.abs_value_us = INT64_MAX; + u_nbo = GNUNET_new (uint64_t); + scratch[0] = u_nbo; + *u_nbo = GNUNET_htonll (abs.abs_value_us); + param_values[0] = (void *) u_nbo; + param_lengths[0] = sizeof(uint64_t); + param_formats[0] = 1; + return 1; +} + + +struct GNUNET_PQ_QueryParam +GNUNET_PQ_query_param_timestamp (const struct GNUNET_TIME_Timestamp *x) +{ + struct GNUNET_PQ_QueryParam res = { + .conv = &qconv_timestamp, + .data = x, + .size = sizeof(*x), + .num_params = 1 + }; + + return res; +} + + +struct GNUNET_PQ_QueryParam +GNUNET_PQ_query_param_timestamp_nbo ( + const struct GNUNET_TIME_TimestampNBO *x) +{ + return GNUNET_PQ_query_param_absolute_time_nbo (&x->abs_time_nbo); +} + + /* end of pq_query_helper.c */ diff --git a/src/pq/pq_result_helper.c b/src/pq/pq_result_helper.c @@ -757,6 +757,148 @@ GNUNET_PQ_result_spec_absolute_time_nbo (const char *name, * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL) */ static enum GNUNET_GenericReturnValue +extract_timestamp (void *cls, + PGresult *result, + int row, + const char *fname, + size_t *dst_size, + void *dst) +{ + struct GNUNET_TIME_Timestamp *udst = dst; + struct GNUNET_TIME_Absolute abs; + const int64_t *res; + int fnum; + + (void) cls; + fnum = PQfnumber (result, + fname); + if (fnum < 0) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + if (PQgetisnull (result, + row, + fnum)) + return GNUNET_NO; + GNUNET_assert (NULL != dst); + if (sizeof(struct GNUNET_TIME_Absolute) != *dst_size) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + if (sizeof(int64_t) != + PQgetlength (result, + row, + fnum)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + res = (int64_t *) PQgetvalue (result, + row, + fnum); + if (INT64_MAX == GNUNET_ntohll ((uint64_t) *res)) + { + abs = GNUNET_TIME_UNIT_FOREVER_ABS; + } + else + { + abs.abs_value_us = GNUNET_ntohll ((uint64_t) *res); + if (0 != abs.abs_value_us % GNUNET_TIME_UNIT_SECONDS.rel_value_us) + { + /* timestamps must be multiple of seconds! */ + GNUNET_break (0); + return GNUNET_SYSERR; + } + } + udst->abs_time = abs; + return GNUNET_OK; +} + + +struct GNUNET_PQ_ResultSpec +GNUNET_PQ_result_spec_timestamp (const char *name, + struct GNUNET_TIME_Timestamp *at) +{ + struct GNUNET_PQ_ResultSpec res = { + .conv = &extract_timestamp, + .dst = (void *) at, + .dst_size = sizeof(*at), + .fname = name + }; + + return res; +} + + +/** + * Extract data from a Postgres database @a result at row @a row. + * + * @param cls closure + * @param result where to extract data from + * @param int row to extract data from + * @param fname name (or prefix) of the fields to extract from + * @param[in,out] dst_size where to store size of result, may be NULL + * @param[out] dst where to store the result + * @return + * #GNUNET_YES if all results could be extracted + * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL) + */ +static enum GNUNET_GenericReturnValue +extract_timestamp_nbo (void *cls, + PGresult *result, + int row, + const char *fname, + size_t *dst_size, + void *dst) +{ + struct GNUNET_TIME_TimestampNBO *udst = dst; + struct GNUNET_TIME_Timestamp t; + enum GNUNET_GenericReturnValue r; + + r = extract_timestamp (&t, + result, + row, + fname, + dst_size, + dst); + if (GNUNET_OK != r) + return r; + *udst = GNUNET_TIME_timestamp_hton (t); + return r; +} + + +struct GNUNET_PQ_ResultSpec +GNUNET_PQ_result_spec_timestamp_nbo (const char *name, + struct GNUNET_TIME_TimestampNBO *at) +{ + struct GNUNET_PQ_ResultSpec res = { + .conv = &extract_timestamp_nbo, + .dst = (void *) at, + .dst_size = sizeof(*at), + .fname = name + }; + + return res; +} + + +/** + * Extract data from a Postgres database @a result at row @a row. + * + * @param cls closure + * @param result where to extract data from + * @param int row to extract data from + * @param fname name (or prefix) of the fields to extract from + * @param[in,out] dst_size where to store size of result, may be NULL + * @param[out] dst where to store the result + * @return + * #GNUNET_YES if all results could be extracted + * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL) + */ +static enum GNUNET_GenericReturnValue extract_uint16 (void *cls, PGresult *result, int row, diff --git a/src/util/Makefile.am b/src/util/Makefile.am @@ -144,7 +144,7 @@ libgnunetutil_la_LIBADD = \ libgnunetutil_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) \ - -version-info 14:0:0 + -version-info 15:0:0 GNUNET_ECC = gnunet-ecc GNUNET_SCRYPT = gnunet-scrypt diff --git a/src/util/getopt_helpers.c b/src/util/getopt_helpers.c @@ -38,7 +38,7 @@ * @param value not used (NULL) * @return #GNUNET_NO (do not continue, not an error) */ -static int +static enum GNUNET_GenericReturnValue print_version (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, void *scls, const char *option, @@ -53,12 +53,6 @@ print_version (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, } -/** - * Define the option to print the version of - * the application (-v option) - * - * @param version string with the version number - */ struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_option_version (const char *version) { @@ -90,7 +84,7 @@ GNUNET_GETOPT_option_version (const char *version) * @param value not used (NULL) * @return #GNUNET_NO (do not continue, not an error) */ -static int +static enum GNUNET_GenericReturnValue format_help (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, void *scls, const char *option, @@ -192,12 +186,6 @@ OUTER: } -/** - * Defining the option to print the command line - * help text (-h option). - * - * @param about string with brief description of the application - */ struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_option_help (const char *about) { @@ -229,7 +217,7 @@ GNUNET_GETOPT_option_help (const char *about) * @param value not used (NULL) * @return #GNUNET_OK */ -static int +static enum GNUNET_GenericReturnValue increment_value (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, void *scls, const char *option, @@ -245,15 +233,6 @@ increment_value (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, } -/** - * Increment @a val each time the option flag is given by one. - * - * @param shortName short name of the option - * @param name long name of the option - * @param argumentHelp help text for the option argument - * @param description long help text for the option - * @param[out] val increment by 1 each time the option is present - */ struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_option_increment_uint (char shortName, const char *name, @@ -272,12 +251,6 @@ GNUNET_GETOPT_option_increment_uint (char shortName, } -/** - * Define the '-V' verbosity option. Using the option more - * than once increments @a level each time. - * - * @param[out] level set to the verbosity level - */ struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_option_verbose (unsigned int *level) { @@ -308,7 +281,7 @@ GNUNET_GETOPT_option_verbose (unsigned int *level) * @param value not used (NULL) * @return #GNUNET_OK */ -static int +static enum GNUNET_GenericReturnValue set_one (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, void *scls, const char *option, @@ -324,16 +297,6 @@ set_one (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, } -/** - * Allow user to specify a flag (which internally means setting - * an integer to 1/#GNUNET_YES/#GNUNET_OK. - * - * @param shortName short name of the option - * @param name long name of the option - * @param argumentHelp help text for the option argument - * @param description long help text for the option - * @param[out] val set to 1 if the option is present - */ struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_option_flag (char shortName, const char *name, @@ -366,7 +329,7 @@ GNUNET_GETOPT_option_flag (char shortName, * @param value actual value of the option (a string) * @return #GNUNET_OK */ -static int +static enum GNUNET_GenericReturnValue set_string (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, void *scls, const char *option, @@ -383,15 +346,6 @@ set_string (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, } -/** - * Allow user to specify a string. - * - * @param shortName short name of the option - * @param name long name of the option - * @param argumentHelp help text for the option argument - * @param description long help text for the option - * @param[out] str set to the string - */ struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_option_string (char shortName, const char *name, @@ -413,12 +367,6 @@ GNUNET_GETOPT_option_string (char shortName, } -/** - * Define the '-L' log level option. Note that we do not check - * that the log level is valid here. - * - * @param[out] level set to the log level - */ struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_option_loglevel (char **level) { @@ -447,7 +395,7 @@ GNUNET_GETOPT_option_loglevel (char **level) * @param value actual value of the option (a string) * @return #GNUNET_OK */ -static int +static enum GNUNET_GenericReturnValue set_filename (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, void *scls, const char *option, @@ -464,15 +412,6 @@ set_filename (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, } -/** - * Allow user to specify a filename (automatically path expanded). - * - * @param shortName short name of the option - * @param name long name of the option - * @param argumentHelp help text for the option argument - * @param description long help text for the option - * @param[out] str set to the string - */ struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_option_filename (char shortName, const char *name, @@ -494,11 +433,6 @@ GNUNET_GETOPT_option_filename (char shortName, } -/** - * Allow user to specify log file name (-l option) - * - * @param[out] logfn set to the name of the logfile - */ struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_option_logfile (char **logfn) { @@ -517,11 +451,6 @@ GNUNET_GETOPT_option_logfile (char **logfn) } -/** - * Allow user to specify configuration file name (-c option) - * - * @param[out] fn set to the name of the configuration file - */ struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_option_cfgfile (char **fn) { @@ -552,7 +481,7 @@ GNUNET_GETOPT_option_cfgfile (char **fn) * @param value actual value of the option as a string. * @return #GNUNET_OK if parsing the value worked */ -static int +static enum GNUNET_GenericReturnValue set_ulong (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, void *scls, const char *option, @@ -573,15 +502,6 @@ set_ulong (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, } -/** - * Allow user to specify an `unsigned long long` - * - * @param shortName short name of the option - * @param name long name of the option - * @param argumentHelp help text for the option argument - * @param description long help text for the option - * @param[out] val set to the value specified at the command line - */ struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_option_ulong (char shortName, const char *name, @@ -616,7 +536,7 @@ GNUNET_GETOPT_option_ulong (char shortName, * @param value actual value of the option as a string. * @return #GNUNET_OK if parsing the value worked */ -static int +static enum GNUNET_GenericReturnValue set_timetravel_time (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, void *scls, const char *option, @@ -664,15 +584,6 @@ set_timetravel_time (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, } -/** - * Allow user to specify a `long long` with an offset to add to the current - * system time to construct the time seen by the application. Used for - * debugging / testing. - * - * @param shortName short name of the option - * @param name long name of the option - * @param[out] val set to the time specified at the command line - */ struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_option_timetravel (char shortName, const char *name) @@ -684,8 +595,7 @@ GNUNET_GETOPT_option_timetravel (char shortName, .description = _ ( "modify system time by given offset (for debugging/testing only)"), .require_argument = 1, - .processor = - &set_timetravel_time + .processor = &set_timetravel_time }; return clo; @@ -705,7 +615,7 @@ GNUNET_GETOPT_option_timetravel (char shortName, * @param value actual value of the option as a string. * @return #GNUNET_OK if parsing the value worked */ -static int +static enum GNUNET_GenericReturnValue set_relative_time (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, void *scls, const char *option, @@ -725,16 +635,6 @@ set_relative_time (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, } -/** - * Allow user to specify a `struct GNUNET_TIME_Relative` - * (using human-readable "fancy" time). - * - * @param shortName short name of the option - * @param name long name of the option - * @param argumentHelp help text for the option argument - * @param description long help text for the option - * @param[out] val set to the time specified at the command line - */ struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_option_relative_time (char shortName, const char *name, @@ -748,8 +648,7 @@ GNUNET_GETOPT_option_relative_time (char shortName, .argumentHelp = argumentHelp, .description = description, .require_argument = 1, - .processor = - &set_relative_time, + .processor = &set_relative_time, .scls = (void *) val }; @@ -770,7 +669,7 @@ GNUNET_GETOPT_option_relative_time (char shortName, * @param value actual value of the option as a string. * @return #GNUNET_OK if parsing the value worked */ -static int +static enum GNUNET_GenericReturnValue set_absolute_time (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, void *scls, const char *option, @@ -790,16 +689,6 @@ set_absolute_time (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, } -/** - * Allow user to specify a `struct GNUNET_TIME_Absolute` - * (using human-readable "fancy" time). - * - * @param shortName short name of the option - * @param name long name of the option - * @param argumentHelp help text for the option argument - * @param description long help text for the option - * @param[out] val set to the time specified at the command line - */ struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_option_absolute_time (char shortName, const char *name, @@ -813,8 +702,71 @@ GNUNET_GETOPT_option_absolute_time (char shortName, .argumentHelp = argumentHelp, .description = description, .require_argument = 1, - .processor = - &set_absolute_time, + .processor = &set_absolute_time, + .scls = (void *) val + }; + + return clo; +} + + +/** + * Set an option of type 'struct GNUNET_TIME_Timestamp' from the command line. + * A pointer to this function should be passed as part of the + * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options + * of this type. It should be followed by a pointer to a value of + * type 'struct GNUNET_TIME_Absolute'. + * + * @param ctx command line processing context + * @param scls additional closure (will point to the `struct GNUNET_TIME_Absolute`) + * @param option name of the option + * @param value actual value of the option as a string. + * @return #GNUNET_OK if parsing the value worked + */ +static enum GNUNET_GenericReturnValue +set_timestamp (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, + void *scls, + const char *option, + const char *value) +{ + struct GNUNET_TIME_Timestamp *t = scls; + struct GNUNET_TIME_Absolute abs; + + (void) ctx; + if (GNUNET_OK != + GNUNET_STRINGS_fancy_time_to_absolute (value, + &abs)) + { + fprintf (stderr, + _ ("You must pass a timestamp to the `%s' option.\n"), + option); + return GNUNET_SYSERR; + } + if (0 != abs.abs_value_us % GNUNET_TIME_UNIT_SECONDS.rel_value_us) + { + fprintf (stderr, + _ ("The maximum precision allowed for timestamps is seconds.\n")); + return GNUNET_SYSERR; + } + t->abs_time = abs; + return GNUNET_OK; +} + + +struct GNUNET_GETOPT_CommandLineOption +GNUNET_GETOPT_option_timestamp (char shortName, + const char *name, + const char *argumentHelp, + const char *description, + struct GNUNET_TIME_Timestamp *val) +{ + struct GNUNET_GETOPT_CommandLineOption clo = { + .shortName = shortName, + .name = name, + .argumentHelp = argumentHelp, + .description = description, + .require_argument = 1, + .processor = &set_timestamp, .scls = (void *) val }; @@ -835,7 +787,7 @@ GNUNET_GETOPT_option_absolute_time (char shortName, * @param value actual value of the option as a string. * @return #GNUNET_OK if parsing the value worked */ -static int +static enum GNUNET_GenericReturnValue set_uint (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, void *scls, const char *option, @@ -864,15 +816,6 @@ set_uint (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, } -/** - * Allow user to specify an unsigned integer. - * - * @param shortName short name of the option - * @param name long name of the option - * @param argumentHelp help text for the option argument - * @param description long help text for the option - * @param[out] val set to the value specified at the command line - */ struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_option_uint (char shortName, const char *name, @@ -907,7 +850,7 @@ GNUNET_GETOPT_option_uint (char shortName, * @param value actual value of the option as a string. * @return #GNUNET_OK if parsing the value worked */ -static int +static enum GNUNET_GenericReturnValue set_uint16 (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, void *scls, const char *option, @@ -938,15 +881,6 @@ set_uint16 (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, } -/** - * Allow user to specify an uint16_t. - * - * @param shortName short name of the option - * @param name long name of the option - * @param argumentHelp help text for the option argument - * @param description long help text for the option - * @param[out] val set to the value specified at the command line - */ struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_option_uint16 (char shortName, const char *name, @@ -998,7 +932,7 @@ struct Base32Context * @param value actual value of the option as a string. * @return #GNUNET_OK if parsing the value worked */ -static int +static enum GNUNET_GenericReturnValue set_base32 (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, void *scls, const char *option, @@ -1036,17 +970,6 @@ free_bc (void *cls) } -/** - * Allow user to specify a binary value using Crockford - * Base32 encoding. - * - * @param shortName short name of the option - * @param name long name of the option - * @param argumentHelp help text for the option argument - * @param description long help text for the option - * @param[out] val binary value decoded from Crockford Base32-encoded argument - * @param val_size size of @a val in bytes - */ struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_option_base32_fixed_size (char shortName, const char *name, @@ -1073,12 +996,6 @@ GNUNET_GETOPT_option_base32_fixed_size (char shortName, } -/** - * Make the given option mandatory. - * - * @param opt option to modify - * @return @a opt with the mandatory flag set. - */ struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_option_mandatory (struct GNUNET_GETOPT_CommandLineOption opt) { @@ -1087,12 +1004,6 @@ GNUNET_GETOPT_option_mandatory (struct GNUNET_GETOPT_CommandLineOption opt) } -/** - * Make the given option mutually exclusive with other options. - * - * @param opt option to modify - * @return @a opt with the exclusive flag set. - */ struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_option_exclusive (struct GNUNET_GETOPT_CommandLineOption opt) { diff --git a/src/util/strings.c b/src/util/strings.c @@ -201,7 +201,7 @@ struct ConversionTable * @param output where to store the result * @return #GNUNET_OK on success, #GNUNET_SYSERR on error */ -static int +static enum GNUNET_GenericReturnValue convert_with_table (const char *input, const struct ConversionTable *table, unsigned long long *output) @@ -256,7 +256,7 @@ convert_with_table (const char *input, } -int +enum GNUNET_GenericReturnValue GNUNET_STRINGS_fancy_size_to_bytes (const char *fancy_size, unsigned long long *size) { @@ -280,7 +280,7 @@ GNUNET_STRINGS_fancy_size_to_bytes (const char *fancy_size, } -int +enum GNUNET_GenericReturnValue GNUNET_STRINGS_fancy_time_to_relative (const char *fancy_time, struct GNUNET_TIME_Relative *rtime) { @@ -322,7 +322,7 @@ GNUNET_STRINGS_fancy_time_to_relative (const char *fancy_time, } -int +enum GNUNET_GenericReturnValue GNUNET_STRINGS_fancy_time_to_absolute (const char *fancy_time, struct GNUNET_TIME_Absolute *atime) { @@ -354,6 +354,15 @@ GNUNET_STRINGS_fancy_time_to_absolute (const char *fancy_time, } +enum GNUNET_GenericReturnValue +GNUNET_STRINGS_fancy_time_to_timestamp (const char *fancy_time, + struct GNUNET_TIME_Timestamp *atime) +{ + return GNUNET_STRINGS_fancy_time_to_absolute (fancy_time, + &atime->abs_time); +} + + char * GNUNET_STRINGS_conv (const char *input, size_t len, @@ -607,7 +616,7 @@ GNUNET_STRINGS_absolute_time_to_string (struct GNUNET_TIME_Absolute t) time_t tt; struct tm *tp; - if (t.abs_value_us == GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us) + if (GNUNET_TIME_absolute_is_never (t)) return "end of time"; tt = t.abs_value_us / 1000LL / 1000LL; tp = localtime (&tt); @@ -616,7 +625,8 @@ GNUNET_STRINGS_absolute_time_to_string (struct GNUNET_TIME_Absolute t) * As for msvcrt, use the wide variant, which always returns utf16 * (otherwise we'd have to detect current codepage or use W32API character * set conversion routines to convert to UTF8). - */strftime (buf, sizeof(buf), "%a %b %d %H:%M:%S %Y", tp); + */ + strftime (buf, sizeof(buf), "%a %b %d %H:%M:%S %Y", tp); return buf; } diff --git a/src/util/time.c b/src/util/time.c @@ -58,27 +58,35 @@ GNUNET_TIME_get_offset () } -int -GNUNET_TIME_round_abs (struct GNUNET_TIME_Absolute *at) +struct GNUNET_TIME_Timestamp +GNUNET_TIME_absolute_to_timestamp (struct GNUNET_TIME_Absolute at) { - if (at->abs_value_us == GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us) - return GNUNET_OK; - if (0 == at->abs_value_us % 1000000) - return GNUNET_OK; - at->abs_value_us -= at->abs_value_us % 1000000; - return GNUNET_NO; + struct GNUNET_TIME_Timestamp ts; + + if (GNUNET_TIME_absolute_is_never (at)) + return GNUNET_TIME_UNIT_FOREVER_TS; + ts.abs_time.abs_value_us = at.abs_value_us - at.abs_value_us % 1000000; + return ts; +} + + +struct GNUNET_TIME_TimestampNBO +GNUNET_TIME_timestamp_hton (struct GNUNET_TIME_Timestamp t) +{ + struct GNUNET_TIME_TimestampNBO tn; + + tn.abs_time_nbo = GNUNET_TIME_absolute_hton (t.abs_time); + return tn; } -int -GNUNET_TIME_round_rel (struct GNUNET_TIME_Relative *rt) +struct GNUNET_TIME_Timestamp +GNUNET_TIME_timestamp_ntoh (struct GNUNET_TIME_TimestampNBO tn) { - if (rt->rel_value_us == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us) - return GNUNET_OK; - if (0 == rt->rel_value_us % 1000000) - return GNUNET_OK; - rt->rel_value_us -= rt->rel_value_us % 1000000; - return GNUNET_NO; + struct GNUNET_TIME_Timestamp t; + + t.abs_time = GNUNET_TIME_absolute_ntoh (tn.abs_time_nbo); + return t; } @@ -96,6 +104,14 @@ GNUNET_TIME_absolute_get () } +struct GNUNET_TIME_Timestamp +GNUNET_TIME_timestamp_get () +{ + return GNUNET_TIME_absolute_to_timestamp ( + GNUNET_TIME_absolute_get ()); +} + + struct GNUNET_TIME_Relative GNUNET_TIME_relative_get_zero_ () { @@ -177,12 +193,114 @@ GNUNET_TIME_absolute_get_forever_ () } +const char * +GNUNET_TIME_timestamp2s (struct GNUNET_TIME_Timestamp ts) +{ + static GNUNET_THREAD_LOCAL char buf[255]; + time_t tt; + struct tm *tp; + + if (GNUNET_TIME_absolute_is_never (ts.abs_time)) + return "end of time"; + tt = ts.abs_time.abs_value_us / 1000LL / 1000LL; + tp = localtime (&tt); + /* This is hacky, but i don't know a way to detect libc character encoding. + * Just expect utf8 from glibc these days. + * As for msvcrt, use the wide variant, which always returns utf16 + * (otherwise we'd have to detect current codepage or use W32API character + * set conversion routines to convert to UTF8). + */ + strftime (buf, + sizeof(buf), + "%a %b %d %H:%M:%S %Y", + tp); + return buf; +} + + +const char * +GNUNET_TIME_absolute2s (struct GNUNET_TIME_Absolute t) +{ + static GNUNET_THREAD_LOCAL char buf[255]; + time_t tt; + struct tm *tp; + + if (GNUNET_TIME_absolute_is_never (t)) + return "end of time"; + tt = t.abs_value_us / 1000LL / 1000LL; + tp = localtime (&tt); + /* This is hacky, but i don't know a way to detect libc character encoding. + * Just expect utf8 from glibc these days. + * As for msvcrt, use the wide variant, which always returns utf16 + * (otherwise we'd have to detect current codepage or use W32API character + * set conversion routines to convert to UTF8). + */ + strftime (buf, + sizeof(buf), + "%a %b %d %H:%M:%S %Y", + tp); + return buf; +} + + +const char * +GNUNET_TIME_relative2s (struct GNUNET_TIME_Relative delta, + bool do_round) +{ + static GNUNET_THREAD_LOCAL char buf[128]; + const char *unit = /* time unit */ "µs"; + uint64_t dval = delta.rel_value_us; + + if (GNUNET_TIME_relative_is_forever (delta)) + return "forever"; + if (0 == delta.rel_value_us) + return "0 ms"; + if ( ((GNUNET_YES == do_round) && + (dval > 5 * 1000)) || + (0 == (dval % 1000))) + { + dval = dval / 1000; + unit = /* time unit */ "ms"; + if (((GNUNET_YES == do_round) && (dval > 5 * 1000)) || (0 == (dval % 1000))) + { + dval = dval / 1000; + unit = /* time unit */ "s"; + if (((GNUNET_YES == do_round) && (dval > 5 * 60)) || (0 == (dval % 60))) + { + dval = dval / 60; + unit = /* time unit */ "m"; + if (((GNUNET_YES == do_round) && (dval > 5 * 60)) || (0 == (dval % 60))) + { + dval = dval / 60; + unit = /* time unit */ "h"; + if (((GNUNET_YES == do_round) && (dval > 5 * 24)) || + (0 == (dval % 24))) + { + dval = dval / 24; + if (1 == dval) + unit = /* time unit */ "day"; + else + unit = /* time unit */ "days"; + } + } + } + } + } + GNUNET_snprintf (buf, + sizeof(buf), + "%llu %s", + (unsigned long long) dval, + unit); + return buf; +} + + struct GNUNET_TIME_Absolute GNUNET_TIME_relative_to_absolute (struct GNUNET_TIME_Relative rel) { struct GNUNET_TIME_Absolute ret; - if (rel.rel_value_us == UINT64_MAX) + if (GNUNET_TIME_relative_is_forever (rel)) return GNUNET_TIME_UNIT_FOREVER_ABS; struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); @@ -196,6 +314,14 @@ GNUNET_TIME_relative_to_absolute (struct GNUNET_TIME_Relative rel) } +struct GNUNET_TIME_Timestamp +GNUNET_TIME_relative_to_timestamp (struct GNUNET_TIME_Relative rel) +{ + return GNUNET_TIME_absolute_to_timestamp ( + GNUNET_TIME_relative_to_absolute (rel)); +} + + struct GNUNET_TIME_Relative GNUNET_TIME_relative_min (struct GNUNET_TIME_Relative t1, struct GNUNET_TIME_Relative t2) @@ -228,12 +354,28 @@ GNUNET_TIME_absolute_max (struct GNUNET_TIME_Absolute t1, } +struct GNUNET_TIME_Timestamp +GNUNET_TIME_timestamp_max (struct GNUNET_TIME_Timestamp t1, + struct GNUNET_TIME_Timestamp t2) +{ + return (t1.abs_time.abs_value_us > t2.abs_time.abs_value_us) ? t1 : t2; +} + + +struct GNUNET_TIME_Timestamp +GNUNET_TIME_timestamp_min (struct GNUNET_TIME_Timestamp t1, + struct GNUNET_TIME_Timestamp t2) +{ + return (t1.abs_time.abs_value_us < t2.abs_time.abs_value_us) ? t1 : t2; +} + + struct GNUNET_TIME_Relative GNUNET_TIME_absolute_get_remaining (struct GNUNET_TIME_Absolute future) { struct GNUNET_TIME_Relative ret; - if (future.abs_value_us == UINT64_MAX) + if (GNUNET_TIME_absolute_is_never (future)) return GNUNET_TIME_UNIT_FOREVER_REL; struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); @@ -250,7 +392,7 @@ GNUNET_TIME_absolute_get_difference (struct GNUNET_TIME_Absolute start, { struct GNUNET_TIME_Relative ret; - if (end.abs_value_us == UINT64_MAX) + if (GNUNET_TIME_absolute_is_never (end)) return GNUNET_TIME_UNIT_FOREVER_REL; if (end.abs_value_us < start.abs_value_us) return GNUNET_TIME_UNIT_ZERO; @@ -279,8 +421,8 @@ GNUNET_TIME_absolute_add (struct GNUNET_TIME_Absolute start, { struct GNUNET_TIME_Absolute ret; - if ((start.abs_value_us == UINT64_MAX) || - (duration.rel_value_us == UINT64_MAX)) + if (GNUNET_TIME_absolute_is_never (start) || + GNUNET_TIME_relative_is_forever (duration)) return GNUNET_TIME_UNIT_FOREVER_ABS; if (start.abs_value_us + duration.rel_value_us < start.abs_value_us) { @@ -300,7 +442,7 @@ GNUNET_TIME_absolute_subtract (struct GNUNET_TIME_Absolute start, if (start.abs_value_us <= duration.rel_value_us) return GNUNET_TIME_UNIT_ZERO_ABS; - if (start.abs_value_us == GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us) + if (GNUNET_TIME_absolute_is_never (start)) return GNUNET_TIME_UNIT_FOREVER_ABS; ret.abs_value_us = start.abs_value_us - duration.rel_value_us; return ret; @@ -315,7 +457,7 @@ GNUNET_TIME_relative_multiply (struct GNUNET_TIME_Relative rel, if (0 == factor) return GNUNET_TIME_UNIT_ZERO; - if (rel.rel_value_us == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us) + if (GNUNET_TIME_relative_is_forever (rel)) return GNUNET_TIME_UNIT_FOREVER_REL; ret.rel_value_us = rel.rel_value_us * factor; if (ret.rel_value_us / factor != rel.rel_value_us) @@ -328,7 +470,8 @@ GNUNET_TIME_relative_multiply (struct GNUNET_TIME_Relative rel, struct GNUNET_TIME_Relative -relative_multiply_double (struct GNUNET_TIME_Relative rel, double factor) +relative_multiply_double (struct GNUNET_TIME_Relative rel, + double factor) { struct GNUNET_TIME_Relative out; double m; @@ -337,7 +480,7 @@ relative_multiply_double (struct GNUNET_TIME_Relative rel, double factor) if (0 == factor) return GNUNET_TIME_UNIT_ZERO; - if (rel.rel_value_us == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us) + if (GNUNET_TIME_relative_is_forever (rel)) return GNUNET_TIME_UNIT_FOREVER_REL; m = ((double) rel.rel_value_us) * factor; @@ -361,7 +504,7 @@ GNUNET_TIME_relative_saturating_multiply (struct GNUNET_TIME_Relative rel, if (0 == factor) return GNUNET_TIME_UNIT_ZERO; - if (rel.rel_value_us == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us) + if (GNUNET_TIME_relative_is_forever (rel)) return GNUNET_TIME_UNIT_FOREVER_REL; ret.rel_value_us = rel.rel_value_us * factor; if (ret.rel_value_us / factor != rel.rel_value_us) @@ -379,7 +522,7 @@ GNUNET_TIME_relative_divide (struct GNUNET_TIME_Relative rel, struct GNUNET_TIME_Relative ret; if ((0 == factor) || - (rel.rel_value_us == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)) + (GNUNET_TIME_relative_is_forever (rel))) return GNUNET_TIME_UNIT_FOREVER_REL; ret.rel_value_us = rel.rel_value_us / factor; return ret; @@ -538,6 +681,20 @@ GNUNET_TIME_absolute_from_s (uint64_t s_after_epoch) } +struct GNUNET_TIME_Timestamp +GNUNET_TIME_timestamp_from_s (uint64_t s_after_epoch) +{ + struct GNUNET_TIME_Timestamp ret; + + ret.abs_time.abs_value_us + = GNUNET_TIME_UNIT_SECONDS.rel_value_us * s_after_epoch; + if (ret.abs_time.abs_value_us / GNUNET_TIME_UNIT_SECONDS.rel_value_us + != s_after_epoch) + ret = GNUNET_TIME_UNIT_FOREVER_TS; + return ret; +} + + struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_ntoh (struct GNUNET_TIME_AbsoluteNBO a) { @@ -645,6 +802,13 @@ GNUNET_TIME_randomized_backoff (struct GNUNET_TIME_Relative rt, } +bool +GNUNET_TIME_absolute_is_zero (struct GNUNET_TIME_Absolute abs) +{ + return 0 == abs.abs_value_us; +} + + struct GNUNET_TIME_Relative GNUNET_TIME_randomize (struct GNUNET_TIME_Relative r) {