예제 #1
0
    private void confirmfail(WvDbusMsg response)
    {
	WVPASS(response.type = Wv.Dbus.MType.Error);
	WVPASS(response.signature = "s");
	var i = response.iter();
	WVPASSEQ(i.pop(), failmsg);
    }
예제 #2
0
파일: msg.cs 프로젝트: apenwarr/versaplex
	public WvDbusMsg reply(string signature)
	{
	    WvDbusMsg reply = new WvDbusMsg();
	    reply.type = Dbus.MType.MethodReturn;
	    reply.flags = Dbus.MFlag.NoReplyExpected | Dbus.MFlag.NoAutoStart;
	    reply.rserial = this.serial;
	    reply.dest = this.sender;
	    reply.signature = signature;
	    return reply;
	}
예제 #3
0
파일: vxapi.cs 프로젝트: apenwarr/versaplex
    internal static void SendChunkRecordSignal(WvDbus conn,
					       WvDbusMsg call, string sender,
					    VxColumnInfo[] colinfo,
					    object[][] data, byte[][] nulls)
    {
	WvDbusWriter writer =
	    VxDbusRouter.PrepareRecordsetWriter(colinfo, data, nulls);
	writer.Write(call.serial);

	new WvDbusSignal(call.sender, call.path, "vx.db", "ChunkRecordsetSig",
		   "a(issnny)vaayu")
	    .write(writer)
	    .send(conn);
    }
예제 #4
0
파일: vxapi.cs 프로젝트: apenwarr/versaplex
    static void CallGetSchemaChecksums(WvDbus conn,
					       WvDbusMsg call, out WvDbusMsg reply)
    {
        if (call.signature.ne()) {
            reply = CreateUnknownMethodReply(call, "GetSchemaChecksums");
            return;
        }

        string clientid = GetClientId(call);
        if (clientid == null)
        {
            reply = call.err_reply("org.freedesktop.DBus.Error.Failed",
				   "Could not identify the client");
            return;
        }

        // FIXME: Add vx.db.toomuchdata error
        WvDbusWriter writer = new WvDbusWriter();

	//FIXME:  No exception catching?
        using (var dbi = VxSqlPool.create(clientid))
        {
            VxDbSchema backend = new VxDbSchema(dbi);
            VxSchemaChecksums sums = backend.GetChecksums();
            sums.WriteChecksums(writer);
        }

        reply = call.reply(VxSchemaChecksums.GetDbusSignature()).write(writer);
    }
예제 #5
0
파일: vxapi.cs 프로젝트: apenwarr/versaplex
    static void CallExecChunkRecordset(WvDbus conn,
					       WvDbusMsg call, out WvDbusMsg reply)
    {
	// XXX: Stuff in this comment block shamelessly stolen from
	// "CallExecRecordset".
        if (call.signature != "s") {
            reply = CreateUnknownMethodReply(call, "ExecChunkRecordset");
            return;
        }

        if (call.Body == null) {
            reply = call.err_reply
		("org.freedesktop.DBus.Error.InvalidSignature",
		 "Signature provided but no body received");
            return;
        }
	/// XXX

        VxDb.ExecChunkRecordset(conn, call, out reply);
    }
예제 #6
0
파일: vxapi.cs 프로젝트: apenwarr/versaplex
    public static void CallExecRecordset(WvDbus conn,
					 WvDbusMsg call, out WvDbusMsg reply)
    {
        if (call.signature != "s") {
            reply = CreateUnknownMethodReply(call, "ExecRecordset");
            return;
        }

        if (call.Body == null) {
            reply = call.err_reply
		("org.freedesktop.DBus.Error.InvalidSignature",
		 "Signature provided but no body received");
            return;
        }

        string clientid = GetClientId(call);
        if (clientid == null)
        {
            reply = call.err_reply("org.freedesktop.DBus.Error.Failed",
				   "Could not identify the client");
            return;
        }

	var it = call.iter();
        string query = it.pop();

        VxColumnInfo[] colinfo;
        object[][] data;
        byte[][] nullity;
        VxDb.ExecRecordset(clientid, (string)query, 
            out colinfo, out data, out nullity);

        // FIXME: Add vx.db.toomuchdata error
	WvDbusWriter writer = PrepareRecordsetWriter(colinfo, data, nullity);
	
        reply = call.reply("a(issnny)vaay").write(writer);
    }
