Sending/Recieving structures in UNIX

Posted on 2005-04-19
Medium Priority
Last Modified: 2008-02-01

I am trying to send and receive structures that contain, char buffers inside of the structure between my kernel code and my user land/process. My problem lies in that I am passing a structure that has some pointers to buffers within this structure and these buffers are always showing empty/zeros when I receive them on the userland side.
I get all the correct values for ints/booleans and etc. that are in my structure but the _MALLOCed buffers, from the kernel extension are empty. I suspect it has to do something with the way I filling out the mbuf because like I said I can receive the struct on the userland side, the pointers seem good to the buffers with in the structure but these buffers are just empty, zeroed out.
Maybe if someone can take a look at the code below they have some suggestions or see something I do not.
The code from the kernel side is:
struct Test_Struct
    int n1;
    int n2;
    char* buf1;
struct Test_Struct *test;
test = _MALLOC(sizeof(struct Test_Struct), M_TEMP, M_WIATOK|M_ZERO);
if((test->buf1 = _MALLOC(50, M_TEMP, M_WAITOK|M_ZERO)) != 0)
    bcopy("Here comes the test data", test->buf1, 20);
    test->n1 = 66;
    test->n2 = 678;
// now send the struct to user land
struct mbuf *m;
size_t len = sizeof(Test_Struct);
if(len > MCLBYTES)
    return EMSGSIZE;
if ((m = m_gethdr(M_NOWAIT, MT_DATA)) == NULL)
    return ENOBUFS;
m->m_flags |= M_EOR;
if(len >MLEN)
    if(!(m->m_flags & M_EXT))
bcopy(test, mtod(m, void*), len);
m->m_pkthdr.len = m->m_len=len;
ctl_enqueuembuf(ctlref, m, flags);  // this is a call equivalent to send(nfd, void*, int), a Mac OS X thing, don't worry about it, it works.
// ctlref is a pointer to previously registered controller, that is hooked to this kernel extension
Below is a sample of the code in userland that receives the data from ctl_enqueuembuf:
struct Test_Struct teststruct;
int nBytesRc;
nBytesRc = recv(nfd, &teststruct, sizeof(teststruct), 0);
if(nBytesRc > 0)
    // do what every with teststruct.buf1; and other members of the received struct.
    This is where I can look at the teststruct and buf1 is always empty.
Question by:atomic928
LVL 27

Expert Comment

ID: 13832492
If I may be allowed to start from scratch.

This process of sending arbitary structures over communication links is called marshalling. Generally you'd send an indication of what object is being marshalled and the contents, usually in address order. Any dynamic contents would necessarily have to be prefixed by a length attribute followed by the data.

Given a structure X you'd need two procedures, marshallX and unmarshallX. The first takes a struct and returns a string, the second takes a string and retuns a struct.

Now strings are problamatic, since marshalling can include bytes of binary zero, so I'd have a global buffer of some large size and write the marshalled data into it. The marshall procedure returns the number of bytes written. Simarly the unmarshall procedure reads this global buffer, takes the length as a parameter and returns a new structure.

I'd now have procedures which marshall and unmarshall integers (int2/long) and char*. These take a buffer position and write/read the data. With char* you'd write data into the  buffer incrementing the pointer until a binary zero, or read until a binary zero.

Now when sending data over sockets you must NOT assume that the recv call will read exectly the same number of bytes that the send call has written. Therefore it is necessary to send a message length each time and to use this message length on reading. On unmarshalling you'd use this length to check that you have got and processed all the data. In this way you get a very secure communication.

I hope that starts you off in thr right direction.
LVL 55

Accepted Solution

Jaime Olivares earned 1500 total points
ID: 13842343
I face sometimes this problem. I have solved this by creating a "universal" way to store binary data. Some kind of "binary XML", there are 4 sub-fields for each field:
1 byte:   field code (instead of field name), to identify each field, because you can spare space by not including some unneeded fields
1 byte:   specify data type (bool,int8,int16,int32,float,double,binary,string) and lenght type (int8, int16, int32)
1-4 bytes: field lenght (according to previous byte, but only for binary and string)
1-n bytes: the data itself

Featured Post

Keep up with what's happening at Experts Exchange!

Sign up to receive Decoded, a new monthly digest with product updates, feature release info, continuing education opportunities, and more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Navigation is an important part of web design from a usability perspective. But it is often a pain when it comes to a developer’s perspective. By navigation, it often means menuing. This is less theory and more practical of how to get a specific gro…
If you haven’t already, I encourage you to read the first article (http://www.experts-exchange.com/articles/18680/An-Introduction-to-R-Programming-and-R-Studio.html) in my series to gain a basic foundation of R and R Studio.  You will also find the …
The goal of the video will be to teach the user the concept of local variables and scope. An example of a locally defined variable will be given as well as an explanation of what scope is in C++. The local variable and concept of scope will be relat…
Viewers will learn how to properly install Eclipse with the necessary JDK, and will take a look at an introductory Java program. Download Eclipse installation zip file: Extract files from zip file: Download and install JDK 8: Open Eclipse and …
Suggested Courses
Course of the Month14 days, 15 hours left to enroll

839 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question