ruby-libstorj 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (92) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/.gitmodules +3 -0
  4. data/.rspec +1 -0
  5. data/Gemfile +23 -0
  6. data/Gemfile.lock +111 -0
  7. data/Guardfile +21 -0
  8. data/LICENSE +502 -0
  9. data/README.md +262 -0
  10. data/Rakefile +76 -0
  11. data/ext/libstorj/.gitignore +47 -0
  12. data/ext/libstorj/.travis.yml +27 -0
  13. data/ext/libstorj/Doxyfile +2427 -0
  14. data/ext/libstorj/LICENSE +502 -0
  15. data/ext/libstorj/Makefile.am +6 -0
  16. data/ext/libstorj/README.md +198 -0
  17. data/ext/libstorj/autogen.sh +3 -0
  18. data/ext/libstorj/configure.ac +64 -0
  19. data/ext/libstorj/depends/Makefile +153 -0
  20. data/ext/libstorj/depends/config.guess +1462 -0
  21. data/ext/libstorj/depends/config.sub +1823 -0
  22. data/ext/libstorj/depends/extract-osx-sdk.sh +33 -0
  23. data/ext/libstorj/depends/packages/cctools.mk +7 -0
  24. data/ext/libstorj/depends/packages/clang.mk +7 -0
  25. data/ext/libstorj/depends/packages/gmp.mk +23 -0
  26. data/ext/libstorj/depends/packages/gnutls.mk +25 -0
  27. data/ext/libstorj/depends/packages/json-c.mk +7 -0
  28. data/ext/libstorj/depends/packages/libcurl.mk +39 -0
  29. data/ext/libstorj/depends/packages/libmicrohttpd.mk +7 -0
  30. data/ext/libstorj/depends/packages/libuv.mk +7 -0
  31. data/ext/libstorj/depends/packages/nettle.mk +30 -0
  32. data/ext/libstorj/libstorj.pc.in +11 -0
  33. data/ext/libstorj/src/Makefile.am +23 -0
  34. data/ext/libstorj/src/bip39.c +233 -0
  35. data/ext/libstorj/src/bip39.h +64 -0
  36. data/ext/libstorj/src/bip39_english.h +2074 -0
  37. data/ext/libstorj/src/cli.c +1494 -0
  38. data/ext/libstorj/src/crypto.c +525 -0
  39. data/ext/libstorj/src/crypto.h +178 -0
  40. data/ext/libstorj/src/downloader.c +1923 -0
  41. data/ext/libstorj/src/downloader.h +163 -0
  42. data/ext/libstorj/src/http.c +688 -0
  43. data/ext/libstorj/src/http.h +175 -0
  44. data/ext/libstorj/src/rs.c +962 -0
  45. data/ext/libstorj/src/rs.h +99 -0
  46. data/ext/libstorj/src/storj.c +1523 -0
  47. data/ext/libstorj/src/storj.h +1014 -0
  48. data/ext/libstorj/src/uploader.c +2736 -0
  49. data/ext/libstorj/src/uploader.h +181 -0
  50. data/ext/libstorj/src/utils.c +336 -0
  51. data/ext/libstorj/src/utils.h +65 -0
  52. data/ext/libstorj/test/Makefile.am +27 -0
  53. data/ext/libstorj/test/mockbridge.c +260 -0
  54. data/ext/libstorj/test/mockbridge.json +687 -0
  55. data/ext/libstorj/test/mockbridgeinfo.json +1836 -0
  56. data/ext/libstorj/test/mockfarmer.c +358 -0
  57. data/ext/libstorj/test/storjtests.h +41 -0
  58. data/ext/libstorj/test/tests.c +1617 -0
  59. data/ext/libstorj/test/tests_rs.c +869 -0
  60. data/ext/ruby-libstorj/extconf.rb +8 -0
  61. data/ext/ruby-libstorj/ruby-libstorj.cc +17 -0
  62. data/lib/ruby-libstorj.rb +1 -0
  63. data/lib/ruby-libstorj/arg_forwarding_task.rb +58 -0
  64. data/lib/ruby-libstorj/env.rb +178 -0
  65. data/lib/ruby-libstorj/ext/bucket.rb +71 -0
  66. data/lib/ruby-libstorj/ext/create_bucket_request.rb +53 -0
  67. data/lib/ruby-libstorj/ext/curl_code.rb +139 -0
  68. data/lib/ruby-libstorj/ext/ext.rb +71 -0
  69. data/lib/ruby-libstorj/ext/file.rb +84 -0
  70. data/lib/ruby-libstorj/ext/get_bucket_request.rb +45 -0
  71. data/lib/ruby-libstorj/ext/json_request.rb +51 -0
  72. data/lib/ruby-libstorj/ext/list_files_request.rb +63 -0
  73. data/lib/ruby-libstorj/ext/types.rb +226 -0
  74. data/lib/ruby-libstorj/ext/upload_options.rb +38 -0
  75. data/lib/ruby-libstorj/libstorj.rb +22 -0
  76. data/lib/ruby-libstorj/mixins/storj.rb +27 -0
  77. data/lib/ruby-libstorj/struct.rb +42 -0
  78. data/ruby-libstorj.gemspec +57 -0
  79. data/spec/helpers/options.yml.example +22 -0
  80. data/spec/helpers/shared_rake_examples.rb +132 -0
  81. data/spec/helpers/storj_options.rb +96 -0
  82. data/spec/helpers/upload.data +3 -0
  83. data/spec/helpers/upload.data.sha256 +1 -0
  84. data/spec/libstorj_spec.rb +0 -0
  85. data/spec/ruby-libstorj/arg_forwarding_task_spec.rb +311 -0
  86. data/spec/ruby-libstorj/env_spec.rb +353 -0
  87. data/spec/ruby-libstorj/ext_spec.rb +75 -0
  88. data/spec/ruby-libstorj/json_request_spec.rb +13 -0
  89. data/spec/ruby-libstorj/libstorj_spec.rb +81 -0
  90. data/spec/ruby-libstorj/struct_spec.rb +64 -0
  91. data/spec/spec_helper.rb +113 -0
  92. metadata +136 -0