예제 #7
0
파일: vxapi.cs 프로젝트: apenwarr/versaplex
    static void CallExecScalar(WvDbus conn,
				       WvDbusMsg call, out WvDbusMsg reply)
    {
        if (call.signature != "s") {
            reply = CreateUnknownMethodReply(call, "ExecScalar");
            return;
        }

        if (call.Body == null) {
            reply = call.err_reply
		("org.freedesktop.DBus.Error.InvalidSignature",
		 "Signature provided but no body received");
            return;
        }

        string clientid = GetClientId(call);
        if (clientid == null)
        {
            reply = call.err_reply("org.freedesktop.DBus.Error.Failed",
				   "Could not identify the client");
            return;
        }

	var it = call.iter();
        string query = it.pop();

        object result;
	VxColumnType coltype;
        VxDb.ExecScalar(clientid, (string)query,
			out coltype, out result);

        WvDbusWriter writer = new WvDbusWriter();
	writer.WriteSig(VxColumnTypeToSignature(coltype));
	WriteV(writer, coltype, result);

        reply = call.reply("v").write(writer);
    }
예제 #8
0
파일: vxapi.cs 프로젝트: apenwarr/versaplex
    static void CallQuit(WvDbus conn,
				 WvDbusMsg call, out WvDbusMsg reply)
    {
	// FIXME: Check permissions here
        WvDbusWriter writer = new WvDbusWriter();
	writer.Write("Quit");
        reply = call.reply("s").write(writer);
	Versaplexd.want_to_die = true;
    }
예제 #9
0
파일: vxapi.cs 프로젝트: apenwarr/versaplex
    static void CallGetSchemaData(WvDbus conn,
					  WvDbusMsg call, out WvDbusMsg reply)
    {
        if (call.signature != "ss") {
            reply = CreateUnknownMethodReply(call, "GetSchemaData");
            return;
        }

        string clientid = GetClientId(call);
        if (clientid == null)
        {
            reply = call.err_reply("org.freedesktop.DBus.Error.Failed",
				   "Could not identify the client");
            return;
        }

	var it = call.iter();
        string tablename = it.pop();
	string where = it.pop();

        WvDbusWriter writer = new WvDbusWriter();

	// FIXME: No exception catching?
	// FIXME: Should receive the replace/skip parameters via dbus
        using (var dbi = VxSqlPool.create(clientid))
        {
            VxDbSchema backend = new VxDbSchema(dbi);
            string schemadata = backend.GetSchemaData(tablename, 0, where,
						      null, null);
            writer.Write(schemadata);
        }

        reply = call.reply("s").write(writer);
    }
예제 #10
0
    private static void HandleCancelQuery(WvDbus conn, WvDbusMsg msg)
    {
	log.print(WvLog.L.Debug4, "Received CancelQuery request\n");
	//FIXME:  Should I be in yet another thread?
	Action perform = null;
	if (msg.signature != "u" && msg.signature != "s")
	{
	    //accept 's' signatures for Perl DBus, which is stupid and can't
	    //send me 'u' parameters, even though the api accepts them.
	    log.print(WvLog.L.Debug4, "CancelQuery:  bad signature {0}\n",
			msg.signature);
	    perform = () => {
		conn.send(msg.err_reply(
			    "org.freedesktop.DBus.Error.UnknownMethod",
			    "No overload of {0} has signature '{1}'",
			    "CancelQuery", msg.signature));
	    };
	}
	else
	{
	    var it = msg.iter();
	    uint tokill;
	    if (msg.signature == "s")
	    {
		log.print(WvLog.L.Debug4,
			    "CancelQuery: converting arg from string\n");
		string temps = it.pop();
		tokill = Convert.ToUInt32(temps);
	    }
	    else
		tokill = it.pop();

	    log.print(WvLog.L.Debug4,
			"CancelQuery: try killing msg id {0}\n", tokill);

	    lock (action_mutex)
	    {
		if (curaction != null && curaction.conn == conn &&
		    curaction.src.serial == tokill)
		{
		    log.print(WvLog.L.Debug4,
				"CancelQuery: killing current action!\n");
			    
		    WvSqlRows_IDataReader.Cancel();
		    curaction = null;
		}
		else
		{
		    log.print(WvLog.L.Debug4,
				"CancelQuery: traversing action queue...\n");
			    
		    //Traverse the action queue, killing stuff
		    foreach (VxActionTriple t in action_queue)
			if (t.conn == conn && t.src.serial == tokill)
			{
			    log.print(WvLog.L.Debug4,
					"CancelQuery: found culprit, killing.\n");
			    //action_queue.Remove(t);
			    //FIXME:  What message should we really put here?
			    t.action = () => {
			    	conn.send(t.src.err_reply("vx.db.sqlerror",
					    "This message got canceled"));
			    };
			    break;
			}
		}
	    }

	    //Pointless return to make Perl happy.
	    perform = () => {
		WvDbusWriter writer = new WvDbusWriter();
		writer.Write("Cancel");
		conn.send(msg.reply("s").write(writer));
	    };
	    log.print(WvLog.L.Debug4, "CancelQuery:  complete\n");
	}

	//FIXME:  It's not clear whether for just add operations, in conjuction
	//with RemoveAt(0) going on in the otherthread, we need a mutex.
	action_queue.Add(new VxActionTriple(conn, msg, perform));
    }
