diff options
author | Christian Grothoff <christian@grothoff.org> | 2019-11-24 22:33:58 +0100 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2019-11-24 22:33:58 +0100 |
commit | fc9d4a99a1488a6313f661258e455fb8f443a4d1 (patch) | |
tree | 7799035f2098de9968f078c4d67aa891231b12d9 | |
parent | c4b5ac29367dd1d845c19851504784bdbdbc1fd5 (diff) | |
download | sync-fc9d4a99a1488a6313f661258e455fb8f443a4d1.tar.gz sync-fc9d4a99a1488a6313f661258e455fb8f443a4d1.tar.bz2 sync-fc9d4a99a1488a6313f661258e455fb8f443a4d1.zip |
implement sync_api_download
-rw-r--r-- | src/include/sync_service.h | 22 | ||||
-rw-r--r-- | src/lib/Makefile.am | 1 | ||||
-rw-r--r-- | src/lib/sync_api_download.c | 221 | ||||
-rw-r--r-- | src/sync/sync-httpd_mhd.c | 2 |
4 files changed, 238 insertions, 8 deletions
diff --git a/src/include/sync_service.h b/src/include/sync_service.h index 47dfdb4..e0651f2 100644 --- a/src/include/sync_service.h +++ b/src/include/sync_service.h @@ -262,6 +262,21 @@ void SYNC_upload_cancel (struct SYNC_UploadOperation *uo); +struct SYNC_DownloadDetails +{ + + struct SYNC_AccountSignatureP sig; + + struct GNUNET_HashCode prev_backup_hash; + + struct GNUNET_HashCode curr_backup_hash; + + const void *backup; + + size_t backup_size; + +}; + /** * Function called with the results of a #SYNC_download(). * @@ -278,11 +293,8 @@ SYNC_upload_cancel (struct SYNC_UploadOperation *uo); */ typedef void (*SYNC_DownloadCallback)(void *cls, - const struct SYNC_AccountPublicKeyP *sig, - const struct GNUNET_HashCode *prev_backup_hash, - const struct GNUNET_HashCode *curr_backup_hash, - size_t backup_size, - const void *backup); + unsigned int http_status, + const struct SYNC_DownloadDetails *dd); /** diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index b1b1d92..20ceab4 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -14,6 +14,7 @@ libsync_la_LDFLAGS = \ -no-undefined libsync_la_SOURCES = \ + sync_api_curl_defaults.c sync_api_curl_defaults.h \ sync_api_download.c \ sync_api_upload.c diff --git a/src/lib/sync_api_download.c b/src/lib/sync_api_download.c index e9780e1..a8750c1 100644 --- a/src/lib/sync_api_download.c +++ b/src/lib/sync_api_download.c @@ -28,7 +28,9 @@ #include <microhttpd.h> /* just for HTTP status codes */ #include <gnunet/gnunet_util_lib.h> #include <gnunet/gnunet_curl_lib.h> +#include <taler/taler_signatures.h> #include "sync_service.h" +#include "sync_api_curl_defaults.h" /** @@ -62,10 +64,187 @@ struct SYNC_DownloadOperation */ void *cb_cls; + /** + * Public key of the account we are downloading from. + */ + struct SYNC_AccountPublicKeyP account_pub; + + /** + * Signature returned in the "Sync-Signature" + * header, or all zeros for none. + */ + struct SYNC_AccountSignatureP account_sig; + + /** + * Hash code returned by the server in the + * "Sync-Previous" header, or all zeros for + * none. + */ + struct GNUNET_HashCode sync_previous; + }; /** + * Function called when we're done processing the + * HTTP /backup request. + * + * @param cls the `struct SYNC_DownloadOperation` + * @param response_code HTTP response code, 0 on error + * @param response + */ +static void +handle_download_finished (void *cls, + long response_code, + const void *data, + size_t data_size) +{ + struct SYNC_DownloadOperation *download = cls; + + download->job = NULL; + switch (response_code) + { + case 0: + break; + case MHD_HTTP_OK: + { + struct SYNC_DownloadDetails dd; + struct SYNC_UploadSignaturePS usp; + + usp.purpose.purpose = htonl (TALER_SIGNATURE_SYNC_BACKUP_UPLOAD); + usp.purpose.size = htonl (sizeof (usp)); + usp.old_backup_hash = download->sync_previous; + GNUNET_CRYPTO_hash (data, + data_size, + &usp.new_backup_hash); + if (GNUNET_OK != + GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_SYNC_BACKUP_UPLOAD, + &usp.purpose, + &download->account_sig.eddsa_sig, + &download->account_pub.eddsa_pub)) + { + GNUNET_break_op (0); + response_code = 0; + break; + } + /* Success, call callback with all details! */ + memset (&dd, 0, sizeof (dd)); + dd.sig = download->account_sig; + dd.prev_backup_hash = download->sync_previous; + dd.curr_backup_hash = usp.new_backup_hash; + dd.backup = data; + dd.backup_size = data_size; + download->cb (download->cb_cls, + response_code, + &dd); + download->cb = NULL; + SYNC_download_cancel (download); + return; + } + case MHD_HTTP_BAD_REQUEST: + /* This should never happen, either us or the sync server is buggy + (or API version conflict); just pass JSON reply to the application */ + break; + case MHD_HTTP_NOT_FOUND: + /* Nothing really to verify */ + break; + case MHD_HTTP_INTERNAL_SERVER_ERROR: + /* Server had an internal issue; we should retry, but this API + leaves this to the application */ + break; + default: + /* unexpected response code */ + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected response code %u\n", + (unsigned int) response_code); + GNUNET_break (0); + response_code = 0; + break; + } + if (NULL != download->cb) + { + download->cb (download->cb_cls, + response_code, + NULL); + download->cb = NULL; + } + SYNC_download_cancel (download); +} + + +/** + * Handle HTTP header received by curl. + * + * @param buffer one line of HTTP header data + * @param size size of an item + * @param nitems number of items passed + * @param userdata our `struct SYNC_DownloadOperation *` + * @return `size * nitems` + */ +static size_t +handle_header (char *buffer, + size_t size, + size_t nitems, + void *userdata) +{ + struct SYNC_DownloadOperation *download = userdata; + size_t total = size * nitems; + char *ndup; + const char *hdr_type; + char *hdr_val; + + ndup = GNUNET_strndup (buffer, + total); + hdr_type = strtok (ndup, + ":"); + if (NULL == hdr_type) + { + GNUNET_free (ndup); + return total; + } + hdr_val = strtok (NULL, + ""); + if (NULL == hdr_val) + { + GNUNET_free (ndup); + return total; + } + if (' ' == *hdr_val) + hdr_val++; + if (0 == strcasecmp (hdr_type, + "Sync-Signature")) + { + if (GNUNET_OK != + GNUNET_STRINGS_string_to_data (hdr_val, + strlen (hdr_val), + &download->account_sig, + sizeof (struct SYNC_AccountSignatureP))) + { + GNUNET_break_op (0); + GNUNET_free (ndup); + return 0; + } + } + if (0 == strcasecmp (hdr_type, + "Sync-Previous")) + { + if (GNUNET_OK != + GNUNET_STRINGS_string_to_data (hdr_val, + strlen (hdr_val), + &download->sync_previous, + sizeof (struct GNUNET_HashCode))) + { + GNUNET_break_op (0); + GNUNET_free (ndup); + return 0; + } + } + GNUNET_free (ndup); + return total; +} + + +/** * Download the latest version of a backup for account @a pub. * * @param ctx for HTTP client request processing @@ -82,8 +261,39 @@ SYNC_download (struct GNUNET_CURL_Context *ctx, SYNC_DownloadCallback cb, void *cb_cls) { - GNUNET_break (0); - return NULL; + struct SYNC_DownloadOperation *download; + char *pub_str; + CURL *eh; + + download = GNUNET_new (struct SYNC_DownloadOperation); + download->account_pub = *pub; + pub_str = GNUNET_STRINGS_data_to_string_alloc (pub, + sizeof (*pub)); + GNUNET_asprintf (&download->url, + "%s%sbackup/%s", + base_url, + '/' == base_url[strlen (base_url) - 1] + ? "" + : "/", + pub_str); + GNUNET_free (pub_str); + eh = SYNC_curl_easy_get_ (download->url); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_HEADERFUNCTION, + &handle_header)); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_HEADERDATA, + download)); + download->cb = cb; + download->cb_cls = cb_cls; + download->job = GNUNET_CURL_job_add_raw (ctx, + eh, + GNUNET_NO, + &handle_download_finished, + download); + return download; } @@ -95,6 +305,13 @@ SYNC_download (struct GNUNET_CURL_Context *ctx, void SYNC_download_cancel (struct SYNC_DownloadOperation *download) { + if (NULL != download->job) + { + GNUNET_CURL_job_cancel (download->job); + download->job = NULL; + } + GNUNET_free (download->url); + GNUNET_free (download); } diff --git a/src/sync/sync-httpd_mhd.c b/src/sync/sync-httpd_mhd.c index 75f2a63..f7449a5 100644 --- a/src/sync/sync-httpd_mhd.c +++ b/src/sync/sync-httpd_mhd.c @@ -85,4 +85,4 @@ SH_MHD_handler_agpl_redirect (struct SH_RequestHandler *rh, } -/* end of taler-exchange-httpd_mhd.c */ +/* end of sync-httpd_mhd.c */ |