@@ -0,0 +1,178 @@
1
+ /**
2
+ * @file crypto.h
3
+ * @brief Storj crypto utilities.
4
+ *
5
+ * Helper crypto utilities
6
+ */
7
+ #ifndef STORJ_CRYPTO_H
8
+ #define STORJ_CRYPTO_H
9
+
10
+ #include <nettle/aes.h>
11
+ #include <nettle/ripemd160.h>
12
+ #include <nettle/hmac.h>
13
+ #include <nettle/pbkdf2.h>
14
+ #include <nettle/sha.h>
15
+ #include <nettle/ctr.h>
16
+ #include <nettle/gcm.h>
17
+ #include <nettle/base64.h>
18
+
19
+ #include "bip39.h"
20
+ #include "utils.h"
21
+
22
+ #define DETERMINISTIC_KEY_SIZE 64
23
+ #define DETERMINISTIC_KEY_HEX_SIZE 32
24
+ #define BUCKET_NAME_MAGIC "398734aab3c4c30c9f22590e83a95f7e43556a45fc2b3060e0c39fde31f50272"
25
+
26
+ static const uint8_t BUCKET_META_MAGIC[32] = {66,150,71,16,50,114,88,160,163,35,154,65,162,213,226,215,70,138,57,61,52,19,210,170,38,164,162,200,86,201,2,81};
27
+
28
+ int sha256_of_str(const uint8_t *str, int str_len, uint8_t *digest);
29
+
30
+ int sha512_of_str(const uint8_t *str, int str_len, uint8_t *digest);
31
+
32
+ int ripemd160_of_str(const uint8_t *str, int str_len, uint8_t *digest);
33
+
34
+ int ripemd160sha256(uint8_t *data, uint64_t data_size, uint8_t *digest);
35
+
36
+ int ripemd160sha256_as_string(uint8_t *data, uint64_t data_size, char *digest);
37
+
38
+ int double_ripemd160sha256(uint8_t *data, uint64_t data_size, uint8_t *digest);
39
+
40
+ int double_ripemd160sha256_as_string(uint8_t *data, uint64_t data_size,
41
+ char **digest);
42
+
43
+ void pbkdf2_hmac_sha512(unsigned key_length,
44
+ const uint8_t *key,
45
+ unsigned iterations,
46
+ unsigned salt_length, const uint8_t *salt,
47
+ unsigned length, uint8_t *dst);
48
+
49
+ /**
50
+ * @brief Generate a bucket's key
51
+ *
52
+ * @param[in] Character array of the mnemonic
53
+ * @param[in] bucket_id Character array of bucket id
54
+ * @param[out] bucket_key 64 byte character array that is the bucket's key
55
+ * @return A non-zero error value on failure and 0 on success.
56
+ */
57
+ int generate_bucket_key(const char *mnemonic, const char *bucket_id,
58
+ char **bucket_key);
59
+
60
+ /**
61
+ * @brief Generate a file's key
62
+ *
63
+ * @param[in] Character array of the mnemonic
64
+ * @param[in] bucket_id Character array of bucket id
65
+ * @param[in] index Character array of index
66
+ * @param[out] file_key 64 byte character array that is the bucket's key
67
+ * @return A non-zero error value on failure and 0 on success.
68
+ */
69
+ int generate_file_key(const char *mnemonic,
70
+ const char *bucket_id,
71
+ const char *index,
72
+ char **file_key);
73
+
74
+ /**
75
+ * @brief Calculate deterministic key by getting sha512 of key + id
76
+ *
77
+ * @param[in] Character array of the key
78
+ * @param[in] key_len Integer value of length of key
79
+ * @param[in] id Character array id
80
+ * @param[out] buffer 64 byte character array of the deterministic key
81
+ * @return A non-zero error value on failure and 0 on success.
82
+ */
83
+ int get_deterministic_key(const char *key, int key_len,
84
+ const char *id, char **buffer);
85
+
86
+ /**
87
+ * @brief Increment the iv for ctr decryption/encryption
88
+ *
89
+ * This function will modify iv and increment the counter based
90
+ * on the bytes position and the AES block size, useful for decrypting
91
+ * shards asynchronously.
92
+ *
93
+ * The iv must be 16 bytes, the AES block size, and the bytes_position
94
+ * must a multiple of 16.
95
+ *
96
+ * @param[out] iv The ctr/iv to be incremented
97
+ * @return A non-zero value on failure
98
+ */
99
+ int increment_ctr_aes_iv(uint8_t *iv, uint64_t bytes_position);
100
+
101
+ /**
102
+ * @brief Will derive an encryption key from passhrase
103
+ *
104
+ * Will use PBKDF2 to generate an encryption key from the passphrase.
105
+ *
106
+ * @param[in] passphrase - The passhrase
107
+ * @param[in] salt - The salt used in the key derivation function
108
+ * @return A key or NULL on failure.
109
+ */
110
+ uint8_t *key_from_passphrase(const char *passphrase, const char *salt);
111
+
112
+ /**
113
+ * @brief Will encrypt data with passphrase
114
+ *
115
+ * Data is encrypted using AES-256-CTR with a key generated from a key
116
+ * derivation function with the passphrase.
117
+ *
118
+ * @param[in] passphrase - The passhrase used to encrypt the data
119
+ * @param[in] salt - The salt used in the key derivation function
120
+ * @param[in] data - The data to be encrypted
121
+ * @param[out] result - The encrypted data encoded as hex string
122
+ * @return A non-zero error value on failure and 0 on success.
123
+ */
124
+ int encrypt_data(const char *passphrase,
125
+ const char *salt,
126
+ const char *data,
127
+ char **result);
128
+
129
+ /**
130
+ * @brief Will decrypt data with passphrase
131
+ *
132
+ * Data is decrypted using AES-256-CTR with a key generated from a key
133
+ * derivation function with the passphrase.
134
+ *
135
+ * @param[in] passphrase - The passhrase used to encrypt the data
136
+ * @param[in] salt - The salt used in the key derivation function
137
+ * @param[in] data - The hex string of encoded data
138
+ * @param[out] result - The decrypted data
139
+ */
140
+ int decrypt_data(const char *passphrase,
141
+ const char *salt,
142
+ const char *data,
143
+ char **result);
144
+
145
+ /**
146
+ * @brief Will encrypt file meta
147
+ *
148
+ * This will encrypt file meta information using AES-256-GCM. The
149
+ * resulting buffer will concat digest, iv and cipher text as base54
150
+ * null terminated string.
151
+ *
152
+ * @param[in] filemeta - The null terminated filename
153
+ * @param[in] encrypt_key - The key used to encrypt the file meta (32 bytes)
154
+ * @param[in] encrypt_iv - The iv to use for encryption (32 bytes)
155
+ * @param[out] buffer_base64 - The base64 encoded encrypted data including
156
+ * digest, iv and cipher text
157
+ * @return A non-zero value on error, zero on success.
158
+ */
159
+ int encrypt_meta(const char *filemeta,
160
+ uint8_t *encrypt_key,
161
+ uint8_t *encrypt_iv,
162
+ char **buffer_base64);
163
+
164
+ /**
165
+ * @brief Will decrypt file meta
166
+ *
167
+ * This will decrypt file meta information.
168
+ *
169
+ * @param[in] buffer_base64 - The base64 encrypted data
170
+ * @param[in] decrypt_key - The key used to decrypt the file (32 bytes)
171
+ * @param[out] filemeta - The null terminated filename
172
+ * @return A non-zero value on error, zero on success.
173
+ */
174
+ int decrypt_meta(const char *buffer_base64,
175
+ uint8_t *decrypt_key,
176
+ char **filemeta);
177
+
178
+ #endif /* STORJ_CRYPTO_H */
@@ -0,0 +1,1923 @@
1
+ #include "downloader.h"
2
+
3
+ static void free_exchange_report(storj_exchange_report_t *report)
4
+ {
5
+ free(report->data_hash);
6
+ free(report->reporter_id);
7
+ free(report->farmer_id);
8
+ free(report->client_id);
9
+ free(report);
10
+ }
11
+
12
+ static void free_download_state(storj_download_state_t *state)
13
+ {
14
+ for (int i = 0; i < state->total_pointers; i++) {
15
+ storj_pointer_t *pointer = &state->pointers[i];
16
+
17
+ free(pointer->token);
18
+ free(pointer->shard_hash);
19
+ free(pointer->farmer_id);
20
+ free(pointer->farmer_address);
21
+
22
+ free_exchange_report(pointer->report);
23
+ }
24
+
25
+ if (state->excluded_farmer_ids) {
26
+ free(state->excluded_farmer_ids);
27
+ }
28
+
29
+ if (state->decrypt_key) {
30
+ memset_zero(state->decrypt_key, SHA256_DIGEST_SIZE);
31
+ free(state->decrypt_key);
32
+ }
33
+
34
+ if (state->decrypt_ctr) {
35
+ memset_zero(state->decrypt_ctr, AES_BLOCK_SIZE);
36
+ free(state->decrypt_ctr);
37
+ }
38
+
39
+ if (state->info) {
40
+ if (state->info->erasure) {
41
+ free((char *)state->info->erasure);
42
+ }
43
+ free((char *)state->info->hmac);
44
+ free(state->info);
45
+ }
46
+
47
+ if (state->hmac) {
48
+ free((char *)state->hmac);
49
+ }
50
+
51
+ free(state->pointers);
52
+ free(state);
53
+ }
54
+
55
+ static void request_pointers(uv_work_t *work)
56
+ {
57
+ json_request_download_t *req = work->data;
58
+ storj_download_state_t *state = req->state;
59
+
60
+ int status_code = 0;
61
+ int request_status = fetch_json(req->http_options, req->options, req->method,
62
+ req->path, req->body, req->auth,
63
+ &req->response, &status_code);
64
+
65
+
66
+ if (request_status) {
67
+ state->log->warn(state->env->log_options, state->handle,
68
+ "Request pointers error: %i", request_status);
69
+ }
70
+
71
+ req->status_code = status_code;
72
+
73
+ if (!req->response) {
74
+ req->status_code = -1;
75
+ }
76
+
77
+ }
78
+
79
+ static void request_replace_pointer(uv_work_t *work)
80
+ {
81
+ json_request_replace_pointer_t *req = work->data;
82
+ storj_download_state_t *state = req->state;
83
+
84
+ int status_code = 0;
85
+
86
+ int excluded_farmer_ids_len = (req->excluded_farmer_ids) ? strlen(req->excluded_farmer_ids) : 0;
87
+ char query_args[BUFSIZ];
88
+ memset(query_args, '\0', BUFSIZ);
89
+ snprintf(query_args, BUFSIZ,
90
+ "?limit=1&skip=%i&exclude=%s",
91
+ req->pointer_index,
92
+ req->excluded_farmer_ids);
93
+
94
+ int path_len = 9 + strlen(req->bucket_id) + 7 +
95
+ strlen(req->file_id) + strlen(query_args);
96
+ char *path = calloc(path_len + 1, sizeof(char));
97
+ if (!path) {
98
+ req->error_status = STORJ_MEMORY_ERROR;
99
+ return;
100
+ }
101
+
102
+ strcat(path, "/buckets/");
103
+ strcat(path, req->bucket_id);
104
+ strcat(path, "/files/");
105
+ strcat(path, req->file_id);
106
+ strcat(path, query_args);
107
+
108
+ int request_status = fetch_json(req->http_options, req->options, "GET",
109
+ path, NULL, true,
110
+ &req->response, &status_code);
111
+
112
+ if (request_status) {
113
+ state->log->warn(state->env->log_options, state->handle,
114
+ "Request replace pointer error: %i", request_status);
115
+ }
116
+
117
+ req->status_code = status_code;
118
+
119
+ if (!req->response) {
120
+ req->status_code = -1;
121
+ }
122
+
123
+ free(path);
124
+
125
+ }
126
+
127
+ static void set_pointer_from_json(storj_download_state_t *state,
128
+ storj_pointer_t *p,
129
+ struct json_object *json,
130
+ bool is_replaced)
131
+ {
132
+ if (!json_object_is_type(json, json_type_object)) {
133
+ state->error_status = STORJ_BRIDGE_JSON_ERROR;
134
+ return;
135
+ }
136
+
137
+ struct json_object *token_value;
138
+ char *token = NULL;
139
+ if (json_object_object_get_ex(json, "token", &token_value)) {
140
+ token = (char *)json_object_get_string(token_value);
141
+ }
142
+
143
+ struct json_object *hash_value;
144
+ if (!json_object_object_get_ex(json, "hash", &hash_value)) {
145
+ state->error_status = STORJ_BRIDGE_JSON_ERROR;
146
+ return;
147
+ }
148
+ char *hash = (char *)json_object_get_string(hash_value);
149
+
150
+ struct json_object *size_value;
151
+ if (!json_object_object_get_ex(json, "size", &size_value)) {
152
+ state->error_status = STORJ_BRIDGE_JSON_ERROR;
153
+ return;
154
+ }
155
+ uint64_t size = json_object_get_int64(size_value);
156
+
157
+ struct json_object *parity_value;
158
+ bool parity = false;
159
+ if (json_object_object_get_ex(json, "parity", &parity_value)) {
160
+ parity = json_object_get_boolean(parity_value);
161
+ }
162
+
163
+ struct json_object *index_value;
164
+ if (!json_object_object_get_ex(json, "index", &index_value)) {
165
+ state->error_status = STORJ_BRIDGE_JSON_ERROR;
166
+ return;
167
+ }
168
+ uint32_t index = json_object_get_int(index_value);
169
+
170
+ struct json_object *farmer_value;
171
+ char *address = NULL;
172
+ uint32_t port = 0;
173
+ char *farmer_id = NULL;
174
+ if (json_object_object_get_ex(json, "farmer", &farmer_value) &&
175
+ json_object_is_type(farmer_value, json_type_object)) {
176
+
177
+ struct json_object *address_value;
178
+ if (!json_object_object_get_ex(farmer_value, "address",
179
+ &address_value)) {
180
+ state->error_status = STORJ_BRIDGE_JSON_ERROR;
181
+ return;
182
+ }
183
+ address = (char *)json_object_get_string(address_value);
184
+
185
+ struct json_object *port_value;
186
+ if (!json_object_object_get_ex(farmer_value, "port", &port_value)) {
187
+ state->error_status = STORJ_BRIDGE_JSON_ERROR;
188
+ return;
189
+ }
190
+ port = json_object_get_int(port_value);
191
+
192
+ struct json_object *farmer_id_value;
193
+ if (!json_object_object_get_ex(farmer_value, "nodeID",
194
+ &farmer_id_value)) {
195
+ state->error_status = STORJ_BRIDGE_JSON_ERROR;
196
+ return;
197
+ }
198
+ farmer_id = (char *)json_object_get_string(farmer_id_value);
199
+ }
200
+
201
+ if (is_replaced) {
202
+ p->replace_count += 1;
203
+ } else {
204
+ p->replace_count = 0;
205
+ }
206
+
207
+ // Check to see if we have a token for this shard, otherwise
208
+ // we will immediatly move this shard to POINTER_MISSING
209
+ // so that it can be retried and possibly recovered.
210
+ if (address && token) {
211
+ // reset the status
212
+ p->status = POINTER_CREATED;
213
+ } else {
214
+ state->log->warn(state->env->log_options,
215
+ state->handle,
216
+ "Missing shard %s at index %i",
217
+ hash,
218
+ index);
219
+ p->status = POINTER_MISSING;
220
+ }
221
+
222
+ p->size = size;
223
+ p->parity = parity;
224
+ p->downloaded_size = 0;
225
+ p->index = index;
226
+ p->farmer_port = port;
227
+
228
+ if (is_replaced) {
229
+ free(p->token);
230
+ free(p->shard_hash);
231
+ free(p->farmer_address);
232
+ free(p->farmer_id);
233
+ }
234
+ if (token) {
235
+ p->token = strdup(token);
236
+ } else {
237
+ p->token = NULL;
238
+ }
239
+ p->shard_hash = strdup(hash);
240
+ if (address) {
241
+ p->farmer_address = strdup(address);
242
+ } else {
243
+ p->farmer_address = NULL;
244
+ }
245
+ if (farmer_id) {
246
+ p->farmer_id = strdup(farmer_id);
247
+ } else {
248
+ p->farmer_id = NULL;
249
+ }
250
+
251
+ // setup exchange report values
252
+ if (is_replaced) {
253
+ free_exchange_report(p->report);
254
+ }
255
+ p->report = malloc(
256
+ sizeof(storj_exchange_report_t));
257
+
258
+ if (!p->report) {
259
+ state->error_status = STORJ_MEMORY_ERROR;
260
+ return;
261
+ }
262
+
263
+ const char *client_id = state->env->bridge_options->user;
264
+ p->report->reporter_id = strdup(client_id);
265
+ p->report->client_id = strdup(client_id);
266
+ p->report->data_hash = strdup(hash);
267
+ if (farmer_id) {
268
+ p->report->farmer_id = strdup(farmer_id);
269
+ } else {
270
+ p->report->farmer_id = NULL;
271
+ }
272
+ p->report->send_status = 0; // not sent
273
+ p->report->send_count = 0;
274
+
275
+ // these values will be changed in after_request_shard
276
+ p->report->start = 0;
277
+ p->report->end = 0;
278
+ p->report->code = STORJ_REPORT_FAILURE;
279
+ p->report->message = STORJ_REPORT_DOWNLOAD_ERROR;
280
+
281
+ p->work = NULL;
282
+
283
+ if (!state->shard_size) {
284
+ // TODO make sure all except last shard is the same size
285
+ state->shard_size = size;
286
+ state->log->debug(state->env->log_options,
287
+ state->handle,
288
+ "Shard size set to %" PRIu64,
289
+ state->shard_size);
290
+ };
291
+ }
292
+
293
+ static void append_pointers_to_state(storj_download_state_t *state,
294
+ struct json_object *res)
295
+ {
296
+ int length = json_object_array_length(res);
297
+
298
+ if (length == 0) {
299
+ state->log->debug(state->env->log_options,
300
+ state->handle,
301
+ "Finished requesting pointers");
302
+ state->pointers_completed = true;
303
+ } else if (length > 0) {
304
+
305
+ int prev_total_pointers = state->total_pointers;
306
+ int total_pointers = state->total_pointers + length;
307
+
308
+ if (state->total_pointers > 0) {
309
+ state->pointers = realloc(state->pointers,
310
+ total_pointers * sizeof(storj_pointer_t));
311
+ } else {
312
+ state->pointers = malloc(length * sizeof(storj_pointer_t) * 100);
313
+ }
314
+ if (!state->pointers) {
315
+ state->error_status = STORJ_MEMORY_ERROR;
316
+ return;
317
+ }
318
+
319
+ state->total_pointers = total_pointers;
320
+ state->total_shards = total_pointers;
321
+
322
+ for (int i = 0; i < length; i++) {
323
+
324
+ // get the relative index
325
+ int j = i + prev_total_pointers;
326
+
327
+ struct json_object *json = json_object_array_get_idx(res, i);
328
+
329
+ set_pointer_from_json(state, &state->pointers[j], json, false);
330
+
331
+ // Keep track of the number of data and parity pointers
332
+ storj_pointer_t *pointer = &state->pointers[j];
333
+ if (pointer->parity) {
334
+ state->total_parity_pointers += 1;
335
+ }
336
+ }
337
+ }
338
+
339
+ }
340
+
341
+ static void after_request_pointers(uv_work_t *work, int status)
342
+ {
343
+ json_request_download_t *req = work->data;
344
+ storj_download_state_t *state = req->state;
345
+
346
+ state->pending_work_count--;
347
+ state->requesting_pointers = false;
348
+
349
+ if (req->response) {
350
+ state->log->debug(state->env->log_options, state->handle,
351
+ "Finished request pointers - JSON Response %s",
352
+ json_object_to_json_string(req->response));
353
+ }
354
+
355
+ if (status != 0) {
356
+
357
+ state->error_status = STORJ_BRIDGE_POINTER_ERROR;
358
+
359
+ } else if (req->status_code == 429 || req->status_code == 420) {
360
+
361
+ state->error_status = STORJ_BRIDGE_RATE_ERROR;
362
+
363
+ } else if (req->status_code != 200) {
364
+ if (req->status_code > 0 && req->status_code < 500) {
365
+ state->error_status = STORJ_BRIDGE_POINTER_ERROR;
366
+ } else {
367
+ state->pointer_fail_count += 1;
368
+ }
369
+
370
+ state->log->debug(state->env->log_options, state->handle,
371
+ "Request pointers fail count: %i",
372
+ state->pointer_fail_count);
373
+
374
+ if (state->pointer_fail_count >= STORJ_MAX_POINTER_TRIES) {
375
+ state->pointer_fail_count = 0;
376
+ state->error_status = STORJ_BRIDGE_POINTER_ERROR;
377
+ }
378
+
379
+ } else if (!json_object_is_type(req->response, json_type_array)) {
380
+ state->error_status = STORJ_BRIDGE_JSON_ERROR;
381
+ } else {
382
+ append_pointers_to_state(state, req->response);
383
+ }
384
+
385
+ queue_next_work(state);
386
+
387
+ if (req->response) {
388
+ json_object_put(req->response);
389
+ }
390
+ free(req->path);
391
+ free(req);
392
+ free(work);
393
+ }
394
+
395
+ static void after_request_replace_pointer(uv_work_t *work, int status)
396
+ {
397
+ json_request_replace_pointer_t *req = work->data;
398
+ storj_download_state_t *state = req->state;
399
+
400
+ state->pending_work_count--;
401
+ state->requesting_pointers = false;
402
+
403
+ state->log->debug(state->env->log_options, state->handle,
404
+ "Finished request replace pointer %i - JSON Response: %s",
405
+ req->pointer_index,
406
+ json_object_to_json_string(req->response));
407
+
408
+ if (status != 0) {
409
+
410
+ state->error_status = STORJ_BRIDGE_REPOINTER_ERROR;
411
+
412
+ } else if (req->error_status) {
413
+
414
+ state->error_status = req->error_status;
415
+
416
+ } else if (req->status_code == 429 || req->status_code == 420) {
417
+
418
+ state->error_status = STORJ_BRIDGE_RATE_ERROR;
419
+
420
+ } else if (req->status_code != 200) {
421
+
422
+ if (req->status_code > 0 && req->status_code < 500) {
423
+ state->pointers[req->pointer_index].status = POINTER_MISSING;
424
+ } else {
425
+ // Update status so that it will be retried
426
+ state->pointers[req->pointer_index].status = POINTER_ERROR_REPORTED;
427
+ state->pointer_fail_count += 1;
428
+ }
429
+
430
+ state->log->debug(state->env->log_options, state->handle,
431
+ "Request replace pointer fail count: %i",
432
+ state->pointer_fail_count);
433
+
434
+ if (state->pointer_fail_count >= STORJ_MAX_POINTER_TRIES) {
435
+ // Skip retrying mark as missing
436
+ state->pointer_fail_count = 0;
437
+ state->pointers[req->pointer_index].status = POINTER_MISSING;
438
+ }
439
+
440
+ } else if (!json_object_is_type(req->response, json_type_array)) {
441
+ state->error_status = STORJ_BRIDGE_JSON_ERROR;
442
+ } else {
443
+ struct json_object *json = json_object_array_get_idx(req->response, 0);
444
+
445
+ set_pointer_from_json(state,
446
+ &state->pointers[req->pointer_index],
447
+ json,
448
+ true);
449
+
450
+ if (state->pointers[req->pointer_index].index != req->pointer_index) {
451
+
452
+ state->log->error(state->env->log_options,
453
+ state->handle,
454
+ "Replacement shard index %i does not match %i",
455
+ state->pointers[req->pointer_index].index,
456
+ req->pointer_index);
457
+
458
+ state->error_status = STORJ_BRIDGE_JSON_ERROR;
459
+ }
460
+ }
461
+
462
+ queue_next_work(state);
463
+
464
+ json_object_put(req->response);
465
+ free(work->data);
466
+ free(work);
467
+ }
468
+
469
+ static void queue_request_pointers(storj_download_state_t *state)
470
+ {
471
+ if (state->requesting_pointers || state->canceled) {
472
+ return;
473
+ }
474
+
475
+ // queue request to replace pointer if any pointers have failure
476
+ for (int i = 0; i < state->total_pointers; i++) {
477
+
478
+ storj_pointer_t *pointer = &state->pointers[i];
479
+
480
+ if (pointer->replace_count >= STORJ_DEFAULT_MIRRORS) {
481
+ state->log->warn(state->env->log_options,
482
+ state->handle,
483
+ "Unable to download shard %s at index %i",
484
+ pointer->shard_hash,
485
+ pointer->index);
486
+ pointer->replace_count = 0;
487
+ pointer->status = POINTER_MISSING;
488
+ return;
489
+ }
490
+
491
+ if (pointer->status == POINTER_ERROR_REPORTED) {
492
+
493
+ // exclude this farmer id from future requests
494
+ state->log->debug(state->env->log_options,
495
+ state->handle,
496
+ "Adding farmer_id %s to excluded list",
497
+ pointer->report->farmer_id);
498
+
499
+ if (!state->excluded_farmer_ids) {
500
+ state->excluded_farmer_ids = calloc(42, sizeof(char));
501
+ if (!state->excluded_farmer_ids) {
502
+ state->error_status = STORJ_MEMORY_ERROR;
503
+ return;
504
+ }
505
+ strcat(state->excluded_farmer_ids, pointer->report->farmer_id);
506
+ } else {
507
+ state->excluded_farmer_ids =
508
+ realloc(state->excluded_farmer_ids,
509
+ strlen(state->excluded_farmer_ids) + 42);
510
+ if (!state->excluded_farmer_ids) {
511
+ state->error_status = STORJ_MEMORY_ERROR;
512
+ return;
513
+ }
514
+ strcat(state->excluded_farmer_ids, ",");
515
+ strcat(state->excluded_farmer_ids, pointer->report->farmer_id);
516
+ }
517
+
518
+ json_request_replace_pointer_t *req =
519
+ malloc(sizeof(json_request_replace_pointer_t));
520
+ if (!req) {
521
+ state->error_status = STORJ_MEMORY_ERROR;
522
+ return;
523
+ }
524
+
525
+ req->pointer_index = i;
526
+
527
+ req->http_options = state->env->http_options;
528
+ req->options = state->env->bridge_options;
529
+ req->bucket_id = state->bucket_id;
530
+ req->file_id = state->file_id;
531
+ req->state = state;
532
+ req->excluded_farmer_ids = state->excluded_farmer_ids;
533
+ req->error_status = 0;
534
+ req->response = NULL;
535
+ req->status_code = 0;
536
+
537
+ uv_work_t *work = malloc(sizeof(uv_work_t));
538
+ if (!work) {
539
+ state->error_status = STORJ_MEMORY_ERROR;
540
+ return;
541
+ }
542
+ work->data = req;
543
+
544
+ state->log->info(state->env->log_options,
545
+ state->handle,
546
+ "Requesting replacement pointer at index: %i",
547
+ req->pointer_index);
548
+
549
+ state->pending_work_count++;
550
+ int status = uv_queue_work(state->env->loop,
551
+ (uv_work_t*) work,
552
+ request_replace_pointer,
553
+ after_request_replace_pointer);
554
+
555
+ if (status) {
556
+ state->error_status = STORJ_QUEUE_ERROR;
557
+ return;
558
+ }
559
+
560
+ pointer->status = POINTER_BEING_REPLACED;
561
+
562
+ // we're done until the next pass
563
+ state->requesting_pointers = true;
564
+ return;
565
+ }
566
+
567
+ }
568
+
569
+ // only request the next set of pointers if we're not finished
570
+ if (state->pointers_completed) {
571
+ return;
572
+ }
573
+
574
+ json_request_download_t *req = malloc(sizeof(json_request_download_t));
575
+ if (!req) {
576
+ state->error_status = STORJ_MEMORY_ERROR;
577
+ return;
578
+ }
579
+
580
+ char query_args[BUFSIZ];
581
+ memset(query_args, '\0', BUFSIZ);
582
+ snprintf(query_args, BUFSIZ, "?limit=3&skip=%d", state->total_pointers);
583
+
584
+ int path_len = 9 + strlen(state->bucket_id) + 7 +
585
+ strlen(state->file_id) + strlen(query_args);
586
+
587
+ char *path = calloc(path_len + 1, sizeof(char));
588
+ if (!path) {
589
+ state->error_status = STORJ_MEMORY_ERROR;
590
+ return;
591
+ }
592
+ strcat(path, "/buckets/");
593
+ strcat(path, state->bucket_id);
594
+ strcat(path, "/files/");
595
+ strcat(path, state->file_id);
596
+ strcat(path, query_args);
597
+
598
+ req->http_options = state->env->http_options;
599
+ req->options = state->env->bridge_options;
600
+ req->method = "GET";
601
+ req->path = path;
602
+ req->body = NULL;
603
+ req->auth = true;
604
+
605
+ req->state = state;
606
+
607
+ uv_work_t *work = malloc(sizeof(uv_work_t));
608
+ if (!work) {
609
+ state->error_status = STORJ_MEMORY_ERROR;
610
+ return;
611
+ }
612
+ work->data = req;
613
+
614
+ state->log->info(state->env->log_options,
615
+ state->handle,
616
+ "Requesting next set of pointers, total pointers: %i",
617
+ state->total_pointers);
618
+
619
+ state->pending_work_count++;
620
+ int status = uv_queue_work(state->env->loop, (uv_work_t*) work,
621
+ request_pointers, after_request_pointers);
622
+
623
+ if (status) {
624
+ state->error_status = STORJ_QUEUE_ERROR;
625
+ return;
626
+ }
627
+
628
+ state->requesting_pointers = true;
629
+ }
630
+
631
+ static void request_shard(uv_work_t *work)
632
+ {
633
+ shard_request_download_t *req = work->data;
634
+
635
+ int status_code;
636
+ int write_code = 0;
637
+
638
+ req->start = get_time_milliseconds();
639
+
640
+ uint64_t file_position = req->pointer_index * req->state->shard_size;
641
+
642
+ int error_status = fetch_shard(req->http_options,
643
+ req->farmer_id,
644
+ req->farmer_proto,
645
+ req->farmer_host,
646
+ req->farmer_port,
647
+ req->shard_hash,
648
+ req->shard_total_bytes,
649
+ req->token,
650
+ req->state->destination,
651
+ file_position,
652
+ &status_code,
653
+ &write_code,
654
+ &req->progress_handle,
655
+ req->canceled);
656
+
657
+ req->end = get_time_milliseconds();
658
+
659
+ if (write_code != 0) {
660
+ req->state->log->error(req->state->env->log_options, req->state->handle,
661
+ "Put shard read error: %i", write_code);
662
+ }
663
+
664
+ if (error_status) {
665
+ req->error_status = error_status;
666
+ } else if (status_code != 200) {
667
+ switch(status_code) {
668
+ case 401:
669
+ case 403:
670
+ req->error_status = STORJ_FARMER_AUTH_ERROR;
671
+ break;
672
+ case 504:
673
+ req->error_status = STORJ_FARMER_TIMEOUT_ERROR;
674
+ break;
675
+ default:
676
+ req->error_status = STORJ_FARMER_REQUEST_ERROR;
677
+ }
678
+ } else {
679
+ req->error_status = 0;
680
+ }
681
+ }
682
+
683
+ static void free_request_shard_work(uv_handle_t *progress_handle)
684
+ {
685
+ uv_work_t *work = progress_handle->data;
686
+ shard_request_download_t *req = work->data;
687
+
688
+ free(req);
689
+ free(work);
690
+ }
691
+
692
+ static uint64_t calculate_data_filesize(storj_download_state_t *state)
693
+ {
694
+ uint64_t total_bytes = 0;
695
+
696
+ for (int i = 0; i < state->total_pointers; i++) {
697
+ storj_pointer_t *pointer = &state->pointers[i];
698
+ if (pointer->parity) {
699
+ continue;
700
+ }
701
+ total_bytes += pointer->size;
702
+ }
703
+
704
+ return total_bytes;
705
+ }
706
+
707
+ static void report_progress(storj_download_state_t *state)
708
+ {
709
+ uint64_t downloaded_bytes = 0;
710
+ uint64_t total_bytes = 0;
711
+
712
+ for (int i = 0; i < state->total_pointers; i++) {
713
+
714
+ storj_pointer_t *pointer = &state->pointers[i];
715
+
716
+ downloaded_bytes += pointer->downloaded_size;
717
+ total_bytes += pointer->size;
718
+ }
719
+
720
+ double total_progress = (double)downloaded_bytes / (double)total_bytes;
721
+
722
+ state->progress_cb(total_progress,
723
+ downloaded_bytes,
724
+ total_bytes,
725
+ state->handle);
726
+ }
727
+
728
+ static void after_request_shard(uv_work_t *work, int status)
729
+ {
730
+ shard_request_download_t *req = work->data;
731
+
732
+ req->state->pending_work_count--;
733
+ req->state->resolving_shards -= 1;
734
+
735
+ uv_handle_t *progress_handle = (uv_handle_t *) &req->progress_handle;
736
+
737
+ // free the download progress
738
+ free(progress_handle->data);
739
+
740
+ // assign work so that we can free after progress_handle is closed
741
+ progress_handle->data = work;
742
+
743
+ // update the pointer status
744
+ storj_pointer_t *pointer = &req->state->pointers[req->pointer_index];
745
+
746
+ pointer->report->start = req->start;
747
+ pointer->report->end = req->end;
748
+
749
+ if (req->error_status) {
750
+
751
+ req->state->log->warn(req->state->env->log_options,
752
+ req->state->handle,
753
+ "Error downloading shard: %s, reason: %s",
754
+ req->shard_hash,
755
+ storj_strerror(req->error_status));
756
+
757
+ pointer->status = POINTER_ERROR;
758
+
759
+ switch(req->error_status) {
760
+ case STORJ_FARMER_INTEGRITY_ERROR:
761
+ pointer->report->code = STORJ_REPORT_FAILURE;
762
+ pointer->report->message = STORJ_REPORT_FAILED_INTEGRITY;
763
+ default:
764
+ pointer->report->code = STORJ_REPORT_FAILURE;
765
+ pointer->report->message = STORJ_REPORT_DOWNLOAD_ERROR;
766
+ }
767
+
768
+ } else {
769
+
770
+ req->state->log->info(req->state->env->log_options,
771
+ req->state->handle,
772
+ "Finished downloading shard: %s",
773
+ req->shard_hash);
774
+
775
+ pointer->report->code = STORJ_REPORT_SUCCESS;
776
+ pointer->report->message = STORJ_REPORT_SHARD_DOWNLOADED;
777
+ pointer->status = POINTER_DOWNLOADED;
778
+
779
+ // Make sure the downloaded size is updated
780
+ pointer->downloaded_size = pointer->size;
781
+
782
+ report_progress(req->state);
783
+
784
+ }
785
+
786
+ queue_next_work(req->state);
787
+
788
+ // close the async progress handle
789
+ uv_close(progress_handle, free_request_shard_work);
790
+ }
791
+
792
+ static void progress_request_shard(uv_async_t* async)
793
+ {
794
+ shard_download_progress_t *progress = async->data;
795
+
796
+ storj_download_state_t *state = progress->state;
797
+
798
+ state->pointers[progress->pointer_index].downloaded_size = progress->bytes;
799
+
800
+ report_progress(state);
801
+ }
802
+
803
+ static void queue_request_shards(storj_download_state_t *state)
804
+ {
805
+ if (state->canceled) {
806
+ return;
807
+ }
808
+
809
+ int i = 0;
810
+
811
+ while (state->resolving_shards < state->download_max_concurrency &&
812
+ i < state->total_pointers) {
813
+
814
+ storj_pointer_t *pointer = &state->pointers[i];
815
+
816
+ if (pointer->status == POINTER_CREATED) {
817
+ shard_request_download_t *req = malloc(sizeof(shard_request_download_t));
818
+ if (!req) {
819
+ state->error_status = STORJ_MEMORY_ERROR;
820
+ return;
821
+ }
822
+
823
+ req->http_options = state->env->http_options;
824
+ req->farmer_id = pointer->farmer_id;
825
+ req->farmer_proto = "http";
826
+ req->farmer_host = pointer->farmer_address;
827
+ req->farmer_port = pointer->farmer_port;
828
+ req->shard_hash = pointer->shard_hash;
829
+ req->shard_total_bytes = pointer->size;
830
+ req->byte_position = state->shard_size * i;
831
+ req->token = pointer->token;
832
+ req->error_status = 0;
833
+
834
+ req->pointer_index = pointer->index;
835
+
836
+ req->state = state;
837
+ req->canceled = &state->canceled;
838
+
839
+ uv_work_t *work = malloc(sizeof(uv_work_t));
840
+ if (!work) {
841
+ state->error_status = STORJ_MEMORY_ERROR;
842
+ return;
843
+ }
844
+
845
+ work->data = req;
846
+
847
+ state->resolving_shards += 1;
848
+ pointer->status = POINTER_BEING_DOWNLOADED;
849
+ pointer->work = work;
850
+
851
+ state->log->info(state->env->log_options,
852
+ state->handle,
853
+ "Queue request shard: %s",
854
+ req->shard_hash);
855
+
856
+ // setup download progress reporting
857
+ shard_download_progress_t *progress =
858
+ malloc(sizeof(shard_download_progress_t));
859
+ if (!progress) {
860
+ state->error_status = STORJ_MEMORY_ERROR;
861
+ return;
862
+ }
863
+
864
+ progress->pointer_index = pointer->index;
865
+ progress->bytes = 0;
866
+ progress->state = state;
867
+
868
+ req->progress_handle.data = progress;
869
+
870
+ uv_async_init(state->env->loop, &req->progress_handle,
871
+ progress_request_shard);
872
+
873
+ // queue download
874
+ state->pending_work_count++;
875
+ int status = uv_queue_work(state->env->loop, (uv_work_t*) work,
876
+ request_shard, after_request_shard);
877
+ if (status) {
878
+ state->error_status = STORJ_QUEUE_ERROR;
879
+ return;
880
+ }
881
+ }
882
+
883
+ i++;
884
+ }
885
+ }
886
+
887
+ static void send_exchange_report(uv_work_t *work)
888
+ {
889
+ shard_send_report_t *req = work->data;
890
+ storj_download_state_t *state = req->state;
891
+
892
+ struct json_object *body = json_object_new_object();
893
+
894
+ json_object_object_add(body, "dataHash",
895
+ json_object_new_string(req->report->data_hash));
896
+
897
+ json_object_object_add(body, "reporterId",
898
+ json_object_new_string(req->report->reporter_id));
899
+
900
+ json_object_object_add(body, "farmerId",
901
+ json_object_new_string(req->report->farmer_id));
902
+
903
+ json_object_object_add(body, "clientId",
904
+ json_object_new_string(req->report->client_id));
905
+
906
+ json_object_object_add(body, "exchangeStart",
907
+ json_object_new_int64(req->report->start));
908
+
909
+ json_object_object_add(body, "exchangeEnd",
910
+ json_object_new_int64(req->report->end));
911
+
912
+ json_object_object_add(body, "exchangeResultCode",
913
+ json_object_new_int(req->report->code));
914
+
915
+ json_object_object_add(body, "exchangeResultMessage",
916
+ json_object_new_string(req->report->message));
917
+
918
+ int status_code = 0;
919
+
920
+ // there should be an empty object in response
921
+ struct json_object *response = NULL;
922
+ int request_status = fetch_json(req->http_options,
923
+ req->options, "POST",
924
+ "/reports/exchanges", body,
925
+ true, &response, &status_code);
926
+
927
+
928
+ if (request_status) {
929
+ state->log->warn(state->env->log_options, state->handle,
930
+ "Send exchange report error: %i", request_status);
931
+ }
932
+
933
+ req->status_code = status_code;
934
+
935
+ // free all memory for body and response
936
+ if (response) {
937
+ json_object_put(response);
938
+ }
939
+ json_object_put(body);
940
+ }
941
+
942
+ static void after_send_exchange_report(uv_work_t *work, int status)
943
+ {
944
+ shard_send_report_t *req = work->data;
945
+
946
+ req->state->pending_work_count--;
947
+
948
+ // set status so that this pointer can be replaced
949
+ if (req->report->send_count >= STORJ_MAX_REPORT_TRIES ||
950
+ req->status_code == 201) {
951
+
952
+ storj_pointer_t *pointer = &req->state->pointers[req->pointer_index];
953
+
954
+ if (pointer->status == POINTER_ERROR) {
955
+ pointer->status = POINTER_ERROR_REPORTED;
956
+ }
957
+ }
958
+
959
+ if (req->status_code == 201) {
960
+ // set the status so that this pointer can be replaced
961
+ req->report->send_status = 2; // report has been sent
962
+ } else {
963
+ req->report->send_status = 0; // reset report back to unsent
964
+ }
965
+
966
+ queue_next_work(req->state);
967
+
968
+ free(work->data);
969
+ free(work);
970
+
971
+ }
972
+
973
+ static void queue_send_exchange_reports(storj_download_state_t *state)
974
+ {
975
+
976
+ if (state->canceled) {
977
+ return;
978
+ }
979
+
980
+ for (int i = 0; i < state->total_pointers; i++) {
981
+
982
+ storj_pointer_t *pointer = &state->pointers[i];
983
+
984
+ if (pointer->report->send_status < 1 &&
985
+ pointer->report->send_count < STORJ_MAX_REPORT_TRIES &&
986
+ pointer->report->start > 0 &&
987
+ pointer->report->end > 0) {
988
+
989
+ uv_work_t *work = malloc(sizeof(uv_work_t));
990
+ if (!work) {
991
+ state->error_status = STORJ_MEMORY_ERROR;
992
+ return;
993
+ }
994
+
995
+ shard_send_report_t *req = malloc(sizeof(shard_send_report_t));
996
+ if (!req) {
997
+ state->error_status = STORJ_MEMORY_ERROR;
998
+ return;
999
+ }
1000
+
1001
+ req->http_options = state->env->http_options;
1002
+ req->options = state->env->bridge_options;
1003
+ req->status_code = 0;
1004
+ req->report = pointer->report;
1005
+ req->report->send_status = 1; // being reported
1006
+ req->report->send_count += 1;
1007
+ req->state = state;
1008
+ req->pointer_index = i;
1009
+
1010
+ work->data = req;
1011
+
1012
+ state->pending_work_count++;
1013
+ int status = uv_queue_work(state->env->loop, (uv_work_t*) work,
1014
+ send_exchange_report,
1015
+ after_send_exchange_report);
1016
+ if (status) {
1017
+ state->error_status = STORJ_QUEUE_ERROR;
1018
+ return;
1019
+ }
1020
+ }
1021
+ }
1022
+ }
1023
+
1024
+ static void determine_decryption_key_v1(storj_download_state_t *state)
1025
+ {
1026
+ uint8_t *index = NULL;
1027
+ char *file_key_as_str = NULL;
1028
+
1029
+ file_key_as_str = calloc(DETERMINISTIC_KEY_SIZE + 1, sizeof(char));
1030
+ if (!file_key_as_str) {
1031
+ state->error_status = STORJ_MEMORY_ERROR;
1032
+ goto cleanup;
1033
+ }
1034
+
1035
+ if (generate_file_key(state->env->encrypt_options->mnemonic,
1036
+ state->bucket_id,
1037
+ state->info->index, &file_key_as_str)) {
1038
+ state->error_status = STORJ_MEMORY_ERROR;
1039
+ goto cleanup;
1040
+ }
1041
+ file_key_as_str[DETERMINISTIC_KEY_SIZE] = '\0';
1042
+
1043
+ uint8_t *decrypt_key = str2hex(strlen(file_key_as_str), file_key_as_str);
1044
+ if (!decrypt_key) {
1045
+ state->error_status = STORJ_MEMORY_ERROR;
1046
+ goto cleanup;
1047
+ }
1048
+
1049
+ state->decrypt_key = decrypt_key;
1050
+
1051
+ index = str2hex(strlen(state->info->index), (char *)state->info->index);
1052
+ if (!index) {
1053
+ state->error_status = STORJ_MEMORY_ERROR;
1054
+ goto cleanup;
1055
+ }
1056
+
1057
+ uint8_t *decrypt_ctr = calloc(AES_BLOCK_SIZE, sizeof(uint8_t));
1058
+ if (!decrypt_ctr) {
1059
+ state->error_status = STORJ_MEMORY_ERROR;
1060
+ goto cleanup;
1061
+ }
1062
+
1063
+ memcpy(decrypt_ctr, index, AES_BLOCK_SIZE);
1064
+ state->decrypt_ctr = decrypt_ctr;
1065
+
1066
+ cleanup:
1067
+ if (file_key_as_str) {
1068
+ free(file_key_as_str);
1069
+ }
1070
+ if (index) {
1071
+ free(index);
1072
+ }
1073
+ }
1074
+
1075
+ static void determine_decryption_key_v0(storj_download_state_t *state)
1076
+ {
1077
+ char *file_key = calloc(DETERMINISTIC_KEY_SIZE + 1, sizeof(char));
1078
+ if (!file_key) {
1079
+ state->error_status = STORJ_MEMORY_ERROR;
1080
+ return;
1081
+ }
1082
+
1083
+ if (generate_file_key(state->env->encrypt_options->mnemonic,
1084
+ state->bucket_id,
1085
+ state->file_id, &file_key)) {
1086
+ state->error_status = STORJ_MEMORY_ERROR;
1087
+ return;
1088
+ }
1089
+ file_key[DETERMINISTIC_KEY_SIZE] = '\0';
1090
+
1091
+ uint8_t *decrypt_key = calloc(SHA256_DIGEST_SIZE + 1, sizeof(uint8_t));
1092
+ if (!decrypt_key) {
1093
+ state->error_status = STORJ_MEMORY_ERROR;
1094
+ return;
1095
+ }
1096
+
1097
+ sha256_of_str((uint8_t *)file_key, DETERMINISTIC_KEY_SIZE, decrypt_key);
1098
+ decrypt_key[SHA256_DIGEST_SIZE] = '\0';
1099
+
1100
+ memset_zero(file_key, DETERMINISTIC_KEY_SIZE + 1);
1101
+ free(file_key);
1102
+
1103
+ state->decrypt_key = decrypt_key;
1104
+
1105
+ uint8_t *file_id_hash = calloc(RIPEMD160_DIGEST_SIZE + 1, sizeof(uint8_t));
1106
+ if (!file_id_hash) {
1107
+ state->error_status = STORJ_MEMORY_ERROR;
1108
+ return;
1109
+ }
1110
+ ripemd160_of_str((uint8_t *)state->file_id,
1111
+ strlen(state->file_id), file_id_hash);
1112
+ file_id_hash[RIPEMD160_DIGEST_SIZE] = '\0';
1113
+
1114
+ uint8_t *decrypt_ctr = calloc(AES_BLOCK_SIZE, sizeof(uint8_t));
1115
+ if (!decrypt_ctr) {
1116
+ state->error_status = STORJ_MEMORY_ERROR;
1117
+ return;
1118
+ }
1119
+ memcpy(decrypt_ctr, file_id_hash, AES_BLOCK_SIZE);
1120
+
1121
+ free(file_id_hash);
1122
+
1123
+ state->decrypt_ctr = decrypt_ctr;
1124
+ }
1125
+
1126
+ static void determine_decryption_key(storj_download_state_t *state)
1127
+ {
1128
+ if (!state->env->encrypt_options ||
1129
+ !state->env->encrypt_options->mnemonic) {
1130
+
1131
+ state->decrypt_key = NULL;
1132
+ state->decrypt_ctr = NULL;
1133
+ } else {
1134
+ if (state->info->index) {
1135
+ // calculate decryption key based on the index
1136
+ determine_decryption_key_v1(state);
1137
+ } else {
1138
+ // calculate decryption key based on the file_id
1139
+ determine_decryption_key_v0(state);
1140
+ }
1141
+ };
1142
+ }
1143
+
1144
+ static void after_request_info(uv_work_t *work, int status)
1145
+ {
1146
+ file_info_request_t *req = work->data;
1147
+
1148
+ req->state->pending_work_count--;
1149
+ req->state->requesting_info = false;
1150
+
1151
+ if (status != 0) {
1152
+ req->state->error_status = STORJ_BRIDGE_FILEINFO_ERROR;
1153
+ } else if (req->status_code == 200 || req->status_code == 304) {
1154
+ req->state->info = req->info;
1155
+ if (req->info->erasure) {
1156
+ if (strcmp(req->info->erasure, "reedsolomon") == 0) {
1157
+ req->state->rs = true;
1158
+ req->state->truncated = false;
1159
+ } else {
1160
+ req->state->error_status = STORJ_FILE_UNSUPPORTED_ERASURE;
1161
+ }
1162
+ }
1163
+
1164
+ // Now that we have info we can calculate the decryption key
1165
+ determine_decryption_key(req->state);
1166
+
1167
+ } else if (req->error_status) {
1168
+ switch(req->error_status) {
1169
+ case STORJ_BRIDGE_REQUEST_ERROR:
1170
+ case STORJ_BRIDGE_INTERNAL_ERROR:
1171
+ req->state->info_fail_count += 1;
1172
+ break;
1173
+ default:
1174
+ req->state->error_status = req->error_status;
1175
+ break;
1176
+ }
1177
+ if (req->state->info_fail_count >= STORJ_MAX_INFO_TRIES) {
1178
+ req->state->info_fail_count = 0;
1179
+ req->state->error_status = req->error_status;
1180
+ }
1181
+ } else {
1182
+ req->state->error_status = STORJ_BRIDGE_FILEINFO_ERROR;
1183
+ }
1184
+
1185
+ queue_next_work(req->state);
1186
+
1187
+ free(req);
1188
+ free(work);
1189
+
1190
+ }
1191
+
1192
+ static void request_info(uv_work_t *work)
1193
+ {
1194
+ file_info_request_t *req = work->data;
1195
+ storj_download_state_t *state = req->state;
1196
+
1197
+ int path_len = 9 + strlen(req->bucket_id) + 7 + strlen(req->file_id) + 5;
1198
+ char *path = calloc(path_len + 1, sizeof(char));
1199
+ if (!path) {
1200
+ req->error_status = STORJ_MEMORY_ERROR;
1201
+ return;
1202
+ }
1203
+
1204
+ strcat(path, "/buckets/");
1205
+ strcat(path, req->bucket_id);
1206
+ strcat(path, "/files/");
1207
+ strcat(path, req->file_id);
1208
+ strcat(path, "/info");
1209
+
1210
+ int status_code = 0;
1211
+ struct json_object *response = NULL;
1212
+ int request_status = fetch_json(req->http_options,
1213
+ req->options,
1214
+ "GET",
1215
+ path,
1216
+ NULL,
1217
+ true,
1218
+ &response,
1219
+ &status_code);
1220
+
1221
+ req->status_code = status_code;
1222
+
1223
+ state->log->debug(state->env->log_options,
1224
+ state->handle,
1225
+ "fn[request_info] - JSON Response: %s",
1226
+ json_object_to_json_string(response));
1227
+
1228
+ if (request_status) {
1229
+ req->error_status = STORJ_BRIDGE_REQUEST_ERROR;
1230
+ state->log->warn(state->env->log_options, state->handle,
1231
+ "Request file info error: %i", request_status);
1232
+
1233
+ } else if (status_code == 200 || status_code == 304) {
1234
+
1235
+ req->info = malloc(sizeof(storj_file_meta_t));
1236
+ req->info->created = NULL;
1237
+ req->info->filename = NULL;
1238
+ req->info->mimetype = NULL;
1239
+ req->info->erasure = NULL;
1240
+ req->info->size = 0;
1241
+ req->info->hmac = NULL;
1242
+ req->info->id = NULL;
1243
+ req->info->decrypted = false;
1244
+ req->info->index = NULL;
1245
+
1246
+ struct json_object *erasure_obj;
1247
+ struct json_object *erasure_value;
1248
+ char *erasure = NULL;
1249
+ if (json_object_object_get_ex(response, "erasure", &erasure_obj)) {
1250
+ if (json_object_object_get_ex(erasure_obj, "type", &erasure_value)) {
1251
+ erasure = (char *)json_object_get_string(erasure_value);
1252
+ } else {
1253
+ state->log->warn(state->env->log_options, state->handle,
1254
+ "value missing from erasure response");
1255
+ }
1256
+ }
1257
+
1258
+ if (erasure) {
1259
+ req->info->erasure = strdup(erasure);
1260
+ }
1261
+
1262
+ struct json_object *index_value;
1263
+ char *index = NULL;
1264
+ if (json_object_object_get_ex(response, "index", &index_value)) {
1265
+ index = (char *)json_object_get_string(index_value);
1266
+ }
1267
+
1268
+ if (index) {
1269
+ req->info->index = strdup(index);
1270
+ }
1271
+
1272
+ struct json_object *hmac_obj;
1273
+ if (!json_object_object_get_ex(response, "hmac", &hmac_obj)) {
1274
+ state->log->warn(state->env->log_options, state->handle,
1275
+ "hmac missing from response");
1276
+ goto clean_up;
1277
+ }
1278
+ if (!json_object_is_type(hmac_obj, json_type_object)) {
1279
+ state->log->warn(state->env->log_options, state->handle,
1280
+ "hmac not an object");
1281
+ goto clean_up;
1282
+ }
1283
+
1284
+ // check the type of hmac
1285
+ struct json_object *hmac_type;
1286
+ if (!json_object_object_get_ex(hmac_obj, "type", &hmac_type)) {
1287
+ state->log->warn(state->env->log_options, state->handle,
1288
+ "hmac.type missing from response");
1289
+ goto clean_up;
1290
+ }
1291
+ if (!json_object_is_type(hmac_type, json_type_string)) {
1292
+ state->log->warn(state->env->log_options, state->handle,
1293
+ "hmac.type not a string");
1294
+ goto clean_up;
1295
+ }
1296
+ char *hmac_type_str = (char *)json_object_get_string(hmac_type);
1297
+ if (0 != strcmp(hmac_type_str, "sha512")) {
1298
+ state->log->warn(state->env->log_options, state->handle,
1299
+ "hmac.type is unknown");
1300
+ goto clean_up;
1301
+ }
1302
+
1303
+ // get the hmac value
1304
+ struct json_object *hmac_value;
1305
+ if (!json_object_object_get_ex(hmac_obj, "value", &hmac_value)) {
1306
+ state->log->warn(state->env->log_options, state->handle,
1307
+ "hmac.value missing from response");
1308
+ goto clean_up;
1309
+ }
1310
+ if (!json_object_is_type(hmac_value, json_type_string)) {
1311
+ state->log->warn(state->env->log_options, state->handle,
1312
+ "hmac.value not a string");
1313
+ goto clean_up;
1314
+ }
1315
+ char *hmac = (char *)json_object_get_string(hmac_value);
1316
+ req->info->hmac = strdup(hmac);
1317
+
1318
+ } else if (status_code == 403 || status_code == 401) {
1319
+ req->error_status = STORJ_BRIDGE_AUTH_ERROR;
1320
+ } else if (status_code == 404 || status_code == 400) {
1321
+ req->error_status = STORJ_BRIDGE_FILE_NOTFOUND_ERROR;
1322
+ } else if (status_code == 500) {
1323
+ req->error_status = STORJ_BRIDGE_INTERNAL_ERROR;
1324
+ } else {
1325
+ req->error_status = STORJ_BRIDGE_REQUEST_ERROR;
1326
+ }
1327
+
1328
+ clean_up:
1329
+ if (response) {
1330
+ json_object_put(response);
1331
+ }
1332
+ free(path);
1333
+ }
1334
+
1335
+ static void queue_request_info(storj_download_state_t *state)
1336
+ {
1337
+ if (state->requesting_info || state->canceled) {
1338
+ return;
1339
+ }
1340
+
1341
+ uv_work_t *work = malloc(sizeof(uv_work_t));
1342
+ if (!work) {
1343
+ state->error_status = STORJ_MEMORY_ERROR;
1344
+ return;
1345
+ }
1346
+
1347
+ state->requesting_info = true;
1348
+
1349
+ file_info_request_t *req = malloc(sizeof(file_info_request_t));
1350
+ req->http_options = state->env->http_options;
1351
+ req->options = state->env->bridge_options;
1352
+ req->status_code = 0;
1353
+ req->bucket_id = state->bucket_id;
1354
+ req->file_id = state->file_id;
1355
+ req->error_status = 0;
1356
+ req->info = NULL;
1357
+ req->state = state;
1358
+
1359
+ work->data = req;
1360
+
1361
+ state->pending_work_count++;
1362
+ int status = uv_queue_work(state->env->loop, (uv_work_t*) work,
1363
+ request_info,
1364
+ after_request_info);
1365
+ if (status) {
1366
+ state->error_status = STORJ_QUEUE_ERROR;
1367
+ return;
1368
+ }
1369
+
1370
+ }
1371
+
1372
+ static int prepare_file_hmac(storj_download_state_t *state)
1373
+ {
1374
+ // initialize the hmac with the decrypt key
1375
+ struct hmac_sha512_ctx hmac_ctx;
1376
+ hmac_sha512_set_key(&hmac_ctx, SHA256_DIGEST_SIZE, state->decrypt_key);
1377
+
1378
+ for (int i = 0; i < state->total_pointers; i++) {
1379
+
1380
+ storj_pointer_t *pointer = &state->pointers[i];
1381
+
1382
+ if (!pointer->shard_hash ||
1383
+ strlen(pointer->shard_hash) != RIPEMD160_DIGEST_SIZE * 2) {
1384
+ return 1;
1385
+ }
1386
+
1387
+ struct base16_decode_ctx base16_ctx;
1388
+ base16_decode_init(&base16_ctx);
1389
+
1390
+ size_t decode_len = 0;
1391
+ uint8_t hash[RIPEMD160_DIGEST_SIZE];
1392
+ if (!base16_decode_update(&base16_ctx,
1393
+ &decode_len,
1394
+ hash,
1395
+ RIPEMD160_DIGEST_SIZE * 2,
1396
+ (uint8_t *)pointer->shard_hash)) {
1397
+ return 1;
1398
+
1399
+ }
1400
+ if (!base16_decode_final(&base16_ctx) ||
1401
+ decode_len != RIPEMD160_DIGEST_SIZE) {
1402
+ return 1;
1403
+ }
1404
+ hmac_sha512_update(&hmac_ctx, RIPEMD160_DIGEST_SIZE, hash);
1405
+ }
1406
+
1407
+ uint8_t digest_raw[SHA512_DIGEST_SIZE];
1408
+ hmac_sha512_digest(&hmac_ctx, SHA512_DIGEST_SIZE, digest_raw);
1409
+
1410
+ size_t digest_len = BASE16_ENCODE_LENGTH(SHA512_DIGEST_SIZE);
1411
+ state->hmac = calloc(digest_len + 1, sizeof(char));
1412
+ if (!state->hmac) {
1413
+ return 1;
1414
+ }
1415
+
1416
+ base16_encode_update((uint8_t *)state->hmac, SHA512_DIGEST_SIZE, digest_raw);
1417
+
1418
+ return 0;
1419
+ }
1420
+
1421
+ static bool has_missing_shard(storj_download_state_t *state)
1422
+ {
1423
+ bool missing = false;
1424
+ for (int i = 0; i < state->total_pointers; i++) {
1425
+ storj_pointer_t *pointer = &state->pointers[i];
1426
+ if (pointer->status == POINTER_MISSING) {
1427
+ missing = true;
1428
+ }
1429
+ }
1430
+ return missing;
1431
+ }
1432
+
1433
+ static bool can_recover_shards(storj_download_state_t *state)
1434
+ {
1435
+ if (state->pointers_completed) {
1436
+ uint32_t missing_pointers = 0;
1437
+
1438
+ for (int i = 0; i < state->total_pointers; i++) {
1439
+ storj_pointer_t *pointer = &state->pointers[i];
1440
+ if (pointer->status == POINTER_MISSING) {
1441
+ missing_pointers += 1;
1442
+ }
1443
+ }
1444
+
1445
+ if (missing_pointers > state->total_parity_pointers) {
1446
+ return false;
1447
+ }
1448
+ }
1449
+
1450
+ return true;
1451
+ }
1452
+
1453
+ static void after_recover_shards(uv_work_t *work, int status)
1454
+ {
1455
+ file_request_recover_t *req = work->data;
1456
+ storj_download_state_t *state = req->state;
1457
+
1458
+ state->pending_work_count--;
1459
+ state->recovering_shards = false;
1460
+ state->truncated = true;
1461
+
1462
+ if (status != 0) {
1463
+ req->state->error_status = STORJ_QUEUE_ERROR;
1464
+ } else if (req->error_status) {
1465
+ req->state->error_status = req->error_status;
1466
+ } else {
1467
+ // Recovery was successful and the pointers have been finished
1468
+ for (int i = 0; i < state->total_pointers; i++) {
1469
+ state->pointers[i].status = POINTER_FINISHED;
1470
+ state->completed_shards += 1;
1471
+ }
1472
+ }
1473
+
1474
+ queue_next_work(state);
1475
+
1476
+ memset_zero(req->decrypt_key, SHA256_DIGEST_SIZE);
1477
+ free(req->decrypt_key);
1478
+
1479
+ memset_zero(req->decrypt_ctr, AES_BLOCK_SIZE);
1480
+ free(req->decrypt_ctr);
1481
+
1482
+ free(req->zilch);
1483
+ free(req);
1484
+ free(work);
1485
+ }
1486
+
1487
+ static void recover_shards(uv_work_t *work)
1488
+ {
1489
+ file_request_recover_t *req = work->data;
1490
+ storj_download_state_t *state = req->state;
1491
+ reed_solomon* rs = NULL;
1492
+ uint8_t *data_map = NULL;
1493
+ uint8_t **data_blocks = NULL;
1494
+ uint8_t **fec_blocks = NULL;
1495
+
1496
+ int error = 0;
1497
+
1498
+ struct aes256_ctx ctx;
1499
+ uint64_t bytes_decrypted = 0;
1500
+ size_t len = AES_BLOCK_SIZE * 8;
1501
+
1502
+ // Make sure that the file is the correct size before recovering
1503
+ // shards in case that the last shard is the one being recovered.
1504
+ #ifdef _WIN32
1505
+
1506
+ HANDLE prefile = (HANDLE)_get_osfhandle(req->fd);
1507
+ if (prefile == INVALID_HANDLE_VALUE) {
1508
+ req->error_status = STORJ_FILE_RESIZE_ERROR;
1509
+ return;
1510
+ }
1511
+
1512
+ LARGE_INTEGER presize;
1513
+ presize.HighPart = (uint32_t)((req->filesize & 0xFFFFFFFF00000000LL) >> 32);
1514
+ presize.LowPart = (uint32_t)(req->filesize & 0xFFFFFFFFLL);
1515
+
1516
+ if (!SetFilePointerEx(prefile, presize, 0, FILE_BEGIN)) {
1517
+ req->error_status = STORJ_FILE_RESIZE_ERROR;
1518
+ return;
1519
+ }
1520
+
1521
+ if (!SetEndOfFile(prefile)) {
1522
+ req->error_status = STORJ_FILE_RESIZE_ERROR;
1523
+ return;
1524
+ }
1525
+
1526
+ #else
1527
+ if (ftruncate(req->fd, req->filesize)) {
1528
+ // errno for more details
1529
+ req->error_status = STORJ_FILE_RESIZE_ERROR;
1530
+ }
1531
+ #endif
1532
+
1533
+ error = map_file(req->fd, req->filesize, &data_map, false);
1534
+ if (error) {
1535
+ req->error_status = STORJ_MAPPING_ERROR;
1536
+ goto finish;
1537
+ }
1538
+
1539
+ if (!req->has_missing) {
1540
+ goto decrypt;
1541
+ }
1542
+
1543
+ fec_init();
1544
+
1545
+ rs = reed_solomon_new(req->data_shards, req->parity_shards);
1546
+ if (!rs) {
1547
+ req->error_status = STORJ_MEMORY_ERROR;
1548
+ goto finish;
1549
+ }
1550
+
1551
+ data_blocks = (uint8_t**)malloc(req->data_shards * sizeof(uint8_t *));
1552
+ if (!data_blocks) {
1553
+ req->error_status = STORJ_MEMORY_ERROR;
1554
+ goto finish;
1555
+ }
1556
+
1557
+ fec_blocks = (uint8_t**)malloc(req->parity_shards * sizeof(uint8_t *));
1558
+ if (!fec_blocks) {
1559
+ req->error_status = STORJ_MEMORY_ERROR;
1560
+ goto finish;
1561
+ }
1562
+
1563
+ for (int i = 0; i < req->data_shards; i++) {
1564
+ data_blocks[i] = data_map + i * req->shard_size;
1565
+ }
1566
+
1567
+ for (int i = 0; i < req->parity_shards; i++) {
1568
+ fec_blocks[i] = data_map + (req->data_shards + i) * req->shard_size;
1569
+ }
1570
+
1571
+ uint32_t total_shards = req->data_shards + req->parity_shards;
1572
+
1573
+ state->log->debug(state->env->log_options, state->handle,
1574
+ "Recovering shards, data_shards: %i, " \
1575
+ "parity_shards: %i, shard_size: %" PRIu64 ", " \
1576
+ "file_size: %" PRIu64,
1577
+ req->data_shards,
1578
+ req->parity_shards,
1579
+ req->shard_size,
1580
+ req->data_filesize);
1581
+
1582
+ error = reed_solomon_reconstruct(rs, data_blocks, fec_blocks,
1583
+ req->zilch, total_shards,
1584
+ req->shard_size, req->data_filesize);
1585
+
1586
+ if (error) {
1587
+ req->error_status = STORJ_FILE_RECOVER_ERROR;
1588
+ goto finish;
1589
+ }
1590
+
1591
+
1592
+ decrypt:
1593
+
1594
+ aes256_set_encrypt_key(&ctx, req->decrypt_key);
1595
+
1596
+ while (bytes_decrypted < req->data_filesize) {
1597
+
1598
+ if (bytes_decrypted + len > req->data_filesize) {
1599
+ len = req->data_filesize - bytes_decrypted;
1600
+ }
1601
+
1602
+ ctr_crypt(&ctx, (nettle_cipher_func *)aes256_encrypt,
1603
+ AES_BLOCK_SIZE, req->decrypt_ctr,
1604
+ len,
1605
+ (uint8_t *)data_map + bytes_decrypted,
1606
+ (uint8_t *)data_map + bytes_decrypted);
1607
+
1608
+ bytes_decrypted += len;
1609
+ }
1610
+
1611
+ finish:
1612
+ if (data_map) {
1613
+ error = unmap_file(data_map, req->filesize);
1614
+ if (error) {
1615
+ req->error_status = STORJ_UNMAPPING_ERROR;
1616
+ }
1617
+ }
1618
+
1619
+ if (data_blocks) {
1620
+ free(data_blocks);
1621
+ }
1622
+
1623
+ if (fec_blocks) {
1624
+ free(fec_blocks);
1625
+ }
1626
+
1627
+ if (rs) {
1628
+ reed_solomon_release(rs);
1629
+ }
1630
+
1631
+ #ifdef _WIN32
1632
+
1633
+ HANDLE file = (HANDLE)_get_osfhandle(req->fd);
1634
+ if (file == INVALID_HANDLE_VALUE) {
1635
+ req->error_status = STORJ_FILE_RESIZE_ERROR;
1636
+ return;
1637
+ }
1638
+
1639
+ LARGE_INTEGER size;
1640
+ size.HighPart = (uint32_t)((req->data_filesize & 0xFFFFFFFF00000000LL) >> 32);
1641
+ size.LowPart = (uint32_t)(req->data_filesize & 0xFFFFFFFFLL);
1642
+
1643
+ if (!SetFilePointerEx(file, size, 0, FILE_BEGIN)) {
1644
+ req->error_status = STORJ_FILE_RESIZE_ERROR;
1645
+ return;
1646
+ }
1647
+
1648
+ if (!SetEndOfFile(file)) {
1649
+ req->error_status = STORJ_FILE_RESIZE_ERROR;
1650
+ return;
1651
+ }
1652
+
1653
+ #else
1654
+ if (ftruncate(req->fd, req->data_filesize)) {
1655
+ // errno for more details
1656
+ req->error_status = STORJ_FILE_RESIZE_ERROR;
1657
+ }
1658
+ #endif
1659
+
1660
+ }
1661
+
1662
+ static void queue_recover_shards(storj_download_state_t *state)
1663
+ {
1664
+ if (!state->recovering_shards && state->pointers_completed) {
1665
+
1666
+ int total_missing = 0;
1667
+ bool has_missing = false;
1668
+ bool is_ready = true;
1669
+
1670
+ uint8_t *zilch = (uint8_t *)calloc(1, state->total_pointers);
1671
+
1672
+ for (int i = 0; i < state->total_pointers; i++) {
1673
+ storj_pointer_t *pointer = &state->pointers[i];
1674
+ if (pointer->status == POINTER_MISSING) {
1675
+ total_missing += 1;
1676
+ has_missing = true;
1677
+ zilch[i] = 1;
1678
+ }
1679
+
1680
+ if (pointer->status != POINTER_MISSING &&
1681
+ pointer->status != POINTER_DOWNLOADED) {
1682
+ is_ready = false;
1683
+ state->log->debug(state->env->log_options,
1684
+ state->handle,
1685
+ "Pointer %i not ready with status: %i",
1686
+ i, pointer->status);
1687
+
1688
+ }
1689
+ }
1690
+
1691
+ if (!is_ready) {
1692
+ free(zilch);
1693
+ return;
1694
+ }
1695
+
1696
+ state->log->info(state->env->log_options,
1697
+ state->handle,
1698
+ "Queuing recovery of %i of %i shards",
1699
+ total_missing, state->total_shards);
1700
+
1701
+ file_request_recover_t *req = malloc(sizeof(file_request_recover_t));
1702
+ if (!req) {
1703
+ state->error_status = STORJ_MEMORY_ERROR;
1704
+ return;
1705
+ }
1706
+
1707
+ uv_work_t *work = malloc(sizeof(uv_work_t));
1708
+ if (!work) {
1709
+ state->error_status = STORJ_MEMORY_ERROR;
1710
+ return;
1711
+ }
1712
+
1713
+ req->fd = fileno(state->destination);
1714
+ req->filesize = state->shard_size * state->total_pointers;
1715
+ req->data_filesize = calculate_data_filesize(state);
1716
+ req->data_shards = state->total_pointers - state->total_parity_pointers;
1717
+ req->parity_shards = state->total_parity_pointers;
1718
+ req->shard_size = state->shard_size;
1719
+ req->zilch = zilch;
1720
+ req->has_missing = has_missing;
1721
+
1722
+ if (state->decrypt_key && state->decrypt_ctr) {
1723
+ req->decrypt_key = calloc(SHA256_DIGEST_SIZE, sizeof(uint8_t));
1724
+ if (!req->decrypt_key) {
1725
+ state->error_status = STORJ_MEMORY_ERROR;
1726
+ return;
1727
+ }
1728
+ req->decrypt_ctr = calloc(AES_BLOCK_SIZE, sizeof(uint8_t));
1729
+ if (!req->decrypt_ctr) {
1730
+ state->error_status = STORJ_MEMORY_ERROR;
1731
+ return;
1732
+ }
1733
+ memcpy(req->decrypt_key, state->decrypt_key, SHA256_DIGEST_SIZE);
1734
+ memcpy(req->decrypt_ctr, state->decrypt_ctr, AES_BLOCK_SIZE);
1735
+
1736
+ increment_ctr_aes_iv(req->decrypt_ctr, 0);
1737
+ } else {
1738
+ req->decrypt_key = NULL;
1739
+ req->decrypt_ctr = NULL;
1740
+ }
1741
+
1742
+ req->state = state;
1743
+ req->error_status = 0;
1744
+
1745
+ work->data = req;
1746
+
1747
+ state->pending_work_count++;
1748
+ int status = uv_queue_work(state->env->loop, (uv_work_t*) work,
1749
+ recover_shards, after_recover_shards);
1750
+
1751
+ if (status) {
1752
+ state->error_status = STORJ_QUEUE_ERROR;
1753
+ return;
1754
+ }
1755
+
1756
+ state->recovering_shards = true;
1757
+ }
1758
+ }
1759
+
1760
+ static void queue_next_work(storj_download_state_t *state)
1761
+ {
1762
+ // report any errors
1763
+ if (state->error_status != 0) {
1764
+ if (!state->finished && state->pending_work_count == 0) {
1765
+
1766
+ state->finished = true;
1767
+ state->finished_cb(state->error_status,
1768
+ state->destination,
1769
+ state->handle);
1770
+
1771
+ free_download_state(state);
1772
+ }
1773
+
1774
+ return;
1775
+ }
1776
+
1777
+ // report download complete
1778
+ if (state->pointers_completed &&
1779
+ state->completed_shards == state->total_shards &&
1780
+ state->truncated) {
1781
+
1782
+ if (!state->finished && state->pending_work_count == 0) {
1783
+
1784
+ // calculate the hmac of all shard hashes
1785
+ if (prepare_file_hmac(state)) {
1786
+ state->error_status = STORJ_FILE_GENERATE_HMAC_ERROR;
1787
+ }
1788
+
1789
+ if (state->info && state->info->hmac) {
1790
+ if (0 != strcmp(state->info->hmac, state->hmac)) {
1791
+ state->error_status = STORJ_FILE_DECRYPTION_ERROR;
1792
+ }
1793
+ } else {
1794
+ state->log->warn(state->env->log_options,
1795
+ state->handle,
1796
+ "Unable to verify decryption integrity" \
1797
+ ", missing hmac from file info.");
1798
+ }
1799
+
1800
+ state->finished = true;
1801
+ state->finished_cb(state->error_status, state->destination, state->handle);
1802
+
1803
+ free_download_state(state);
1804
+ return;
1805
+ }
1806
+
1807
+ goto finish_up;
1808
+ }
1809
+
1810
+ queue_request_pointers(state);
1811
+
1812
+ if (!state->info) {
1813
+ queue_request_info(state);
1814
+ }
1815
+
1816
+ if (state->info) {
1817
+ queue_request_shards(state);
1818
+
1819
+ if (state->rs) {
1820
+ if (can_recover_shards(state)) {
1821
+ queue_recover_shards(state);
1822
+ } else {
1823
+ state->error_status = STORJ_FILE_SHARD_MISSING_ERROR;
1824
+ queue_next_work(state);
1825
+ return;
1826
+ }
1827
+ } else {
1828
+ if (!has_missing_shard(state)) {
1829
+ queue_recover_shards(state);
1830
+ } else {
1831
+ state->error_status = STORJ_FILE_SHARD_MISSING_ERROR;
1832
+ queue_next_work(state);
1833
+ return;
1834
+ }
1835
+ }
1836
+ }
1837
+
1838
+ queue_send_exchange_reports(state);
1839
+
1840
+ finish_up:
1841
+
1842
+ state->log->debug(state->env->log_options, state->handle,
1843
+ "Pending work count: %d", state->pending_work_count);
1844
+
1845
+ }
1846
+
1847
+ STORJ_API int storj_bridge_resolve_file_cancel(storj_download_state_t *state)
1848
+ {
1849
+ if (state->canceled) {
1850
+ return 0;
1851
+ }
1852
+
1853
+ state->canceled = true;
1854
+ state->error_status = STORJ_TRANSFER_CANCELED;
1855
+
1856
+ // loop over all pointers, and cancel any that are queued to be downloaded
1857
+ // any downloads that are in-progress will monitor the state->canceled
1858
+ // status and exit when set to true
1859
+ for (int i = 0; i < state->total_pointers; i++) {
1860
+ storj_pointer_t *pointer = &state->pointers[i];
1861
+ if (pointer->status == POINTER_BEING_DOWNLOADED) {
1862
+ uv_cancel((uv_req_t *)pointer->work);
1863
+ }
1864
+ }
1865
+
1866
+ return 0;
1867
+ }
1868
+
1869
+ STORJ_API storj_download_state_t *storj_bridge_resolve_file(storj_env_t *env,
1870
+ const char *bucket_id,
1871
+ const char *file_id,
1872
+ FILE *destination,
1873
+ void *handle,
1874
+ storj_progress_cb progress_cb,
1875
+ storj_finished_download_cb finished_cb)
1876
+ {
1877
+ storj_download_state_t *state = malloc(sizeof(storj_download_state_t));
1878
+ if (!state) {
1879
+ return NULL;
1880
+ }
1881
+
1882
+ // setup download state
1883
+ state->total_bytes = 0;
1884
+ state->info = NULL;
1885
+ state->requesting_info = false;
1886
+ state->info_fail_count = 0;
1887
+ state->env = env;
1888
+ state->file_id = file_id;
1889
+ state->bucket_id = bucket_id;
1890
+ state->destination = destination;
1891
+ state->progress_cb = progress_cb;
1892
+ state->finished_cb = finished_cb;
1893
+ state->finished = false;
1894
+ state->total_shards = 0;
1895
+ state->download_max_concurrency = STORJ_DOWNLOAD_CONCURRENCY;
1896
+ state->completed_shards = 0;
1897
+ state->resolving_shards = 0;
1898
+ state->total_pointers = 0;
1899
+ state->total_parity_pointers = 0;
1900
+ state->rs = false;
1901
+ state->recovering_shards = false;
1902
+ state->truncated = true;
1903
+ state->pointers = NULL;
1904
+ state->pointers_completed = false;
1905
+ state->pointer_fail_count = 0;
1906
+ state->requesting_pointers = false;
1907
+ state->error_status = STORJ_TRANSFER_OK;
1908
+ state->writing = false;
1909
+ state->shard_size = 0;
1910
+ state->excluded_farmer_ids = NULL;
1911
+ state->hmac = NULL;
1912
+ state->pending_work_count = 0;
1913
+ state->canceled = false;
1914
+ state->log = env->log;
1915
+ state->handle = handle;
1916
+ state->decrypt_key = NULL;
1917
+ state->decrypt_ctr = NULL;
1918
+
1919
+ // start download
1920
+ queue_next_work(state);
1921
+
1922
+ return state;
1923
+ }