Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
353d0e5df35ea3468a5d5780015c0c62ae4bd981
[simgrid.git] / src / gras / DataDesc / ddt_exchange.c
1 /* $Id$ */
2
3 /* ddt_exchange - send/recv data described                                  */
4
5 /* Authors: Olivier Aumage, Martin Quinson                                  */
6 /* Copyright (C) 2003, 2004 the GRAS posse.                                 */
7
8 /* This program is free software; you can redistribute it and/or modify it
9    under the terms of the license (GNU LGPL) which comes with this package. */
10
11 #include "DataDesc/datadesc_private.h"
12
13 GRAS_LOG_NEW_DEFAULT_SUBCATEGORY(exchange,datadesc);
14
15 const char *gras_datadesc_cat_names[9] = { 
16   "undefined", 
17   "scalar", "struct", "union", "ref", "array", "ignored",
18   "invalid"};
19
20 static gras_datadesc_type_t *int_type = NULL;
21 static gras_datadesc_type_t *pointer_type = NULL;    
22 static gras_error_t gras_dd_send_int(gras_socket_t *sock,             int  i);
23 static gras_error_t gras_dd_recv_int(gras_socket_t *sock, int r_arch, int *i);
24
25 static gras_error_t
26 gras_dd_alloc_ref(gras_dict_t *refs,  long int     size,
27                   char       **r_ref, long int     r_len,
28                   char       **l_ref);
29 static int 
30 gras_dd_is_r_null(char **r_ptr, long int length);
31
32 static gras_error_t 
33 gras_datadesc_send_rec(gras_socket_t        *sock,
34                        gras_cbps_t       *state,
35                        gras_dict_t          *refs,
36                        gras_datadesc_type_t *type, 
37                        char                 *data);
38 static gras_error_t
39 gras_datadesc_recv_rec(gras_socket_t        *sock, 
40                        gras_cbps_t       *state,
41                        gras_dict_t          *refs,
42                        gras_datadesc_type_t *type,
43                        int                   r_arch,
44                        char                **r_data,
45                        long int              r_lgr,
46                        char                 *dst,
47                        int                   subsize);
48
49
50 static gras_error_t
51 gras_dd_send_int(gras_socket_t *sock,int i) {
52
53   if (!int_type) {
54     int_type = gras_datadesc_by_name("int");
55      gras_assert(int_type);  
56   }
57    
58   DEBUG1("send_int(%d)",i);
59   return gras_trp_chunk_send(sock, (char*)&i, int_type->size[GRAS_THISARCH]);
60 }
61
62 static gras_error_t
63 gras_dd_recv_int(gras_socket_t *sock, int r_arch, int *i) {
64   gras_error_t errcode;
65
66   if (!int_type) {
67      int_type = gras_datadesc_by_name("int");
68      gras_assert(int_type);
69   }
70
71   if (int_type->size[GRAS_THISARCH] >= int_type->size[r_arch]) {
72     TRY(gras_trp_chunk_recv(sock, (char*)i, int_type->size[r_arch]));
73     TRY(gras_dd_convert_elm(int_type,1,r_arch, i,i));
74   } else {
75     void *ptr = NULL;
76     ptr = malloc((size_t)int_type->size[r_arch]);
77     TRY(gras_trp_chunk_recv(sock, (char*)ptr, int_type->size[r_arch]));
78     TRY(gras_dd_convert_elm(int_type,1,r_arch, ptr,i));
79     free(ptr);
80   }
81   DEBUG1("recv_int(%d)",*i);
82
83   return no_error;
84 }
85
86 /*
87  * Note: here we suppose that the remote NULL is a sequence 
88  *       of 'length' bytes set to 0.
89  * FIXME: Check in configure?
90  */
91 static int 
92 gras_dd_is_r_null(char **r_ptr, long int length) {
93   int i;
94
95   for (i=0; i<length; i++) {
96     if ( ((unsigned char*)r_ptr) [i]) {
97       return 0;
98     }
99   }
100
101   return 1;
102 }
103
104 static gras_error_t
105 gras_dd_alloc_ref(gras_dict_t *refs,
106                   long int     size,
107                   char       **r_ref,
108                   long int     r_len, /* pointer_type->size[r_arch] */
109                   char       **l_ref) {
110   char *l_data = NULL;
111   gras_error_t errcode;
112
113   gras_assert1(size>0,"Cannot allocate %ld bytes!", size);
114   if (! (l_data = malloc((size_t)size)) )
115     RAISE_MALLOC;
116
117   *l_ref = l_data;
118   DEBUG2("l_data=%p, &l_data=%p",l_data,&l_data);
119
120   DEBUG3("alloc_ref: r_ref=%p; *r_ref=%p, r_len=%ld",
121          r_ref, r_ref?*r_ref:NULL, r_len);
122   if (r_ref && !gras_dd_is_r_null( r_ref, r_len)) {
123     void *ptr = malloc(sizeof(void *));
124     if (!ptr)
125       RAISE_MALLOC;
126
127     memcpy(ptr,l_ref, sizeof(void *));
128
129     DEBUG2("Insert %p under %p",*(void**)ptr, *(void**)r_ref);
130
131     TRY(gras_dict_set_ext(refs,(const char *) r_ref, r_len, ptr, free));
132   }
133   return no_error;
134 }
135
136 /**
137  * gras_datadesc_type_cmp:
138  *
139  * Compares two datadesc types with the same semantic than strcmp.
140  *
141  * This comparison does not take the set headers into account (name and ID), 
142  * but only the payload (actual type description).
143  */
144 int gras_datadesc_type_cmp(const gras_datadesc_type_t *d1,
145                            const gras_datadesc_type_t *d2) {
146   int ret,cpt;
147   gras_dd_cat_field_t *field1,*field2;
148   gras_datadesc_type_t *field_desc_1,*field_desc_2;
149
150   if (d1 == d2) return 0; /* easy optimization */
151
152   if (!d1 && d2) {
153     DEBUG0("ddt_cmp: !d1 && d2 => 1");
154     return 1;
155   }
156   if (!d1 && !d2) {
157     DEBUG0("ddt_cmp: !d1 && !d2 => 0");
158     return 0;
159   }
160   if ( d1 && !d2) {
161     DEBUG0("ddt_cmp: d1 && !d2 => -1");
162     return -1;
163   }
164
165   for (cpt=0; cpt<gras_arch_count; cpt++) {
166     if (d1->size[cpt] != d2->size[cpt]) {
167       DEBUG5("ddt_cmp: %s->size=%ld  !=  %s->size=%ld (on %s)",
168              d1->name,d1->size[cpt],d2->name,d2->size[cpt],
169              gras_arches[cpt].name);
170       return d1->size[cpt] >  d2->size[cpt] ? 1 : -1;
171     }
172
173     if (d1->alignment[cpt] != d2->alignment[cpt]) {
174       DEBUG5("ddt_cmp: %s->alignment=%ld  !=  %s->alignment=%ld (on %s)",
175              d1->name,d1->alignment[cpt],d2->name,d2->alignment[cpt],
176              gras_arches[cpt].name);
177       return d1->alignment[cpt] > d2->alignment[cpt] ? 1 : -1;
178     }
179
180     if (d1->aligned_size[cpt] != d2->aligned_size[cpt]) {
181       DEBUG5("ddt_cmp: %s->aligned_size=%ld  !=  %s->aligned_size=%ld (on %s)",
182              d1->name,d1->aligned_size[cpt],d2->name,d2->aligned_size[cpt],
183              gras_arches[cpt].name);
184       return d1->aligned_size[cpt] > d2->aligned_size[cpt] ? 1 : -1;
185     }
186   }
187
188   if (d1->category_code != d2->category_code) {
189     DEBUG4("ddt_cmp: %s->cat=%s  !=  %s->cat=%s",
190            d1->name,gras_datadesc_cat_names[d1->category_code],
191            d2->name,gras_datadesc_cat_names[d2->category_code]);
192     return d1->category_code > d2->category_code ? 1 : -1;
193   }
194
195   if (d1->send != d2->send) {
196     DEBUG4("ddt_cmp: %s->send=%p  !=  %s->send=%p",
197            d1->name,d1->send, d2->name,d2->send);
198     return d1->send > d2->send ? 1 : -1;
199   }
200
201   if (d1->recv != d2->recv) {
202     DEBUG4("ddt_cmp: %s->recv=%p  !=  %s->recv=%p",
203            d1->name,d1->recv, d2->name,d2->recv);
204     return d1->recv > d2->recv ? 1 : -1;
205   }
206
207   switch (d1->category_code) {
208   case e_gras_datadesc_type_cat_scalar:
209     if (d1->category.scalar_data.encoding != d2->category.scalar_data.encoding)
210       return d1->category.scalar_data.encoding > d2->category.scalar_data.encoding ? 1 : -1 ;
211     break;
212     
213   case e_gras_datadesc_type_cat_struct:    
214     if (gras_dynar_length(d1->category.struct_data.fields) != 
215         gras_dynar_length(d2->category.struct_data.fields)) {
216       DEBUG4("ddt_cmp: %s (having %d fields) !=  %s (having %d fields)",
217              d1->name, gras_dynar_length(d1->category.struct_data.fields),
218              d2->name, gras_dynar_length(d2->category.struct_data.fields));
219       
220       return gras_dynar_length(d1->category.struct_data.fields) >
221         gras_dynar_length(d2->category.struct_data.fields) ?
222         1 : -1;
223     }
224     gras_dynar_foreach(d1->category.struct_data.fields, cpt, field1) {
225       
226       gras_dynar_get(d2->category.struct_data.fields, cpt, &field2);
227       gras_datadesc_by_id(field1->code,&field_desc_1); /* FIXME: errcode ignored */
228       gras_datadesc_by_id(field2->code,&field_desc_2);
229       ret = gras_datadesc_type_cmp(field_desc_1,field_desc_2);
230       if (ret) {
231         DEBUG6("%s->field[%d]=%s != %s->field[%d]=%s",
232                d1->name,cpt,field1->name,              
233                d2->name,cpt,field2->name);
234         return ret;
235       }
236       
237     }
238     break;
239     
240   case e_gras_datadesc_type_cat_union:
241     if (d1->category.union_data.selector != d2->category.union_data.selector) 
242       return d1->category.union_data.selector > d2->category.union_data.selector ? 1 : -1;
243     
244     if (gras_dynar_length(d1->category.union_data.fields) != 
245         gras_dynar_length(d2->category.union_data.fields))
246       return gras_dynar_length(d1->category.union_data.fields) >
247              gras_dynar_length(d2->category.union_data.fields) ?
248         1 : -1;
249     
250     gras_dynar_foreach(d1->category.union_data.fields, cpt, field1) {
251       
252       gras_dynar_get(d2->category.union_data.fields, cpt, field2);
253       gras_datadesc_by_id(field1->code,&field_desc_1); /* FIXME: errcode ignored */
254       gras_datadesc_by_id(field2->code,&field_desc_2);
255       ret = gras_datadesc_type_cmp(field_desc_1,field_desc_2);
256       if (ret)
257         return ret;
258       
259     }
260     break;
261     
262     
263   case e_gras_datadesc_type_cat_ref:
264     if (d1->category.ref_data.selector != d2->category.ref_data.selector) 
265       return d1->category.ref_data.selector > d2->category.ref_data.selector ? 1 : -1;
266     
267     if (d1->category.ref_data.code != d2->category.ref_data.code) 
268       return d1->category.ref_data.code > d2->category.ref_data.code ? 1 : -1;
269     break;
270     
271   case e_gras_datadesc_type_cat_array:
272     if (d1->category.array_data.code != d2->category.array_data.code) 
273       return d1->category.array_data.code > d2->category.array_data.code ? 1 : -1;
274     
275     if (d1->category.array_data.fixed_size != d2->category.array_data.fixed_size) 
276       return d1->category.array_data.fixed_size > d2->category.array_data.fixed_size ? 1 : -1;
277     
278     if (d1->category.array_data.dynamic_size != d2->category.array_data.dynamic_size) 
279       return d1->category.array_data.dynamic_size > d2->category.array_data.dynamic_size ? 1 : -1;
280     
281     break;
282     
283   case e_gras_datadesc_type_cat_ignored:
284     /* That's ignored... */
285   default:
286     /* two stupidly created ddt are equally stupid ;) */
287     break;
288   }
289   return 0;
290   
291 }
292
293 /**
294  * gras_datadesc_cpy:
295  *
296  * Copy the data pointed by src and described by type 
297  * to a new location, and store a pointer to it in dst.
298  *
299  */
300 gras_error_t gras_datadesc_cpy(gras_datadesc_type_t *type, 
301                                void *src, 
302                                void **dst) {
303   RAISE_UNIMPLEMENTED;
304 }
305
306 static gras_error_t 
307 gras_datadesc_send_rec(gras_socket_t        *sock,
308                        gras_cbps_t       *state,
309                        gras_dict_t          *refs,
310                        gras_datadesc_type_t *type, 
311                        char                 *data) {
312
313   gras_error_t          errcode;
314   int                   cpt;
315   gras_datadesc_type_t *sub_type; /* type on which we recurse */
316   
317   VERB2("Send a %s (%s)", 
318         type->name, gras_datadesc_cat_names[type->category_code]);
319
320   if (type->send) {
321     type->send(state,data);
322   }
323
324   switch (type->category_code) {
325   case e_gras_datadesc_type_cat_scalar:
326     TRY(gras_trp_chunk_send(sock, data, type->size[GRAS_THISARCH]));
327     break;
328
329   case e_gras_datadesc_type_cat_struct: {
330     gras_dd_cat_struct_t  struct_data;
331     gras_dd_cat_field_t  *field;
332     char                 *field_data;
333     
334     struct_data = type->category.struct_data;
335     gras_assert1(struct_data.closed,
336       "Please call gras_datadesc_declare_struct_close on %s before sending it",
337                 type->name);
338     VERB1(">> Send all fields of the structure %s",type->name);
339     gras_dynar_foreach(struct_data.fields, cpt, field) {
340       field_data = data;
341       field_data += field->offset[GRAS_THISARCH];
342       
343       errcode=gras_datadesc_by_id(field->code, &sub_type);
344       if (errcode != no_error) 
345         RAISE4(errcode,
346                "Got %s while searching for the sub type %d, #%d of %s",
347                gras_error_name(errcode),field->code,cpt,type->name);
348       
349       if (field->pre)
350         field->pre(state,field_data);
351       
352       VERB1("Send field %s",field->name);
353       TRY(gras_datadesc_send_rec(sock,state,refs,sub_type, field_data));
354       
355       if (field->post)
356         field->post(state,field_data);
357     }
358     VERB1("<< Sent all fields of the structure %s", type->name);
359     
360     break;
361   }
362
363   case e_gras_datadesc_type_cat_union: {
364     gras_dd_cat_union_t    union_data;
365     gras_dd_cat_field_t   *field;
366     int                    field_num;
367     
368     union_data = type->category.union_data;
369     
370     gras_assert1(union_data.closed,
371                 "Please call gras_datadesc_declare_union_close on %s before sending it",
372                 type->name);
373     /* retrieve the field number */
374     field_num = union_data.selector(state, data);
375     
376     gras_assert1(field_num > 0,
377                  "union field selector of %s gave a negative value", 
378                  type->name);
379     
380     gras_assert3(field_num < gras_dynar_length(union_data.fields),
381          "union field selector of %s returned %d but there is only %d fields", 
382                  type->name, field_num, gras_dynar_length(union_data.fields));
383
384     /* Send the field number */
385     TRY(gras_dd_send_int(sock, field_num));
386     
387     /* Send the content */
388     gras_dynar_get(union_data.fields, field_num, field);
389     TRY(gras_datadesc_by_id(field->code, &sub_type));
390     
391     if (field->pre)
392       field->pre(state,data);
393     
394     TRY(gras_datadesc_send_rec(sock,state,refs, sub_type, data));
395       
396     if (field->post)
397       field->post(state,data);
398     
399     break;
400   }
401     
402   case e_gras_datadesc_type_cat_ref: {
403     gras_dd_cat_ref_t      ref_data;
404     int                    ref_code;
405
406     void                 **ref=(void**)data;
407     void *dummy;
408     
409     ref_data = type->category.ref_data;
410     
411     /* Detect the referenced type and send it to peer if needed */
412     ref_code = ref_data.code;
413     if (ref_code < 0) {
414       ref_code = ref_data.selector(state,data);
415       TRY(gras_dd_send_int(sock, ref_code));
416     }
417     
418     /* Send the actual value of the pointer for cycle handling */
419     if (!pointer_type) {
420       pointer_type = gras_datadesc_by_name("data pointer");
421       gras_assert(pointer_type);
422     }
423      
424     TRY(gras_trp_chunk_send(sock, (char*)data,
425                             pointer_type->size[GRAS_THISARCH]));
426     
427     /* Send the pointed data only if not already sent */
428     if (*(void**)data == NULL) {
429       VERB0("Not sending NULL referenced data");
430       break;
431     }
432     errcode = gras_dict_get_ext(refs,(char*)ref, sizeof(void*), &dummy);
433     if (errcode == mismatch_error) {
434       VERB1("Sending data referenced at %p", *ref);
435       TRY(gras_dict_set_ext(refs, (char*)ref, sizeof(void*), ref, NULL));
436       TRY(gras_datadesc_by_id(ref_code, &sub_type));
437       TRY(gras_datadesc_send_rec(sock,state,refs, sub_type, *ref));
438       
439     } else if (errcode == no_error) {
440       VERB1("Not sending data referenced at %p (already done)", *ref);
441     } else {
442       return errcode;
443     }
444     
445     break;
446   }
447
448   case e_gras_datadesc_type_cat_array: {
449     gras_dd_cat_array_t    array_data;
450     long int               count;
451     char                  *ptr=data;
452     long int               elm_size;
453     
454     array_data = type->category.array_data;
455     
456     /* determine and send the element count */
457     count = array_data.fixed_size;
458     if (count <= 0) {
459       count = array_data.dynamic_size(state,data);
460       gras_assert1(count >=0,
461                    "Invalid (negative) array size for type %s",type->name);
462       TRY(gras_dd_send_int(sock, count));
463     }
464     
465     /* send the content */
466     TRY(gras_datadesc_by_id(array_data.code, &sub_type));
467     elm_size = sub_type->aligned_size[GRAS_THISARCH];
468     if (sub_type->category_code == e_gras_datadesc_type_cat_scalar) {
469       VERB1("Array of %ld scalars, send it in one shot",count);
470       TRY(gras_trp_chunk_send(sock, data, 
471                               sub_type->aligned_size[GRAS_THISARCH] * count));
472     } else {
473       for (cpt=0; cpt<count; cpt++) {
474         TRY(gras_datadesc_send_rec(sock,state,refs, sub_type, ptr));
475         ptr += elm_size;
476       }
477     }
478     break;
479   }
480
481   default:
482     gras_assert0(0, "Invalid type");
483   }
484
485   return no_error;
486 }
487
488 /**
489  * gras_datadesc_send:
490  *
491  * Copy the data pointed by src and described by type to the socket
492  *
493  */
494 gras_error_t gras_datadesc_send(gras_socket_t *sock, 
495                                 gras_datadesc_type_t *type, 
496                                 void *src) {
497
498   gras_error_t errcode;
499   gras_cbps_t *state = NULL;
500   gras_dict_t    *refs; /* all references already sent */
501  
502   TRY(gras_dict_new(&refs));
503   TRY(gras_cbps_new(&state));
504
505   errcode = gras_datadesc_send_rec(sock,state,refs,type,(char*)src);
506
507   gras_dict_free(&refs);
508   gras_cbps_free(&state);
509
510   return errcode;
511 }
512
513 /**
514  * gras_datadesc_recv_rec:
515  *
516  * Do the data reception job recursively.
517  *
518  * subsize used only to deal with vicious case of reference to dynamic array.
519  *  This size is needed at the reference reception level (to allocate enough 
520  * space) and at the array reception level (to fill enough room). 
521  * 
522  * Having this size passed as an argument of the recursive function is a crude
523  * hack, but I was told that working code is sometimes better than neat one ;)
524  */
525 gras_error_t
526 gras_datadesc_recv_rec(gras_socket_t        *sock, 
527                        gras_cbps_t          *state,
528                        gras_dict_t          *refs,
529                        gras_datadesc_type_t *type,
530                        int                   r_arch,
531                        char                **r_data,
532                        long int              r_lgr,
533                        char                 *l_data,
534                        int                   subsize) {
535
536   gras_error_t          errcode;
537   int                   cpt;
538   gras_datadesc_type_t *sub_type;
539
540   VERB2("Recv a %s @%p", type->name, l_data);
541   gras_assert(l_data);
542
543   switch (type->category_code) {
544   case e_gras_datadesc_type_cat_scalar:
545     if (type->size[GRAS_THISARCH] == type->size[r_arch]) {
546       TRY(gras_trp_chunk_recv(sock, (char*)l_data, type->size[r_arch]));
547       TRY(gras_dd_convert_elm(type,1,r_arch, l_data,l_data));
548     } else {
549       void *ptr = NULL;
550       ptr = malloc((size_t)type->size[r_arch]);
551       TRY(gras_trp_chunk_recv(sock, (char*)ptr, type->size[r_arch]));
552       TRY(gras_dd_convert_elm(type,1,r_arch, ptr,l_data));
553       free(ptr);
554     }
555     break;
556
557   case e_gras_datadesc_type_cat_struct: {
558     gras_dd_cat_struct_t   struct_data;
559     gras_dd_cat_field_t   *field;
560
561     struct_data = type->category.struct_data;
562
563     gras_assert1(struct_data.closed,
564                 "Please call gras_datadesc_declare_struct_close on %s before receiving it",
565                 type->name);
566     VERB1(">> Receive all fields of the structure %s",type->name);
567     gras_dynar_foreach(struct_data.fields, cpt, field) {
568       char                 *field_data = l_data + field->offset[GRAS_THISARCH];
569
570       TRY(gras_datadesc_by_id(field->code, &sub_type));
571
572       TRY(gras_datadesc_recv_rec(sock,state,refs, sub_type,
573                                  r_arch,NULL,0,
574                                  field_data,-1));
575     }
576     VERB1("<< Received all fields of the structure %s", type->name);
577     
578     break;
579   }
580
581   case e_gras_datadesc_type_cat_union: {
582     gras_dd_cat_union_t    union_data;
583     gras_dd_cat_field_t   *field;
584     int                    field_num;
585
586     union_data = type->category.union_data;
587
588     gras_assert1(union_data.closed,
589                 "Please call gras_datadesc_declare_union_close on %s before receiving it",
590                 type->name);
591     /* retrieve the field number */
592     TRY(gras_dd_recv_int(sock, r_arch, &field_num));
593     if (field_num < 0)
594       RAISE1(mismatch_error,
595              "Received union field for %s is negative", type->name);
596     if (field_num < gras_dynar_length(union_data.fields)) 
597       RAISE3(mismatch_error,
598              "Received union field for %s is %d but there is only %d fields", 
599              type->name, field_num, gras_dynar_length(union_data.fields));
600     
601     /* Recv the content */
602     gras_dynar_get(union_data.fields, field_num, field);
603     TRY(gras_datadesc_by_id(field->code, &sub_type));
604     
605     TRY(gras_datadesc_recv_rec(sock,state,refs, sub_type,
606                                r_arch,NULL,0,
607                                l_data,-1));
608     break;
609   }
610
611   case e_gras_datadesc_type_cat_ref: {
612     char             **r_ref = NULL;
613     char             **l_ref = NULL;
614     gras_dd_cat_ref_t  ref_data;
615     int                ref_code;
616     
617     ref_data = type->category.ref_data;
618
619     /* Get the referenced type locally or from peer */
620     ref_code = ref_data.code;
621     if (ref_code < 0) 
622       TRY(gras_dd_recv_int(sock, r_arch, &ref_code));
623
624     /* Get the actual value of the pointer for cycle handling */
625     if (!pointer_type) {
626       pointer_type = gras_datadesc_by_name("data pointer");
627       gras_assert(pointer_type);
628     }
629
630     if (! (r_ref = malloc((size_t)pointer_type->size[r_arch])) )
631       RAISE_MALLOC;
632     TRY(gras_trp_chunk_recv(sock, (char*)r_ref,
633                             pointer_type->size[r_arch]));
634
635     /* Receive the pointed data only if not already sent */
636     if (gras_dd_is_r_null(r_ref, pointer_type->size[r_arch])) {
637       VERB1("Not receiving data remotely referenced @%p since it's NULL",
638             *(void **)r_ref);
639       *(void**)l_data = NULL;
640       free(r_ref);
641       break;
642     }
643     errcode = gras_dict_get_ext(refs,
644                                 (char*)r_ref, pointer_type->size[r_arch],
645                                 (void**)&l_ref);
646
647
648     if (errcode == mismatch_error) {
649       int subsubcount = -1;
650       void *l_referenced=NULL;
651
652       TRY(gras_datadesc_by_id(ref_code, &sub_type));
653       
654       VERB2("Receiving a ref to '%s', remotely @%p",
655             sub_type->name, *(void**)r_ref);
656       if (sub_type->category_code == e_gras_datadesc_type_cat_array) {
657         /* Damn. Reference to a dynamic array. Allocating the size for it 
658            is more complicated */
659         gras_dd_cat_array_t array_data = sub_type->category.array_data;
660         gras_datadesc_type_t *subsub_type;
661
662         subsubcount = array_data.fixed_size;
663         if (subsubcount < 0)
664           TRY(gras_dd_recv_int(sock, r_arch, &subsubcount));
665
666         TRY(gras_datadesc_by_id(array_data.code, &subsub_type));
667
668
669         TRY(gras_dd_alloc_ref(refs,
670                               subsub_type->size[GRAS_THISARCH] * subsubcount, 
671                               r_ref,pointer_type->size[r_arch], 
672                               (char**)&l_referenced));
673       } else {
674         TRY(gras_dd_alloc_ref(refs,sub_type->size[GRAS_THISARCH], 
675                               r_ref,pointer_type->size[r_arch], 
676                               (char**)&l_referenced));
677       }
678
679       TRY(gras_datadesc_recv_rec(sock,state,refs, sub_type,
680                                  r_arch,r_ref,pointer_type->size[r_arch],
681                                  (char*)l_referenced, subsubcount));
682       *(void**)l_data=l_referenced;
683       VERB3("'%s' remotely referenced at %p locally at %p",
684             sub_type->name, *(void**)r_ref, l_referenced);
685       
686     } else if (errcode == no_error) {
687       VERB2("NOT receiving data remotely referenced @%p (already done, @%p here)",
688             *(void**)r_ref, *(void**)l_ref);
689
690       *(void**)l_data=*l_ref;
691
692     } else {
693       return errcode;
694     }
695     free(r_ref);
696     break;
697   }
698
699   case e_gras_datadesc_type_cat_array: {
700     gras_dd_cat_array_t    array_data;
701     int       count;
702     char     *ptr;
703     long int  elm_size;
704
705     array_data = type->category.array_data;
706     /* determine element count locally, or from caller, or from peer */
707     count = array_data.fixed_size;
708     if (count <= 0)
709       count = subsize;
710     if (count < 0)
711       TRY(gras_dd_recv_int(sock, r_arch, &count));
712     if (count < 0)
713       RAISE1(mismatch_error,
714              "Invalid (negative) array size for type %s",type->name);
715
716     /* receive the content */
717     TRY(gras_datadesc_by_id(array_data.code, &sub_type));
718     if (sub_type->category_code == e_gras_datadesc_type_cat_scalar) {
719       VERB1("Array of %d scalars, get it in one shoot", count);
720       if (sub_type->aligned_size[GRAS_THISARCH] >= 
721           sub_type->aligned_size[r_arch]) {
722         TRY(gras_trp_chunk_recv(sock, (char*)l_data, 
723                                 sub_type->aligned_size[r_arch] * count));
724         TRY(gras_dd_convert_elm(sub_type,count,r_arch, l_data,l_data));
725       } else {
726         ptr = malloc((size_t)sub_type->aligned_size[r_arch] * count);
727         TRY(gras_trp_chunk_recv(sock, (char*)ptr, 
728                                 sub_type->size[r_arch] * count));
729         TRY(gras_dd_convert_elm(sub_type,count,r_arch, ptr,l_data));
730         free(ptr);
731       }
732     } else {
733       /* not scalar content, get it recursively (may contain pointers) */
734       elm_size = sub_type->aligned_size[GRAS_THISARCH];
735       VERB2("Receive a %d-long array of %s",count, sub_type->name);
736
737       ptr = l_data;
738       for (cpt=0; cpt<count; cpt++) {
739         TRY(gras_datadesc_recv_rec(sock,state,refs, sub_type,
740                                    r_arch, NULL, 0, ptr,-1));
741         ptr += elm_size;
742       }
743     }
744     break;
745   }
746         
747   default:
748     gras_assert0(0, "Invalid type");
749   }
750   
751   if (type->recv)
752     type->recv(state,l_data);
753
754   return no_error;
755 }
756
757 /**
758  * gras_datadesc_recv:
759  *
760  * Get an instance of the datatype described by @type from the @socket, 
761  * and store a pointer to it in @dst
762  *
763  */
764 gras_error_t
765 gras_datadesc_recv(gras_socket_t *sock, 
766                    gras_datadesc_type_t *type, 
767                    int r_arch,
768                    void *dst) {
769
770   gras_error_t errcode;
771   gras_cbps_t *state = NULL; /* callback persistent state */
772   gras_dict_t    *refs;         /* all references already sent */
773
774   TRY(gras_dict_new(&refs));
775   TRY(gras_cbps_new(&state));
776
777   errcode = gras_datadesc_recv_rec(sock, state, refs, type, 
778                                    r_arch, NULL, 0,
779                                    (char *) dst,-1);
780
781   gras_dict_free(&refs);
782   gras_cbps_free(&state);
783
784   return errcode;
785 }