Statistics
| Branch: | Revision:

grapes / src / CloudSupport / libs3_delegate_helper.c @ 98b047dd

History | View | Annotate | Download (20.3 KB)

1
/*
2
 *  Copyright (c) 2011 Andrea Zito
3
 *
4
 *  This is free software; see lgpl-2.1.txt
5
 *
6
 *
7
 *  Delegate cloud_handler for AmazonS3 based on the libs3 library.
8
 *  Supported parameters (*required):
9
 *
10
 *  - s3_access_key*:  the Amazon access key id
11
 *  - s3_secret_key*:  the Amazon secret access key
12
 *  - s3_bucket_name*: the bucket on which operate
13
 *  - s3_protocol:     http (default) or https
14
 *  - s3_blocking_put: a value of 1 enable blocking operation.
15
 *                     (default: disabled)
16
 */
17
#include <stdlib.h>
18
#include <stdio.h>
19
#include <unistd.h>
20
#include <string.h>
21
#include <sys/time.h>
22

    
23
#include <libs3.h>
24

    
25
#include "net_helper.h"
26
#include "cloud_helper_iface.h"
27
#include "request_handler.h"
28
#include "config.h"
29

    
30
#define CLOUD_NODE_ADDR "0.0.0.0"
31

    
32
/***********************************************************************
33
 * Interface prototype for cloud_helper_delegate
34
 ***********************************************************************/
35
struct delegate_iface {
36
  void* (*cloud_helper_init)(struct nodeID *local, const char *config);
37
  int (*get_from_cloud)(void *context, const char *key, uint8_t *header_ptr,
38
                        int header_size, int free_header);
39
  int (*get_from_cloud_default)(void *context, const char *key,
40
                                uint8_t *header_ptr, int header_size, int free_header,
41
                                uint8_t *defval_ptr, int defval_size, int free_defval);
42
  int (*put_on_cloud)(void *context, const char *key, uint8_t *buffer_ptr,
43
                      int buffer_size, int free_buffer);
44
  struct nodeID* (*get_cloud_node)(void *context, uint8_t variant);
45
  time_t (*timestamp_cloud)(void *context);
46
  int (*is_cloud_node)(void *context, struct nodeID* node);
47
  int (*wait4cloud)(void *context, struct timeval *tout);
48
  int (*recv_from_cloud)(void *context, uint8_t *buffer_ptr, int buffer_size);
49
};
50

    
51
/***********************************************************************
52
 * libs3 data structures
53
 ***********************************************************************/
54
/* response properties handler */
55
static S3Status
56
libs3_response_properties_callback
57
(const S3ResponseProperties *properties,
58
 void *callbackData);
59

    
60
/* request completion callback */
61
static void
62
libs3_response_complete_callback
63
(S3Status status,
64
 const S3ErrorDetails *error,
65
 void *callbackData);
66

    
67
/* put request callback */
68
static int
69
libs3_put_object_data_callback
70
(int bufferSize,
71
 char *buffer,
72
 void *callbackData);
73

    
74
/* get request callback */
75
static S3Status
76
libs3_get_object_data_callback
77
(int bufferSize,
78
 const char *buffer,
79
 void *callbackData);
80

    
81

    
82
static S3PutObjectHandler libs3_put_object_handler =
83
  {
84
    {
85
      &libs3_response_properties_callback,
86
      &libs3_response_complete_callback
87
    },
88
    &libs3_put_object_data_callback
89
  };
90

    
91
static S3GetObjectHandler libs3_get_object_handler =
92
  {
93
    {
94
      &libs3_response_properties_callback,
95
      &libs3_response_complete_callback
96
    },
97
    &libs3_get_object_data_callback
98
  };
99

    
100

    
101
/***********************************************************************
102
 * libs3_delegate_helper contexts
103
 ***********************************************************************/
104

    
105
/* libs3 cloud context definition */
106
struct libs3_cloud_context {
107
  struct req_handler_ctx *req_handler;
108
  S3BucketContext s3_bucket_context;
109
  int blocking_put_request;
110
  time_t last_rsp_timestamp;
111
};
112

    
113
/***********************************************************************
114
 * Requests/Response pool data structures
115
 ***********************************************************************/
