summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2019-11-24 22:33:58 +0100
committerChristian Grothoff <christian@grothoff.org>2019-11-24 22:33:58 +0100
commitfc9d4a99a1488a6313f661258e455fb8f443a4d1 (patch)
tree7799035f2098de9968f078c4d67aa891231b12d9
parentc4b5ac29367dd1d845c19851504784bdbdbc1fd5 (diff)
downloadsync-fc9d4a99a1488a6313f661258e455fb8f443a4d1.tar.gz
sync-fc9d4a99a1488a6313f661258e455fb8f443a4d1.tar.bz2
sync-fc9d4a99a1488a6313f661258e455fb8f443a4d1.zip
implement sync_api_download
-rw-r--r--src/include/sync_service.h22
-rw-r--r--src/lib/Makefile.am1
-rw-r--r--src/lib/sync_api_download.c221
-rw-r--r--src/sync/sync-httpd_mhd.c2
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 */