1

I Have some XDR data packets which are sent over a TCP socket. Here a snippet of my code:

const size_t BUFFER_LENGTH = 2000;
XDR xdr;
char *buffer = new char[BUFFER_LENGTH];
xdrmem_create(&xdr, buffer, BUFFER_LENGTH, XDR_ENCODE);

const std::string requestId = request->getPacket()->getRequestId();
MyPacket responcePacket(requestId, status,message);
responcePacket.serialize(&xdr);

unsigned int byteSent = write(*socketDescriptor_, buffer, BUFFER_LENGTH);
delete buffer;
if(byteSent!=BUFFER_LENGTH)
{
    throw Exception("Error during write!");
}

where the packet is serialized as follow:

class MyPacket:

    void MyPacket::serialize(XDR* xdr)
    {
        // Convert Enum to int
        int _messageType = (int) messageType_;
        uint32_t _status = (uint32_t) status_;

        //Copy all strings to c_string
        char *_requestId = new char[requestId_.length() + 1];
        std::strcpy(_requestId,requestId_.c_str());

        char *_message = new char[message_.length() + 1];
        std::strcpy(_message,message_.c_str());

        bool status = xdr_int(xdr, &_messageType) &&
                    xdr_string(xdr, &_requestId, REQUESTID_LENGTH_) &&
                    xdr_u_int(xdr, &_status ) &&
                    xdr_string(xdr, &_message, MESSAGE_LENGTH_);

        delete _requestId;
        delete _message;

        if(!status)
        {
            throw new Exception("Error while serializing MyPacket.");
        }
    }

....

}

As a first test I am assuming the maximum packet size to be 2000 and I am always reading 2000 from the other side. As a first test this work fine but I would like to be able to send and receive less information when not required. Furthermore i do not want to have to recompile the client in case i increase the packet size on my server.

I would like to know if there is a proper way to send and receive this stream without having to prepend the packet size myself. And In case I have to prepend this myself is there a way to easily get the xdr size?

Cheers,

ADDITION: I tried using a xdr_rec buffer as follows:

XDR ixdr;
int i;
xdrrec_create (&ixdr,0,0,reinterpret_cast<char*> (&ui),&underflow,0);
ixdr.x_op = XDR_DECODE;

cout << "xdrrec_eof: " << xdrrec_eof (&ixdr) <<endl;
cout << "xdrrec_skiprecord: " << xdrrec_skiprecord (&ixdr) <<endl;

for(j=0;j<10;j++){
    xdr_uint32_t (&ixdr, &i);
    cerr << "i: " << i << endl;
}xdr_destroy (&ixdr);

If i feed to it a correct buffer with 10 uint32 all works great. Now I tried to cut some bytes at the end of my buffer and I was expecting either xdrrec_eof or xdrrec_skiprecord to give me an error. This is what I wanted to use to detect that I did not have received all the data yet. What happens instead is that both return with success and the xdr_uint32_t blocks the code execution. So what i now really still miss is a way to detect that i had received the full packet before start decoding it with xdr_uint32_t. Any suggestion?

Stefano
  • 3,981
  • 8
  • 36
  • 66
  • What XDR library are you using? – David Schwartz Mar 15 '16 at 08:00
  • Hi, I am on Linux and I simply include – Stefano Mar 15 '16 at 08:01
  • 1
    The packet size is irrelevant. You just have to read when the XDR library asks you to read. One of the XDR stream types deals with streams with length words in them, but it's been over 20 years and I don't remember which. – user207421 Mar 15 '16 at 08:18
  • Are you suggesting to use xdrrec instead of xdrmem? – Stefano Mar 15 '16 at 09:38
  • or do you think xdrstdio would be better? – Stefano Mar 15 '16 at 09:51
  • i found this example: http://www.codesynthesis.com/~boris/blog/2007/08/13/writing-xdr-expanding-buffer/ this would work for writing just the amount of information I need but for reading I do not know how to determine when to stop reading – Stefano Mar 15 '16 at 10:22
  • 1
    Yes, it was `xdr_rec`, the one where you supply your own read and write functions. – user207421 Mar 15 '16 at 23:04
  • I do not really know how can i bind this with a socket descriptor.... any sudgestion? – Stefano Mar 16 '16 at 09:39
  • Err, read the documentation? It's 22 years since I did this but it wasn't difficult. – user207421 Mar 16 '16 at 20:43
  • i tried and i did quite a few tests. I have just updated the question with my latest find out. Thanks – Stefano Mar 17 '16 at 09:49
  • I don't understand why you think you need to 'receive a full packet *before* start[ing] decoding'. You don't. `xdr_rec` will call your `read()` function as often as it needs to. – user207421 Mar 17 '16 at 10:01
  • The problem is that xdr_uint32_t is blocking so if i have the read and the xdr_uint32_t in the same thread and i run xdr_uint32_t before having finished reading the whole stream this risks to block the application. So probably i need to have the socket reading and the decoding in 2 separate threads.... – Stefano Mar 17 '16 at 10:37
  • @Stefano That doesn't make any sense. See my edited answer. – user207421 Mar 17 '16 at 23:21

1 Answers1

1

The packet size is irrelevant. You just have to read when the XDR library asks you to read. The XDR xdr_rec stream type deals with streams with length words in them. All you have to do is supply it with your own read and write functions. It's 22 years since I did this but it wasn't difficult. I don't understand why you think you need to 'receive a full packet before start[ing] decoding'. You don't. xdr_rec will call your read() function as often as it needs to.

The problem is that xdr_uint32_t is blocking

No. XDR functions are not blocking. Not one of them. Read the source. It is the read() function that blocks.

so if i have the read and the xdr_uint32_t in the same thread and i run xdr_uint32_t before having finished reading the whole stream

That doesn't make sense. Read what I wrote above. 'You just have to read when the XDR library asks you to read.' Not before.

this risks to block the application. So probably i need to have the socket reading and the decoding in 2 separate threads.

No. You don't seem to understand how xdr_rec works. You create an xdr_rec object and supply it with a read callback function and a write callback function. From there on you just call whatever XDR routines you like, and they call the read or write callbacks as appropriate. You don't call them at all. There is no requirement to 'read the whole stream' first.

You should do all this in a single thread.

user207421
  • 305,947
  • 44
  • 307
  • 483