116
enum operation_t {PUT=0, GET=1};
117
struct libs3_request {
118
  enum operation_t op;
119
  char *key;
120

    
121
  /* For GET operations this point to the header.
122
     For PUT this is the pointer to the actual data */
123
  uint8_t *data;
124
  int data_length;
125
  int free_data;
126

    
127
  uint8_t *default_value;
128
  int default_value_length;
129
  int free_default_value;
130

    
131
  struct libs3_cloud_context *ctx;
132
};
133
typedef struct libs3_request libs3_request_t;
134

    
135
struct libs3_get_response {
136
  S3Status status;
137
  uint8_t *data;
138
  uint8_t *current_byte;
139

    
140
  int data_length;
141
  int read_bytes;
142
  time_t last_timestamp;
143
};
144
typedef struct libs3_get_response libs3_get_response_t;
145

    
146
struct libs3_callback_context {
147
  libs3_request_t *current_req;
148

    
149
  /* point to the current byte to read/write */
150
  uint8_t *start_ptr;
151

    
152
  /* number of bytes read/written until now */
153
  int bytes;
154

    
155
  /* store for get request */
156
  uint8_t *buffer;
157
  size_t buffer_size;
158

    
159
  time_t last_timestamp;
160
  S3Status status;
161
};
162

    
163

    
164
static void free_request(void *req_ptr)
165
{
166
  libs3_request_t *req;
167
  if (!req_ptr) return;
168

    
169
  req = (libs3_request_t *) req_ptr;
170

    
171
  free(req->key);
172
  if (req->free_data > 0) free(req->data);
173
  if (req->free_default_value > 0)
174
    free(req->default_value);
175

    
176
  free(req);
177
}
178

    
179
static void free_response(libs3_get_response_t *rsp) {
180
  if (rsp->data) free(rsp->data);
181

    
182
  free(rsp);
183
}
184

    
185
/************************************************************************
186
 * libs3 callback implementation
187
 ************************************************************************/
188
static S3Status
189
libs3_response_properties_callback(const S3ResponseProperties *properties,
190
                                   void *context)
191
{
192
  struct libs3_callback_context *req_ctx;
193
  req_ctx = (struct libs3_callback_context *) context;
194

    
195
  if (properties->lastModified > 0) {
196
    req_ctx->last_timestamp = (time_t) properties->lastModified;
197
  } else {
198
    req_ctx->last_timestamp = 0;
199
  }
200

    
201
  if (properties->contentLength && req_ctx->current_req->op == GET) {
202
    uint64_t actual_length;
203
    size_t supported_length;
204

    
205
    actual_length = (properties->contentLength +
206
                     req_ctx->current_req->data_length);
207
    supported_length = (size_t) actual_length;
208

    
209
    /* This is probably useless as if actual_length is so big
210
       there is no way we can keep it all in memory */
211
    if (supported_length < actual_length)
212
      return S3StatusAbortedByCallback;
213

    
214
    req_ctx->buffer = malloc(actual_length);
215
    if (!req_ctx->buffer)
216
      return S3StatusAbortedByCallback;
217
    req_ctx->buffer_size = actual_length;
218

    
219
    if (req_ctx->current_req->data_length > 0) {
220
      memcpy(req_ctx->buffer,
221
             req_ctx->current_req->data,
222
             req_ctx->current_req->data_length);
223
    }
224
    req_ctx->start_ptr = req_ctx->buffer + req_ctx->current_req->data_length;
225
    req_ctx->bytes = 0;
226
  }
227

    
228
  return S3StatusOK;
229
}
230

    
231
/* request completion callback */
232
static void
233
libs3_response_complete_callback(S3Status status, const S3ErrorDetails *error,
234
                                 void *context)
235
{
236
  struct libs3_callback_context *req_ctx;
237
  req_ctx = (struct libs3_callback_context *) context;
238

    
239
  fprintf(stderr, "COMPLETE: %d\n", req_ctx->status);
240
  req_ctx->status = status;
241
  fprintf(stderr, "COMPLETE: %d\n", req_ctx->status);
242
  if (status != S3StatusOK) {
243
    if (error) {
244
      if (error->message) {
245
        fprintf(stderr, "libs3_delegate_helper: Error performing request" \
246
                "-> %s\n", error->message);
247
      } else {
248
        fprintf(stderr, "libs3_delegate_helper: Unknown error performing " \
249
                "request\n");
250
      }
251
    }
252
  }
253
}
254

    
255
/* put request callback */
256
static int
257
libs3_put_object_data_callback(int bufferSize, char *buffer,
258
                               void *context)
