11#include "wvdbusconn.h"
13#include "wvstrutils.h"
18static WvString translate(WvStringParm dbus_moniker)
21 WvStringList::Iter i(l);
23 if (!strncasecmp(dbus_moniker,
"unix:", 5))
26 l.
split(dbus_moniker+5,
",");
27 for (i.rewind(); i.next(); )
29 if (!strncasecmp(*i,
"path=", 5))
31 else if (!strncasecmp(*i,
"abstract=", 9))
33 else if (!strncasecmp(*i,
"tmpdir=", 7))
39 return WvString(
"unix:%s/dbus.sock", tmpdir);
41 else if (!strncasecmp(dbus_moniker,
"tcp:", 4))
44 l.
split(dbus_moniker+4,
",");
45 for (i.rewind(); i.next(); )
47 if (!strncasecmp(*i,
"family=", 7))
49 else if (!strncasecmp(*i,
"host=", 5))
51 else if (!strncasecmp(*i,
"port=", 5))
55 return WvString(
"tcp:%s:%s", host, port);
59 return WvString(
"tcp:0.0.0.0:%s", port);
70 if (!strcasecmp(s,
"starter"))
72 WvString startbus(getenv(
"DBUS_STARTER_ADDRESS"));
74 return IWvStream::create(translate(startbus));
77 WvString starttype(getenv(
"DBUS_STARTER_BUS_TYPE"));
78 if (!!starttype && !strcasecmp(starttype,
"system"))
80 else if (!!starttype && !strcasecmp(starttype,
"session"))
85 if (!strcasecmp(s,
"system"))
92 WvString bus(getenv(
"DBUS_SYSTEM_BUS_ADDRESS"));
94 return IWvStream::create(translate(bus));
97 if (!strcasecmp(s,
"session"))
99 WvString bus(getenv(
"DBUS_SESSION_BUS_ADDRESS"));
101 return IWvStream::create(translate(bus));
104 return IWvStream::create(translate(s));
116 ++conncount),
WvLog::Debug5),
119 init(_auth, _client);
127 ++conncount),
WvLog::Debug5),
130 log(
"Connecting to '%s'\n", moniker);
131 init(_auth, _client);
135void WvDBusConn::init(
IWvDBusAuth *_auth,
bool _client)
137 log(
"Initializing.\n");
140 authorized = in_post_select =
false;
141 if (!client) set_uniquename(
WvString(
":%s.0", conncount));
158 log(
"Shutting down.\n");
160 log(
"Error was: %s\n", errstr());
185 uint32_t flags = (DBUS_NAME_FLAG_ALLOW_REPLACEMENT |
186 DBUS_NAME_FLAG_REPLACE_EXISTING);
187 WvDBusMsg msg(
"org.freedesktop.DBus",
"/org/freedesktop/DBus",
188 "org.freedesktop.DBus",
"RequestName");
190 send(msg, onreply, msec_timeout);
199 log(
" >> %s\n", msg);
203 log(
" .> %s\n", msg);
204 return msg.get_serial();
213 add_pending(msg, onreply, msec_timeout);
227 { reply =
new WvDBusMsg(msg);
return true; }
232 wv::function<
void(uint32_t)> serial_cb)
236 send(msg, wv::bind(&xxReplyWaiter::reply_wait, &rw, _1),
239 serial_cb(msg.get_serial());
240 while (!rw.reply &&
isok())
245 "while waiting for reply.",
252void WvDBusConn::out(WvStringParm s)
259const char *WvDBusConn::in()
268void WvDBusConn::send_hello()
270 WvDBusMsg msg(
"org.freedesktop.DBus",
"/org/freedesktop/DBus",
271 "org.freedesktop.DBus",
"Hello");
272 send(msg, wv::bind(&WvDBusConn::_registered,
this, _1));
273 WvDBusMsg msg2(
"org.freedesktop.DBus",
"/org/freedesktop/DBus",
274 "org.freedesktop.DBus",
"AddMatch");
275 msg2.append(
"type='signal'");
280void WvDBusConn::set_uniquename(WvStringParm s)
284 log(
"Assigned name '%s'\n", s);
286 log.app = WvString(
"DBus %s%s", client ?
"" :
"s",
uniquename());
290void WvDBusConn::try_auth()
292 bool done = auth->authorize(*
this);
296 if (out_queue.used())
298 log(
" >> (sending enqueued messages)\n");
309 callbacks.append(
new CallbackInfo(pri, cb, cookie),
true);
316 CallbackInfoList::Iter i(callbacks);
317 for (i.rewind(); i.next(); )
318 if (i->cookie == cookie)
323int WvDBusConn::priority_order(
const CallbackInfo *a,
const CallbackInfo *b)
325 return a->pri - b->pri;
333 uint32_t rserial = msg.get_replyserial();
336 Pending *p = pending[rserial];
346 CallbackInfoList::Sorter i(callbacks, priority_order);
347 for (i.rewind(); i.next(); )
349 bool handled = i->cb(msg);
350 if (handled)
return true;
357WvDBusClientAuth::WvDBusClientAuth()
359 sent_request =
false;
363wvuid_t WvDBusClientAuth::get_uid()
375 c.out(
"AUTH EXTERNAL %s\r\n\0",
WvHexEncoder().strflushstr(uid));
380 const char *line = c.in();
383 if (!strncasecmp(line,
"OK ", 3))
388 else if (!strncasecmp(line,
"ERROR ", 6))
389 c.
seterr(
"Auth failed: %s", line);
391 c.
seterr(
"Unknown AUTH response: '%s'", line);
399time_t WvDBusConn::mintimeout_msec()
402 PendingDict::Iter i(pending);
403 for (i.rewind(); i.next(); )
405 if (!when || when > i->valid_until)
406 when = i->valid_until;
410 else if (when <= wvstime())
413 return msecdiff(when, wvstime());
417bool WvDBusConn::post_select(SelectInfo &si)
420 if (si.inherit_request)
return ready;
422 if (in_post_select)
return false;
423 in_post_select =
true;
425 if (!authorized && ready)
430 WvTime now = wvstime();
431 PendingDict::Iter i(pending);
432 for (i.rewind(); i.next(); )
434 if (now > i->valid_until)
436 log(
"Expiring %s\n", i->msg);
437 expire_pending(i.ptr());
443 if (authorized && ready)
453 size_t amt = needed - in_queue.used();
467 alarm(mintimeout_msec());
468 in_post_select =
false;
475 return !out_queue.used() && pending.isempty();
479void WvDBusConn::expire_pending(Pending *p)
483 WvDBusCallback xcb(p->cb);
486 "Timed out while waiting for reply");
492void WvDBusConn::cancel_pending(uint32_t serial)
494 Pending *p = pending[serial];
497 WvDBusCallback xcb(p->cb);
498 WvDBusMsg msg(p->msg);
500 WvDBusError e(msg, DBUS_ERROR_FAILED,
501 "Canceled while waiting for reply");
507void WvDBusConn::add_pending(
WvDBusMsg &msg, WvDBusCallback cb,
510 uint32_t serial = msg.get_serial();
513 cancel_pending(serial);
514 pending.add(
new Pending(msg, cb, msec_timeout),
true);
515 alarm(mintimeout_msec());
519bool WvDBusConn::_registered(
WvDBusMsg &msg)
521 WvDBusMsg::Iter i(msg);
522 _uniquename = i.getnext().get_str();
523 set_uniquename(_uniquename);
The basic interface which is included by all other XPLC interfaces and objects.
virtual bool authorize(WvDBusConn &c)
Main action callback.
virtual void close()
Close the underlying stream.
virtual bool filter_func(WvDBusMsg &msg)
Called by for each received message.
virtual ~WvDBusConn()
Release this connection.
WvDBusConn(WvStringParm moniker, IWvDBusAuth *_auth=NULL, bool _client=true)
Creates a new dbus connection using the given WvStreams moniker.
CallbackPri
The priority level of a callback registration.
WvDBusMsg send_and_wait(WvDBusMsg msg, time_t msec_timeout=WVDBUS_DEFAULT_TIMEOUT, wv::function< void(uint32_t)> serial_cb=0)
Send a message on the bus and wait for a reply to come in, returning the message when it does.
void request_name(WvStringParm name, const WvDBusCallback &onreply=0, time_t msec_timeout=WVDBUS_DEFAULT_TIMEOUT)
Request the given service name on DBus.
bool isidle()
Returns true if there are no outstanding messages that have not received (or timed out) their reply.
uint32_t send(WvDBusMsg msg)
Send a message on the bus, not expecting any reply.
void add_callback(CallbackPri pri, WvDBusCallback cb, void *cookie=NULL)
Adds a callback to the connection: all received messages will be sent to all callbacks to look at and...
void del_callback(void *cookie)
Delete all callbacks that have the given cookie.
WvString uniquename() const
Return this connection's unique name on the bus, assigned by the server at connect time.
WvDBusMsg & append(const char *s)
The following methods are designed to allow appending various arguments to the message.
static WvDBusMsg * demarshal(WvBuf &buf)
Demarshals a new WvDBusMsg from a buffer containing its binary DBus protocol representation.
static size_t demarshal_bytes_needed(WvBuf &buf)
Given a buffer containing what might be the header of a DBus message, checks how many bytes need to b...
void marshal(WvBuf &buf)
Locks this message, encodes it in DBus binary protocol format, and adds it to the given buffer.
A WvLog stream accepts log messages from applications and forwards them to all registered WvLogRcv's.
A type-safe version of WvMonikerBase that lets you provide create functions for object types other th...
virtual void close()
Close this stream.
WvStreamClone(IWvStream *_cloned=NULL)
Constructs the stream, then calls setclone(_cloned).
virtual bool isok() const
return true if the stream is actually usable right now
virtual bool post_select(SelectInfo &si)
post_select() is called after select(), and returns true if this object is now ready.
virtual int geterr() const
If isok() is false, return the system error number corresponding to the error, -1 for a special error...
void delay_output(bool is_delayed)
force write() to always buffer output.
void alarm(time_t msec_timeout)
set an alarm, ie.
virtual size_t write(const void *buf, size_t count)
Write data to the stream.
void runonce(time_t msec_timeout=-1)
Exactly the same as: if (select(timeout)) callback();.
char * getline(time_t wait_msec=0, char separator='\n', int readahead=1024)
Read up to one line of data from the stream and return a pointer to the internal buffer containing th...
virtual size_t read(void *buf, size_t count)
read a data block on the stream.
time_t alarm_remaining()
return the number of milliseconds remaining before the alarm will go off; -1 means no alarm is set (i...
virtual void seterr(int _errnum)
Override seterr() from WvError so that it auto-closes the stream.
This is a WvList of WvStrings, and is a really handy way to parse strings.
void split(WvStringParm s, const char *splitchars=" \t\r\n", int limit=0)
split s and form a list ignoring splitchars (except at beginning and end) ie.
WvString is an implementation of a simple and efficient printable-string class.
Based on (and interchangeable with) struct timeval.
char * trim_string(char *string)
Trims whitespace from the beginning and end of the character string, including carriage return / line...