예제 #11
0
파일: vxapi.cs 프로젝트: apenwarr/versaplex
    public static string GetClientId(WvDbusMsg call)
    {
        string sender = call.sender;

        // For now, the client ID is just the username of the Unix UID that
        // DBus has associated with the connection.
        string username;
	var conn = Versaplexd.conn;
        if (!usernames.TryGetValue(sender, out username))
        {
	    try
	    {
		// FIXME:  This will likely change as we find a more
		//   universal way to do SSL authentication via D-Bus.
		username = VxSqlPool.GetUsernameForCert(
				conn.GetCertFingerprint(sender));
	    }
	    catch
	    {
		try
		{
		    // FIXME: This system call isn't actually standard
		    username = conn.GetUnixUserName(sender);
		}
		catch
		{
		    try
		    {
			// FIXME: This system call is standard, but not useful
			//   on Windows.
			username = conn.GetUnixUser(sender).ToString();
		    }
		    catch
		    {
			username = "******"; // use default connection, if any
		    }
		}
	    }


	    
            // Remember the result, so we don't have to ask DBus all the time
            usernames[sender] = username;
	    
	    log.print(WvLog.L.Info,
		      "New connection '{0}' is user '{1}'\n",
		      sender, username);
        }

        return username;
    }
예제 #12
0
파일: vxapi.cs 프로젝트: apenwarr/versaplex
    void ExecuteCall(MethodCallProcessor processor,
		     WvDbus conn,
		     WvDbusMsg call, out WvDbusMsg reply)
    {
        try {
            processor(conn, call, out reply);
        } catch (VxRequestException e) {
            reply = call.err_reply(e.DBusErrorType, e.Message);
            log.print("SQL result: {0}\n", e.Short());
        } catch (Exception e) {
            reply = call.err_reply("vx.db.exception", 
                    "An internal error occurred.");
            log.print("{0}\n", e.ToString());
        }
    }
예제 #13
0
파일: vxapi.cs 프로젝트: apenwarr/versaplex
    public bool route(WvDbus conn, WvDbusMsg msg, out WvDbusMsg reply)
    {
	MethodCallProcessor p;
	
	if (msg.ifc != "vx.db" || msg.path != "/db")
	{
	    reply = null;
	    return false;
	}
	
	if (msg.method == "Test")
	    p = CallTest;
	else if (msg.method == "Quit")
	    p = CallQuit;
	else if (msg.method == "ExecScalar")
	    p = CallExecScalar;
	else if (msg.method == "ExecRecordset")
	    p = CallExecRecordset;
	else if (msg.method == "ExecChunkRecordset")
	    p = CallExecChunkRecordset;
	else if (msg.method == "GetSchemaChecksums")
	    p = CallGetSchemaChecksums;
	else if (msg.method == "GetSchema")
	    p = CallGetSchema;
	else if (msg.method == "PutSchema")
	    p = CallPutSchema;
	else if (msg.method == "DropSchema")
	    p = CallDropSchema;
	else if (msg.method == "GetSchemaData")
	    p = CallGetSchemaData;
	else if (msg.method == "PutSchemaData")
	    p = CallPutSchemaData;
	else
	{
	    // FIXME: this should be done at a higher level somewhere
            reply = msg.err_reply(
                    "org.freedesktop.DBus.Error.UnknownMethod",
                    "Method name {0} not found on interface {1}",
                    msg.method, msg.ifc);
	    return true;
	}
	ExecuteCall(p, conn, msg, out reply);
	return true;
    }