259
{
260
  struct libs3_callback_context *req_ctx;
261
  int towrite;
262
  fprintf(stderr, "FUCK I'M HERE AND I'M OK >> buffer=%d, status=%d, buffer=%p\n", bufferSize, req_ctx->status, buffer);
263
  req_ctx = (struct libs3_callback_context *) context;
264

    
265
  towrite = req_ctx->current_req->data_length - req_ctx->bytes;
266

    
267
  req_ctx->status = S3StatusOK;
268

    
269
  if (towrite == 0)
270
    return 0;
271

    
272
  towrite = (towrite > bufferSize)? bufferSize : towrite;
273

    
274
  memcpy(buffer, req_ctx->start_ptr, towrite);
275
  req_ctx->bytes += towrite;
276
  fprintf(stderr, "FUCK I'M HERE AND I'M OK >> towrite=%d, buffer=%d, status=%d\n", towrite, bufferSize, req_ctx->status);
277
  return towrite;
278
}
279

    
280
/* get request callback */
281
static S3Status
282
libs3_get_object_data_callback(int bufferSize, const char *buffer,
283
                               void *context)
284
{
285
  struct libs3_callback_context *req_ctx;
286
  req_ctx = (struct libs3_callback_context *) context;
287

    
288
  /* The buffer should have been prepared by the properties callback.
289
     If not, it means that s3 didn't report the content length */
290
  if (!req_ctx->buffer) {
291
    req_ctx->buffer = malloc(bufferSize + req_ctx->current_req->data_length);
292
    if (!req_ctx->buffer) return S3StatusAbortedByCallback;
293

    
294
    if (req_ctx->current_req->data_length > 0) {
295
      memcpy(req_ctx->buffer,
296
             req_ctx->current_req->data,
297
             req_ctx->current_req->data_length);
298
    }
299
    req_ctx->start_ptr = req_ctx->buffer + req_ctx->current_req->data_length;
300
    req_ctx->bytes = 0;
301
    req_ctx->buffer_size = bufferSize;
302
  }
303

    
304
  /* If s3 didn't report the content length we make room for it on
305
     the fly */
306
  if (req_ctx->bytes + bufferSize > req_ctx->buffer_size) {
307
    int new_size;
308
    uint8_t *old;
309

    
310
    new_size = req_ctx->buffer_size + (bufferSize * 2);
311

    
312
    old = req_ctx->buffer;
313
    req_ctx->buffer = realloc(req_ctx->buffer, new_size);
314
    if (!req_ctx->buffer) {
315
      free(old);
316
      return S3StatusAbortedByCallback;
317
    }
318

    
319
    req_ctx->start_ptr = (req_ctx->buffer +
320
                          req_ctx->bytes +
321
                          req_ctx->current_req->data_length);
322
  }
323

    
324
  memcpy(req_ctx->start_ptr, buffer, bufferSize);
325
  req_ctx->bytes += bufferSize;
326

    
327
  return S3StatusOK;
328
}
329

    
330
/************************************************************************
331
 * request_handler thread implementation
332
 ************************************************************************/
