WvStreams
wvdbusmarshal.cc
00001 /* -*- Mode: C++ -*-
00002  * Worldvisions Weaver Software:
00003  *   Copyright (C) 2004-2006 Net Integration Technologies, Inc.
00004  * 
00005  * Wrapper code for marshalling/demarshalling WvDBusMsg objects.  This is
00006  * in a separate file from WvDBusMsg in case you want to use a WvDBusMsg
00007  * but not our special/gross marshalling code from wvdbusmarshal_c.c.
00008  * 
00009  */ 
00010 #include "wvdbusmsg.h"
00011 #undef interface // windows
00012 #include <dbus/dbus.h>
00013 
00014 
00015 static int wvdbus_message_length(const char *buf, size_t len)
00016 {
00017     int msglen = dbus_message_demarshal_bytes_needed(buf, len);
00018     if (msglen > 0)
00019         return msglen;
00020     else if (msglen == 0)
00021         return DBUS_MINIMUM_HEADER_SIZE;
00022 
00023     return 0;
00024 }
00025 
00026 
00027 WvDBusMsg *WvDBusMsg::demarshal(WvBuf &buf)
00028 {
00029     // to make sure bytes are aligned (as required by d-bus), copy them into a 
00030     // new buffer (not very efficient, but what can you do without reworking
00031     // our buffer implementation)
00032     WvDynBuf alignedbuf;
00033     size_t buflen = buf.used();
00034     alignedbuf.put(buf.peek(0, buflen), buflen);
00035 
00036     // first get size of message to demarshal. if too little or bad length,
00037     // return NULL (possibly after consuming the bad data)
00038     size_t messagelen = wvdbus_message_length((const char *)
00039                                               alignedbuf.peek(0, buflen), 
00040                                               buflen);
00041     if (messagelen == 0) // invalid message data
00042     {
00043         buf.get(buflen); // clear invalid crap - the best we can do
00044         return NULL;
00045     }
00046     else if (messagelen > buflen) // not enough data
00047         return NULL;
00048 
00049     // Assuming that worked and we can demarshal a message, try to do so
00050     DBusError error;
00051     dbus_error_init(&error);
00052     DBusMessage *_msg = dbus_message_demarshal((const char *)
00053                                                alignedbuf.peek(0, buflen), 
00054                                                messagelen, &error);
00055     if (dbus_error_is_set(&error))
00056         dbus_error_free (&error);
00057     buf.get(messagelen);
00058 
00059     if (_msg)
00060     {
00061         WvDBusMsg *msg = new WvDBusMsg(_msg);
00062         dbus_message_unref(_msg);
00063         return msg;
00064     }
00065     else
00066         return NULL;
00067 }
00068 
00069 
00070 size_t WvDBusMsg::demarshal_bytes_needed(WvBuf &buf)
00071 {
00072     // to make sure bytes are aligned (as required by d-bus), copy them into a 
00073     // new buffer (not very efficient, but what can you do without reworking
00074     // our buffer implementation)
00075     WvDynBuf alignedbuf;
00076     size_t used = buf.used();
00077     alignedbuf.put(buf.peek(0, used), used);
00078 
00079     return wvdbus_message_length((const char *)alignedbuf.peek(0, used), used);
00080 }
00081 
00082 
00083 void WvDBusMsg::marshal(WvBuf &buf)
00084 {
00085     DBusMessage *msg = *this;
00086 
00087     static uint32_t global_serial = 1000;   
00088     if (!dbus_message_get_serial(msg))
00089     {
00090         dbus_message_set_serial(msg, ++global_serial);
00091     }
00092 
00093     dbus_message_lock (msg); 
00094     char *cbuf;
00095     int len;
00096     dbus_message_marshal(msg, &cbuf, &len);
00097     buf.put(cbuf, len);
00098     free(cbuf);
00099 }