Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Fix miscasted logging arguments
[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_dd_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_dd_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->pre != d2->pre) {
196     DEBUG4("ddt_cmp: %s->pre=%p  !=  %s->pre=%p",
197            d1->name,d1->pre, d2->name,d2->pre);
198     return d1->pre > d2->pre ? 1 : -1;
199   }
200
201   if (d1->post != d2->post) {
202     DEBUG4("ddt_cmp: %s->post=%p  !=  %s->post=%p",
203            d1->name,d1->post, d2->name,d2->post);
204     return d1->post > d2->post ? 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_dd_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->pre) {
321     type->pre(state,type,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,sub_type,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,sub_type,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, type, 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,sub_type,data);
393     
394     TRY(gras_datadesc_send_rec(sock,state,refs, sub_type, data));
395       
396     if (field->post)
397       field->post(state,sub_type,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,type,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,type,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   if (type->post) {
486     type->post(state,type,data);
487   }
488
489   return no_error;
490 }
491
492 /**
493  * gras_datadesc_send:
494  *
495  * Copy the data pointed by src and described by type to the socket
496  *
497  */
498 gras_error_t gras_datadesc_send(gras_socket_t *sock, 
499                                 gras_datadesc_type_t *type, 
500                                 void *src) {
501
502   gras_error_t errcode;
503   gras_dd_cbps_t *state = NULL;
504   gras_dict_t    *refs; /* all references already sent */
505  
506   TRY(gras_dict_new(&refs));
507   TRY(gras_dd_cbps_new(&state));
508
509   errcode = gras_datadesc_send_rec(sock,state,refs,type,(char*)src);
510
511   gras_dict_free(&refs);
512   gras_dd_cbps_free(&state);
513
514   return errcode;
515 }
516
517 /**
518  * gras_datadesc_recv_rec:
519  *
520  * Do the data reception job recursively.
521  *
522  * subsize used only to deal with vicious case of reference to dynamic array.
523  *  This size is needed at the reference reception level (to allocate enough 
524  * space) and at the array reception level (to fill enough room). 
525  * 
526  * Having this size passed as an argument of the recursive function is a crude
527  * hack, but I was told that working code is sometimes better than neat one ;)
528  */
529 gras_error_t
530 gras_datadesc_recv_rec(gras_socket_t        *sock, 
531                        gras_dd_cbps_t       *state,
532                        gras_dict_t          *refs,
533                        gras_datadesc_type_t *type,
534                        int                   r_arch,
535                        char                **r_data,
536                        long int              r_lgr,
537                        char                 *l_data,
538                        int                   subsize) {
539
540   gras_error_t          errcode;
541   int                   cpt;
542   gras_datadesc_type_t *sub_type;
543
544   VERB2("Recv a %s @%p", type->name, l_data);
545   gras_assert(l_data);
546
547   switch (type->category_code) {
548   case e_gras_datadesc_type_cat_scalar:
549     if (type->size[GRAS_THISARCH] == type->size[r_arch]) {
550       TRY(gras_trp_chunk_recv(sock, (char*)l_data, type->size[r_arch]));
551       TRY(gras_dd_convert_elm(type,1,r_arch, l_data,l_data));
552     } else {
553       void *ptr = NULL;
554       ptr = malloc((size_t)type->size[r_arch]);
555       TRY(gras_trp_chunk_recv(sock, (char*)ptr, type->size[r_arch]));
556       TRY(gras_dd_convert_elm(type,1,r_arch, ptr,l_data));
557       free(ptr);
558     }
559     break;
560
561   case e_gras_datadesc_type_cat_struct: {
562     gras_dd_cat_struct_t   struct_data;
563     gras_dd_cat_field_t   *field;
564
565     struct_data = type->category.struct_data;
566
567     gras_assert1(struct_data.closed,
568                 "Please call gras_datadesc_declare_struct_close on %s before receiving it",
569                 type->name);
570     VERB1(">> Receive all fields of the structure %s",type->name);
571     gras_dynar_foreach(struct_data.fields, cpt, field) {
572       char                 *field_data = l_data + field->offset[GRAS_THISARCH];
573
574       TRY(gras_datadesc_by_id(field->code, &sub_type));
575
576       TRY(gras_datadesc_recv_rec(sock,state,refs, sub_type,
577                                  r_arch,NULL,0,
578                                  field_data,-1));
579     }
580     VERB1("<< Received all fields of the structure %s", type->name);
581     
582     break;
583   }
584
585   case e_gras_datadesc_type_cat_union: {
586     gras_dd_cat_union_t    union_data;
587     gras_dd_cat_field_t   *field;
588     int                    field_num;
589
590     union_data = type->category.union_data;
591
592     gras_assert1(union_data.closed,
593                 "Please call gras_datadesc_declare_union_close on %s before receiving it",
594                 type->name);
595     /* retrieve the field number */
596     TRY(gras_dd_recv_int(sock, r_arch, &field_num));
597     if (field_num < 0)
598       RAISE1(mismatch_error,
599              "Received union field for %s is negative", type->name);
600     if (field_num < gras_dynar_length(union_data.fields)) 
601       RAISE3(mismatch_error,
602              "Received union field for %s is %d but there is only %d fields", 
603              type->name, field_num, gras_dynar_length(union_data.fields));
604     
605     /* Recv the content */
606     gras_dynar_get(union_data.fields, field_num, field);
607     TRY(gras_datadesc_by_id(field->code, &sub_type));
608     
609     TRY(gras_datadesc_recv_rec(sock,state,refs, sub_type,
610                                r_arch,NULL,0,
611                                l_data,-1));
612     break;
613   }
614
615   case e_gras_datadesc_type_cat_ref: {
616     char             **r_ref = NULL;
617     char             **l_ref = NULL;
618     gras_dd_cat_ref_t  ref_data;
619     int                ref_code;
620     
621     ref_data = type->category.ref_data;
622
623     /* Get the referenced type locally or from peer */
624     ref_code = ref_data.code;
625     if (ref_code < 0) 
626       TRY(gras_dd_recv_int(sock, r_arch, &ref_code));
627
628     /* Get the actual value of the pointer for cycle handling */
629     if (!pointer_type) {
630       pointer_type = gras_datadesc_by_name("data pointer");
631       gras_assert(pointer_type);
632     }
633
634     if (! (r_ref = malloc((size_t)pointer_type->size[r_arch])) )
635       RAISE_MALLOC;
636     TRY(gras_trp_chunk_recv(sock, (char*)r_ref,
637                             pointer_type->size[r_arch]));
638
639     /* Receive the pointed data only if not already sent */
640     if (gras_dd_is_r_null(r_ref, pointer_type->size[r_arch])) {
641       VERB1("Not receiving data remotely referenced @%p since it's NULL",
642             *(void **)r_ref);
643       *(void**)l_data = NULL;
644       free(r_ref);
645       break;
646     }
647     errcode = gras_dict_get_ext(refs,
648                                 (char*)r_ref, pointer_type->size[r_arch],
649                                 (void**)&l_ref);
650
651
652     if (errcode == mismatch_error) {
653       int subsubcount = -1;
654       void *l_referenced=NULL;
655
656       TRY(gras_datadesc_by_id(ref_code, &sub_type));
657       
658       VERB2("Receiving a ref to '%s', remotely @%p",
659             sub_type->name, *(void**)r_ref);
660       if (sub_type->category_code == e_gras_datadesc_type_cat_array) {
661         /* Damn. Reference to a dynamic array. Allocating the size for it 
662            is more complicated */
663         gras_dd_cat_array_t array_data = sub_type->category.array_data;
664         gras_datadesc_type_t *subsub_type;
665
666         subsubcount = array_data.fixed_size;
667         if (subsubcount < 0)
668           TRY(gras_dd_recv_int(sock, r_arch, &subsubcount));
669
670         TRY(gras_datadesc_by_id(array_data.code, &subsub_type));
671
672
673         TRY(gras_dd_alloc_ref(refs,
674                               subsub_type->size[GRAS_THISARCH] * subsubcount, 
675                               r_ref,pointer_type->size[r_arch], 
676                               (char**)&l_referenced));
677       } else {
678         TRY(gras_dd_alloc_ref(refs,sub_type->size[GRAS_THISARCH], 
679                               r_ref,pointer_type->size[r_arch], 
680                               (char**)&l_referenced));
681       }
682
683       TRY(gras_datadesc_recv_rec(sock,state,refs, sub_type,
684                                  r_arch,r_ref,pointer_type->size[r_arch],
685                                  (char*)l_referenced, subsubcount));
686       *(void**)l_data=l_referenced;
687       VERB3("'%s' remotely referenced at %p locally at %p",
688             sub_type->name, *(void**)r_ref, l_referenced);
689       
690     } else if (errcode == no_error) {
691       VERB2("NOT receiving data remotely referenced @%p (already done, @%p here)",
692             *(void**)r_ref, *(void**)l_ref);
693
694       *(void**)l_data=*l_ref;
695
696     } else {
697       return errcode;
698     }
699     free(r_ref);
700     break;
701   }
702
703   case e_gras_datadesc_type_cat_array: {
704     gras_dd_cat_array_t    array_data;
705     int       count;
706     char     *ptr;
707     long int  elm_size;
708
709     array_data = type->category.array_data;
710     /* determine element count locally, or from caller, or from peer */
711     count = array_data.fixed_size;
712     if (count <= 0)
713       count = subsize;
714     if (count < 0)
715       TRY(gras_dd_recv_int(sock, r_arch, &count));
716     if (count < 0)
717       RAISE1(mismatch_error,
718              "Invalid (negative) array size for type %s",type->name);
719
720     /* receive the content */
721     TRY(gras_datadesc_by_id(array_data.code, &sub_type));
722     if (sub_type->category_code == e_gras_datadesc_type_cat_scalar) {
723       VERB1("Array of %d scalars, get it in one shoot", count);
724       if (sub_type->aligned_size[GRAS_THISARCH] >= 
725           sub_type->aligned_size[r_arch]) {
726         TRY(gras_trp_chunk_recv(sock, (char*)l_data, 
727                                 sub_type->aligned_size[r_arch] * count));
728         TRY(gras_dd_convert_elm(sub_type,count,r_arch, l_data,l_data));
729       } else {
730         ptr = malloc((size_t)sub_type->aligned_size[r_arch] * count);
731         TRY(gras_trp_chunk_recv(sock, (char*)ptr, 
732                                 sub_type->size[r_arch] * count));
733         TRY(gras_dd_convert_elm(sub_type,count,r_arch, ptr,l_data));
734         free(ptr);
735       }
736     } else {
737       /* not scalar content, get it recursively (may contain pointers) */
738       elm_size = sub_type->aligned_size[GRAS_THISARCH];
739       VERB2("Receive a %d-long array of %s",count, sub_type->name);
740
741       ptr = l_data;
742       for (cpt=0; cpt<count; cpt++) {
743         TRY(gras_datadesc_recv_rec(sock,state,refs, sub_type,
744                                    r_arch, NULL, 0, ptr,-1));
745         ptr += elm_size;
746       }
747     }
748     break;
749   }
750         
751   default:
752     gras_assert0(0, "Invalid type");
753   }
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_dd_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_dd_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_dd_cbps_free(&state);
784
785   return errcode;
786 }