333

    
334
int should_retry(int *counter, int times)
335
{
336
  if (times > 0){
337
    *counter = times;
338
  } else {
339
    sleep(1); /* give some time to the network */
340
    (*counter)--;
341
  }
342
  return *counter > 0;
343
}
344

    
345

    
346
static int process_put_request(void *req_data, void **rsp_data)
347
{
348
  libs3_request_t *req;
349
  struct libs3_callback_context *cbk_ctx;
350
  int retries_left;
351
  int status;
352

    
353
  req = (libs3_request_t *) req_data;
354

    
355
  should_retry(&retries_left, 3);
356

    
357
  /* put operation never have response */
358
  *rsp_data = NULL;
359

    
360
  cbk_ctx = malloc(sizeof(struct libs3_callback_context));
361
  if (!cbk_ctx) return -1;
362

    
363
  cbk_ctx->current_req = req;
364
  cbk_ctx->status = S3StatusInternalError;
365
  cbk_ctx->start_ptr = req->data;
366
  cbk_ctx->bytes = 0;
367
  cbk_ctx->buffer = NULL;
368
  cbk_ctx->buffer_size = 0;
369

    
370
  do {
371
    S3_put_object(&req->ctx->s3_bucket_context, /* bucket info */
372
                  req->key,                /* key to insert */
373
                  req->data_length,        /* length of data  */
374
                  NULL,                     /* use standard properties */
375
                  NULL,                    /* do a blocking call... */
376
                  &libs3_put_object_handler,/* ...using these callback...*/
377
                  cbk_ctx);                /* ...with this data for context */
378

    
379
    fprintf(stderr, "prima del while: %d\n", cbk_ctx->status);
380
    /* if we get an error related to a temporary network state retry */
381
  } while(S3_status_is_retryable(cbk_ctx->status) &&
382
          should_retry(&retries_left, 0));
383

    
384
  status = (cbk_ctx->status == S3StatusOK) ? 0 : -1;
385

    
386
  free(cbk_ctx);
387

    
388
  return status;
389
}
390

    
391
static int process_get_request(void *req_data, void **rsp_data)
392
{
393
  libs3_request_t *req;
394
  struct libs3_callback_context *cbk_ctx;
395
  struct libs3_get_response *rsp;
396
  int retries_left;
397
  int status;
398

    
399
  req = (libs3_request_t *) req_data;
400

    
401
  should_retry(&retries_left, 3);
402

    
403
  /* Initilize s3 callback data */
404
  cbk_ctx = malloc(sizeof(struct libs3_callback_context));
405
  if (!cbk_ctx) return -1;
406
  cbk_ctx->current_req = req;
407
  cbk_ctx->status = S3StatusInternalError;
408
  cbk_ctx->start_ptr = NULL;
409
  cbk_ctx->bytes = 0;
410
  cbk_ctx->buffer = NULL;
411
  cbk_ctx->buffer_size = 0;
412

    
413

    
414
  do {
415
    S3_get_object(&req->ctx->s3_bucket_context, /* bucket info */
416
                  req->key,                /* key to retrieve */
417
                  NULL,                    /* do not use conditions */
418
                  0,                       /* start from byte 0... */
419
                  0,                       /* ...and read all bytes */
420
                  NULL,                    /* do a blocking call... */
421
                  &libs3_get_object_handler,/* ...using these callback...*/
422
                  cbk_ctx);                /* ...with this data for context */
423

    
424
    /* if we get an error related to a temporary network state retry */
425
  } while(S3_status_is_retryable(cbk_ctx->status) &&
426
          should_retry(&retries_left, 0));
427

    
428

    
429
  rsp = malloc(sizeof(struct libs3_get_response));
430
  if (!rsp) {
431
    if (cbk_ctx->buffer) free(cbk_ctx->buffer);
432
    free(cbk_ctx);
433
    return -1;
434
  }
435

    
436
  *rsp_data = rsp;
437
  rsp->status = cbk_ctx->status;
438
  if (cbk_ctx->status == S3StatusOK) {
439
    rsp->data = cbk_ctx->buffer;
440
    rsp->current_byte = rsp->data;
441
    rsp->data_length = cbk_ctx->bytes + req->data_length;
442
    rsp->read_bytes = 0;
443
    rsp->last_timestamp = cbk_ctx->last_timestamp;
444
  } else {
445
    /* Since there was no value for the specified key. If the caller specified a
446
       default value, use that */
447
    if (req->default_value) {
448
      rsp->data = malloc(req->data_length + req->default_value_length);
449
      if (!rsp->data) return 1;
450
      rsp->current_byte = rsp->data;
451
      if (req->data_length > 0)
452
        memcpy(rsp->data, req->data, req->data_length);
453

    
454
      memcpy(rsp->data, req->default_value, req->default_value_length);
455

    
456
      rsp->status = S3StatusOK;
457
    }
458
  }
459

    
460
  free(cbk_ctx);
461
  status = (rsp->status == S3StatusOK) ? 0 : -1;
462

    
463

    
464
  return status;
465
}
466

    
467

    
468
/************************************************************************
469
 * cloud helper implementation
470
 ************************************************************************/