예제 #14
0
파일: vxapi.cs 프로젝트: apenwarr/versaplex
    internal static void ExecChunkRecordset(WvDbus conn, 
					    WvDbusMsg call, out WvDbusMsg reply)
    {
	string connid = VxDbusRouter.GetClientId(call);
	
        if (connid == null)
        {
            reply = call.err_reply(
                    "org.freedesktop.DBus.Error.Failed",
                    "Could not identify the client");
            return;
        }
        
	var it = call.iter();

	string query = query_parser(it.pop(),
			    VxSqlPool.access_restrictions(connid));

        log.print(WvLog.L.Debug3, "ExecChunkRecordset {0}\n", query);

	//Times we tried going through this loop to completion
	int numtries = 0;

	while (true)
	{
	    try
	    {
		List<object[]> rows = new List<object[]>();
		List<byte[]> rownulls = new List<byte[]>();
		VxColumnInfo[] colinfo;
		
		// Our size here is just an approximation.
		int cursize = 0;
		
		// FIXME:  Sadly, this is stupidly similar to ExecRecordset.
		// Anything we can do here to identify commonalities?
		using (var dbi = VxSqlPool.create(connid))
		using (WvSqlRows resultset = dbi.select(query))
		{
		    var columns = resultset.columns.ToArray();
		    colinfo = ProcessSchema(columns);
		    int ncols = columns.Count();
		
		    foreach (WvSqlRow cur_row in resultset)
		    {
			object[] row = new object[ncols];
			byte[] rownull = new byte[ncols];
			cursize += rownull.Length;
		    
			for (int i = 0; i < ncols; i++) 
			{
			    WvAutoCast cval = cur_row[i];
			    bool isnull = cval.IsNull;

			    row[i] = null;

			    rownull[i] = isnull ? (byte)1 : (byte)0;
			
			    switch (colinfo[i].VxColumnType) 
			    {
				case VxColumnType.Int64:
				    row[i] = !isnull ?
					(Int64)cval : new Int64();
				    cursize += sizeof(Int64);
				    break;
				case VxColumnType.Int32:
				    row[i] = !isnull ?
					(Int32)cval : new Int32();
				    cursize += sizeof(Int32);
				    break;
				case VxColumnType.Int16:
				    row[i] = !isnull ?
					(Int16)cval : new Int16();
				    cursize += sizeof(Int16);
				    break;
				case VxColumnType.UInt8:
				    row[i] = !isnull ?
					(Byte)cval : new Byte();
				    cursize += sizeof(Byte);
				    break;
				case VxColumnType.Bool:
				    row[i] = !isnull ?
					(bool)cval : new Boolean();
				    cursize += sizeof(Boolean);
				    break;
				case VxColumnType.Double:
				    // Might return a Single or Double
				    // FIXME: Check if getting a single causes
				    // this to croak
				    row[i] = !isnull ?
					(double)cval : (double)0.0;
				    cursize += sizeof(double);
				    break;
				case VxColumnType.Uuid:
				    //FIXME:  Do I work?
				    row[i] = !isnull ?
					(string)cval : "";
				    cursize += !isnull ?
					((string)cval).Length * sizeof(Char):0;
				    break;
				case VxColumnType.Binary:
				    {
					if (isnull) 
					{
					    row[i] = new byte[0];
					    break;
					}

					row[i] = (byte[])cval;
					cursize += ((byte[])cval).Length;
					break;
				    }
				case VxColumnType.String:
				    row[i] = !isnull ? (string)cval : "";
				    cursize += !isnull ?
					((string)cval).Length * sizeof(Char):0;
				    break;
				case VxColumnType.DateTime:
				    row[i] = !isnull ?
					new VxDbusDateTime((DateTime)cval) :
					new VxDbusDateTime();
				    cursize += System.Runtime.InteropServices.Marshal.SizeOf((VxDbusDateTime)row[i]);
				    break;
				case VxColumnType.Decimal:
				    row[i] = !isnull ?
					((Decimal)cval).ToString() : "";
				    cursize += ((string)(row[i])).Length *
						sizeof(Char);
				    break;
			    }
			} // column iterator
		    
			rows.Add(row);
			rownulls.Add(rownull);

			if (cursize >= 1024*1024) //approx 1 MB
			{
			    log.print(WvLog.L.Debug4,
				    "(1 MB reached; {0} rows)\n",
				    rows.Count);


			    SendChunkRecordSignal(conn, call, call.sender,
						  colinfo, rows.ToArray(),
						  rownulls.ToArray());
			
			    rows = new List<object[]>();
			    rownulls = new List<byte[]>();
			    cursize = 0;
			}
		    } // row iterator
		} // using

		// OK, we're down to either one more packet or no more data
		// Package that up in the 'reply' to this message, saving some
		// data being sent.
		if (cursize > 0)
		    log.print(WvLog.L.Debug4, "(Remaining data; {0} rows)\n",
			    rows.Count);

		// Create reply, either with or with no data
		WvDbusWriter replywriter =
		    VxDbusRouter.PrepareRecordsetWriter(colinfo,
							rows.ToArray(),
							rownulls.ToArray());
		reply = call.reply("a(issnny)vaay").write(replywriter);
		break;
	    } catch (DbException e) {
		throw new VxSqlException(e.Message, e);
	    } catch (VxConfigException e)
	    {
		if (e.Message.StartsWith("Connect: A network-related or instance-specific error")
		    && ++numtries <= 1)  //only one retry
		{
		    log.print(WvLog.L.Debug4,
			"Can't connect to DB, fishy..., attempting to reconnect... (attempt #{0})\n",
			numtries);
		}
		else
		    throw e;  //rethrow
	    }
	} //while
    }
