I would please like some help with this case.
I need to send one XDR message, that it's composed by 2 files (switch case == OK).
Assuming I have in my code a message
object called response
:
message response;
If I had to only send one file in a message, I would do:
response.message_u.fdata.last_mod_time = last_modification;
response.message_u.fdata.contents.contents_len = file_size;
response.message_u.fdata.contents.contents_val = buffer;
With buffer being:
buffer = malloc(file_size * sizeof(char));
Now, I understand that struct file fdata<2>;
it's a variable size array (2 is the max length) and that I would have them index as something[0]
and something[1]
.
Also I know I need to allocate memory, but I do not know how to do this in this case with multiple files.
Do I need to do one single malloc for everything I need to send? Something like this:
response.message_u.fdata.fdata_val = malloc ( (file_size1 * sizeof(char)) + (file_size2 * sizeof(char)) + (2 * sizeof(uint32_t)));
(2 * sizeof(uint32_t))
: one last_mod_time for each file to send
And the other question how to I refer to each file structure:
response.message_u.fdata[0] //?
response.message_u.fdata.last_mod_time[0] //?
response.message_u.fdata[0].last_mod_time //?
response.message_u.fdata.contents.contents_len[0] //?
response.message_u.fdata.contents.contents_val[0] //?
The .x file:
enum tagtype {
GET = 0,
OK = 1,
QUIT = 2,
ERR = 3
};
struct file {
opaque contents<>;
unsigned int last_mod_time;
};
typedef string filename<256>;
union message switch (tagtype tag) {
case GET:
filename filenamedata<2>;
case OK:
struct file fdata<2>;
case QUIT:
void;
case ERR:
void;
};
The types.c (generated with rpcgen):
#include "xdr_types.h"
bool_t
xdr_tagtype (XDR *xdrs, tagtype *objp)
{
register int32_t *buf;
if (!xdr_enum (xdrs, (enum_t *) objp))
return FALSE;
return TRUE;
}
bool_t
xdr_file (XDR *xdrs, file *objp)
{
register int32_t *buf;
if (!xdr_bytes (xdrs, (char **)&objp->contents.contents_val, (u_int *) &objp->contents.contents_len, ~0))
return FALSE;
if (!xdr_u_int (xdrs, &objp->last_mod_time))
return FALSE;
return TRUE;
}
bool_t
xdr_filename (XDR *xdrs, filename *objp)
{
register int32_t *buf;
if (!xdr_string (xdrs, objp, 256))
return FALSE;
return TRUE;
}
bool_t
xdr_message (XDR *xdrs, message *objp)
{
register int32_t *buf;
if (!xdr_tagtype (xdrs, &objp->tag))
return FALSE;
switch (objp->tag) {
case GET:
if (!xdr_array (xdrs, (char **)&objp->message_u.filenamedata.filenamedata_val, (u_int *) &objp->message_u.filenamedata.filenamedata_len, 10,
sizeof (filename), (xdrproc_t) xdr_filename))
return FALSE;
break;
case OK:
if (!xdr_array (xdrs, (char **)&objp->message_u.fdata.fdata_val, (u_int *) &objp->message_u.fdata.fdata_len, 10, sizeof (file), (xdrproc_t) xdr_file))
return FALSE;
break;
case QUIT:
break;
case ERR:
break;
default:
return FALSE;
}
return TRUE;
}
Thank you for reading this, and trying to understand this. I really appreciate it.
Thank you!
To answer this question it is easier to take a look at the types:
tagtype
,file
,filename
andmessage
that rpcgen generates from your .x file. They are located in yourxdr_types.h
which you didn't include in your question so I used rpcgen with your .x file. The important ones arefile
andmessage
:To answer your 2 questions:
and
No, the part after
response.message_u.fdata.
is wrong. It can either be:or
and you mean the 2nd variant which is
struct file *fdata_val;
. And for that part you have to allocate memory.The following example is for 2 files which will also answer your question about how to refer to the data:
To learn more about the relationship between the XDR specification language and the generated C output this answer on SO: Understanding XDR specification to create a *.x file is helpful.
Further there is a nice book Power Programming with RPC by John Bloomer, it's quite old (1991) but the Remote Procedure Call protocol is it too. This book is about the RPC protocol that uses the XDR for sending/receiving data. The XDR language (using rpcgen, filter functions, etc.) is very well described in that book.