471
static void deallocate_context(struct libs3_cloud_context *ctx)
472
{
473
  if (!ctx) return;
474

    
475
  free(ctx);
476
  return;
477
}
478

    
479

    
480
void* cloud_helper_init(struct nodeID *local, const char *config)
481
{
482
  struct libs3_cloud_context *ctx;
483
  struct tag *cfg_tags;
484
  const char *arg;
485

    
486
  ctx = malloc(sizeof(struct libs3_cloud_context));
487
  memset(ctx, 0, sizeof(struct libs3_cloud_context));
488
  cfg_tags = config_parse(config);
489

    
490
  /* Parse fundametal parameters */
491
  arg = config_value_str(cfg_tags, "s3_access_key");
492
  if (!arg) {
493
    deallocate_context(ctx);
494
    fprintf(stderr,
495
            "libs3_delegate_helper: missing required parameter " \
496
            "'s3_access_key'\n");
497
    return 0;
498
  }
499
  ctx->s3_bucket_context.accessKeyId = strdup(arg);
500

    
501
  arg = config_value_str(cfg_tags, "s3_secret_key");
502
  if (!arg) {
503
    deallocate_context(ctx);
504
    fprintf(stderr,
505
            "libs3_delegate_helper: missing required parameter " \
506
            "'s3_secret_key'\n");
507
    return 0;
508
  }
509
  ctx->s3_bucket_context.secretAccessKey = strdup(arg);
510

    
511
  arg = config_value_str(cfg_tags, "s3_bucket_name");
512
  if (!arg) {
513
    deallocate_context(ctx);
514
    fprintf(stderr,
515
            "libs3_delegate_helper: missing required parameter " \
516
            "'s3_bucket_name'\n");
517
    return 0;
518
  }
519
  ctx->s3_bucket_context.bucketName = strdup(arg);
520

    
521
  ctx->s3_bucket_context.protocol = S3ProtocolHTTPS;
522
  arg = config_value_str(cfg_tags, "s3_protocol");
523
  if (arg) {
524
    if (strcmp(arg, "https") == 0) {
525
      ctx->s3_bucket_context.protocol = S3ProtocolHTTPS;
526
    } else if (strcmp(arg, "http") == 0) {
527
      ctx->s3_bucket_context.protocol = S3ProtocolHTTP;
528
    }
529
  }
530

    
531
  ctx->s3_bucket_context.uriStyle = S3UriStylePath;
532

    
533

    
534
  /* Parse optional parameters */
535
  ctx->blocking_put_request = 1;
536
  arg = config_value_str(cfg_tags, "s3_blocking_put");
537
  if (arg) {
538
    if (strcmp(arg, "1") == 0)
539
      ctx->blocking_put_request = 1;
540
    else if (strcmp(arg, "0") == 0)
541
      ctx->blocking_put_request = 0;
542
  }
543

    
544
  /* Initialize data structures */
545
  if (S3_initialize("libs3_delegate_helper", S3_INIT_ALL) != S3StatusOK) {
546
    fprintf(stderr,
547
            "libs3_delegate_helper: error inizializing libs3\n");
548
    deallocate_context(ctx);
549
    return NULL;
550
  }
551

    
552
  ctx->req_handler = req_handler_init();
553
  if (!ctx->req_handler) {
554
    fprintf(stderr,
555
            "libs3_delegate_helper: error initializing request handler\n");
556
    deallocate_context(ctx);
557
    return NULL;
558
  }
559

    
560
  return ctx;
561
}
562

    
563
int get_from_cloud_default(void *context, const char *key, uint8_t *header_ptr,
564
                           int header_size, int free_header, uint8_t *defval_ptr,
565
                           int defval_size, int free_defval)
566
{
567
  struct libs3_cloud_context *ctx;
568
  libs3_request_t *request;
569

    
570
  ctx = (struct libs3_cloud_context *) context;
571
  request = malloc(sizeof(libs3_request_t));
572

    
573
  if (!request) return 1;
574

    
575
  request->op = GET;
576
  request->key = strdup(key);
577
  request->data = header_ptr;
578
  request->data_length = header_size;
579
  request->free_data = free_header;
580
  request->default_value = defval_ptr;
581
  request->default_value_length = defval_size;
582
  request->free_default_value = free_defval;
583
  request->ctx = ctx;
584

    
585
  req_handler_add_request(ctx->req_handler,
586
                          &process_get_request,
587
                          request,
588
                          &free_request);
589

    
590
  return 0;
591
}
592

    
593
int get_from_cloud(void *context, const char *key, uint8_t *header_ptr,
594
                   int header_size, int free_header)
595
{
596
  return get_from_cloud_default(context, key, header_ptr, header_size,
597
                                free_header, NULL, 0, 0);
598
}
599

    
600
int put_on_cloud(void *context, const char *key, uint8_t *buffer_ptr,
601
                 int buffer_size, int free_buffer)