예제 #15
0
파일: vxapi.cs 프로젝트: apenwarr/versaplex
    static void CallPutSchemaData(WvDbus conn,
					  WvDbusMsg call, out WvDbusMsg reply)
    {
        if (call.signature != "ss") {
            reply = CreateUnknownMethodReply(call, "PutSchemaData");
            return;
        }

        string clientid = GetClientId(call);
        if (clientid == null)
        {
            reply = call.err_reply("org.freedesktop.DBus.Error.Failed",
				   "Could not identify the client");
            return;
        }

	var it = call.iter();
        string tablename = it.pop();
        string text = it.pop();

        using (var dbi = VxSqlPool.create(clientid))
        {
            VxDbSchema backend = new VxDbSchema(dbi);
            backend.PutSchemaData(tablename, text, 0);
        }

        reply = call.reply();
    }
예제 #16
0
    static bool WvDbusMsgReady(WvDbus conn, WvDbusMsg msg)
    {
        // FIXME: This should really queue things to be run from the thread
        // pool and then the response would be sent back through the action
        // queue
        log.print(WvLog.L.Debug4, "WvDbusMsgReady\n");

        switch (msg.type)
	{
	case Wv.Dbus.MType.MethodCall:
	    if (msg.ifc == "vx.db")
	    {
		if (msg.path == "/db" && msg.method == "CancelQuery")
		    HandleCancelQuery(conn, msg);
		else //not 'CancelQuery'
		{
		    //FIXME:  It's not clear whether for just add operations,
		    //in conjuction with RemoveAt(0) going on in the other
		    //thread, we need a mutex.
		    action_queue.Add(new VxActionTriple(conn, msg,
		    () => {
			WvDbusMsg reply;
			if (msgrouter.route(conn, msg, out reply))
			{
			    if (reply == null) {
				// FIXME: Do something if this happens, maybe?
				log.print("Empty reply from RouteWvDbusMsg\n");
			    } else {
				// XXX: Should this be done further down rather
				// than passing the reply out here?
				conn.send(reply);
			    }
			}
		    }));
		}
		return true;
	    }
	    return false;
	    
	default:
	    log.print(WvLog.L.Warning,
		      "Unexpected DBus message received: #{0} {1}->{2} {3}:{4}.{5}\n",
		        msg.serial, msg.sender, msg.dest,
		      msg.path, msg.ifc, msg.method);
	    return false;
        }
    }
예제 #17
0
    private void confirmpass(WvDbusMsg response)
    {
	WVPASS(response.type == Wv.Dbus.MType.MethodReturn);
    }
예제 #18
0
    public VxActionTriple(WvDbus _conn, WvDbusMsg _src, Action _action)
    {
	this.conn = _conn;
	this.src = _src;
	this.action = _action;
    }
