Logo AND Algorithmique Numérique Distribuée

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