602
{
603
  struct libs3_cloud_context *ctx;
604
  libs3_request_t *request;
605

    
606
  ctx = (struct libs3_cloud_context *) context;
607
  request = malloc(sizeof(libs3_request_t));
608

    
609
  if (!request) return 1;
610

    
611
  request->op = PUT;
612
  request->key = strdup(key);
613
  request->data = buffer_ptr;
614
  request->data_length = buffer_size;
615
  request->free_data = free_buffer;
616
  request->default_value = NULL;
617
  request->default_value_length = 0;
618
  request->free_default_value = 0;
619
  request->ctx = ctx;
620

    
621
  if (ctx->blocking_put_request) {
622
    int res;
623
    void *rsp;
624
    res = process_put_request(request, &rsp);
625
    free_request(request);
626
    return res;
627
  }
628
  else {
629
    return req_handler_add_request(ctx->req_handler, &process_put_request,
630
                                   request, &free_request);
631
  }
632
}
633

    
634
struct nodeID* get_cloud_node(void *context, uint8_t variant)
635
{
636
  return create_node(CLOUD_NODE_ADDR, variant);
637
}
638

    
639
time_t timestamp_cloud(void *context)
640
{
641
  struct libs3_cloud_context *ctx;
642
  ctx = (struct libs3_cloud_context *) context;
643

    
644
  return ctx->last_rsp_timestamp;
645
}
646

    
647
int is_cloud_node(void *context, struct nodeID* node)
648
{
649
  char buff[96];
650
  node_ip(node, buff, 96);
651
  return strcmp(buff, CLOUD_NODE_ADDR) == 0;
652
}
653

    
654
int wait4cloud(void *context, struct timeval *tout)
655
{
656
  struct libs3_cloud_context *ctx;
657
  libs3_get_response_t *rsp;
658

    
659
  ctx = (struct libs3_cloud_context *) context;
660

    
661
  rsp = (libs3_get_response_t*)req_handler_wait4response(ctx->req_handler, tout);
662

    
663
  if (rsp) {
664
    if (rsp->status == S3StatusOK) {
665
      ctx->last_rsp_timestamp = rsp->last_timestamp;
666
      return 1;
667
    } else {
668
      /* there was some error with the request */
669
      req_handler_remove_response(ctx->req_handler);
670
      free_response(rsp);
671
      return -1;
672
    }
673
  } else {
674
    return 0;
675
  }
676
}
677

    
678
int recv_from_cloud(void *context, uint8_t *buffer_ptr, int buffer_size)
679
{
680
  struct libs3_cloud_context *ctx;
681
  libs3_get_response_t *rsp;
682
  int remaining;
683
  int toread;
684

    
685
  ctx = (struct libs3_cloud_context *) context;
686

    
687
  rsp = (libs3_get_response_t *) req_handler_get_response(ctx->req_handler);
688
  if (!rsp) return -1;
689

    
690
  /* If do not have further data just remove the request */
691
  if (rsp->read_bytes == rsp->data_length) {
692
    req_handler_remove_response(ctx->req_handler);
693
    free_response(rsp);
694
    return 0;
695
  }
696

    
697
  remaining = rsp->data_length - rsp->read_bytes;
698
  toread = (remaining <= buffer_size)? remaining : buffer_size;
699

    
700
  memcpy(buffer_ptr, rsp->current_byte, toread);
701
  rsp->current_byte += toread;
702
  rsp->read_bytes += toread;
703

    
704
  /* remove the response only if the read bytes are less the the allocated
705
     buuffer otherwise the client can't know when a single response finished */
706
  if (rsp->read_bytes == rsp->data_length && rsp->read_bytes < buffer_size){
707
    req_handler_remove_response(ctx->req_handler);
708
    free_response(rsp);
709
  }
710

    
711
  return toread;
712
}
713

    
714
struct delegate_iface delegate_impl = {
715
  .cloud_helper_init = &cloud_helper_init,
716
  .get_from_cloud = &get_from_cloud,
717
  .get_from_cloud_default = &get_from_cloud_default,
718
  .put_on_cloud = &put_on_cloud,
719
  .get_cloud_node = &get_cloud_node,
720
  .timestamp_cloud = &timestamp_cloud,
721
  .is_cloud_node = &is_cloud_node,
722
  .wait4cloud = &wait4cloud,
723
  .recv_from_cloud = &recv_from_cloud
724
};