ruby-libstorj 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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,2736 @@
1
+ #include "uploader.h"
2
+
3
+ static void print_shard_info(storj_upload_state_t *state, int index) {
4
+ shard_tracker_t *shard = &state->shard[index];
5
+ shard_meta_t *shard_meta = state->shard[index].meta;
6
+ farmer_pointer_t *p = state->shard[index].pointer;
7
+
8
+ printf("\n================\n");
9
+
10
+ printf("Shard index [%d]\n", index);
11
+
12
+ printf("=== Shard Tracker ===\n");
13
+ printf("progress: %d\n", shard->progress);
14
+ printf("push_frame_request_count: %d\n", shard->push_frame_request_count);
15
+ printf("push_shard_request_count: %d\n", shard->push_shard_request_count);
16
+ printf("index: %d\n", shard->index);
17
+ printf("uploaded_size: %"PRIu64"\n", shard->uploaded_size);
18
+
19
+ printf("\n=== Shard Pointer ===\n");
20
+ printf("token: %s\n", p->token);
21
+ printf("farmer_user_agent: %s\n", p->farmer_user_agent);
22
+ printf("farmer_protocol: %s\n", p->farmer_protocol);
23
+ printf("farmer_address: %s\n", p->farmer_address);
24
+ printf("farmer_port: %s\n", p->farmer_port);
25
+ printf("farmer_node_id: %s\n", p->farmer_node_id);
26
+
27
+ printf("\n=== Shard Meta ===\n");
28
+ printf("hash: %s\n", shard_meta->hash);
29
+ printf("index: %d\n", shard_meta->index);
30
+ printf("size: %"PRIu64"\n", shard_meta->size);
31
+ printf("is_parity: %d\n", shard_meta->is_parity);
32
+ for (int i = 0; i < STORJ_SHARD_CHALLENGES; i++ ) {
33
+ printf("Challenge [%d]: %s\n", i, (char *)shard_meta->challenges_as_str[i]);
34
+ }
35
+ for (int i = 0; i < STORJ_SHARD_CHALLENGES; i++ ) {
36
+ printf("Leaf [%d]: %s\n", i, (char *)shard_meta->tree[i]);
37
+ }
38
+
39
+ printf("================\n");
40
+
41
+ return;
42
+
43
+ }
44
+
45
+ static uv_work_t *uv_work_new()
46
+ {
47
+ uv_work_t *work = malloc(sizeof(uv_work_t));
48
+ return work;
49
+ }
50
+
51
+ static uv_work_t *frame_work_new(int *index, storj_upload_state_t *state)
52
+ {
53
+ uv_work_t *work = uv_work_new();
54
+ if (!work) {
55
+ return NULL;
56
+ }
57
+
58
+ frame_request_t *req = malloc(sizeof(frame_request_t));
59
+ if (!req) {
60
+ return NULL;
61
+ }
62
+
63
+ req->http_options = state->env->http_options;
64
+ req->options = state->env->bridge_options;
65
+ req->upload_state = state;
66
+ req->error_status = 0;
67
+ req->status_code = 0;
68
+ req->log = state->log;
69
+
70
+ if (index != NULL) {
71
+ req->shard_meta_index = *index;
72
+ req->farmer_pointer = farmer_pointer_new();
73
+ }
74
+
75
+ work->data = req;
76
+
77
+ return work;
78
+ }
79
+
80
+ static uv_work_t *shard_meta_work_new(int index, storj_upload_state_t *state)
81
+ {
82
+ uv_work_t *work = uv_work_new();
83
+ if (!work) {
84
+ return NULL;
85
+ }
86
+ frame_builder_t *req = malloc(sizeof(frame_builder_t));
87
+ if (!req) {
88
+ return NULL;
89
+ }
90
+ req->shard_meta = malloc(sizeof(shard_meta_t));
91
+ if (!req->shard_meta) {
92
+ return NULL;
93
+ }
94
+ req->upload_state = state;
95
+ req->log = state->log;
96
+
97
+ // make sure we switch between parity and data shards files.
98
+ // When using Reed solomon must also read from encrypted file
99
+ // rather than the original file for the data
100
+ if (index + 1 > state->total_data_shards) {
101
+ req->shard_file = state->parity_file;
102
+ } else if (state->rs) {
103
+ req->shard_file = state->encrypted_file;
104
+ } else {
105
+ req->shard_file = state->original_file;
106
+ }
107
+ // Reset shard index when using parity shards
108
+ req->shard_meta->index = (index + 1 > state->total_data_shards) ? index - state->total_data_shards: index;
109
+
110
+ // Position on shard_meta array
111
+ req->shard_meta_index = index;
112
+
113
+ req->error_status = 0;
114
+ req->status_code = 0;
115
+
116
+ work->data = req;
117
+
118
+ return work;
119
+ }
120
+
121
+ static storj_exchange_report_t *storj_exchange_report_new()
122
+ {
123
+ storj_exchange_report_t *report = malloc(sizeof(storj_exchange_report_t));
124
+ if (!report) {
125
+ return NULL;
126
+ }
127
+ report->data_hash = NULL;
128
+ report->reporter_id = NULL;
129
+ report->farmer_id = NULL;
130
+ report->client_id = NULL;
131
+ report->message = NULL;
132
+
133
+ report->send_status = STORJ_REPORT_NOT_PREPARED; // not sent
134
+ report->start = 0;
135
+ report->end = 0;
136
+ report->code = 0;
137
+ report->send_count = 0;
138
+
139
+ return report;
140
+ }
141
+
142
+ static farmer_pointer_t *farmer_pointer_new()
143
+ {
144
+ farmer_pointer_t *pointer = calloc(sizeof(farmer_pointer_t), sizeof(char));
145
+ if (!pointer) {
146
+ return NULL;
147
+ }
148
+ pointer->token = NULL;
149
+ pointer->farmer_user_agent = NULL;
150
+ pointer->farmer_protocol = NULL;
151
+ pointer->farmer_address = NULL;
152
+ pointer->farmer_port = NULL;
153
+ pointer->farmer_node_id = NULL;
154
+
155
+ return pointer;
156
+ }
157
+
158
+ static shard_meta_t *shard_meta_new()
159
+ {
160
+ shard_meta_t *meta = calloc(sizeof(shard_meta_t), sizeof(char));
161
+ if (!meta) {
162
+ return NULL;
163
+ }
164
+ meta->hash = NULL;
165
+
166
+ return meta;
167
+ }
168
+
169
+ static storj_encryption_ctx_t *prepare_encryption_ctx(uint8_t *ctr, uint8_t *pass)
170
+ {
171
+ storj_encryption_ctx_t *ctx = calloc(sizeof(storj_encryption_ctx_t), sizeof(char));
172
+ if (!ctx) {
173
+ return NULL;
174
+ }
175
+
176
+ ctx->ctx = calloc(sizeof(struct aes256_ctx), sizeof(char));
177
+ if (!ctx->ctx) {
178
+ return NULL;
179
+ }
180
+
181
+ ctx->encryption_ctr = calloc(AES_BLOCK_SIZE, sizeof(char));
182
+ if (!ctx->encryption_ctr) {
183
+ return NULL;
184
+ }
185
+
186
+ memcpy(ctx->encryption_ctr, ctr, AES_BLOCK_SIZE);
187
+
188
+ aes256_set_encrypt_key(ctx->ctx, pass);
189
+
190
+ return ctx;
191
+ }
192
+
193
+ static void shard_meta_cleanup(shard_meta_t *shard_meta)
194
+ {
195
+ if (shard_meta->hash != NULL) {
196
+ free(shard_meta->hash);
197
+ }
198
+
199
+ free(shard_meta);
200
+ }
201
+
202
+ static void pointer_cleanup(farmer_pointer_t *farmer_pointer)
203
+ {
204
+ if (farmer_pointer->token != NULL) {
205
+ free(farmer_pointer->token);
206
+ }
207
+
208
+ if (farmer_pointer->farmer_user_agent != NULL) {
209
+ free(farmer_pointer->farmer_user_agent);
210
+ }
211
+
212
+ if (farmer_pointer->farmer_protocol != NULL) {
213
+ free(farmer_pointer->farmer_protocol);
214
+ }
215
+
216
+ if (farmer_pointer->farmer_address != NULL) {
217
+ free(farmer_pointer->farmer_address);
218
+ }
219
+
220
+ if (farmer_pointer->farmer_port != NULL) {
221
+ free(farmer_pointer->farmer_port);
222
+ }
223
+
224
+ if (farmer_pointer->farmer_node_id != NULL) {
225
+ free(farmer_pointer->farmer_node_id);
226
+ }
227
+
228
+ free(farmer_pointer);
229
+ }
230
+
231
+ static void cleanup_state(storj_upload_state_t *state)
232
+ {
233
+ if (state->final_callback_called) {
234
+ return;
235
+ }
236
+
237
+ if (state->pending_work_count > 0) {
238
+ return;
239
+ }
240
+
241
+ if (state->original_file) {
242
+ fclose(state->original_file);
243
+ }
244
+
245
+ state->final_callback_called = true;
246
+
247
+ if (state->frame_id) {
248
+ free(state->frame_id);
249
+ }
250
+
251
+ if (state->hmac_id) {
252
+ free(state->hmac_id);
253
+ }
254
+
255
+ if (state->encrypted_file_name) {
256
+ free((char *)state->encrypted_file_name);
257
+ }
258
+
259
+ if (state->exclude) {
260
+ free(state->exclude);
261
+ }
262
+
263
+ if (state->encryption_ctr) {
264
+ free(state->encryption_ctr);
265
+ }
266
+
267
+ if (state->encryption_key) {
268
+ free(state->encryption_key);
269
+ }
270
+
271
+ if (state->parity_file) {
272
+ fclose(state->parity_file);
273
+ }
274
+
275
+ if (state->parity_file_path) {
276
+ unlink(state->parity_file_path);
277
+ free(state->parity_file_path);
278
+ }
279
+
280
+ if (state->encrypted_file) {
281
+ fclose(state->encrypted_file);
282
+ }
283
+
284
+ if (state->encrypted_file_path) {
285
+ unlink(state->encrypted_file_path);
286
+ free(state->encrypted_file_path);
287
+ }
288
+
289
+ if (state->index) {
290
+ free((char *)state->index);
291
+ }
292
+
293
+ if (state->shard) {
294
+ for (int i = 0; i < state->total_shards; i++ ) {
295
+
296
+ state->log->debug(state->env->log_options, state->handle,
297
+ "fn[cleanup_state] - Cleaning up shard %d", i);
298
+
299
+ shard_meta_cleanup(state->shard[i].meta);
300
+
301
+ state->log->debug(state->env->log_options, state->handle,
302
+ "fn[cleanup_state] - Cleaning up pointers %d", i);
303
+
304
+ pointer_cleanup(state->shard[i].pointer);
305
+ if (state->shard[i].report) {
306
+ free(state->shard[i].report);
307
+ }
308
+ }
309
+ free(state->shard);
310
+ }
311
+
312
+ state->finished_cb(state->error_status, state->file_id, state->handle);
313
+
314
+ free(state);
315
+ }
316
+
317
+ static void free_encryption_ctx(storj_encryption_ctx_t *ctx)
318
+ {
319
+ if (ctx->encryption_ctr) {
320
+ free(ctx->encryption_ctr);
321
+ }
322
+
323
+ if (ctx->encryption_key) {
324
+ free(ctx->encryption_key);
325
+ }
326
+
327
+ if (ctx->ctx) {
328
+ free(ctx->ctx);
329
+ }
330
+
331
+ free(ctx);
332
+ }
333
+
334
+ static void after_create_bucket_entry(uv_work_t *work, int status)
335
+ {
336
+ post_to_bucket_request_t *req = work->data;
337
+ storj_upload_state_t *state = req->upload_state;
338
+
339
+ state->pending_work_count -= 1;
340
+
341
+ if (status == UV_ECANCELED) {
342
+ state->add_bucket_entry_count = 0;
343
+ state->creating_bucket_entry = false;
344
+ goto clean_variables;
345
+ }
346
+
347
+ state->add_bucket_entry_count += 1;
348
+ state->creating_bucket_entry = false;
349
+
350
+ if (req->error_status) {
351
+ state->error_status = req->error_status;
352
+ goto clean_variables;
353
+ }
354
+
355
+ // Check if we got a 200 status and token
356
+ if (req->status_code == 200 || req->status_code == 201) {
357
+
358
+ req->log->info(state->env->log_options, state->handle,
359
+ "Successfully Added bucket entry");
360
+
361
+ state->add_bucket_entry_count = 0;
362
+ state->completed_upload = true;
363
+
364
+ struct json_object *file_id_value = NULL;
365
+ char *file_id = NULL;
366
+ if (json_object_object_get_ex(req->response, "id", &file_id_value)) {
367
+ file_id = (char *)json_object_get_string(file_id_value);
368
+ }
369
+
370
+ if (file_id) {
371
+ state->file_id = strdup(file_id);
372
+ }
373
+
374
+ } else if (state->add_bucket_entry_count == 6) {
375
+ state->error_status = STORJ_BRIDGE_REQUEST_ERROR;
376
+ }
377
+
378
+ clean_variables:
379
+ queue_next_work(state);
380
+ if (req->response) {
381
+ json_object_put(req->response);
382
+ }
383
+ free(req);
384
+ free(work);
385
+ }
386
+
387
+ static void create_bucket_entry(uv_work_t *work)
388
+ {
389
+ post_to_bucket_request_t *req = work->data;
390
+ storj_upload_state_t *state = req->upload_state;
391
+
392
+ req->log->info(state->env->log_options, state->handle,
393
+ "[%s] Creating bucket entry... (retry: %d)",
394
+ state->file_name,
395
+ state->add_bucket_entry_count);
396
+
397
+ struct json_object *body = json_object_new_object();
398
+ json_object *frame = json_object_new_string(state->frame_id);
399
+ json_object_object_add(body, "frame", frame);
400
+
401
+ json_object *file_name = json_object_new_string(state->encrypted_file_name);
402
+ json_object_object_add(body, "filename", file_name);
403
+
404
+ json_object *index = json_object_new_string(state->index);
405
+ json_object_object_add(body, "index", index);
406
+
407
+ struct json_object *hmac = json_object_new_object();
408
+
409
+ json_object *type = json_object_new_string("sha512");
410
+ json_object_object_add(hmac, "type", type);
411
+
412
+ json_object *value = json_object_new_string(state->hmac_id);
413
+ json_object_object_add(hmac, "value", value);
414
+
415
+ json_object_object_add(body, "hmac", hmac);
416
+
417
+ if (state->rs) {
418
+ struct json_object *erasure = json_object_new_object();
419
+ json_object *erasure_type = json_object_new_string("reedsolomon");
420
+ json_object_object_add(erasure, "type", erasure_type);
421
+ json_object_object_add(body, "erasure", erasure);
422
+ }
423
+
424
+ int path_len = strlen(state->bucket_id) + 16;
425
+ char *path = calloc(path_len + 1, sizeof(char));
426
+ if (!path) {
427
+ req->error_status = STORJ_MEMORY_ERROR;
428
+ return;
429
+ }
430
+ sprintf(path, "%s%s%s%c", "/buckets/", state->bucket_id, "/files", '\0');
431
+
432
+ req->log->debug(state->env->log_options, state->handle,
433
+ "fn[create_bucket_entry] - JSON body: %s", json_object_to_json_string(body));
434
+
435
+ int status_code;
436
+ int request_status = fetch_json(req->http_options,
437
+ req->options,
438
+ "POST",
439
+ path,
440
+ body,
441
+ true,
442
+ &req->response,
443
+ &status_code);
444
+
445
+ req->log->debug(state->env->log_options,
446
+ state->handle,
447
+ "fn[create_bucket_entry] - JSON Response: %s",
448
+ json_object_to_json_string(req->response));
449
+
450
+
451
+ if (request_status) {
452
+ req->log->warn(state->env->log_options, state->handle,
453
+ "Create bucket entry error: %i", request_status);
454
+ }
455
+
456
+
457
+ req->status_code = status_code;
458
+
459
+ json_object_put(body);
460
+ free(path);
461
+ }
462
+
463
+ static int prepare_bucket_entry_hmac(storj_upload_state_t *state)
464
+ {
465
+ struct hmac_sha512_ctx hmac_ctx;
466
+ hmac_sha512_set_key(&hmac_ctx, SHA256_DIGEST_SIZE, state->encryption_key);
467
+
468
+ for (int i = 0; i < state->total_shards; i++) {
469
+
470
+ shard_tracker_t *shard = &state->shard[i];
471
+
472
+ if (!shard->meta ||
473
+ !shard->meta->hash ||
474
+ strlen(shard->meta->hash) != RIPEMD160_DIGEST_SIZE * 2) {
475
+ return 1;
476
+ }
477
+
478
+ struct base16_decode_ctx base16_ctx;
479
+ base16_decode_init(&base16_ctx);
480
+
481
+ size_t decode_len = 0;
482
+ uint8_t hash[RIPEMD160_DIGEST_SIZE];
483
+ if (!base16_decode_update(&base16_ctx, &decode_len, hash,
484
+ RIPEMD160_DIGEST_SIZE * 2,
485
+ (uint8_t *)shard->meta->hash)) {
486
+ return 1;
487
+
488
+ }
489
+ if (!base16_decode_final(&base16_ctx) ||
490
+ decode_len != RIPEMD160_DIGEST_SIZE) {
491
+ return 1;
492
+ }
493
+ hmac_sha512_update(&hmac_ctx, RIPEMD160_DIGEST_SIZE, hash);
494
+ }
495
+
496
+ uint8_t digest_raw[SHA512_DIGEST_SIZE];
497
+ hmac_sha512_digest(&hmac_ctx, SHA512_DIGEST_SIZE, digest_raw);
498
+
499
+ size_t digest_len = BASE16_ENCODE_LENGTH(SHA512_DIGEST_SIZE);
500
+ state->hmac_id = calloc(digest_len + 1, sizeof(char));
501
+ if (!state->hmac_id) {
502
+ return 1;
503
+ }
504
+
505
+ base16_encode_update((uint8_t *)state->hmac_id, SHA512_DIGEST_SIZE, digest_raw);
506
+
507
+ return 0;
508
+ }
509
+
510
+ static void queue_create_bucket_entry(storj_upload_state_t *state)
511
+ {
512
+ uv_work_t *work = uv_work_new();
513
+ if (!work) {
514
+ state->error_status = STORJ_MEMORY_ERROR;
515
+ return;
516
+ }
517
+
518
+ post_to_bucket_request_t *req = malloc(sizeof(post_to_bucket_request_t));
519
+ if (!req) {
520
+ state->error_status = STORJ_MEMORY_ERROR;
521
+ return;
522
+ }
523
+
524
+ if (prepare_bucket_entry_hmac(state)) {
525
+ state->error_status = STORJ_FILE_GENERATE_HMAC_ERROR;
526
+ return;
527
+ }
528
+
529
+ req->http_options = state->env->http_options;
530
+ req->options = state->env->bridge_options;
531
+ req->upload_state = state;
532
+ req->response = NULL;
533
+ req->error_status = 0;
534
+ req->status_code = 0;
535
+ req->log = state->log;
536
+ work->data = req;
537
+
538
+ state->pending_work_count += 1;
539
+ int status = uv_queue_work(state->env->loop, (uv_work_t*) work,
540
+ create_bucket_entry, after_create_bucket_entry);
541
+
542
+ if (status) {
543
+ state->error_status = STORJ_QUEUE_ERROR;
544
+ return;
545
+ }
546
+
547
+ state->creating_bucket_entry = true;
548
+ }
549
+
550
+ static void free_push_shard_work(uv_handle_t *progress_handle)
551
+ {
552
+ uv_work_t *work = progress_handle->data;
553
+ push_shard_request_t *req = work->data;
554
+
555
+ if (req) {
556
+ free(req);
557
+ }
558
+
559
+ if (work) {
560
+ free(work);
561
+ }
562
+ }
563
+
564
+ static void after_push_shard(uv_work_t *work, int status)
565
+ {
566
+ push_shard_request_t *req = work->data;
567
+ storj_upload_state_t *state = req->upload_state;
568
+ uv_handle_t *progress_handle = (uv_handle_t *) &req->progress_handle;
569
+ shard_tracker_t *shard = &state->shard[req->shard_meta_index];
570
+
571
+ // free the upload progress
572
+ free(progress_handle->data);
573
+
574
+ // assign work so that we can free after progress_handle is closed
575
+ progress_handle->data = work;
576
+
577
+ state->pending_work_count -= 1;
578
+
579
+ if (status == UV_ECANCELED) {
580
+ shard->push_shard_request_count = 0;
581
+ shard->progress = AWAITING_PUSH_FRAME;
582
+ shard->report->send_status = STORJ_REPORT_NOT_PREPARED;
583
+ goto clean_variables;
584
+ }
585
+
586
+ // Update times on exchange report
587
+ shard->report->start = req->start;
588
+ shard->report->end = req->end;
589
+
590
+ // Check if we got a 200 status and token
591
+ if (!req->error_status &&
592
+ (req->status_code == 200 ||
593
+ req->status_code == 201 ||
594
+ req->status_code == 304)) {
595
+
596
+ req->log->info(state->env->log_options, state->handle,
597
+ "Successfully transferred shard index %d",
598
+ req->shard_meta_index);
599
+
600
+ shard->progress = COMPLETED_PUSH_SHARD;
601
+ state->completed_shards += 1;
602
+ shard->push_shard_request_count = 0;
603
+
604
+ // Update the uploaded size outside of the progress async handle
605
+ shard->uploaded_size = shard->meta->size;
606
+
607
+ // Update the exchange report with success
608
+ shard->report->code = STORJ_REPORT_SUCCESS;
609
+ shard->report->message = STORJ_REPORT_SHARD_UPLOADED;
610
+ shard->report->send_status = STORJ_REPORT_AWAITING_SEND;
611
+
612
+ } else if (!state->canceled){
613
+
614
+ // Update the exchange report with failure
615
+ shard->report->code = STORJ_REPORT_FAILURE;
616
+ shard->report->message = STORJ_REPORT_UPLOAD_ERROR;
617
+ shard->report->send_status = STORJ_REPORT_AWAITING_SEND;
618
+
619
+ if (shard->push_shard_request_count == 6) {
620
+
621
+ req->log->error(state->env->log_options, state->handle,
622
+ "Failed to push shard %d\n", req->shard_meta_index);
623
+
624
+ state->error_status = STORJ_FARMER_REQUEST_ERROR;
625
+ } else {
626
+ req->log->warn(state->env->log_options, state->handle,
627
+ "Failed to push shard %d... Retrying...",
628
+ req->shard_meta_index);
629
+
630
+ // We go back to getting a new pointer instead of retrying push with same pointer
631
+ shard->progress = AWAITING_PUSH_FRAME;
632
+ shard->push_shard_request_count += 1;
633
+
634
+ // Add pointer to exclude for future calls
635
+ if (state->exclude == NULL) {
636
+ state->exclude = calloc(strlen(shard->pointer->farmer_node_id) + 1, sizeof(char));
637
+ if (!state->exclude) {
638
+ state->error_status = STORJ_MEMORY_ERROR;
639
+ return;
640
+ }
641
+ strcpy(state->exclude, shard->pointer->farmer_node_id);
642
+ } else {
643
+ int new_len = strlen(state->exclude) + strlen(shard->pointer->farmer_node_id) + 1;
644
+ state->exclude = realloc(state->exclude, new_len + 1);
645
+ strcat(state->exclude, ",");
646
+ strcat(state->exclude, shard->pointer->farmer_node_id);
647
+ state->exclude[new_len] = '\0';
648
+ }
649
+ }
650
+ }
651
+
652
+ clean_variables:
653
+ queue_next_work(state);
654
+ // close the async progress handle
655
+ uv_close(progress_handle, free_push_shard_work);
656
+ }
657
+
658
+ static void push_shard(uv_work_t *work)
659
+ {
660
+ push_shard_request_t *req = work->data;
661
+ storj_upload_state_t *state = req->upload_state;
662
+ shard_tracker_t *shard = &state->shard[req->shard_meta_index];
663
+
664
+ req->log->info(state->env->log_options, state->handle,
665
+ "Transfering Shard index %d... (retry: %d)",
666
+ req->shard_meta_index,
667
+ state->shard[req->shard_meta_index].push_shard_request_count);
668
+
669
+ int status_code = 0;
670
+ int read_code = 0;
671
+
672
+ req->start = get_time_milliseconds();
673
+
674
+ uint64_t file_position = req->shard_index * state->shard_size;
675
+
676
+ storj_encryption_ctx_t *encryption_ctx = NULL;
677
+ if (!state->rs) {
678
+ // Initialize the encryption context
679
+ encryption_ctx = prepare_encryption_ctx(state->encryption_ctr,
680
+ state->encryption_key);
681
+ if (!encryption_ctx) {
682
+ state->error_status = STORJ_MEMORY_ERROR;
683
+ goto clean_variables;
684
+ }
685
+ // Increment the iv to proper placement because we may be reading from the middle of the file
686
+ increment_ctr_aes_iv(encryption_ctx->encryption_ctr, req->shard_meta_index * state->shard_size);
687
+ }
688
+
689
+ int req_status = put_shard(req->http_options,
690
+ shard->pointer->farmer_node_id,
691
+ "http",
692
+ shard->pointer->farmer_address,
693
+ atoi(shard->pointer->farmer_port),
694
+ shard->meta->hash,
695
+ shard->meta->size,
696
+ req->shard_file,
697
+ file_position,
698
+ encryption_ctx,
699
+ shard->pointer->token,
700
+ &status_code,
701
+ &read_code,
702
+ &req->progress_handle,
703
+ req->canceled);
704
+
705
+ if (read_code != 0) {
706
+ req->log->error(state->env->log_options, state->handle,
707
+ "Put shard read error: %i", read_code);
708
+ }
709
+
710
+ if (req_status) {
711
+ req->error_status = req_status;
712
+ req->log->error(state->env->log_options, state->handle,
713
+ "Put shard request error code: %i", req_status);
714
+ }
715
+
716
+ req->end = get_time_milliseconds();
717
+
718
+ req->status_code = status_code;
719
+
720
+ clean_variables:
721
+ if (encryption_ctx) {
722
+ free_encryption_ctx(encryption_ctx);
723
+ }
724
+ }
725
+
726
+ static void progress_put_shard(uv_async_t* async)
727
+ {
728
+
729
+ shard_upload_progress_t *progress = async->data;
730
+
731
+ storj_upload_state_t *state = progress->state;
732
+
733
+ state->shard[progress->pointer_index].uploaded_size = progress->bytes;
734
+
735
+ uint64_t uploaded_bytes = 0;
736
+ uint64_t total_bytes = 0;
737
+
738
+ for (int i = 0; i < state->total_shards; i++) {
739
+
740
+ shard_tracker_t *shard = &state->shard[i];
741
+
742
+ uploaded_bytes += shard->uploaded_size;
743
+ total_bytes += shard->meta->size;
744
+ }
745
+
746
+ double total_progress = (double)uploaded_bytes / (double)total_bytes;
747
+
748
+ if (state->progress_finished) {
749
+ return;
750
+ }
751
+
752
+ if (uploaded_bytes == total_bytes) {
753
+ state->progress_finished = true;
754
+ }
755
+
756
+ state->progress_cb(total_progress,
757
+ uploaded_bytes,
758
+ total_bytes,
759
+ state->handle);
760
+
761
+
762
+ }
763
+
764
+ static void queue_push_shard(storj_upload_state_t *state, int index)
765
+ {
766
+ uv_work_t *work = uv_work_new();
767
+ if (!work) {
768
+ state->error_status = STORJ_MEMORY_ERROR;
769
+ return;
770
+ }
771
+
772
+ push_shard_request_t *req = malloc(sizeof(push_shard_request_t));
773
+ if (!req) {
774
+ state->error_status = STORJ_MEMORY_ERROR;
775
+ return;
776
+ }
777
+
778
+ req->http_options = state->env->http_options;
779
+ req->options = state->env->bridge_options;
780
+ req->upload_state = state;
781
+ req->error_status = 0;
782
+ req->log = state->log;
783
+
784
+ // Reset shard index when using parity shards
785
+ req->shard_index = (index + 1 > state->total_data_shards) ? index - state->total_data_shards: index;
786
+
787
+ // make sure we switch between parity and data shards files.
788
+ // When using Reed solomon must also read from encrypted file
789
+ // rather than the original file for the data
790
+ if (index + 1 > state->total_data_shards) {
791
+ req->shard_file = state->parity_file;
792
+ } else if (state->rs) {
793
+ req->shard_file = state->encrypted_file;
794
+ } else {
795
+ req->shard_file = state->original_file;
796
+ }
797
+
798
+ // Position on shard_meta array
799
+ req->shard_meta_index = index;
800
+
801
+ req->status_code = 0;
802
+
803
+ req->canceled = &state->canceled;
804
+
805
+ // setup upload progress reporting
806
+ shard_upload_progress_t *progress =
807
+ malloc(sizeof(shard_upload_progress_t));
808
+
809
+ if (!progress) {
810
+ state->error_status = STORJ_MEMORY_ERROR;
811
+ return;
812
+ }
813
+
814
+ progress->pointer_index = index;
815
+ progress->bytes = 0;
816
+ progress->state = state;
817
+
818
+ req->progress_handle.data = progress;
819
+
820
+ uv_async_init(state->env->loop, &req->progress_handle,
821
+ progress_put_shard);
822
+
823
+ work->data = req;
824
+
825
+ state->pending_work_count += 1;
826
+ int status = uv_queue_work(state->env->loop, (uv_work_t*) work,
827
+ push_shard, after_push_shard);
828
+
829
+ if (status) {
830
+ state->error_status = STORJ_QUEUE_ERROR;
831
+ return;
832
+ }
833
+
834
+ state->shard[index].progress = PUSHING_SHARD;
835
+
836
+ if (state->shard[index].report->farmer_id != NULL) {
837
+ free(state->shard[index].report);
838
+ state->shard[index].report = storj_exchange_report_new();
839
+ }
840
+
841
+ if (!state->shard[index].report) {
842
+ state->error_status = STORJ_MEMORY_ERROR;
843
+ return;
844
+ }
845
+
846
+ // setup the exchange report
847
+ storj_exchange_report_t *report = state->shard[index].report;
848
+ report->data_hash = state->shard[index].meta->hash;
849
+ report->reporter_id = (char *)state->env->bridge_options->user;
850
+ report->farmer_id = state->shard[index].pointer->farmer_node_id;
851
+ report->client_id = (char *)state->env->bridge_options->user;
852
+ report->pointer_index = index;
853
+ report->start = 0;
854
+ report->end = 0;
855
+ report->code = 0;
856
+ report->message = NULL;
857
+ report->send_status = 0; // not sent
858
+ report->send_count = 0;
859
+
860
+ state->shard[index].work = work;
861
+ }
862
+
863
+ static void after_push_frame(uv_work_t *work, int status)
864
+ {
865
+ frame_request_t *req = work->data;
866
+ storj_upload_state_t *state = req->upload_state;
867
+ farmer_pointer_t *pointer = req->farmer_pointer;
868
+
869
+ state->pending_work_count -= 1;
870
+
871
+ if (status == UV_ECANCELED) {
872
+ state->shard[req->shard_meta_index].push_frame_request_count = 0;
873
+ state->shard[req->shard_meta_index].progress = AWAITING_PUSH_FRAME;
874
+ goto clean_variables;
875
+ }
876
+
877
+ // Increment request count every request for retry counts
878
+ state->shard[req->shard_meta_index].push_frame_request_count += 1;
879
+
880
+ if (req->status_code == 429 || req->status_code == 420) {
881
+
882
+ state->error_status = STORJ_BRIDGE_RATE_ERROR;
883
+
884
+ } else if ((req->status_code == 200 || req->status_code == 201) &&
885
+ pointer->token != NULL) {
886
+ // Check if we got a 200 status and token
887
+
888
+ // Reset for if we need to get a new pointer later
889
+ state->shard[req->shard_meta_index].push_frame_request_count = 0;
890
+ state->shard[req->shard_meta_index].progress = AWAITING_PUSH_SHARD;
891
+
892
+ farmer_pointer_t *p = state->shard[req->shard_meta_index].pointer;
893
+
894
+ // Add token to shard[].pointer
895
+ p->token = calloc(strlen(pointer->token) + 1, sizeof(char));
896
+ if (!p->token) {
897
+ state->error_status = STORJ_MEMORY_ERROR;
898
+ goto clean_variables;
899
+ }
900
+ memcpy(p->token, pointer->token, strlen(pointer->token));
901
+
902
+ // Add farmer_user_agent to shard[].pointer
903
+ p->farmer_user_agent = calloc(strlen(pointer->farmer_user_agent) + 1,
904
+ sizeof(char));
905
+ if (!p->farmer_user_agent) {
906
+ state->error_status = STORJ_MEMORY_ERROR;
907
+ goto clean_variables;
908
+ }
909
+ memcpy(p->farmer_user_agent, pointer->farmer_user_agent,
910
+ strlen(pointer->farmer_user_agent));
911
+
912
+ // Add farmer_address to shard[].pointer
913
+ p->farmer_address = calloc(strlen(pointer->farmer_address) + 1,
914
+ sizeof(char));
915
+ if (!p->farmer_address) {
916
+ state->error_status = STORJ_MEMORY_ERROR;
917
+ goto clean_variables;
918
+ }
919
+ memcpy(p->farmer_address, pointer->farmer_address,
920
+ strlen(pointer->farmer_address));
921
+
922
+ // Add farmer_port to shard[].pointer
923
+ p->farmer_port = calloc(strlen(pointer->farmer_port) + 1, sizeof(char));
924
+ if (!p->farmer_port) {
925
+ state->error_status = STORJ_MEMORY_ERROR;
926
+ goto clean_variables;
927
+ }
928
+ memcpy(p->farmer_port, pointer->farmer_port,
929
+ strlen(pointer->farmer_port));
930
+
931
+ // Add farmer_protocol to shard[].pointer
932
+ p->farmer_protocol = calloc(strlen(pointer->farmer_protocol) + 1,
933
+ sizeof(char));
934
+ if (!p->farmer_protocol) {
935
+ state->error_status = STORJ_MEMORY_ERROR;
936
+ goto clean_variables;
937
+ }
938
+ memcpy(p->farmer_protocol, pointer->farmer_protocol,
939
+ strlen(pointer->farmer_protocol));
940
+
941
+ // Add farmer_node_id to shard[].pointer
942
+ p->farmer_node_id = calloc(strlen(pointer->farmer_node_id) + 1,
943
+ sizeof(char));
944
+ if (!p->farmer_node_id) {
945
+ state->error_status = STORJ_MEMORY_ERROR;
946
+ goto clean_variables;
947
+ }
948
+ memcpy(p->farmer_node_id, pointer->farmer_node_id,
949
+ strlen(pointer->farmer_node_id));
950
+
951
+ state->log->info(
952
+ state->env->log_options,
953
+ state->handle,
954
+ "Contract negotiated with: "
955
+ "{ "
956
+ "\"userAgent: \"%s\", "
957
+ "\"protocol:\" \"%s\", "
958
+ "\"port\": \"%s\", "
959
+ "\"nodeID\": \"%s\""
960
+ "}",
961
+ p->farmer_user_agent,
962
+ p->farmer_protocol,
963
+ p->farmer_port,
964
+ p->farmer_node_id
965
+ );
966
+
967
+ } else if (state->shard[req->shard_meta_index].push_frame_request_count ==
968
+ STORJ_MAX_PUSH_FRAME_COUNT) {
969
+ state->error_status = STORJ_BRIDGE_OFFER_ERROR;
970
+ } else {
971
+ state->shard[req->shard_meta_index].progress = AWAITING_PUSH_FRAME;
972
+ }
973
+
974
+ clean_variables:
975
+ queue_next_work(state);
976
+ if (pointer) {
977
+ pointer_cleanup(pointer);
978
+ }
979
+
980
+ free(req);
981
+ free(work);
982
+ }
983
+
984
+ static void push_frame(uv_work_t *work)
985
+ {
986
+ frame_request_t *req = work->data;
987
+ storj_upload_state_t *state = req->upload_state;
988
+ shard_meta_t *shard_meta = state->shard[req->shard_meta_index].meta;
989
+
990
+ req->log->info(state->env->log_options, state->handle,
991
+ "Pushing frame for shard index %d... (retry: %d)",
992
+ req->shard_meta_index,
993
+ state->shard[req->shard_meta_index].push_frame_request_count);
994
+
995
+ char resource[strlen(state->frame_id) + 9];
996
+ memset(resource, '\0', strlen(state->frame_id) + 9);
997
+ strcpy(resource, "/frames/");
998
+ strcat(resource, state->frame_id);
999
+
1000
+ // Prepare the body
1001
+ struct json_object *body = json_object_new_object();
1002
+
1003
+ // Add shard hash
1004
+ json_object *shard_hash = json_object_new_string(shard_meta->hash);
1005
+ json_object_object_add(body, "hash", shard_hash);
1006
+
1007
+ // Add shard size
1008
+ json_object *shard_size = json_object_new_int64(shard_meta->size);
1009
+ json_object_object_add(body, "size", shard_size);
1010
+
1011
+ // Add shard index
1012
+ json_object *shard_index = json_object_new_int(req->shard_meta_index);
1013
+ json_object_object_add(body, "index", shard_index);
1014
+
1015
+ json_object *parity_shard = NULL;
1016
+ if (req->shard_meta_index + 1 > state->total_data_shards) {
1017
+ parity_shard = json_object_new_boolean(true);
1018
+ } else {
1019
+ parity_shard = json_object_new_boolean(false);
1020
+ }
1021
+ json_object_object_add(body, "parity", parity_shard);
1022
+
1023
+ // Add challenges
1024
+ json_object *challenges = json_object_new_array();
1025
+ for (int i = 0; i < STORJ_SHARD_CHALLENGES; i++ ) {
1026
+ json_object_array_add(challenges,
1027
+ json_object_new_string(
1028
+ (char *)shard_meta->challenges_as_str[i]));
1029
+ }
1030
+ json_object_object_add(body, "challenges", challenges);
1031
+
1032
+ // Add Tree
1033
+ json_object *tree = json_object_new_array();
1034
+ for (int i = 0; i < STORJ_SHARD_CHALLENGES; i++ ) {
1035
+ json_object_array_add(tree,
1036
+ json_object_new_string(
1037
+ (char *)shard_meta->tree[i]));
1038
+ }
1039
+ json_object_object_add(body, "tree", tree);
1040
+
1041
+ // Add exclude (Don't try to upload to farmers that have failed before)
1042
+ json_object *exclude = json_object_new_array();
1043
+ if (state->exclude) {
1044
+ char *exclude_list = calloc(strlen(state->exclude) + 1, sizeof(char));
1045
+ if (!exclude_list) {
1046
+ req->error_status = STORJ_MEMORY_ERROR;
1047
+ goto clean_variables;
1048
+ }
1049
+ strcpy(exclude_list, state->exclude);
1050
+
1051
+ char *node_id = strtok(exclude_list, ",");
1052
+ while (node_id != NULL) {
1053
+ json_object_array_add(exclude, json_object_new_string(node_id));
1054
+ node_id = strtok (NULL, ",");
1055
+ }
1056
+ free(exclude_list);
1057
+ }
1058
+
1059
+ json_object_object_add(body, "exclude", exclude);
1060
+
1061
+ req->log->debug(state->env->log_options, state->handle,
1062
+ "fn[push_frame] - JSON body: %s", json_object_to_json_string(body));
1063
+
1064
+ int status_code;
1065
+ struct json_object *response = NULL;
1066
+ int request_status = fetch_json(req->http_options,
1067
+ req->options,
1068
+ "PUT",
1069
+ resource,
1070
+ body,
1071
+ true,
1072
+ &response,
1073
+ &status_code);
1074
+
1075
+ req->log->debug(state->env->log_options, state->handle,
1076
+ "fn[push_frame] - JSON Response: %s",
1077
+ json_object_to_json_string(response));
1078
+
1079
+ if (request_status) {
1080
+ req->log->warn(state->env->log_options, state->handle,
1081
+ "Push frame error: %i", request_status);
1082
+ req->error_status = STORJ_BRIDGE_REQUEST_ERROR;
1083
+ goto clean_variables;
1084
+ }
1085
+
1086
+ struct json_object *obj_token;
1087
+ if (!json_object_object_get_ex(response, "token", &obj_token)) {
1088
+ req->error_status = STORJ_BRIDGE_JSON_ERROR;
1089
+ goto clean_variables;
1090
+ }
1091
+
1092
+ struct json_object *obj_farmer;
1093
+ if (!json_object_object_get_ex(response, "farmer", &obj_farmer)) {
1094
+ req->error_status = STORJ_BRIDGE_JSON_ERROR;
1095
+ goto clean_variables;
1096
+ }
1097
+
1098
+ struct json_object *obj_farmer_address;
1099
+ if (!json_object_object_get_ex(obj_farmer, "address",
1100
+ &obj_farmer_address)) {
1101
+
1102
+ req->error_status = STORJ_BRIDGE_JSON_ERROR;
1103
+ goto clean_variables;
1104
+ }
1105
+
1106
+ struct json_object *obj_farmer_port;
1107
+ if (!json_object_object_get_ex(obj_farmer, "port", &obj_farmer_port)) {
1108
+ req->error_status = STORJ_BRIDGE_JSON_ERROR;
1109
+ goto clean_variables;
1110
+ }
1111
+
1112
+ struct json_object *obj_farmer_user_agent;
1113
+ if (!json_object_object_get_ex(obj_farmer, "userAgent",
1114
+ &obj_farmer_user_agent)) {
1115
+
1116
+ req->error_status = STORJ_BRIDGE_JSON_ERROR;
1117
+ goto clean_variables;
1118
+ }
1119
+
1120
+ struct json_object *obj_farmer_protocol;
1121
+ if (!json_object_object_get_ex(obj_farmer, "protocol",
1122
+ &obj_farmer_protocol)) {
1123
+
1124
+ req->error_status = STORJ_BRIDGE_JSON_ERROR;
1125
+ goto clean_variables;
1126
+ }
1127
+
1128
+ struct json_object *obj_farmer_node_id;
1129
+ if (!json_object_object_get_ex(obj_farmer, "nodeID",
1130
+ &obj_farmer_node_id)) {
1131
+
1132
+ req->error_status = STORJ_BRIDGE_JSON_ERROR;
1133
+ goto clean_variables;
1134
+ }
1135
+
1136
+ if (!json_object_is_type(obj_token, json_type_string)) {
1137
+
1138
+ req->error_status = STORJ_BRIDGE_JSON_ERROR;
1139
+ goto clean_variables;
1140
+ }
1141
+
1142
+ // Token
1143
+ char *token = (char *)json_object_get_string(obj_token);
1144
+ req->farmer_pointer->token = calloc(strlen(token) + 1, sizeof(char));
1145
+ if (!req->farmer_pointer->token) {
1146
+ req->error_status = STORJ_MEMORY_ERROR;
1147
+ goto clean_variables;
1148
+ }
1149
+ memcpy(req->farmer_pointer->token, token, strlen(token));
1150
+
1151
+ // Farmer user agent
1152
+ char *farmer_user_agent =
1153
+ (char *)json_object_get_string(obj_farmer_user_agent);
1154
+ req->farmer_pointer->farmer_user_agent =
1155
+ calloc(strlen(farmer_user_agent) + 1, sizeof(char));
1156
+ if (!req->farmer_pointer->farmer_user_agent) {
1157
+ req->error_status = STORJ_MEMORY_ERROR;
1158
+ goto clean_variables;
1159
+ }
1160
+ memcpy(req->farmer_pointer->farmer_user_agent,
1161
+ farmer_user_agent,
1162
+ strlen(farmer_user_agent));
1163
+
1164
+ // Farmer protocol
1165
+ char *farmer_protocol = (char *)json_object_get_string(obj_farmer_protocol);
1166
+ req->farmer_pointer->farmer_protocol =
1167
+ calloc(strlen(farmer_protocol) + 1, sizeof(char));
1168
+ if (!req->farmer_pointer->farmer_protocol) {
1169
+ req->error_status = STORJ_MEMORY_ERROR;
1170
+ goto clean_variables;
1171
+ }
1172
+ memcpy(req->farmer_pointer->farmer_protocol,
1173
+ farmer_protocol,
1174
+ strlen(farmer_protocol));
1175
+
1176
+ // Farmer address
1177
+ char *farmer_address = (char *)json_object_get_string(obj_farmer_address);
1178
+ req->farmer_pointer->farmer_address =
1179
+ calloc(strlen(farmer_address) + 1, sizeof(char));
1180
+ if (!req->farmer_pointer->farmer_address) {
1181
+ req->error_status = STORJ_MEMORY_ERROR;
1182
+ goto clean_variables;
1183
+ }
1184
+ memcpy(req->farmer_pointer->farmer_address,
1185
+ farmer_address,
1186
+ strlen(farmer_address));
1187
+
1188
+ // Farmer port
1189
+ char *farmer_port = (char *)json_object_get_string(obj_farmer_port);
1190
+ req->farmer_pointer->farmer_port = calloc(strlen(farmer_port) + 1, sizeof(char));
1191
+ if (!req->farmer_pointer->farmer_port) {
1192
+ req->error_status = STORJ_MEMORY_ERROR;
1193
+ goto clean_variables;
1194
+ }
1195
+ memcpy(req->farmer_pointer->farmer_port, farmer_port, strlen(farmer_port));
1196
+
1197
+ // Farmer node id
1198
+ char *farmer_node_id = (char *)json_object_get_string(obj_farmer_node_id);
1199
+ req->farmer_pointer->farmer_node_id =
1200
+ calloc(strlen(farmer_node_id) + 1, sizeof(char));
1201
+ if (!req->farmer_pointer->farmer_node_id) {
1202
+ req->error_status = STORJ_MEMORY_ERROR;
1203
+ goto clean_variables;
1204
+ }
1205
+ memcpy(req->farmer_pointer->farmer_node_id,
1206
+ farmer_node_id,
1207
+ strlen(farmer_node_id));
1208
+
1209
+ // Status code
1210
+ req->status_code = status_code;
1211
+
1212
+ clean_variables:
1213
+ if (response) {
1214
+ json_object_put(response);
1215
+ }
1216
+ if (body) {
1217
+ json_object_put(body);
1218
+ }
1219
+ }
1220
+
1221
+ static void queue_push_frame(storj_upload_state_t *state, int index)
1222
+ {
1223
+ if (state->shard[index].pointer->token != NULL) {
1224
+ pointer_cleanup(state->shard[index].pointer);
1225
+ state->shard[index].pointer = farmer_pointer_new();
1226
+ if (!state->shard[index].pointer) {
1227
+ state->error_status = STORJ_MEMORY_ERROR;
1228
+ return;
1229
+ }
1230
+ }
1231
+
1232
+ uv_work_t *shard_work = frame_work_new(&index, state);
1233
+ if (!shard_work) {
1234
+ state->error_status = STORJ_MEMORY_ERROR;
1235
+ return;
1236
+ }
1237
+
1238
+ state->pending_work_count += 1;
1239
+ int status = uv_queue_work(state->env->loop, (uv_work_t*) shard_work,
1240
+ push_frame, after_push_frame);
1241
+ if (status) {
1242
+ state->error_status = STORJ_QUEUE_ERROR;
1243
+ return;
1244
+ }
1245
+
1246
+ state->shard[index].progress = PUSHING_FRAME;
1247
+ }
1248
+
1249
+ static void after_prepare_frame(uv_work_t *work, int status)
1250
+ {
1251
+ frame_builder_t *req = work->data;
1252
+ shard_meta_t *shard_meta = req->shard_meta;
1253
+ storj_upload_state_t *state = req->upload_state;
1254
+
1255
+ state->pending_work_count -= 1;
1256
+
1257
+ if (status == UV_ECANCELED) {
1258
+ state->shard[shard_meta->index].progress = AWAITING_PREPARE_FRAME;
1259
+ goto clean_variables;
1260
+ }
1261
+
1262
+ if (req->error_status) {
1263
+ state->error_status = req->error_status;
1264
+ goto clean_variables;
1265
+ }
1266
+
1267
+ /* set the shard_meta to a struct array in the state for later use. */
1268
+
1269
+ // Add Hash
1270
+ state->shard[req->shard_meta_index].meta->hash =
1271
+ calloc(RIPEMD160_DIGEST_SIZE * 2 + 1, sizeof(char));
1272
+
1273
+ if (!state->shard[req->shard_meta_index].meta->hash) {
1274
+ state->error_status = STORJ_MEMORY_ERROR;
1275
+ goto clean_variables;
1276
+ }
1277
+
1278
+ memcpy(state->shard[req->shard_meta_index].meta->hash,
1279
+ shard_meta->hash,
1280
+ RIPEMD160_DIGEST_SIZE * 2);
1281
+
1282
+ req->log->info(state->env->log_options, state->handle,
1283
+ "Shard (%d) hash: %s", req->shard_meta_index,
1284
+ state->shard[req->shard_meta_index].meta->hash);
1285
+
1286
+ // Add challenges_as_str
1287
+ state->log->debug(state->env->log_options, state->handle,
1288
+ "Challenges for shard index %d",
1289
+ req->shard_meta_index);
1290
+
1291
+ for (int i = 0; i < STORJ_SHARD_CHALLENGES; i++ ) {
1292
+ memcpy(state->shard[req->shard_meta_index].meta->challenges_as_str[i],
1293
+ shard_meta->challenges_as_str[i],
1294
+ 64);
1295
+
1296
+ state->log->debug(state->env->log_options, state->handle,
1297
+ "Shard %d Challenge [%d]: %s",
1298
+ req->shard_meta_index,
1299
+ i,
1300
+ state->shard[req->shard_meta_index].meta->challenges_as_str[i]);
1301
+ }
1302
+
1303
+ // Add Merkle Tree leaves.
1304
+ state->log->debug(state->env->log_options, state->handle,
1305
+ "Tree for shard index %d",
1306
+ req->shard_meta_index);
1307
+
1308
+ for (int i = 0; i < STORJ_SHARD_CHALLENGES; i++ ) {
1309
+ memcpy(state->shard[req->shard_meta_index].meta->tree[i],
1310
+ shard_meta->tree[i],
1311
+ 40);
1312
+
1313
+ state->log->debug(state->env->log_options, state->handle,
1314
+ "Shard %d Leaf [%d]: %s", req->shard_meta_index, i,
1315
+ state->shard[req->shard_meta_index].meta->tree[i]);
1316
+ }
1317
+
1318
+ // Add index
1319
+ state->shard[req->shard_meta_index].meta->index = shard_meta->index;
1320
+
1321
+ // Add size
1322
+ state->shard[req->shard_meta_index].meta->size = shard_meta->size;
1323
+
1324
+ state->log->info(state->env->log_options, state->handle,
1325
+ "Successfully created frame for shard index %d",
1326
+ req->shard_meta_index);
1327
+
1328
+ state->shard[req->shard_meta_index].progress = AWAITING_PUSH_FRAME;
1329
+
1330
+ clean_variables:
1331
+ queue_next_work(state);
1332
+ if (shard_meta) {
1333
+ shard_meta_cleanup(shard_meta);
1334
+ }
1335
+
1336
+ free(req);
1337
+ free(work);
1338
+ }
1339
+
1340
+ static void prepare_frame(uv_work_t *work)
1341
+ {
1342
+ frame_builder_t *req = work->data;
1343
+ shard_meta_t *shard_meta = req->shard_meta;
1344
+ storj_upload_state_t *state = req->upload_state;
1345
+
1346
+ // Set the challenges
1347
+ uint8_t buff[32];
1348
+ for (int i = 0; i < STORJ_SHARD_CHALLENGES; i++ ) {
1349
+ memset_zero(buff, 32);
1350
+
1351
+ random_buffer(buff, 32);
1352
+ memcpy(shard_meta->challenges[i], buff, 32);
1353
+
1354
+ // Convert the uint8_t challenges to character arrays
1355
+ char *challenge_as_str = hex2str(32, buff);
1356
+ if (!challenge_as_str) {
1357
+ req->error_status = STORJ_MEMORY_ERROR;
1358
+ goto clean_variables;
1359
+ }
1360
+ memcpy(shard_meta->challenges_as_str[i], challenge_as_str, strlen(challenge_as_str));
1361
+ free(challenge_as_str);
1362
+ }
1363
+
1364
+ // Hash of the shard_data
1365
+ shard_meta->hash = calloc(RIPEMD160_DIGEST_SIZE*2 + 2, sizeof(char));
1366
+ if (!shard_meta->hash) {
1367
+ req->error_status = STORJ_MEMORY_ERROR;
1368
+ goto clean_variables;
1369
+ }
1370
+
1371
+ req->log->info(state->env->log_options, state->handle,
1372
+ "Creating frame for shard index %d",
1373
+ req->shard_meta_index);
1374
+
1375
+ // Sha256 of encrypted data for calculating shard has
1376
+ uint8_t prehash_sha256[SHA256_DIGEST_SIZE];
1377
+
1378
+ // Initialize context for sha256 of encrypted data
1379
+ struct sha256_ctx shard_hash_ctx;
1380
+ sha256_init(&shard_hash_ctx);
1381
+
1382
+ // Calculate the merkle tree with challenges
1383
+ struct sha256_ctx first_sha256_for_leaf[STORJ_SHARD_CHALLENGES];
1384
+ for (int i = 0; i < STORJ_SHARD_CHALLENGES; i++ ) {
1385
+ sha256_init(&first_sha256_for_leaf[i]);
1386
+ sha256_update(&first_sha256_for_leaf[i], 32, (uint8_t *)&shard_meta->challenges[i]);
1387
+ }
1388
+
1389
+ storj_encryption_ctx_t *encryption_ctx = NULL;
1390
+ if (!state->rs) {
1391
+ // Initialize the encryption context
1392
+ encryption_ctx = prepare_encryption_ctx(state->encryption_ctr, state->encryption_key);
1393
+ if (!encryption_ctx) {
1394
+ state->error_status = STORJ_MEMORY_ERROR;
1395
+ goto clean_variables;
1396
+ }
1397
+ // Increment the iv to proper placement because we may be reading from the middle of the file
1398
+ increment_ctr_aes_iv(encryption_ctx->encryption_ctr, req->shard_meta_index * state->shard_size);
1399
+ }
1400
+
1401
+ uint8_t cphr_txt[AES_BLOCK_SIZE * 256];
1402
+ memset_zero(cphr_txt, AES_BLOCK_SIZE * 256);
1403
+ char read_data[AES_BLOCK_SIZE * 256];
1404
+ memset_zero(read_data, AES_BLOCK_SIZE * 256);
1405
+ unsigned long int read_bytes = 0;
1406
+ uint64_t total_read = 0;
1407
+
1408
+ do {
1409
+ if (state->canceled) {
1410
+ goto clean_variables;
1411
+ }
1412
+
1413
+ read_bytes = pread(fileno(req->shard_file),
1414
+ read_data, AES_BLOCK_SIZE * 256,
1415
+ shard_meta->index*state->shard_size + total_read);
1416
+
1417
+ if (read_bytes == -1) {
1418
+ req->log->warn(state->env->log_options, state->handle,
1419
+ "Error reading file: %d",
1420
+ errno);
1421
+ req->error_status = STORJ_FILE_READ_ERROR;
1422
+ goto clean_variables;
1423
+ }
1424
+
1425
+ total_read += read_bytes;
1426
+
1427
+ if (!state->rs) {
1428
+ // Encrypt data
1429
+ ctr_crypt(encryption_ctx->ctx, (nettle_cipher_func *)aes256_encrypt,
1430
+ AES_BLOCK_SIZE, encryption_ctx->encryption_ctr, read_bytes,
1431
+ (uint8_t *)cphr_txt, (uint8_t *)read_data);
1432
+ } else {
1433
+ // Just use the already encrypted data
1434
+ memcpy(cphr_txt, read_data, AES_BLOCK_SIZE*256);
1435
+ }
1436
+
1437
+ sha256_update(&shard_hash_ctx, read_bytes, cphr_txt);
1438
+
1439
+ for (int i = 0; i < STORJ_SHARD_CHALLENGES; i++ ) {
1440
+ sha256_update(&first_sha256_for_leaf[i], read_bytes, cphr_txt);
1441
+ }
1442
+
1443
+ memset_zero(read_data, AES_BLOCK_SIZE * 256);
1444
+ memset_zero(cphr_txt, AES_BLOCK_SIZE * 256);
1445
+
1446
+ } while(total_read < state->shard_size && read_bytes > 0);
1447
+
1448
+ shard_meta->size = total_read;
1449
+
1450
+ sha256_digest(&shard_hash_ctx, SHA256_DIGEST_SIZE, prehash_sha256);
1451
+
1452
+ uint8_t prehash_ripemd160[RIPEMD160_DIGEST_SIZE];
1453
+ memset_zero(prehash_ripemd160, RIPEMD160_DIGEST_SIZE);
1454
+ ripemd160_of_str(prehash_sha256, SHA256_DIGEST_SIZE, prehash_ripemd160);
1455
+
1456
+ // Shard Hash
1457
+ char *hash = hex2str(RIPEMD160_DIGEST_SIZE, prehash_ripemd160);
1458
+ if (!hash) {
1459
+ req->error_status = STORJ_MEMORY_ERROR;
1460
+ goto clean_variables;
1461
+ }
1462
+ memcpy(shard_meta->hash, hash, strlen(hash));
1463
+ free(hash);
1464
+
1465
+ uint8_t preleaf_sha256[SHA256_DIGEST_SIZE];
1466
+ memset_zero(preleaf_sha256, SHA256_DIGEST_SIZE);
1467
+ uint8_t preleaf_ripemd160[RIPEMD160_DIGEST_SIZE];
1468
+ memset_zero(preleaf_ripemd160, RIPEMD160_DIGEST_SIZE);
1469
+ char leaf[RIPEMD160_DIGEST_SIZE*2 +1];
1470
+ memset(leaf, '\0', RIPEMD160_DIGEST_SIZE*2 +1);
1471
+ for (int i = 0; i < STORJ_SHARD_CHALLENGES; i++ ) {
1472
+ // finish first sha256 for leaf
1473
+ sha256_digest(&first_sha256_for_leaf[i], SHA256_DIGEST_SIZE, preleaf_sha256);
1474
+
1475
+ // ripemd160 result of sha256
1476
+ ripemd160_of_str(preleaf_sha256, SHA256_DIGEST_SIZE, preleaf_ripemd160);
1477
+
1478
+ // sha256 and ripemd160 again
1479
+ ripemd160sha256_as_string(preleaf_ripemd160, RIPEMD160_DIGEST_SIZE, leaf);
1480
+
1481
+ memcpy(shard_meta->tree[i], leaf, RIPEMD160_DIGEST_SIZE*2 + 1);
1482
+ }
1483
+
1484
+ clean_variables:
1485
+ if (encryption_ctx) {
1486
+ free_encryption_ctx(encryption_ctx);
1487
+ }
1488
+ }
1489
+
1490
+ static void queue_prepare_frame(storj_upload_state_t *state, int index)
1491
+ {
1492
+ uv_work_t *shard_work = shard_meta_work_new(index, state);
1493
+ if (!shard_work) {
1494
+ state->error_status = STORJ_MEMORY_ERROR;
1495
+ return;
1496
+ }
1497
+
1498
+ state->pending_work_count += 1;
1499
+ int status = uv_queue_work(state->env->loop, (uv_work_t*) shard_work,
1500
+ prepare_frame, after_prepare_frame);
1501
+
1502
+ if (status) {
1503
+ state->error_status = STORJ_QUEUE_ERROR;
1504
+ return;
1505
+ }
1506
+
1507
+ state->shard[index].progress = PREPARING_FRAME;
1508
+ }
1509
+
1510
+ static void after_create_encrypted_file(uv_work_t *work, int status)
1511
+ {
1512
+ encrypt_file_req_t *req = work->data;
1513
+ storj_upload_state_t *state = req->upload_state;
1514
+
1515
+ state->pending_work_count -= 1;
1516
+ state->create_encrypted_file_count += 1;
1517
+
1518
+ uint64_t encrypted_file_size = 0;
1519
+ #ifdef _WIN32
1520
+ struct _stati64 st;
1521
+ _stati64(state->encrypted_file_path, &st);
1522
+ encrypted_file_size = st.st_size;
1523
+ #else
1524
+ struct stat st;
1525
+ stat(state->encrypted_file_path, &st);
1526
+ encrypted_file_size = st.st_size;
1527
+ #endif
1528
+
1529
+ if (req->error_status != 0 || state->file_size != encrypted_file_size) {
1530
+ state->log->warn(state->env->log_options, state->handle,
1531
+ "Failed to encrypt data.");
1532
+
1533
+ if (state->create_encrypted_file_count == 6) {
1534
+ state->error_status = STORJ_FILE_ENCRYPTION_ERROR;
1535
+ }
1536
+ } else {
1537
+ state->log->info(state->env->log_options, state->handle,
1538
+ "Successfully encrypted file");
1539
+
1540
+ state->encrypted_file = fopen(state->encrypted_file_path, "r");
1541
+ if (!state->encrypted_file) {
1542
+ state->error_status = STORJ_FILE_READ_ERROR;
1543
+ }
1544
+ }
1545
+
1546
+ state->creating_encrypted_file = false;
1547
+
1548
+ clean_variables:
1549
+ queue_next_work(state);
1550
+ free(work->data);
1551
+ free(work);
1552
+ }
1553
+
1554
+ static void create_encrypted_file(uv_work_t *work)
1555
+ {
1556
+ encrypt_file_req_t *req = work->data;
1557
+ storj_upload_state_t *state = req->upload_state;
1558
+
1559
+ state->log->info(state->env->log_options, state->handle, "Encrypting file...");
1560
+
1561
+ // Initialize the encryption context
1562
+ storj_encryption_ctx_t *encryption_ctx = prepare_encryption_ctx(state->encryption_ctr,
1563
+ state->encryption_key);
1564
+ if (!encryption_ctx) {
1565
+ state->error_status = STORJ_MEMORY_ERROR;
1566
+ goto clean_variables;
1567
+ }
1568
+
1569
+ uint8_t cphr_txt[AES_BLOCK_SIZE * 256];
1570
+ memset_zero(cphr_txt, AES_BLOCK_SIZE * 256);
1571
+ char read_data[AES_BLOCK_SIZE * 256];
1572
+ memset_zero(read_data, AES_BLOCK_SIZE * 256);
1573
+ unsigned long int read_bytes = 0;
1574
+ unsigned long int written_bytes = 0;
1575
+ uint64_t total_read = 0;
1576
+
1577
+ FILE *encrypted_file = fopen(state->encrypted_file_path, "w+");
1578
+
1579
+ if (encrypted_file == NULL) {
1580
+ state->log->error(state->env->log_options, state->handle,
1581
+ "Can't create file for encrypted data [%s]",
1582
+ state->encrypted_file_path);
1583
+ goto clean_variables;
1584
+ }
1585
+
1586
+ do {
1587
+ if (state->canceled) {
1588
+ goto clean_variables;
1589
+ }
1590
+
1591
+ read_bytes = pread(fileno(state->original_file),
1592
+ read_data, AES_BLOCK_SIZE * 256,
1593
+ total_read);
1594
+
1595
+ if (read_bytes == -1) {
1596
+ state->log->warn(state->env->log_options, state->handle,
1597
+ "Error reading file: %d",
1598
+ errno);
1599
+ req->error_status = STORJ_FILE_READ_ERROR;
1600
+ goto clean_variables;
1601
+ }
1602
+
1603
+ // Encrypt data
1604
+ ctr_crypt(encryption_ctx->ctx, (nettle_cipher_func *)aes256_encrypt,
1605
+ AES_BLOCK_SIZE, encryption_ctx->encryption_ctr, read_bytes,
1606
+ (uint8_t *)cphr_txt, (uint8_t *)read_data);
1607
+
1608
+ written_bytes = pwrite(fileno(encrypted_file), cphr_txt, read_bytes, total_read);
1609
+
1610
+ memset_zero(read_data, AES_BLOCK_SIZE * 256);
1611
+ memset_zero(cphr_txt, AES_BLOCK_SIZE * 256);
1612
+
1613
+ total_read += read_bytes;
1614
+
1615
+ if (written_bytes != read_bytes) {
1616
+ goto clean_variables;
1617
+ }
1618
+
1619
+ } while(total_read < state->file_size && read_bytes > 0);
1620
+
1621
+ clean_variables:
1622
+ if (encrypted_file) {
1623
+ fclose(encrypted_file);
1624
+ }
1625
+ if (encryption_ctx) {
1626
+ free_encryption_ctx(encryption_ctx);
1627
+ }
1628
+ }
1629
+
1630
+ static void queue_create_encrypted_file(storj_upload_state_t *state)
1631
+ {
1632
+ uv_work_t *work = uv_work_new();
1633
+ if (!work) {
1634
+ state->error_status = STORJ_MEMORY_ERROR;
1635
+ return;
1636
+ }
1637
+
1638
+ state->pending_work_count += 1;
1639
+
1640
+ encrypt_file_req_t *req = malloc(sizeof(encrypt_file_req_t));
1641
+
1642
+ req->error_status = 0;
1643
+ req->upload_state = state;
1644
+ work->data = req;
1645
+
1646
+ int status = uv_queue_work(state->env->loop, (uv_work_t*) work,
1647
+ create_encrypted_file, after_create_encrypted_file);
1648
+
1649
+ if (status) {
1650
+ state->error_status = STORJ_QUEUE_ERROR;
1651
+ }
1652
+
1653
+ state->creating_encrypted_file = true;
1654
+ }
1655
+
1656
+ static void after_request_frame_id(uv_work_t *work, int status)
1657
+ {
1658
+ frame_request_t *req = work->data;
1659
+ storj_upload_state_t *state = req->upload_state;
1660
+
1661
+ state->requesting_frame = false;
1662
+ state->pending_work_count -= 1;
1663
+
1664
+ if (status == UV_ECANCELED) {
1665
+ state->frame_request_count = 0;
1666
+ goto clean_variables;
1667
+ }
1668
+
1669
+ state->frame_request_count += 1;
1670
+
1671
+ if (req->status_code == 429 || req->status_code == 420) {
1672
+
1673
+ state->error_status = STORJ_BRIDGE_RATE_ERROR;
1674
+
1675
+ } else if (req->error_status == 0 && req->status_code == 200 && req->frame_id) {
1676
+
1677
+ state->log->info(state->env->log_options, state->handle,
1678
+ "Successfully retrieved frame id: %s", req->frame_id);
1679
+
1680
+ state->frame_id = req->frame_id;
1681
+
1682
+ } else if (state->frame_request_count == 6) {
1683
+ state->error_status = STORJ_BRIDGE_FRAME_ERROR;
1684
+ }
1685
+
1686
+ clean_variables:
1687
+ queue_next_work(state);
1688
+ free(req);
1689
+ free(work);
1690
+ }
1691
+
1692
+ static void request_frame_id(uv_work_t *work)
1693
+ {
1694
+ frame_request_t *req = work->data;
1695
+ storj_upload_state_t *state = req->upload_state;
1696
+
1697
+ req->log->info(state->env->log_options,
1698
+ state->handle,
1699
+ "[%s] Requesting file staging frame... (retry: %d)",
1700
+ state->file_name,
1701
+ state->frame_request_count);
1702
+
1703
+ // Prepare the body
1704
+ struct json_object *body = json_object_new_object();
1705
+
1706
+ int status_code;
1707
+ struct json_object *response = NULL;
1708
+ int request_status = fetch_json(req->http_options,
1709
+ req->options,
1710
+ "POST",
1711
+ "/frames",
1712
+ body,
1713
+ true,
1714
+ &response,
1715
+ &status_code);
1716
+
1717
+
1718
+ if (request_status) {
1719
+ req->log->warn(state->env->log_options, state->handle,
1720
+ "Request frame id error: %i", request_status);
1721
+ }
1722
+
1723
+ req->log->debug(state->env->log_options,
1724
+ state->handle,
1725
+ "fn[request_frame_id] - JSON Response: %s",
1726
+ json_object_to_json_string(response));
1727
+
1728
+ struct json_object *frame_id;
1729
+ if (!json_object_object_get_ex(response, "id", &frame_id)) {
1730
+ req->error_status = STORJ_BRIDGE_JSON_ERROR;
1731
+ goto cleanup;
1732
+ }
1733
+
1734
+ if (!json_object_is_type(frame_id, json_type_string)) {
1735
+ req->error_status = STORJ_BRIDGE_JSON_ERROR;
1736
+ goto cleanup;
1737
+ }
1738
+
1739
+ char *frame_id_str = (char *)json_object_get_string(frame_id);
1740
+ req->frame_id = calloc(strlen(frame_id_str) + 1, sizeof(char));
1741
+ if (!req->frame_id) {
1742
+ req->error_status = STORJ_MEMORY_ERROR;
1743
+ goto cleanup;
1744
+ }
1745
+
1746
+ strcpy(req->frame_id, frame_id_str);
1747
+
1748
+ cleanup:
1749
+ req->status_code = status_code;
1750
+
1751
+ json_object_put(response);
1752
+ json_object_put(body);
1753
+ }
1754
+
1755
+ static void queue_request_frame_id(storj_upload_state_t *state)
1756
+ {
1757
+ uv_work_t *work = frame_work_new(NULL, state);
1758
+ if (!work) {
1759
+ state->error_status = STORJ_MEMORY_ERROR;
1760
+ return;
1761
+ }
1762
+
1763
+ state->pending_work_count += 1;
1764
+ int status = uv_queue_work(state->env->loop, (uv_work_t*) work,
1765
+ request_frame_id, after_request_frame_id);
1766
+
1767
+ if (status) {
1768
+ state->error_status = STORJ_QUEUE_ERROR;
1769
+ }
1770
+
1771
+ state->requesting_frame = true;
1772
+ }
1773
+
1774
+ static void after_create_parity_shards(uv_work_t *work, int status)
1775
+ {
1776
+ parity_shard_req_t *req = work->data;
1777
+ storj_upload_state_t *state = req->upload_state;
1778
+
1779
+ state->pending_work_count -= 1;
1780
+
1781
+ // TODO: Check if file was created
1782
+ if (req->error_status != 0) {
1783
+ state->log->warn(state->env->log_options, state->handle,
1784
+ "Failed to create parity shards");
1785
+
1786
+ state->awaiting_parity_shards = true;
1787
+
1788
+ state->error_status = STORJ_FILE_PARITY_ERROR;
1789
+ } else {
1790
+ state->log->info(state->env->log_options, state->handle,
1791
+ "Successfully created parity shards");
1792
+
1793
+ state->parity_file = fopen(state->parity_file_path, "r");
1794
+
1795
+ if (!state->parity_file) {
1796
+ state->error_status = STORJ_FILE_READ_ERROR;
1797
+ }
1798
+
1799
+ }
1800
+
1801
+ clean_variables:
1802
+ queue_next_work(state);
1803
+ free(work->data);
1804
+ free(work);
1805
+ }
1806
+
1807
+ static void create_parity_shards(uv_work_t *work)
1808
+ {
1809
+ parity_shard_req_t *req = work->data;
1810
+ storj_upload_state_t *state = req->upload_state;
1811
+
1812
+ state->log->info(state->env->log_options, state->handle,
1813
+ "Creating parity shards");
1814
+
1815
+ // ???
1816
+ fec_init();
1817
+
1818
+ uint8_t **data_blocks = NULL;
1819
+ uint8_t **fec_blocks = NULL;
1820
+
1821
+ uint8_t *map = NULL;
1822
+ int status = 0;
1823
+
1824
+ FILE *encrypted_file = fopen(state->encrypted_file_path, "r");
1825
+
1826
+ if (!encrypted_file) {
1827
+ req->error_status = 1;
1828
+ state->log->error(state->env->log_options, state->handle,
1829
+ "Unable to open encrypted file");
1830
+ goto clean_variables;
1831
+ }
1832
+
1833
+ status = map_file(fileno(encrypted_file), state->file_size, &map, true);
1834
+
1835
+ if (status) {
1836
+ req->error_status = 1;
1837
+ state->log->error(state->env->log_options, state->handle,
1838
+ "Could not create mmap original file: %d", status);
1839
+ goto clean_variables;
1840
+ }
1841
+
1842
+ uint64_t parity_size = state->total_shards * state->shard_size - state->file_size;
1843
+
1844
+ // determine parity shard location
1845
+ char *tmp_folder = NULL;
1846
+ if (!state->parity_file_path) {
1847
+ req->error_status = 1;
1848
+ state->log->error(state->env->log_options, state->handle,
1849
+ "No temp folder set for parity shards");
1850
+ goto clean_variables;
1851
+ }
1852
+
1853
+ FILE *parity_file = fopen(state->parity_file_path, "w+");
1854
+ if (!parity_file) {
1855
+ req->error_status = 1;
1856
+ state->log->error(state->env->log_options, state->handle,
1857
+ "Could not open parity file [%s]", state->parity_file_path);
1858
+ goto clean_variables;
1859
+ }
1860
+
1861
+ int falloc_status = allocatefile(fileno(parity_file), parity_size);
1862
+
1863
+ if (falloc_status) {
1864
+ req->error_status = 1;
1865
+ state->log->error(state->env->log_options, state->handle,
1866
+ "Could not allocate space for mmap parity " \
1867
+ "shard file: %i", falloc_status);
1868
+ goto clean_variables;
1869
+ }
1870
+
1871
+ uint8_t *map_parity = NULL;
1872
+ status = map_file(fileno(parity_file), parity_size, &map_parity, false);
1873
+
1874
+ if (status) {
1875
+ req->error_status = 1;
1876
+ state->log->error(state->env->log_options, state->handle,
1877
+ "Could not create mmap parity shard file: %d", status);
1878
+ goto clean_variables;
1879
+ }
1880
+
1881
+ data_blocks = (uint8_t**)malloc(state->total_data_shards * sizeof(uint8_t *));
1882
+ if (!data_blocks) {
1883
+ req->error_status = 1;
1884
+ state->log->error(state->env->log_options, state->handle,
1885
+ "memory error: unable to malloc");
1886
+ goto clean_variables;
1887
+ }
1888
+
1889
+ for (int i = 0; i < state->total_data_shards; i++) {
1890
+ data_blocks[i] = map + i * state->shard_size;
1891
+ }
1892
+
1893
+ fec_blocks = (uint8_t**)malloc(state->total_parity_shards * sizeof(uint8_t *));
1894
+ if (!fec_blocks) {
1895
+ req->error_status = 1;
1896
+ state->log->error(state->env->log_options, state->handle,
1897
+ "memory error: unable to malloc");
1898
+ goto clean_variables;
1899
+ }
1900
+
1901
+ for (int i = 0; i < state->total_parity_shards; i++) {
1902
+ fec_blocks[i] = map_parity + i * state->shard_size;
1903
+ }
1904
+
1905
+ state->log->debug(state->env->log_options, state->handle,
1906
+ "Encoding parity shards, data_shards: %i, " \
1907
+ "parity_shards: %i, shard_size: %" PRIu64 ", " \
1908
+ "file_size: %" PRIu64,
1909
+ state->total_data_shards,
1910
+ state->total_parity_shards,
1911
+ state->shard_size,
1912
+ state->file_size);
1913
+
1914
+
1915
+ reed_solomon *rs = reed_solomon_new(state->total_data_shards,
1916
+ state->total_parity_shards);
1917
+ reed_solomon_encode2(rs, data_blocks, fec_blocks, state->total_shards,
1918
+ state->shard_size, state->file_size);
1919
+ reed_solomon_release(rs);
1920
+
1921
+ clean_variables:
1922
+ if (data_blocks) {
1923
+ free(data_blocks);
1924
+ }
1925
+
1926
+ if (fec_blocks) {
1927
+ free(fec_blocks);
1928
+ }
1929
+
1930
+ if (tmp_folder) {
1931
+ free(tmp_folder);
1932
+ }
1933
+
1934
+ if (map) {
1935
+ unmap_file(map, state->file_size);
1936
+ }
1937
+
1938
+ if (map_parity) {
1939
+ unmap_file(map_parity, parity_size);
1940
+ }
1941
+
1942
+ if (parity_file) {
1943
+ fclose(parity_file);
1944
+ }
1945
+
1946
+ if (encrypted_file) {
1947
+ fclose(encrypted_file);
1948
+ }
1949
+ }
1950
+
1951
+
1952
+ static void queue_create_parity_shards(storj_upload_state_t *state)
1953
+ {
1954
+ uv_work_t *work = uv_work_new();
1955
+ if (!work) {
1956
+ state->error_status = STORJ_MEMORY_ERROR;
1957
+ return;
1958
+ }
1959
+
1960
+ state->pending_work_count += 1;
1961
+
1962
+ parity_shard_req_t *req = malloc(sizeof(parity_shard_req_t));
1963
+
1964
+ req->error_status = 0;
1965
+ req->upload_state = state;
1966
+ work->data = req;
1967
+
1968
+ int status = uv_queue_work(state->env->loop, (uv_work_t*) work,
1969
+ create_parity_shards, after_create_parity_shards);
1970
+
1971
+ if (status) {
1972
+ state->error_status = STORJ_QUEUE_ERROR;
1973
+ }
1974
+
1975
+ state->awaiting_parity_shards = false;
1976
+ }
1977
+
1978
+ static void after_send_exchange_report(uv_work_t *work, int status)
1979
+ {
1980
+ shard_send_report_t *req = work->data;
1981
+
1982
+ req->state->pending_work_count -= 1;
1983
+
1984
+ if (status == UV_ECANCELED) {
1985
+ req->report->send_count = 0;
1986
+ req->report->send_status = STORJ_REPORT_AWAITING_SEND;
1987
+
1988
+ goto clean_variables;
1989
+ }
1990
+
1991
+ req->report->send_count += 1;
1992
+
1993
+ if (req->status_code == 201) {
1994
+ req->state->env->log->info(req->state->env->log_options,
1995
+ req->state->handle,
1996
+ "Successfully sent exchange report for shard %d",
1997
+ req->report->pointer_index);
1998
+
1999
+ req->report->send_status = STORJ_REPORT_NOT_PREPARED; // report has been sent
2000
+ } else if (req->report->send_count == 6) {
2001
+ req->report->send_status = STORJ_REPORT_NOT_PREPARED; // report failed retries
2002
+ } else {
2003
+ req->report->send_status = STORJ_REPORT_AWAITING_SEND; // reset report back to unsent
2004
+ }
2005
+
2006
+ clean_variables:
2007
+ queue_next_work(req->state);
2008
+ free(work->data);
2009
+ free(work);
2010
+
2011
+ }
2012
+
2013
+ static void send_exchange_report(uv_work_t *work)
2014
+ {
2015
+ shard_send_report_t *req = work->data;
2016
+ storj_upload_state_t *state = req->state;
2017
+
2018
+ struct json_object *body = json_object_new_object();
2019
+
2020
+ json_object_object_add(body, "dataHash",
2021
+ json_object_new_string(req->report->data_hash));
2022
+
2023
+ json_object_object_add(body, "reporterId",
2024
+ json_object_new_string(req->report->reporter_id));
2025
+
2026
+ json_object_object_add(body, "farmerId",
2027
+ json_object_new_string(req->report->farmer_id));
2028
+
2029
+ json_object_object_add(body, "clientId",
2030
+ json_object_new_string(req->report->client_id));
2031
+
2032
+ json_object_object_add(body, "exchangeStart",
2033
+ json_object_new_int64(req->report->start));
2034
+
2035
+ json_object_object_add(body, "exchangeEnd",
2036
+ json_object_new_int64(req->report->end));
2037
+
2038
+ json_object_object_add(body, "exchangeResultCode",
2039
+ json_object_new_int(req->report->code));
2040
+
2041
+ json_object_object_add(body, "exchangeResultMessage",
2042
+ json_object_new_string(req->report->message));
2043
+
2044
+ int status_code = 0;
2045
+
2046
+ // there should be an empty object in response
2047
+ struct json_object *response = NULL;
2048
+ int request_status = fetch_json(req->http_options,
2049
+ req->options, "POST",
2050
+ "/reports/exchanges", body,
2051
+ true, &response, &status_code);
2052
+
2053
+
2054
+ if (request_status) {
2055
+ state->log->warn(state->env->log_options, state->handle,
2056
+ "Send exchange report error: %i", request_status);
2057
+ }
2058
+
2059
+ req->status_code = status_code;
2060
+
2061
+ // free all memory for body and response
2062
+ json_object_put(response);
2063
+ json_object_put(body);
2064
+ }
2065
+
2066
+ static void queue_send_exchange_report(storj_upload_state_t *state, int index)
2067
+ {
2068
+ if (state->shard[index].report->send_count == 6) {
2069
+ return;
2070
+ }
2071
+
2072
+ state->env->log->info(state->env->log_options, state->handle,
2073
+ "Sending exchange report for Shard index %d... (retry: %d)",
2074
+ index,
2075
+ state->shard[index].report->send_count);
2076
+
2077
+ shard_tracker_t *shard = &state->shard[index];
2078
+
2079
+ uv_work_t *work = malloc(sizeof(uv_work_t));
2080
+ assert(work != NULL);
2081
+
2082
+ shard_send_report_t *req = malloc(sizeof(shard_send_report_t));
2083
+
2084
+ req->http_options = state->env->http_options;
2085
+ req->options = state->env->bridge_options;
2086
+ req->status_code = 0;
2087
+ req->report = shard->report;
2088
+ req->report->send_status = STORJ_REPORT_SENDING;
2089
+ req->state = state;
2090
+ req->pointer_index = index;
2091
+
2092
+ work->data = req;
2093
+
2094
+ state->pending_work_count += 1;
2095
+ int status = uv_queue_work(state->env->loop, (uv_work_t*) work,
2096
+ send_exchange_report, after_send_exchange_report);
2097
+ if (status) {
2098
+ state->error_status = STORJ_QUEUE_ERROR;
2099
+ }
2100
+ }
2101
+
2102
+ static void verify_bucket_id_callback(uv_work_t *work_req, int status)
2103
+ {
2104
+ get_bucket_request_t *req = work_req->data;
2105
+ storj_upload_state_t *state = req->handle;
2106
+
2107
+ state->log->info(state->env->log_options, state->handle,
2108
+ "Checking if bucket id [%s] exists", state->bucket_id);
2109
+
2110
+ state->pending_work_count -= 1;
2111
+ state->bucket_verify_count += 1;
2112
+
2113
+ if (req->status_code == 200) {
2114
+ state->bucket_verified = true;
2115
+ goto clean_variables;
2116
+ } else if (req->status_code == 404 || req->status_code == 400) {
2117
+ state->log->error(state->env->log_options, state->handle,
2118
+ "Bucket [%s] doesn't exist", state->bucket_id);
2119
+ state->error_status = STORJ_BRIDGE_BUCKET_NOTFOUND_ERROR;
2120
+ } else {
2121
+ state->log->error(state->env->log_options, state->handle,
2122
+ "Request failed with status code: %i", req->status_code);
2123
+
2124
+ if (state->bucket_verify_count == 6) {
2125
+ state->error_status = STORJ_BRIDGE_REQUEST_ERROR;
2126
+ state->bucket_verify_count = 0;
2127
+ }
2128
+
2129
+ goto clean_variables;
2130
+ }
2131
+ state->bucket_verified = true;
2132
+
2133
+ clean_variables:
2134
+ queue_next_work(state);
2135
+
2136
+ json_object_put(req->response);
2137
+ storj_free_get_bucket_request(req);
2138
+ free(work_req);
2139
+ }
2140
+
2141
+ static void queue_verify_bucket_id(storj_upload_state_t *state)
2142
+ {
2143
+ state->pending_work_count += 1;
2144
+ storj_bridge_get_bucket(state->env, state->bucket_id, state, verify_bucket_id_callback);
2145
+ }
2146
+
2147
+
2148
+ static void verify_file_name_callback(uv_work_t *work_req, int status)
2149
+ {
2150
+ json_request_t *req = work_req->data;
2151
+ storj_upload_state_t *state = req->handle;
2152
+
2153
+ state->pending_work_count -= 1;
2154
+ state->file_verify_count += 1;
2155
+
2156
+ if (req->status_code == 404) {
2157
+ state->file_verified = true;
2158
+ goto clean_variables;
2159
+ } else if (req->status_code == 200) {
2160
+ state->log->error(state->env->log_options, state->handle,
2161
+ "File [%s] already exists", state->file_name);
2162
+ state->error_status = STORJ_BRIDGE_BUCKET_FILE_EXISTS;
2163
+ } else {
2164
+ state->log->error(state->env->log_options, state->handle,
2165
+ "Request failed with status code: %i", req->status_code);
2166
+
2167
+ if (state->file_verify_count == 6) {
2168
+ state->error_status = STORJ_BRIDGE_REQUEST_ERROR;
2169
+ state->file_verify_count = 0;
2170
+ }
2171
+
2172
+ goto clean_variables;
2173
+ }
2174
+
2175
+ state->file_verified = true;
2176
+
2177
+ clean_variables:
2178
+ queue_next_work(state);
2179
+
2180
+ json_object_put(req->response);
2181
+ free(req->path);
2182
+ free(req);
2183
+ free(work_req);
2184
+ }
2185
+
2186
+ static void verify_file_name(uv_work_t *work)
2187
+ {
2188
+ json_request_t *req = work->data;
2189
+ storj_upload_state_t *state = req->handle;
2190
+ int status_code = 0;
2191
+
2192
+ state->log->info(state->env->log_options, state->handle,
2193
+ "Checking if file name [%s] already exists...", state->file_name);
2194
+
2195
+ req->error_code = fetch_json(req->http_options,
2196
+ req->options, req->method, req->path, req->body,
2197
+ req->auth, &req->response, &status_code);
2198
+
2199
+ req->status_code = status_code;
2200
+ }
2201
+
2202
+ static void queue_verify_file_name(storj_upload_state_t *state)
2203
+ {
2204
+ state->pending_work_count += 1;
2205
+
2206
+ CURL *curl = curl_easy_init();
2207
+ if (!curl) {
2208
+ state->error_status = STORJ_MEMORY_ERROR;
2209
+ return;
2210
+ }
2211
+
2212
+ char *escaped = curl_easy_escape(curl, state->encrypted_file_name,
2213
+ strlen(state->encrypted_file_name));
2214
+
2215
+ if (!escaped) {
2216
+ curl_easy_cleanup(curl);
2217
+ state->error_status = STORJ_MEMORY_ERROR;
2218
+ return;
2219
+ }
2220
+
2221
+ char *path = str_concat_many(4, "/buckets/", state->bucket_id,
2222
+ "/file-ids/", escaped);
2223
+ curl_free(escaped);
2224
+ curl_easy_cleanup(curl);
2225
+
2226
+ if (!path) {
2227
+ state->error_status = STORJ_MEMORY_ERROR;
2228
+ return;
2229
+ }
2230
+
2231
+ uv_work_t *work = uv_work_new();
2232
+ if (!work) {
2233
+ state->error_status = STORJ_MEMORY_ERROR;
2234
+ return;
2235
+ }
2236
+
2237
+ json_request_t *req = malloc(sizeof(json_request_t));
2238
+ if (!req) {
2239
+ state->error_status = STORJ_MEMORY_ERROR;
2240
+ return;
2241
+ }
2242
+
2243
+ req->http_options = state->env->http_options;
2244
+ req->options = state->env->bridge_options;
2245
+ req->method = "GET";
2246
+ req->path = path;
2247
+ req->auth = true;
2248
+ req->body = NULL;
2249
+ req->response = NULL;
2250
+ req->error_code = 0;
2251
+ req->status_code = 0;
2252
+ req->handle = state;
2253
+
2254
+ work->data = req;
2255
+
2256
+ int status = uv_queue_work(state->env->loop, (uv_work_t*) work,
2257
+ verify_file_name, verify_file_name_callback);
2258
+
2259
+ if (status) {
2260
+ state->error_status = STORJ_QUEUE_ERROR;
2261
+ return;
2262
+ }
2263
+ }
2264
+
2265
+ // Check if a frame/shard is already being prepared/pushed.
2266
+ // We want to limit disk reads for dd and network activity
2267
+ static int check_in_progress(storj_upload_state_t *state, int status)
2268
+ {
2269
+ int active = 0;
2270
+
2271
+ for (int index = 0; index < state->total_shards; index++ ) {
2272
+ if (state->shard[index].progress == status) {
2273
+ active += 1;
2274
+ }
2275
+ }
2276
+
2277
+ return active;
2278
+ }
2279
+
2280
+ static void queue_push_frame_and_shard(storj_upload_state_t *state)
2281
+ {
2282
+ for (int index = 0; index < state->total_shards; index++) {
2283
+
2284
+ if (state->shard[index].progress == AWAITING_PUSH_FRAME &&
2285
+ state->shard[index].report->send_status == STORJ_REPORT_NOT_PREPARED &&
2286
+ check_in_progress(state, PUSHING_FRAME) < state->push_frame_limit) {
2287
+ queue_push_frame(state, index);
2288
+ }
2289
+
2290
+ if (state->shard[index].progress == AWAITING_PUSH_SHARD &&
2291
+ state->shard[index].report->send_status == STORJ_REPORT_NOT_PREPARED &&
2292
+ check_in_progress(state, PUSHING_SHARD) < state->push_shard_limit) {
2293
+ queue_push_shard(state, index);
2294
+ }
2295
+ }
2296
+ }
2297
+
2298
+ static void queue_next_work(storj_upload_state_t *state)
2299
+ {
2300
+ storj_log_levels_t *log = state->log;
2301
+ storj_log_options_t *log_options = state->env->log_options;
2302
+ void *handle = state->handle;
2303
+ int *pending_work_count = &state->pending_work_count;
2304
+
2305
+ if (state->canceled) {
2306
+ return cleanup_state(state);
2307
+ }
2308
+
2309
+ // report any errors
2310
+ if (state->error_status != 0) {
2311
+ return cleanup_state(state);
2312
+ }
2313
+
2314
+ // report upload complete
2315
+ if (state->completed_upload) {
2316
+ return cleanup_state(state);
2317
+ }
2318
+
2319
+ // Verify bucket_id is exists
2320
+ if (!state->bucket_verified) {
2321
+ queue_verify_bucket_id(state);
2322
+ goto finish_up;
2323
+ }
2324
+
2325
+ // Verify that the file name doesn't exist
2326
+ if (!state->file_verified) {
2327
+ queue_verify_file_name(state);
2328
+ goto finish_up;
2329
+ }
2330
+
2331
+ if (!state->frame_id && !state->requesting_frame) {
2332
+ queue_request_frame_id(state);
2333
+ goto finish_up;
2334
+ }
2335
+
2336
+ if (state->rs) {
2337
+ if (!state->encrypted_file) {
2338
+ queue_create_encrypted_file(state);
2339
+ goto finish_up;
2340
+ }
2341
+
2342
+ // Create parity shards using reed solomon
2343
+ if (state->awaiting_parity_shards) {
2344
+ queue_create_parity_shards(state);
2345
+ goto finish_up;
2346
+ }
2347
+ }
2348
+
2349
+ for (int index = 0; index < state->total_shards; index++ ) {
2350
+ if (state->shard[index].progress == AWAITING_PREPARE_FRAME &&
2351
+ check_in_progress(state, PREPARING_FRAME) < state->prepare_frame_limit) {
2352
+ queue_prepare_frame(state, index);
2353
+ }
2354
+ }
2355
+
2356
+ // report upload complete
2357
+ if (state->completed_shards == state->total_shards &&
2358
+ !state->creating_bucket_entry &&
2359
+ !state->completed_upload) {
2360
+ queue_create_bucket_entry(state);
2361
+ }
2362
+
2363
+ for (int index = 0; index < state->total_shards; index++ ) {
2364
+ if (state->shard[index].report->send_status == STORJ_REPORT_AWAITING_SEND) {
2365
+ queue_send_exchange_report(state, index);
2366
+ }
2367
+ }
2368
+
2369
+ // NB: This needs to be the last thing, there is a bug with mingw
2370
+ // builds and uv_async_init, where leaving a block will cause the state
2371
+ // pointer to change values.
2372
+ if (state->frame_id) {
2373
+ queue_push_frame_and_shard(state);
2374
+ }
2375
+
2376
+ finish_up:
2377
+
2378
+ log->debug(log_options, handle,
2379
+ "Pending work count: %d", *pending_work_count);
2380
+ }
2381
+
2382
+ static void begin_work_queue(uv_work_t *work, int status)
2383
+ {
2384
+ storj_upload_state_t *state = work->data;
2385
+
2386
+ // Load progress bar
2387
+ state->progress_cb(0, 0, 0, state->handle);
2388
+
2389
+ state->pending_work_count -= 1;
2390
+ queue_next_work(state);
2391
+
2392
+ free(work);
2393
+ }
2394
+
2395
+ static void prepare_upload_state(uv_work_t *work)
2396
+ {
2397
+ storj_upload_state_t *state = work->data;
2398
+
2399
+ // Get the file size, expect to be up to 10tb
2400
+ #ifdef _WIN32
2401
+ struct _stati64 st;
2402
+
2403
+ if(_fstati64(fileno(state->original_file), &st) != 0) {
2404
+ state->error_status = STORJ_FILE_INTEGRITY_ERROR;
2405
+ return;
2406
+ }
2407
+ #else
2408
+ struct stat st;
2409
+ if(fstat(fileno(state->original_file), &st) != 0) {
2410
+ state->error_status = STORJ_FILE_INTEGRITY_ERROR;
2411
+ return;
2412
+ }
2413
+ #endif
2414
+
2415
+ state->file_size = st.st_size;
2416
+ if (state->file_size < MIN_SHARD_SIZE) {
2417
+ state->rs = false;
2418
+ }
2419
+
2420
+ // Set Shard calculations
2421
+ state->shard_size = determine_shard_size(state->file_size, 0);
2422
+ if (!state->shard_size || state->shard_size == 0) {
2423
+ state->error_status = STORJ_FILE_SIZE_ERROR;
2424
+ return;
2425
+ }
2426
+
2427
+ state->total_data_shards = ceil((double)state->file_size / state->shard_size);
2428
+ state->total_parity_shards = (state->rs) ? ceil((double)state->total_data_shards * 2.0 / 3.0) : 0;
2429
+ state->total_shards = state->total_data_shards + state->total_parity_shards;
2430
+
2431
+ int tracker_calloc_amount = state->total_shards * sizeof(shard_tracker_t);
2432
+ state->shard = malloc(tracker_calloc_amount);
2433
+ if (!state->shard) {
2434
+ state->error_status = STORJ_MEMORY_ERROR;
2435
+ return;
2436
+ }
2437
+
2438
+ for (int i = 0; i < state->total_shards; i++) {
2439
+ state->shard[i].progress = AWAITING_PREPARE_FRAME;
2440
+ state->shard[i].push_frame_request_count = 0;
2441
+ state->shard[i].push_shard_request_count = 0;
2442
+ state->shard[i].index = i;
2443
+ state->shard[i].pointer = farmer_pointer_new();
2444
+ if (!state->shard[i].pointer) {
2445
+ state->error_status = STORJ_MEMORY_ERROR;
2446
+ return;
2447
+ }
2448
+ state->shard[i].meta = shard_meta_new();
2449
+ if (!state->shard[i].meta) {
2450
+ state->error_status = STORJ_MEMORY_ERROR;
2451
+ return;
2452
+ }
2453
+ state->shard[i].meta->is_parity = (i + 1 > state->total_data_shards) ? true : false;
2454
+ state->shard[i].report = storj_exchange_report_new();
2455
+ if (!state->shard[i].report) {
2456
+ state->error_status = STORJ_MEMORY_ERROR;
2457
+ return;
2458
+ }
2459
+ state->shard[i].uploaded_size = 0;
2460
+ state->shard[i].work = NULL;
2461
+ }
2462
+
2463
+ // Get the bucket key to encrypt the filename
2464
+ char *bucket_key_as_str = calloc(DETERMINISTIC_KEY_SIZE + 1, sizeof(char));
2465
+ generate_bucket_key(state->env->encrypt_options->mnemonic,
2466
+ state->bucket_id,
2467
+ &bucket_key_as_str);
2468
+
2469
+ uint8_t *bucket_key = str2hex(strlen(bucket_key_as_str), bucket_key_as_str);
2470
+ if (!bucket_key) {
2471
+ state->error_status = STORJ_MEMORY_ERROR;
2472
+ return;
2473
+ }
2474
+
2475
+ free(bucket_key_as_str);
2476
+
2477
+ // Get file name encryption key with first half of hmac w/ magic
2478
+ struct hmac_sha512_ctx ctx1;
2479
+ hmac_sha512_set_key(&ctx1, SHA256_DIGEST_SIZE, bucket_key);
2480
+ hmac_sha512_update(&ctx1, SHA256_DIGEST_SIZE, BUCKET_META_MAGIC);
2481
+ uint8_t key[SHA256_DIGEST_SIZE];
2482
+ hmac_sha512_digest(&ctx1, SHA256_DIGEST_SIZE, key);
2483
+
2484
+ // Generate the synthetic iv with first half of hmac w/ bucket and filename
2485
+ struct hmac_sha512_ctx ctx2;
2486
+ hmac_sha512_set_key(&ctx2, SHA256_DIGEST_SIZE, bucket_key);
2487
+ hmac_sha512_update(&ctx2, strlen(state->bucket_id),
2488
+ (uint8_t *)state->bucket_id);
2489
+ hmac_sha512_update(&ctx2, strlen(state->file_name),
2490
+ (uint8_t *)state->file_name);
2491
+ uint8_t filename_iv[SHA256_DIGEST_SIZE];
2492
+ hmac_sha512_digest(&ctx2, SHA256_DIGEST_SIZE, filename_iv);
2493
+
2494
+ free(bucket_key);
2495
+
2496
+ char *encrypted_file_name;
2497
+ encrypt_meta(state->file_name, key, filename_iv, &encrypted_file_name);
2498
+
2499
+ state->encrypted_file_name = encrypted_file_name;
2500
+
2501
+ uint8_t *index = NULL;
2502
+ char *key_as_str = NULL;
2503
+
2504
+ if (state->index) {
2505
+ index = str2hex(strlen(state->index), (char *)state->index);
2506
+ if (!index) {
2507
+ state->error_status = STORJ_MEMORY_ERROR;
2508
+ goto cleanup;
2509
+ }
2510
+ } else {
2511
+ // Get random index used for encryption
2512
+ index = calloc(SHA256_DIGEST_SIZE + 1, sizeof(uint8_t));
2513
+ if (!index) {
2514
+ state->error_status = STORJ_MEMORY_ERROR;
2515
+ goto cleanup;
2516
+ }
2517
+ random_buffer(index, SHA256_DIGEST_SIZE);
2518
+ }
2519
+
2520
+ char *index_as_str = hex2str(SHA256_DIGEST_SIZE, index);
2521
+ if (!index_as_str) {
2522
+ state->error_status = STORJ_MEMORY_ERROR;
2523
+ goto cleanup;
2524
+ }
2525
+
2526
+ state->index = index_as_str;
2527
+
2528
+ // Caculate the file encryption key based on the index
2529
+ key_as_str = calloc(DETERMINISTIC_KEY_SIZE + 1, sizeof(char));
2530
+ if (!key_as_str) {
2531
+ state->error_status = STORJ_MEMORY_ERROR;
2532
+ goto cleanup;
2533
+ }
2534
+
2535
+ int key_status = generate_file_key(state->env->encrypt_options->mnemonic,
2536
+ state->bucket_id,
2537
+ index_as_str,
2538
+ &key_as_str);
2539
+ if (key_status) {
2540
+ switch (key_status) {
2541
+ case 2:
2542
+ state->error_status = STORJ_HEX_DECODE_ERROR;
2543
+ break;
2544
+ default:
2545
+ state->error_status = STORJ_MEMORY_ERROR;
2546
+ }
2547
+ goto cleanup;
2548
+ }
2549
+
2550
+ uint8_t *encryption_key = str2hex(strlen(key_as_str), key_as_str);
2551
+ if (!encryption_key) {
2552
+ state->error_status = STORJ_MEMORY_ERROR;
2553
+ goto cleanup;
2554
+ }
2555
+ state->encryption_key = encryption_key;
2556
+
2557
+ uint8_t *encryption_ctr = calloc(AES_BLOCK_SIZE, sizeof(uint8_t));
2558
+ if (!encryption_ctr) {
2559
+ state->error_status = STORJ_MEMORY_ERROR;
2560
+ goto cleanup;
2561
+ }
2562
+ memcpy(encryption_ctr, index, AES_BLOCK_SIZE);
2563
+ state->encryption_ctr = encryption_ctr;
2564
+
2565
+ if (state->rs) {
2566
+ state->parity_file_path = create_tmp_name(state, ".parity");
2567
+ state->encrypted_file_path = create_tmp_name(state, ".crypt");
2568
+ }
2569
+
2570
+
2571
+ cleanup:
2572
+ if (key_as_str) {
2573
+ free(key_as_str);
2574
+ }
2575
+
2576
+ if (index) {
2577
+ free(index);
2578
+ }
2579
+
2580
+ }
2581
+
2582
+ char *create_tmp_name(storj_upload_state_t *state, char *extension)
2583
+ {
2584
+ char *tmp_folder = strdup(state->env->tmp_path);
2585
+ int encode_len = BASE16_ENCODE_LENGTH(SHA256_DIGEST_SIZE);
2586
+ int file_name_len = strlen(state->encrypted_file_name);
2587
+ int extension_len = strlen(extension);
2588
+ int tmp_folder_len = strlen(tmp_folder);
2589
+ if (tmp_folder[tmp_folder_len - 1] == separator()) {
2590
+ tmp_folder[tmp_folder_len - 1] = '\0';
2591
+ tmp_folder_len -= 1;
2592
+ }
2593
+
2594
+ char *path = calloc(
2595
+ tmp_folder_len + 1 + encode_len + extension_len + 2,
2596
+ sizeof(char)
2597
+ );
2598
+
2599
+ // hash and encode name for filesystem use
2600
+ struct sha256_ctx ctx;
2601
+ uint8_t digest[SHA256_DIGEST_SIZE];
2602
+ uint8_t digest_encoded[encode_len + 1];
2603
+ sha256_init(&ctx);
2604
+ sha256_update(&ctx, file_name_len, state->encrypted_file_name);
2605
+ sha256_digest(&ctx, SHA256_DIGEST_SIZE, digest);
2606
+ base16_encode_update(digest_encoded, SHA256_DIGEST_SIZE, digest);
2607
+ digest_encoded[encode_len] = '\0';
2608
+
2609
+ sprintf(path,
2610
+ "%s%c%s%s%c",
2611
+ tmp_folder,
2612
+ separator(),
2613
+ digest_encoded,
2614
+ extension,
2615
+ '\0');
2616
+
2617
+ free(tmp_folder);
2618
+ return path;
2619
+ }
2620
+
2621
+ STORJ_API int storj_bridge_store_file_cancel(storj_upload_state_t *state)
2622
+ {
2623
+ if (state->canceled) {
2624
+ return 0;
2625
+ }
2626
+
2627
+ state->canceled = true;
2628
+
2629
+ state->error_status = STORJ_TRANSFER_CANCELED;
2630
+
2631
+ // loop over all shards, and cancel any that are queued to be uploaded
2632
+ // any uploads that are in-progress will monitor the state->canceled
2633
+ // status and exit when set to true
2634
+ for (int i = 0; i < state->total_shards; i++) {
2635
+ shard_tracker_t *shard = &state->shard[i];
2636
+ if (shard->progress == PUSHING_SHARD) {
2637
+ uv_cancel((uv_req_t *)shard->work);
2638
+ }
2639
+ }
2640
+
2641
+ return 0;
2642
+ }
2643
+
2644
+ STORJ_API storj_upload_state_t *storj_bridge_store_file(storj_env_t *env,
2645
+ storj_upload_opts_t *opts,
2646
+ void *handle,
2647
+ storj_progress_cb progress_cb,
2648
+ storj_finished_upload_cb finished_cb)
2649
+ {
2650
+ if (!opts->fd) {
2651
+ env->log->error(env->log_options, handle, "Invalid File descriptor");
2652
+ return NULL;
2653
+ }
2654
+
2655
+ storj_upload_state_t *state = malloc(sizeof(storj_upload_state_t));
2656
+ if (!state) {
2657
+ return NULL;
2658
+ }
2659
+
2660
+ state->env = env;
2661
+ if (opts->index && strlen(opts->index) == 64) {
2662
+ state->index = opts->index;
2663
+ } else {
2664
+ state->index = NULL;
2665
+ }
2666
+ state->file_id = NULL;
2667
+ state->file_name = opts->file_name;
2668
+ state->encrypted_file_name = NULL;
2669
+ state->original_file = opts->fd;
2670
+ state->file_size = 0;
2671
+ state->bucket_id = opts->bucket_id;
2672
+ state->bucket_key = NULL;
2673
+ state->completed_shards = 0;
2674
+ state->total_shards = 0;
2675
+ state->total_data_shards = 0;
2676
+ state->total_parity_shards = 0;
2677
+ state->shard_size = 0;
2678
+ state->total_bytes = 0;
2679
+ state->uploaded_bytes = 0;
2680
+ state->exclude = NULL;
2681
+ state->frame_id = NULL;
2682
+ state->hmac_id = NULL;
2683
+ state->encryption_key = NULL;
2684
+ state->encryption_ctr = NULL;
2685
+
2686
+ state->rs = (opts->rs == false) ? false : true;
2687
+ state->awaiting_parity_shards = true;
2688
+ state->parity_file_path = NULL;
2689
+ state->parity_file = NULL;
2690
+
2691
+ // Only use this if rs after encryption
2692
+ state->encrypted_file = NULL;
2693
+ state->encrypted_file_path = NULL;
2694
+ state->creating_encrypted_file = false;
2695
+
2696
+ state->requesting_frame = false;
2697
+ state->completed_upload = false;
2698
+ state->creating_bucket_entry = false;
2699
+ state->received_all_pointers = false;
2700
+ state->final_callback_called = false;
2701
+ state->canceled = false;
2702
+ state->bucket_verified = false;
2703
+ state->file_verified = false;
2704
+
2705
+ state->progress_finished = false;
2706
+
2707
+ state->push_shard_limit = (opts->push_shard_limit > 0) ? (opts->push_shard_limit) : PUSH_SHARD_LIMIT;
2708
+ state->push_frame_limit = (opts->push_frame_limit > 0) ? (opts->push_frame_limit) : PUSH_FRAME_LIMIT;
2709
+ state->prepare_frame_limit = (opts->prepare_frame_limit > 0) ? (opts->prepare_frame_limit) : PREPARE_FRAME_LIMIT;
2710
+
2711
+ state->frame_request_count = 0;
2712
+ state->add_bucket_entry_count = 0;
2713
+ state->bucket_verify_count = 0;
2714
+ state->file_verify_count = 0;
2715
+ state->create_encrypted_file_count = 0;
2716
+
2717
+ state->progress_cb = progress_cb;
2718
+ state->finished_cb = finished_cb;
2719
+ state->error_status = 0;
2720
+ state->log = env->log;
2721
+ state->handle = handle;
2722
+ state->shard = NULL;
2723
+ state->pending_work_count = 0;
2724
+
2725
+ uv_work_t *work = uv_work_new();
2726
+ work->data = state;
2727
+
2728
+ state->pending_work_count += 1;
2729
+
2730
+ int status = uv_queue_work(env->loop, (uv_work_t*) work,
2731
+ prepare_upload_state, begin_work_queue);
2732
+ if (status) {
2733
+ state->error_status = STORJ_QUEUE_ERROR;
2734
+ }
2735
+ return state;
2736
+ }