예제 #19
0
파일: vxapi.cs 프로젝트: apenwarr/versaplex
    static void CallDropSchema(WvDbus conn,
				       WvDbusMsg call, out WvDbusMsg reply)
    {
        if (call.signature != "as") {
            reply = CreateUnknownMethodReply(call, "DropSchema");
            return;
        }

        string clientid = GetClientId(call);
        if (clientid == null)
        {
            reply = call.err_reply("org.freedesktop.DBus.Error.Failed",
				   "Could not identify the client");
            return;
        }

	var it = call.iter();
	string[] keys = it.pop().Cast<string>().ToArray();

        VxSchemaErrors errs;
        using (var dbi = VxSqlPool.create(clientid))
        {
            VxDbSchema backend = new VxDbSchema(dbi);
            errs = backend.DropSchema(keys);
        }

        WvDbusWriter writer = new WvDbusWriter();
        VxSchemaErrors.WriteErrors(writer, errs);

        reply = call.reply(VxSchemaErrors.GetDbusSignature()).write(writer);
        if (errs != null && errs.Count > 0)
        {
            reply.type = Wv.Dbus.MType.Error;
            reply.err = "org.freedesktop.DBus.Error.Failed";
        }
    }
예제 #20
0
파일: vxapi.cs 프로젝트: apenwarr/versaplex
    static WvDbusMsg CreateUnknownMethodReply(WvDbusMsg call, 
        string methodname)
    {
        return call.err_reply("org.freedesktop.DBus.Error.UnknownMethod",
			      "No overload of {0} has signature '{1}'",
			      methodname, call.signature);
    }
예제 #21
0
파일: vxapi.cs 프로젝트: apenwarr/versaplex
    static void CallPutSchema(WvDbus conn,
				      WvDbusMsg call, out WvDbusMsg reply)
    {
        if (call.signature != String.Format("{0}i", 
                VxSchema.GetDbusSignature())) {
            reply = CreateUnknownMethodReply(call, "PutSchema");
            return;
        }

        string clientid = GetClientId(call);
        if (clientid == null)
        {
            reply = call.err_reply("org.freedesktop.DBus.Error.Failed",
				   "Could not identify the client");
            return;
        }

	var it = call.iter();
        VxSchema schema = new VxSchema(it.pop());
        int opts = it.pop();

        VxSchemaErrors errs;
        
        using (var dbi = VxSqlPool.create(clientid))
        {
            VxDbSchema backend = new VxDbSchema(dbi);
            errs = backend.Put(schema, null, (VxPutOpts)opts);
        }

        WvDbusWriter writer = new WvDbusWriter();
        VxSchemaErrors.WriteErrors(writer, errs);

        reply = call.reply(VxSchemaErrors.GetDbusSignature()).write(writer);
        if (errs != null && errs.Count > 0)
        {
            reply.type = Wv.Dbus.MType.Error;
            reply.err = "org.freedesktop.DBus.Error.Failed";
        }
    }
예제 #22
0
파일: vxapi.cs 프로젝트: apenwarr/versaplex
    static void CallTest(WvDbus conn,
				 WvDbusMsg call, out WvDbusMsg reply)
    {
        if (call.signature.ne()) {
            reply = CreateUnknownMethodReply(call, "Test");
            return;
        }

        string clientid = GetClientId(call);
        if (clientid == null)
        {
            reply = call.err_reply("org.freedesktop.DBus.Error.Failed",
				   "Could not identify the client");
            return;
        }

        VxColumnInfo[] colinfo;
        object[][] data;
        byte[][] nullity;
        VxDb.ExecRecordset(clientid, "select 'Works! :D'", 
            out colinfo, out data, out nullity);

        // FIXME: Add vx.db.toomuchdata error
	WvDbusWriter writer = PrepareRecordsetWriter(colinfo, data, nullity);
        reply = call.reply("a(issnny)vaay").write(writer);
    }
예제 #23
0
파일: vxapi.cs 프로젝트: apenwarr/versaplex
    static void CallGetSchema(WvDbus conn,
				      WvDbusMsg call, out WvDbusMsg reply)
    {
        if (call.signature != "as") {
            reply = CreateUnknownMethodReply(call, "GetSchema");
            return;
        }

        string clientid = GetClientId(call);
        if (clientid == null)
        {
            reply = call.err_reply("org.freedesktop.DBus.Error.Failed",
				   "Could not identify the client");
            return;
        }

	var it = call.iter();
        string[] names = it.pop().Cast<string>().ToArray();

        WvDbusWriter writer = new WvDbusWriter();

        using (var dbi = VxSqlPool.create(clientid))
        {
            VxDbSchema backend = new VxDbSchema(dbi);
            VxSchema schema = backend.Get(names);
            schema.WriteSchema(writer);
        }

        reply = call.reply(VxSchema.GetDbusSignature()).write(writer);
    }