11 #include "wvdbusconn.h"
12 #include "wvmoniker.h"
14 #undef interface // windows
15 #include <dbus/dbus.h>
18 static 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));
110 static int conncount;
116 ++conncount),
WvLog::Debug5),
119 init(_auth, _client);
127 ++conncount),
WvLog::Debug5),
130 log(
"Connecting to '%s'\n", moniker);
131 init(_auth, _client);
135 void 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.",
252 void WvDBusConn::out(WvStringParm s)
259 const char *WvDBusConn::in()
268 void 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'");
280 void WvDBusConn::set_uniquename(WvStringParm s)
284 log(
"Assigned name '%s'\n", s);
290 void WvDBusConn::try_auth()
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)
323 int 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;
357 WvDBusClientAuth::WvDBusClientAuth()
359 sent_request =
false;
363 wvuid_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);
399 time_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());
417 bool 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)
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();
479 void WvDBusConn::expire_pending(Pending *p)
483 WvDBusCallback xcb(p->cb);
486 "Timed out while waiting for reply");
492 void WvDBusConn::cancel_pending(uint32_t serial)
494 Pending *p = pending[serial];
497 WvDBusCallback xcb(p->cb);
501 "Canceled while waiting for reply");
507 void 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());
519 bool WvDBusConn::_registered(
WvDBusMsg &msg)
522 _uniquename = i.getnext().get_str();
523 set_uniquename(_uniquename);
void delay_output(bool is_delayed)
force write() to always buffer output.
static WvDBusMsg * demarshal(WvBuf &buf)
Demarshals a new WvDBusMsg from a buffer containing its binary DBus protocol representation.
time_t alarm_remaining()
return the number of milliseconds remaining before the alarm will go off; -1 means no alarm is set (i...
WvDBusConn(WvStringParm moniker, IWvDBusAuth *_auth=NULL, bool _client=true)
Creates a new dbus connection using the given WvStreams moniker.
void runonce(time_t msec_timeout=-1)
Exactly the same as: if (select(timeout)) callback();.
virtual size_t write(const void *buf, size_t count)
Write data to the stream.
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...
uint32_t send(WvDBusMsg msg)
Send a message on the bus, not expecting any reply.
void del_callback(void *cookie)
Delete all callbacks that have the given cookie.
virtual void close()
Close this stream.
WvDBusMsg & append(const char *s)
The following methods are designed to allow appending various arguments to the message.
void request_name(WvStringParm name, const WvDBusCallback &onreply=0, time_t msec_timeout=WVDBUS_DEFAULT_TIMEOUT)
Request the given service name on DBus.
Based on (and interchangeable with) struct timeval.
virtual bool authorize(WvDBusConn &c)
Main action callback.
char * trim_string(char *string)
Trims whitespace from the beginning and end of the character string, including carriage return / line...
WvString uniquename() const
Return this connection's unique name on the bus, assigned by the server at connect time.
void marshal(WvBuf &buf)
Locks this message, encodes it in DBus binary protocol format, and adds it to the given buffer.
virtual void seterr(int _errnum)
Override seterr() from WvError so that it auto-closes the stream.
WvString is an implementation of a simple and efficient printable-string class.
A WvLog stream accepts log messages from applications and forwards them to all registered WvLogRcv's.
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...
A type-safe version of WvMonikerBase that lets you provide create functions for object types other th...
virtual void close()
Close the underlying stream.
bool isidle()
Returns true if there are no outstanding messages that have not received (or timed out) their reply.
virtual size_t read(void *buf, size_t count)
read a data block on the stream.
WvStreamClone simply forwards all requests to the "cloned" stream.
void alarm(time_t msec_timeout)
set an alarm, ie.
virtual ~WvDBusConn()
Release this connection.
virtual int geterr() const
If isok() is false, return the system error number corresponding to the error, -1 for a special error...
virtual bool isok() const
return true if the stream is actually usable right now
virtual bool filter_func(WvDBusMsg &msg)
Called by for each received message.
size_t used() const
Returns the number of elements in the buffer currently available for reading.
This is a WvList of WvStrings, and is a really handy way to parse strings.
virtual bool authorize(WvDBusConn &c)=0
Main action callback.
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.
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.
virtual bool post_select(SelectInfo &si)
post_select() is called after ::select(), and returns true if this object is now ready.
CallbackPri
The priority level of a callback registration.
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...